Merge fx-team to m-c. a=merge
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 28 May 2015 10:08:37 -0400
changeset 278348 f986e55c4e0b41c6b50bd74d287614b564d7895f
parent 278307 6bf6fe1c6516366db3acf1b561a7ed451194c2bd (current diff)
parent 278347 9bd7e886acd38c872ecaeb600dab8561a1adc1c4 (diff)
child 278358 5d39762b0831d10caa84114ddfd597e0a1774ab5
child 278435 270238a6ca275c9014bd556593d5ff0609035bcb
child 278492 8225a3b75df6ec1fecc43ab66855320c6fd924e9
push id897
push userjlund@mozilla.com
push dateMon, 14 Sep 2015 18:56:12 +0000
treeherdermozilla-release@9411e2d2b214 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone41.0a1
first release with
nightly linux32
f986e55c4e0b / 41.0a1 / 20150529030205 / files
nightly linux64
f986e55c4e0b / 41.0a1 / 20150529030205 / files
nightly mac
f986e55c4e0b / 41.0a1 / 20150529030205 / files
nightly win32
f986e55c4e0b / 41.0a1 / 20150529030205 / files
nightly win64
f986e55c4e0b / 41.0a1 / 20150529030205 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge fx-team to m-c. a=merge
browser/app/profile/firefox.js
browser/devtools/performance/modules/widgets/waterfall.js
browser/themes/shared/search/search-indicator-add-engine.png
browser/themes/shared/search/search-indicator-add-engine@2x.png
toolkit/devtools/server/docs/lazy-actor-modules.md
toolkit/themes/windows/global/icons/close-lunaBlue.png
toolkit/themes/windows/global/icons/close-lunaOlive.png
toolkit/themes/windows/global/icons/close-lunaSilver.png
toolkit/themes/windows/global/icons/close-win8.png
--- a/accessible/tests/mochitest/states/a11y.ini
+++ b/accessible/tests/mochitest/states/a11y.ini
@@ -10,16 +10,17 @@ support-files =
 [test_aria.xul]
 [test_aria_imgmap.html]
 [test_aria_widgetitems.html]
 [test_buttons.html]
 [test_controls.html]
 [test_controls.xul]
 [test_doc.html]
 [test_doc_busy.html]
+skip-if = os == 'mac' && os_version == '10.6'
 [test_docarticle.html]
 [test_editablebody.html]
 [test_expandable.xul]
 [test_frames.html]
 [test_inputs.html]
 [test_link.html]
 [test_popup.xul]
 [test_selects.html]
--- a/addon-sdk/source/lib/sdk/tabs/helpers.js
+++ b/addon-sdk/source/lib/sdk/tabs/helpers.js
@@ -22,11 +22,11 @@ function getTabForWindow(win) {
 
   return modelFor(tab);
 }
 exports.getTabForWindow = getTabForWindow;
 
 exports.getTabForRawTab = modelFor;
 
 function getTabForBrowser(browser) {
-  return modelFor(getRawTabForBrowser(browser));
+  return modelFor(getRawTabForBrowser(browser)) || null;
 }
 exports.getTabForBrowser = getTabForBrowser;
--- a/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
+++ b/addon-sdk/source/lib/sdk/tabs/tab-fennec.js
@@ -4,24 +4,25 @@
 'use strict';
 
 const { Cc, Ci } = require('chrome');
 const { Class } = require('../core/heritage');
 const { tabNS, rawTabNS } = require('./namespace');
 const { EventTarget } = require('../event/target');
 const { activateTab, getTabTitle, setTabTitle, closeTab, getTabURL,
         getTabContentWindow, getTabForBrowser, setTabURL, getOwnerWindow,
-        getTabContentDocument, getTabContentType, getTabId } = require('./utils');
+        getTabContentDocument, getTabContentType, getTabId, isTab } = require('./utils');
 const { emit } = require('../event/core');
 const { isPrivate } = require('../private-browsing/utils');
 const { isWindowPrivate } = require('../window/utils');
 const { when: unload } = require('../system/unload');
 const { BLANK } = require('../content/thumbnail');
 const { viewFor } = require('../view/core');
 const { EVENTS } = require('./events');
+const { modelFor } = require('../model/core');
 
 const ERR_FENNEC_MSG = 'This method is not yet supported by Fennec';
 
 const Tab = Class({
   extends: EventTarget,
   initialize: function initialize(options) {
     options = options.tab ? options : { tab: options };
     let tab = options.tab;
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -173,16 +173,19 @@ pref("app.update.mode", 1);
 pref("app.update.silent", false);
 
 // If set to true, the hamburger button will show badges for update events.
 #ifndef RELEASE_BUILD
 pref("app.update.badge", true);
 #else
 pref("app.update.badge", false);
 #endif
+// Give the user x seconds to reboot before showing a badge on the hamburger
+// button. default=4 days
+pref("app.update.badgeWaitTime", 345600);
 
 // If set to true, the Update Service will apply updates in the background
 // when it finishes downloading them.
 pref("app.update.staging.enabled", true);
 
 // Update service URL:
 pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
 // app.update.url.manual is in branding section
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2358,21 +2358,29 @@ function BrowserViewSourceOfDocument(aAr
     args = { browser, outerWindowID, URL };
   } else {
     args = aArgsOrDocument;
   }
 
   let inTab = Services.prefs.getBoolPref("view_source.tab");
   if (inTab) {
     let viewSourceURL = `view-source:${args.URL}`;
-    let tab = gBrowser.loadOneTab(viewSourceURL, {
+    let tabBrowser = gBrowser;
+    // In the case of sidebars and chat windows, gBrowser is defined but null,
+    // because no #content element exists.  For these cases, we need to find
+    // the most recent browser window.
+    if (!tabBrowser) {
+      let browserWindow = RecentWindow.getMostRecentBrowserWindow();
+      tabBrowser = browserWindow.gBrowser;
+    }
+    let tab = tabBrowser.loadOneTab(viewSourceURL, {
       relatedToCurrent: true,
       inBackground: false
     });
-    args.viewSourceBrowser = gBrowser.getBrowserForTab(tab);
+    args.viewSourceBrowser = tabBrowser.getBrowserForTab(tab);
     top.gViewSourceUtils.viewSourceInBrowser(args);
   } else {
     top.gViewSourceUtils.viewSource(args);
   }
 }
 
 /**
  * Opens the View Source dialog for the source loaded in the root
@@ -2556,28 +2564,37 @@ function PageProxyClickHandler(aEvent)
 {
   if (aEvent.button == 1 && gPrefService.getBoolPref("middlemouse.paste"))
     middleMousePaste(aEvent);
 }
 
 // Setup the hamburger button badges for updates, if enabled.
 let gMenuButtonUpdateBadge = {
   enabled: false,
+  badgeWaitTime: 0,
+  timer: null,
 
   init: function () {
     try {
       this.enabled = Services.prefs.getBoolPref("app.update.badge");
     } catch (e) {}
     if (this.enabled) {
+      try {
+        this.badgeWaitTime = Services.prefs.getIntPref("app.update.badgeWaitTime");
+      } catch (e) {
+        this.badgeWaitTime = 345600; // 4 days
+      }
       PanelUI.menuButton.classList.add("badged-button");
       Services.obs.addObserver(this, "update-staged", false);
     }
   },
 
   uninit: function () {
+    if (this.timer)
+      this.timer.cancel();
     if (this.enabled) {
       Services.obs.removeObserver(this, "update-staged");
       PanelUI.panel.removeEventListener("popupshowing", this, true);
       this.enabled = false;
     }
   },
 
   onMenuPanelCommand: function(event) {
@@ -2611,56 +2628,63 @@ let gMenuButtonUpdateBadge = {
     let stringId;
 
     // Update the UI when the background updater is finished.
     switch (status) {
       case STATE_APPLIED:
       case STATE_APPLIED_SVC:
       case STATE_PENDING:
       case STATE_PENDING_SVC:
-        // If the update is successfully applied, or if the updater has fallen back
-        // to non-staged updates, add a badge to the hamburger menu to indicate an
-        // update will be applied once the browser restarts.
-        PanelUI.menuButton.setAttribute("update-status", "succeeded");
-
-        let brandBundle = document.getElementById("bundle_brand");
-        let brandShortName = brandBundle.getString("brandShortName");
-        stringId = "appmenu.restartNeeded.description";
-        updateButtonText = gNavigatorBundle.getFormattedString(stringId,
-                                                               [brandShortName]);
-
-        updateButton.setAttribute("label", updateButtonText);
-        updateButton.setAttribute("update-status", "succeeded");
-        updateButton.hidden = false;
-
-        PanelUI.panel.addEventListener("popupshowing", this, true);
-
+        if (this.timer) {
+          return;
+        }
+        // Give the user badgeWaitTime seconds to react before prompting.
+        this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+        this.timer.initWithCallback(this, this.badgeWaitTime * 1000,
+                                    this.timer.TYPE_ONE_SHOT);
+        // The timer callback will call uninit() when it completes.
         break;
       case STATE_FAILED:
         // Background update has failed, let's show the UI responsible for
         // prompting the user to update manually.
         PanelUI.menuButton.setAttribute("update-status", "failed");
         PanelUI.menuButton.setAttribute("badge", "!");
 
         stringId = "appmenu.updateFailed.description";
         updateButtonText = gNavigatorBundle.getString(stringId);
 
         updateButton.setAttribute("label", updateButtonText);
         updateButton.setAttribute("update-status", "failed");
         updateButton.hidden = false;
 
         PanelUI.panel.addEventListener("popupshowing", this, true);
 
+        this.uninit();
         break;
-      case STATE_DOWNLOADING:
-        // We've fallen back to downloading the full update because the partial
-        // update failed to get staged in the background. Therefore we need to keep
-        // our observer.
-        return;
-    }
+    }
+  },
+
+  notify: function () {
+    // If the update is successfully applied, or if the updater has fallen back
+    // to non-staged updates, add a badge to the hamburger menu to indicate an
+    // update will be applied once the browser restarts.
+    PanelUI.menuButton.setAttribute("update-status", "succeeded");
+
+    let brandBundle = document.getElementById("bundle_brand");
+    let brandShortName = brandBundle.getString("brandShortName");
+    stringId = "appmenu.restartNeeded.description";
+    updateButtonText = gNavigatorBundle.getFormattedString(stringId,
+                                                           [brandShortName]);
+
+    let updateButton = document.getElementById("PanelUI-update-status");
+    updateButton.setAttribute("label", updateButtonText);
+    updateButton.setAttribute("update-status", "succeeded");
+    updateButton.hidden = false;
+
+    PanelUI.panel.addEventListener("popupshowing", this, true);
     this.uninit();
   },
 
   handleEvent: function(e) {
     if (e.type === "popupshowing") {
       PanelUI.menuButton.removeAttribute("badge");
       PanelUI.panel.removeEventListener("popupshowing", this, true);
     }
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -1002,21 +1002,29 @@ nsContextMenu.prototype = {
       reference = focusedWindow.getSelection();
     else if (aContext == "mathml")
       reference = this.target;
     else
       throw "not reached";
 
     let inTab = Services.prefs.getBoolPref("view_source.tab");
     if (inTab) {
-      let tab = gBrowser.loadOneTab("about:blank", {
+      let tabBrowser = gBrowser;
+      // In the case of sidebars and chat windows, gBrowser is defined but null,
+      // because no #content element exists.  For these cases, we need to find
+      // the most recent browser window.
+      if (!tabBrowser) {
+        let browserWindow = RecentWindow.getMostRecentBrowserWindow();
+        tabBrowser = browserWindow.gBrowser;
+      }
+      let tab = tabBrowser.loadOneTab("about:blank", {
         relatedToCurrent: true,
         inBackground: false
       });
-      let viewSourceBrowser = gBrowser.getBrowserForTab(tab);
+      let viewSourceBrowser = tabBrowser.getBrowserForTab(tab);
       if (aContext == "selection") {
         top.gViewSourceUtils
            .viewSourceFromSelectionInBrowser(reference, viewSourceBrowser);
       } else {
         top.gViewSourceUtils
            .viewSourceFromFragmentInBrowser(reference, aContext,
                                             viewSourceBrowser);
       }
--- a/browser/components/loop/content/js/conversation.js
+++ b/browser/components/loop/content/js/conversation.js
@@ -158,17 +158,17 @@ loop.conversation = (function(mozL10n) {
       dispatcher.dispatch(new sharedActions.WindowUnload());
     });
 
     React.render(React.createElement(AppControllerView, {
       roomStore: roomStore, 
       dispatcher: dispatcher, 
       mozLoop: navigator.mozLoop}), document.querySelector("#main"));
 
-    document.body.setAttribute("dir", mozL10n.getDirection());
+    document.body.setAttribute("dir", "rtl");//mozL10n.getDirection());
     document.body.setAttribute("platform", loop.shared.utils.getPlatform());
 
     dispatcher.dispatch(new sharedActions.GetWindowData({
       windowId: windowId
     }));
   }
 
   return {
--- a/browser/components/loop/content/js/conversation.jsx
+++ b/browser/components/loop/content/js/conversation.jsx
@@ -158,17 +158,17 @@ loop.conversation = (function(mozL10n) {
       dispatcher.dispatch(new sharedActions.WindowUnload());
     });
 
     React.render(<AppControllerView
       roomStore={roomStore}
       dispatcher={dispatcher}
       mozLoop={navigator.mozLoop} />, document.querySelector("#main"));
 
-    document.body.setAttribute("dir", mozL10n.getDirection());
+    document.body.setAttribute("dir", "rtl");//mozL10n.getDirection());
     document.body.setAttribute("platform", loop.shared.utils.getPlatform());
 
     dispatcher.dispatch(new sharedActions.GetWindowData({
       windowId: windowId
     }));
   }
 
   return {
--- a/browser/components/loop/content/js/roomStore.js
+++ b/browser/components/loop/content/js/roomStore.js
@@ -86,16 +86,17 @@ loop.store = loop.store || {};
       "deleteRoom",
       "deleteRoomError",
       "emailRoomUrl",
       "getAllRooms",
       "getAllRoomsError",
       "openRoom",
       "shareRoomUrl",
       "updateRoomContext",
+      "updateRoomContextDone",
       "updateRoomContextError",
       "updateRoomList"
     ],
 
     initialize: function(options) {
       if (!options.mozLoop) {
         throw new Error("Missing option mozLoop");
       }
@@ -110,17 +111,18 @@ loop.store = loop.store || {};
     },
 
     getInitialStoreState: function() {
       return {
         activeRoom: this.activeRoomStore ? this.activeRoomStore.getStoreState() : {},
         error: null,
         pendingCreation: false,
         pendingInitialRetrieval: false,
-        rooms: []
+        rooms: [],
+        savingContext: false
       };
     },
 
     /**
      * Registers mozLoop.rooms events.
      */
     startListeningToRoomEvents: function() {
       // Rooms event registration
@@ -468,16 +470,17 @@ loop.store = loop.store || {};
     },
 
     /**
      * Updates the context data attached to a room.
      *
      * @param {sharedActions.UpdateRoomContext} actionData
      */
     updateRoomContext: function(actionData) {
+      this.setStoreState({ savingContext: true });
       this._mozLoop.rooms.get(actionData.roomToken, function(err, room) {
         if (err) {
           this.dispatchAction(new sharedActions.UpdateRoomContextError({
             error: err
           }));
           return;
         }
 
@@ -515,33 +518,43 @@ loop.store = loop.store || {};
         }
         // TODO: there currently is no clear UX defined on what to do when all
         // context data was cleared, e.g. when diff.removed contains all the
         // context properties. Until then, we can't deal with context removal here.
 
         // When no properties have been set on the roomData object, there's nothing
         // to save.
         if (!Object.getOwnPropertyNames(roomData).length) {
+          this.dispatchAction(new sharedActions.UpdateRoomContextDone());
           return;
         }
 
         this.setStoreState({error: null});
         this._mozLoop.rooms.update(actionData.roomToken, roomData,
           function(err, data) {
-            if (err) {
-              this.dispatchAction(new sharedActions.UpdateRoomContextError({
-                error: err
-              }));
-            }
+            var action = err ?
+              new sharedActions.UpdateRoomContextError({ error: err }) :
+              new sharedActions.UpdateRoomContextDone();
+            this.dispatchAction(action);
           }.bind(this));
       }.bind(this));
     },
 
     /**
+     * Handles the updateRoomContextDone action.
+     */
+    updateRoomContextDone: function() {
+      this.setStoreState({ savingContext: false });
+    },
+
+    /**
      * Updating the context data attached to a room error.
      *
      * @param {sharedActions.UpdateRoomContextError} actionData
      */
     updateRoomContextError: function(actionData) {
-      this.setStoreState({error: actionData.error});
+      this.setStoreState({
+        error: actionData.error,
+        savingContext: false
+      });
     }
   });
 })(document.mozL10n || navigator.mozL10n);
--- a/browser/components/loop/content/js/roomViews.js
+++ b/browser/components/loop/content/js/roomViews.js
@@ -24,16 +24,18 @@ loop.roomViews = (function(mozL10n) {
       roomStore: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
     },
 
     componentWillMount: function() {
       this.listenTo(this.props.roomStore, "change:activeRoom",
                     this._onActiveRoomStateChanged);
       this.listenTo(this.props.roomStore, "change:error",
                     this._onRoomError);
+      this.listenTo(this.props.roomStore, "change:savingContext",
+                    this._onRoomSavingContext);
     },
 
     componentWillUnmount: function() {
       this.stopListening(this.props.roomStore);
     },
 
     _onActiveRoomStateChanged: function() {
       // Only update the state if we're mounted, to avoid the problem where
@@ -48,21 +50,31 @@ loop.roomViews = (function(mozL10n) {
       // Only update the state if we're mounted, to avoid the problem where
       // stopListening doesn't nuke the active listeners during a event
       // processing.
       if (this.isMounted()) {
         this.setState({error: this.props.roomStore.getStoreState("error")});
       }
     },
 
+    _onRoomSavingContext: function() {
+      // Only update the state if we're mounted, to avoid the problem where
+      // stopListening doesn't nuke the active listeners during a event
+      // processing.
+      if (this.isMounted()) {
+        this.setState({savingContext: this.props.roomStore.getStoreState("savingContext")});
+      }
+    },
+
     getInitialState: function() {
       var storeState = this.props.roomStore.getStoreState("activeRoom");
       return _.extend({
         // Used by the UI showcase.
-        roomState: this.props.roomState || storeState.roomState
+        roomState: this.props.roomState || storeState.roomState,
+        savingContext: false
       }, storeState);
     }
   };
 
   var SocialShareDropdown = React.createClass({displayName: "SocialShareDropdown",
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       roomUrl: React.PropTypes.string,
@@ -169,16 +181,17 @@ loop.roomViews = (function(mozL10n) {
     mixins: [sharedMixins.DropdownMenuMixin(".room-invitation-overlay")],
 
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       error: React.PropTypes.object,
       mozLoop: React.PropTypes.object.isRequired,
       // This data is supplied by the activeRoomStore.
       roomData: React.PropTypes.object.isRequired,
+      savingContext: React.PropTypes.bool,
       show: React.PropTypes.bool.isRequired,
       showContext: React.PropTypes.bool.isRequired
     },
 
     getInitialState: function() {
       return {
         copiedUrl: false,
         editMode: false,
@@ -238,17 +251,21 @@ loop.roomViews = (function(mozL10n) {
             React.createElement("p", {className: cx({hide: this.state.editMode})}, 
               mozL10n.get("invite_header_text")
             ), 
             React.createElement("a", {className: cx({hide: !canAddContext, "room-invitation-addcontext": true}), 
                onClick: this.handleAddContextClick}, 
               mozL10n.get("context_add_some_label")
             )
           ), 
-          React.createElement("div", {className: "btn-group call-action-group"}, 
+          React.createElement("div", {className: cx({
+            "btn-group": true,
+            "call-action-group": true,
+            hide: this.state.editMode
+          })}, 
             React.createElement("button", {className: "btn btn-info btn-email", 
                     onClick: this.handleEmailButtonClick}, 
               mozL10n.get("email_link_button")
             ), 
             React.createElement("button", {className: "btn btn-info btn-copy", 
                     onClick: this.handleCopyButtonClick}, 
               this.state.copiedUrl ? mozL10n.get("copied_url_button") :
                                       mozL10n.get("copy_url_button2")
@@ -265,16 +282,17 @@ loop.roomViews = (function(mozL10n) {
             show: this.state.showMenu, 
             socialShareButtonAvailable: this.props.socialShareButtonAvailable, 
             socialShareProviders: this.props.socialShareProviders, 
             ref: "menu"}), 
           React.createElement(DesktopRoomContextView, {
             dispatcher: this.props.dispatcher, 
             editMode: this.state.editMode, 
             error: this.props.error, 
+            savingContext: this.props.savingContext, 
             mozLoop: this.props.mozLoop, 
             onEditModeChange: this.handleEditModeChange, 
             roomData: this.props.roomData, 
             show: this.props.showContext || this.state.editMode})
         )
       );
     }
   });
@@ -285,16 +303,17 @@ loop.roomViews = (function(mozL10n) {
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       editMode: React.PropTypes.bool,
       error: React.PropTypes.object,
       mozLoop: React.PropTypes.object.isRequired,
       onEditModeChange: React.PropTypes.func,
       // This data is supplied by the activeRoomStore.
       roomData: React.PropTypes.object.isRequired,
+      savingContext: React.PropTypes.bool.isRequired,
       show: React.PropTypes.bool.isRequired
     },
 
     componentWillReceiveProps: function(nextProps) {
       var newState = {};
       // When the 'show' prop is changed from outside this component, we do need
       // to update the state.
       if (("show" in nextProps) && nextProps.show !== this.props.show) {
@@ -374,16 +393,28 @@ loop.roomViews = (function(mozL10n) {
         if (this.props.onEditModeChange) {
           this.props.onEditModeChange(false);
         }
         return;
       }
       this.setState({ show: false });
     },
 
+    handleContextClick: function(event) {
+      event.stopPropagation();
+      event.preventDefault();
+
+      var url = this._getURL();
+      if (!url || !url.location) {
+        return;
+      }
+
+      this.props.mozLoop.openURL(url.location);
+    },
+
     handleEditClick: function(event) {
       event.preventDefault();
 
       this.setState({ editMode: true });
       if (this.props.onEditModeChange) {
         this.props.onEditModeChange(true);
       }
     },
@@ -392,23 +423,23 @@ loop.roomViews = (function(mozL10n) {
       if (state.checked) {
         // The checkbox was checked, prefill the fields with the values available
         // in `availableContext`.
         var context = this.state.availableContext;
         this.setState({
           newRoomURL: context.url,
           newRoomDescription: context.description,
           newRoomThumbnail: context.previewImage
-        }, this.handleFormSubmit);
+        });
       } else {
         this.setState({
           newRoomURL: "",
           newRoomDescription: "",
           newRoomThumbnail: ""
-        }, this.handleFormSubmit);
+        });
       }
     },
 
     handleFormSubmit: function(event) {
       event && event.preventDefault();
 
       this.props.dispatcher.dispatch(new sharedActions.UpdateRoomContext({
         roomToken: this.props.roomData.roomToken,
@@ -464,96 +495,100 @@ loop.roomViews = (function(mozL10n) {
       if (!this.state.show && !this.state.editMode) {
         return null;
       }
 
       var url = this._getURL();
       var thumbnail = url && url.thumbnail || "";
       var urlDescription = url && url.description || "";
       var location = url && url.location || "";
-      var checkboxLabel = null;
       var locationData = null;
       if (location) {
         locationData = checkboxLabel = sharedUtils.formatURL(location);
       }
       if (!checkboxLabel) {
         try {
           checkboxLabel = sharedUtils.formatURL((this.state.availableContext ?
             this.state.availableContext.url : ""));
         } catch (ex) {}
       }
 
       var cx = React.addons.classSet;
       if (this.state.editMode) {
+        var availableContext = this.state.availableContext;
+        // The checkbox shows as checked when there's already context data
+        // attached to this room.
+        var checked = !!urlDescription;
+        var checkboxLabel = urlDescription || (availableContext && availableContext.url ?
+          availableContext.description : "");
+
         return (
-          React.createElement("div", {className: "room-context"}, 
-            React.createElement("div", {className: "room-context-content"}, 
-              React.createElement("p", {className: cx({"error": !!this.props.error,
-                                "error-display-area": true})}, 
-                mozL10n.get("rooms_change_failed_label")
-              ), 
-              React.createElement("div", {className: "room-context-label"}, mozL10n.get("context_inroom_label")), 
-              React.createElement(sharedViews.Checkbox, {
-                checked: !!url, 
-                disabled: !!url || !checkboxLabel, 
-                label: mozL10n.get("context_edit_activate_label", {
-                  title: checkboxLabel ? checkboxLabel.hostname : ""
-                }), 
-                onChange: this.handleCheckboxChange, 
-                value: location}), 
-              React.createElement("form", {onSubmit: this.handleFormSubmit}, 
-                React.createElement("textarea", {rows: "2", type: "text", className: "room-context-name", 
-                  onBlur: this.handleFormSubmit, 
-                  onKeyDown: this.handleTextareaKeyDown, 
-                  placeholder: mozL10n.get("context_edit_name_placeholder"), 
-                  valueLink: this.linkState("newRoomName")}), 
-                React.createElement("input", {type: "text", className: "room-context-url", 
-                  onBlur: this.handleFormSubmit, 
-                  onKeyDown: this.handleTextareaKeyDown, 
-                  placeholder: "https://", 
-                  valueLink: this.linkState("newRoomURL")}), 
-                React.createElement("textarea", {rows: "4", type: "text", className: "room-context-comments", 
-                  onBlur: this.handleFormSubmit, 
-                  onKeyDown: this.handleTextareaKeyDown, 
-                  placeholder: mozL10n.get("context_edit_comments_placeholder"), 
-                  valueLink: this.linkState("newRoomDescription")})
-              ), 
-              React.createElement("button", {className: "room-context-btn-close", 
-                      onClick: this.handleCloseClick, 
-                      title: mozL10n.get("cancel_button")})
-            )
+          React.createElement("div", {className: "room-context editMode"}, 
+            React.createElement("p", {className: cx({"error": !!this.props.error,
+                              "error-display-area": true})}, 
+              mozL10n.get("rooms_change_failed_label")
+            ), 
+            React.createElement("div", {className: "room-context-label"}, mozL10n.get("context_inroom_label")), 
+            React.createElement(sharedViews.Checkbox, {
+              additionalClass: cx({ hide: !checkboxLabel }), 
+              checked: checked, 
+              disabled: checked, 
+              label: checkboxLabel, 
+              onChange: this.handleCheckboxChange, 
+              value: location}), 
+            React.createElement("form", {onSubmit: this.handleFormSubmit}, 
+              React.createElement("input", {type: "text", className: "room-context-name", 
+                onKeyDown: this.handleTextareaKeyDown, 
+                placeholder: mozL10n.get("context_edit_name_placeholder"), 
+                valueLink: this.linkState("newRoomName")}), 
+              React.createElement("input", {type: "text", className: "room-context-url", 
+                onKeyDown: this.handleTextareaKeyDown, 
+                placeholder: "https://", 
+                disabled: availableContext && availableContext.url === this.state.newRoomURL, 
+                valueLink: this.linkState("newRoomURL")}), 
+              React.createElement("textarea", {rows: "3", type: "text", className: "room-context-comments", 
+                onKeyDown: this.handleTextareaKeyDown, 
+                placeholder: mozL10n.get("context_edit_comments_placeholder"), 
+                valueLink: this.linkState("newRoomDescription")})
+            ), 
+            React.createElement("button", {className: "btn btn-info", 
+                    disabled: this.props.savingContext, 
+                    onClick: this.handleFormSubmit}, 
+              mozL10n.get("context_save_label")
+            ), 
+            React.createElement("button", {className: "room-context-btn-close", 
+                    onClick: this.handleCloseClick, 
+                    title: mozL10n.get("cancel_button")})
           )
         );
       }
 
       if (!locationData) {
         return null;
       }
 
       return (
         React.createElement("div", {className: "room-context"}, 
-          React.createElement("img", {className: "room-context-thumbnail", src: thumbnail}), 
-          React.createElement("div", {className: "room-context-content"}, 
-            React.createElement("div", {className: "room-context-label"}, mozL10n.get("context_inroom_label")), 
+          React.createElement("div", {className: "room-context-label"}, mozL10n.get("context_inroom_label")), 
+          React.createElement("div", {className: "room-context-content", 
+               onClick: this.handleContextClick}, 
+            React.createElement("img", {className: "room-context-thumbnail", src: thumbnail}), 
             React.createElement("div", {className: "room-context-description", 
-                 title: urlDescription}, this._truncate(urlDescription)), 
-            React.createElement("a", {className: "room-context-url", 
-               href: location, 
-               target: "_blank", 
-               title: locationData.location}, locationData.hostname), 
-            this.props.roomData.roomDescription ?
-              React.createElement("div", {className: "room-context-comment"}, this.props.roomData.roomDescription) :
-              null, 
-            React.createElement("button", {className: "room-context-btn-close", 
-                    onClick: this.handleCloseClick, 
-                    title: mozL10n.get("context_hide_tooltip")}), 
-            React.createElement("button", {className: "room-context-btn-edit", 
-                    onClick: this.handleEditClick, 
-                    title: mozL10n.get("context_edit_tooltip")})
-          )
+                 title: urlDescription}, 
+              this._truncate(urlDescription), 
+              React.createElement("a", {className: "room-context-url", 
+                 title: locationData.location}, locationData.hostname)
+            )
+          ), 
+          React.createElement("button", {className: "room-context-btn-close", 
+                  onClick: this.handleCloseClick, 
+                  title: mozL10n.get("context_hide_tooltip")}), 
+          React.createElement("button", {className: "room-context-btn-edit", 
+                  onClick: this.handleEditClick, 
+                  title: mozL10n.get("context_edit_tooltip")})
         )
       );
     }
   });
 
   /**
    * Desktop room conversation view.
    */
@@ -666,16 +701,17 @@ loop.roomViews = (function(mozL10n) {
           return (
             React.createElement("div", {className: "room-conversation-wrapper"}, 
               React.createElement(sharedViews.TextChatView, {dispatcher: this.props.dispatcher}), 
               React.createElement(DesktopRoomInvitationView, {
                 dispatcher: this.props.dispatcher, 
                 error: this.state.error, 
                 mozLoop: this.props.mozLoop, 
                 roomData: roomData, 
+                savingContext: this.state.savingContext, 
                 show: shouldRenderInvitationOverlay, 
                 showContext: shouldRenderContextView, 
                 socialShareButtonAvailable: this.state.socialShareButtonAvailable, 
                 socialShareProviders: this.state.socialShareProviders}), 
               React.createElement("div", {className: "video-layout-wrapper"}, 
                 React.createElement("div", {className: "conversation room-conversation"}, 
                   React.createElement("div", {className: "media nested"}, 
                     React.createElement("div", {className: "video_wrapper remote_wrapper"}, 
@@ -691,16 +727,17 @@ loop.roomViews = (function(mozL10n) {
                     publishStream: this.publishStream, 
                     hangup: this.leaveRoom, 
                     screenShare: screenShareData})
                 )
               ), 
               React.createElement(DesktopRoomContextView, {
                 dispatcher: this.props.dispatcher, 
                 error: this.state.error, 
+                savingContext: this.state.savingContext, 
                 mozLoop: this.props.mozLoop, 
                 roomData: roomData, 
                 show: !shouldRenderInvitationOverlay && shouldRenderContextView})
             )
           );
         }
       }
     }
--- a/browser/components/loop/content/js/roomViews.jsx
+++ b/browser/components/loop/content/js/roomViews.jsx
@@ -24,16 +24,18 @@ loop.roomViews = (function(mozL10n) {
       roomStore: React.PropTypes.instanceOf(loop.store.RoomStore).isRequired
     },
 
     componentWillMount: function() {
       this.listenTo(this.props.roomStore, "change:activeRoom",
                     this._onActiveRoomStateChanged);
       this.listenTo(this.props.roomStore, "change:error",
                     this._onRoomError);
+      this.listenTo(this.props.roomStore, "change:savingContext",
+                    this._onRoomSavingContext);
     },
 
     componentWillUnmount: function() {
       this.stopListening(this.props.roomStore);
     },
 
     _onActiveRoomStateChanged: function() {
       // Only update the state if we're mounted, to avoid the problem where
@@ -48,21 +50,31 @@ loop.roomViews = (function(mozL10n) {
       // Only update the state if we're mounted, to avoid the problem where
       // stopListening doesn't nuke the active listeners during a event
       // processing.
       if (this.isMounted()) {
         this.setState({error: this.props.roomStore.getStoreState("error")});
       }
     },
 
+    _onRoomSavingContext: function() {
+      // Only update the state if we're mounted, to avoid the problem where
+      // stopListening doesn't nuke the active listeners during a event
+      // processing.
+      if (this.isMounted()) {
+        this.setState({savingContext: this.props.roomStore.getStoreState("savingContext")});
+      }
+    },
+
     getInitialState: function() {
       var storeState = this.props.roomStore.getStoreState("activeRoom");
       return _.extend({
         // Used by the UI showcase.
-        roomState: this.props.roomState || storeState.roomState
+        roomState: this.props.roomState || storeState.roomState,
+        savingContext: false
       }, storeState);
     }
   };
 
   var SocialShareDropdown = React.createClass({
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       roomUrl: React.PropTypes.string,
@@ -169,16 +181,17 @@ loop.roomViews = (function(mozL10n) {
     mixins: [sharedMixins.DropdownMenuMixin(".room-invitation-overlay")],
 
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       error: React.PropTypes.object,
       mozLoop: React.PropTypes.object.isRequired,
       // This data is supplied by the activeRoomStore.
       roomData: React.PropTypes.object.isRequired,
+      savingContext: React.PropTypes.bool,
       show: React.PropTypes.bool.isRequired,
       showContext: React.PropTypes.bool.isRequired
     },
 
     getInitialState: function() {
       return {
         copiedUrl: false,
         editMode: false,
@@ -238,17 +251,21 @@ loop.roomViews = (function(mozL10n) {
             <p className={cx({hide: this.state.editMode})}>
               {mozL10n.get("invite_header_text")}
             </p>
             <a className={cx({hide: !canAddContext, "room-invitation-addcontext": true})}
                onClick={this.handleAddContextClick}>
               {mozL10n.get("context_add_some_label")}
             </a>
           </div>
-          <div className="btn-group call-action-group">
+          <div className={cx({
+            "btn-group": true,
+            "call-action-group": true,
+            hide: this.state.editMode
+          })}>
             <button className="btn btn-info btn-email"
                     onClick={this.handleEmailButtonClick}>
               {mozL10n.get("email_link_button")}
             </button>
             <button className="btn btn-info btn-copy"
                     onClick={this.handleCopyButtonClick}>
               {this.state.copiedUrl ? mozL10n.get("copied_url_button") :
                                       mozL10n.get("copy_url_button2")}
@@ -265,16 +282,17 @@ loop.roomViews = (function(mozL10n) {
             show={this.state.showMenu}
             socialShareButtonAvailable={this.props.socialShareButtonAvailable}
             socialShareProviders={this.props.socialShareProviders}
             ref="menu" />
           <DesktopRoomContextView
             dispatcher={this.props.dispatcher}
             editMode={this.state.editMode}
             error={this.props.error}
+            savingContext={this.props.savingContext}
             mozLoop={this.props.mozLoop}
             onEditModeChange={this.handleEditModeChange}
             roomData={this.props.roomData}
             show={this.props.showContext || this.state.editMode} />
         </div>
       );
     }
   });
@@ -285,16 +303,17 @@ loop.roomViews = (function(mozL10n) {
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       editMode: React.PropTypes.bool,
       error: React.PropTypes.object,
       mozLoop: React.PropTypes.object.isRequired,
       onEditModeChange: React.PropTypes.func,
       // This data is supplied by the activeRoomStore.
       roomData: React.PropTypes.object.isRequired,
+      savingContext: React.PropTypes.bool.isRequired,
       show: React.PropTypes.bool.isRequired
     },
 
     componentWillReceiveProps: function(nextProps) {
       var newState = {};
       // When the 'show' prop is changed from outside this component, we do need
       // to update the state.
       if (("show" in nextProps) && nextProps.show !== this.props.show) {
@@ -374,16 +393,28 @@ loop.roomViews = (function(mozL10n) {
         if (this.props.onEditModeChange) {
           this.props.onEditModeChange(false);
         }
         return;
       }
       this.setState({ show: false });
     },
 
+    handleContextClick: function(event) {
+      event.stopPropagation();
+      event.preventDefault();
+
+      var url = this._getURL();
+      if (!url || !url.location) {
+        return;
+      }
+
+      this.props.mozLoop.openURL(url.location);
+    },
+
     handleEditClick: function(event) {
       event.preventDefault();
 
       this.setState({ editMode: true });
       if (this.props.onEditModeChange) {
         this.props.onEditModeChange(true);
       }
     },
@@ -392,23 +423,23 @@ loop.roomViews = (function(mozL10n) {
       if (state.checked) {
         // The checkbox was checked, prefill the fields with the values available
         // in `availableContext`.
         var context = this.state.availableContext;
         this.setState({
           newRoomURL: context.url,
           newRoomDescription: context.description,
           newRoomThumbnail: context.previewImage
-        }, this.handleFormSubmit);
+        });
       } else {
         this.setState({
           newRoomURL: "",
           newRoomDescription: "",
           newRoomThumbnail: ""
-        }, this.handleFormSubmit);
+        });
       }
     },
 
     handleFormSubmit: function(event) {
       event && event.preventDefault();
 
       this.props.dispatcher.dispatch(new sharedActions.UpdateRoomContext({
         roomToken: this.props.roomData.roomToken,
@@ -464,96 +495,100 @@ loop.roomViews = (function(mozL10n) {
       if (!this.state.show && !this.state.editMode) {
         return null;
       }
 
       var url = this._getURL();
       var thumbnail = url && url.thumbnail || "";
       var urlDescription = url && url.description || "";
       var location = url && url.location || "";
-      var checkboxLabel = null;
       var locationData = null;
       if (location) {
         locationData = checkboxLabel = sharedUtils.formatURL(location);
       }
       if (!checkboxLabel) {
         try {
           checkboxLabel = sharedUtils.formatURL((this.state.availableContext ?
             this.state.availableContext.url : ""));
         } catch (ex) {}
       }
 
       var cx = React.addons.classSet;
       if (this.state.editMode) {
+        var availableContext = this.state.availableContext;
+        // The checkbox shows as checked when there's already context data
+        // attached to this room.
+        var checked = !!urlDescription;
+        var checkboxLabel = urlDescription || (availableContext && availableContext.url ?
+          availableContext.description : "");
+
         return (
-          <div className="room-context">
-            <div className="room-context-content">
-              <p className={cx({"error": !!this.props.error,
-                                "error-display-area": true})}>
-                {mozL10n.get("rooms_change_failed_label")}
-              </p>
-              <div className="room-context-label">{mozL10n.get("context_inroom_label")}</div>
-              <sharedViews.Checkbox
-                checked={!!url}
-                disabled={!!url || !checkboxLabel}
-                label={mozL10n.get("context_edit_activate_label", {
-                  title: checkboxLabel ? checkboxLabel.hostname : ""
-                })}
-                onChange={this.handleCheckboxChange}
-                value={location} />
-              <form onSubmit={this.handleFormSubmit}>
-                <textarea rows="2" type="text" className="room-context-name"
-                  onBlur={this.handleFormSubmit}
-                  onKeyDown={this.handleTextareaKeyDown}
-                  placeholder={mozL10n.get("context_edit_name_placeholder")}
-                  valueLink={this.linkState("newRoomName")} />
-                <input type="text" className="room-context-url"
-                  onBlur={this.handleFormSubmit}
-                  onKeyDown={this.handleTextareaKeyDown}
-                  placeholder="https://"
-                  valueLink={this.linkState("newRoomURL")} />
-                <textarea rows="4" type="text" className="room-context-comments"
-                  onBlur={this.handleFormSubmit}
-                  onKeyDown={this.handleTextareaKeyDown}
-                  placeholder={mozL10n.get("context_edit_comments_placeholder")}
-                  valueLink={this.linkState("newRoomDescription")} />
-              </form>
-              <button className="room-context-btn-close"
-                      onClick={this.handleCloseClick}
-                      title={mozL10n.get("cancel_button")}/>
-            </div>
+          <div className="room-context editMode">
+            <p className={cx({"error": !!this.props.error,
+                              "error-display-area": true})}>
+              {mozL10n.get("rooms_change_failed_label")}
+            </p>
+            <div className="room-context-label">{mozL10n.get("context_inroom_label")}</div>
+            <sharedViews.Checkbox
+              additionalClass={cx({ hide: !checkboxLabel })}
+              checked={checked}
+              disabled={checked}
+              label={checkboxLabel}
+              onChange={this.handleCheckboxChange}
+              value={location} />
+            <form onSubmit={this.handleFormSubmit}>
+              <input type="text" className="room-context-name"
+                onKeyDown={this.handleTextareaKeyDown}
+                placeholder={mozL10n.get("context_edit_name_placeholder")}
+                valueLink={this.linkState("newRoomName")} />
+              <input type="text" className="room-context-url"
+                onKeyDown={this.handleTextareaKeyDown}
+                placeholder="https://"
+                disabled={availableContext && availableContext.url === this.state.newRoomURL}
+                valueLink={this.linkState("newRoomURL")} />
+              <textarea rows="3" type="text" className="room-context-comments"
+                onKeyDown={this.handleTextareaKeyDown}
+                placeholder={mozL10n.get("context_edit_comments_placeholder")}
+                valueLink={this.linkState("newRoomDescription")} />
+            </form>
+            <button className="btn btn-info"
+                    disabled={this.props.savingContext}
+                    onClick={this.handleFormSubmit}>
+              {mozL10n.get("context_save_label")}
+            </button>
+            <button className="room-context-btn-close"
+                    onClick={this.handleCloseClick}
+                    title={mozL10n.get("cancel_button")}/>
           </div>
         );
       }
 
       if (!locationData) {
         return null;
       }
 
       return (
         <div className="room-context">
-          <img className="room-context-thumbnail" src={thumbnail}/>
-          <div className="room-context-content">
-            <div className="room-context-label">{mozL10n.get("context_inroom_label")}</div>
+          <div className="room-context-label">{mozL10n.get("context_inroom_label")}</div>
+          <div className="room-context-content"
+               onClick={this.handleContextClick}>
+            <img className="room-context-thumbnail" src={thumbnail}/>
             <div className="room-context-description"
-                 title={urlDescription}>{this._truncate(urlDescription)}</div>
-            <a className="room-context-url"
-               href={location}
-               target="_blank"
-               title={locationData.location}>{locationData.hostname}</a>
-            {this.props.roomData.roomDescription ?
-              <div className="room-context-comment">{this.props.roomData.roomDescription}</div> :
-              null}
-            <button className="room-context-btn-close"
-                    onClick={this.handleCloseClick}
-                    title={mozL10n.get("context_hide_tooltip")}/>
-            <button className="room-context-btn-edit"
-                    onClick={this.handleEditClick}
-                    title={mozL10n.get("context_edit_tooltip")}/>
+                 title={urlDescription}>
+              {this._truncate(urlDescription)}
+              <a className="room-context-url"
+                 title={locationData.location}>{locationData.hostname}</a>
+            </div>
           </div>
+          <button className="room-context-btn-close"
+                  onClick={this.handleCloseClick}
+                  title={mozL10n.get("context_hide_tooltip")}/>
+          <button className="room-context-btn-edit"
+                  onClick={this.handleEditClick}
+                  title={mozL10n.get("context_edit_tooltip")}/>
         </div>
       );
     }
   });
 
   /**
    * Desktop room conversation view.
    */
@@ -666,16 +701,17 @@ loop.roomViews = (function(mozL10n) {
           return (
             <div className="room-conversation-wrapper">
               <sharedViews.TextChatView dispatcher={this.props.dispatcher} />
               <DesktopRoomInvitationView
                 dispatcher={this.props.dispatcher}
                 error={this.state.error}
                 mozLoop={this.props.mozLoop}
                 roomData={roomData}
+                savingContext={this.state.savingContext}
                 show={shouldRenderInvitationOverlay}
                 showContext={shouldRenderContextView}
                 socialShareButtonAvailable={this.state.socialShareButtonAvailable}
                 socialShareProviders={this.state.socialShareProviders} />
               <div className="video-layout-wrapper">
                 <div className="conversation room-conversation">
                   <div className="media nested">
                     <div className="video_wrapper remote_wrapper">
@@ -691,16 +727,17 @@ loop.roomViews = (function(mozL10n) {
                     publishStream={this.publishStream}
                     hangup={this.leaveRoom}
                     screenShare={screenShareData} />
                 </div>
               </div>
               <DesktopRoomContextView
                 dispatcher={this.props.dispatcher}
                 error={this.state.error}
+                savingContext={this.state.savingContext}
                 mozLoop={this.props.mozLoop}
                 roomData={roomData}
                 show={!shouldRenderInvitationOverlay && shouldRenderContextView} />
             </div>
           );
         }
       }
     }
--- a/browser/components/loop/content/shared/css/conversation.css
+++ b/browser/components/loop/content/shared/css/conversation.css
@@ -308,17 +308,18 @@
 }
 
 .call-action-group {
   display: flex;
   padding: 2.5em 4px 0 4px;
   width: 100%;
 }
 
-.call-action-group > .btn {
+.call-action-group > .btn,
+.room-context > .btn {
   min-height: 26px;
   border-radius: 2px;
   margin: 0 4px;
   min-width: 64px;
 }
 
 .call-action-group .btn-group-chevron,
 .call-action-group .btn-group {
@@ -1000,157 +1001,198 @@ body[dir=rtl] .share-service-dropdown .s
   padding: .5rem;
   max-height: 400px;
   position: absolute;
   left: 0;
   bottom: 0;
   width: 100%;
   font-size: .9em;
   display: flex;
-  flex-flow: row nowrap;
+  flex-flow: column nowrap;
   align-content: flex-start;
   align-items: flex-start;
   overflow-x: hidden;
   overflow-y: auto;
+  /* Make the context view float atop the video elements. */
+  z-index: 2;
+}
+
+.room-context.editMode {
+  /* Stretch to the maximum available space whilst not covering the conversation
+     toolbar (26px). */
+  height: calc(100% - 26px);
 }
 
 .room-invitation-overlay .room-context {
   position: relative;
   left: auto;
   bottom: auto;
   flex: 0 1 auto;
 }
 
+.room-invitation-overlay .room-context.editMode {
+  height: 100%;
+}
+
+.room-context-content {
+  flex: 1 1 auto;
+  text-align: start;
+  display: flex;
+  flex-flow: row nowrap;
+  font-size: .9em;
+}
+
 .room-context-thumbnail {
-  width: 16px;
+  /* 16px icon size + 3px border width. */
+  width: 19px;
+  max-height: 19px;
+  border: 3px solid #fff;
+  border-radius: 3px;
+  background-color: #fff;
   -moz-margin-end: 1ch;
-  margin-bottom: 1em;
-  order: 1;
   flex: 0 1 auto;
 }
 
 .room-context-thumbnail[src=""] {
   display: none;
 }
 
-.room-context-content {
-  order: 2;
-  flex: 1 1 auto;
-  text-align: start;
-}
-
-.room-context-content > .error-display-area.error {
+.room-context > .error-display-area.error {
   display: block;
   background-color: rgba(215,67,69,.8);
   border-radius: 3px;
   padding: .5em;
 }
 
-.room-context-content > .error-display-area {
+.room-context > .error-display-area {
   display: none;
 }
 
-.room-context-content > .error-display-area.error {
+.room-context > .error-display-area.error {
   margin: 1em 0 .5em 0;
   text-align: center;
   text-shadow: 1px 1px 0 rgba(0,0,0,.3);
 }
 
-.room-context-content > .checkbox-wrapper {
+.room-context > .checkbox-wrapper {
   margin-bottom: .5em;
 }
 
 .room-context-label {
   margin-bottom: 1em;
 }
 
-.room-context-label,
 .room-context-description,
-.room-context-content > .checkbox-wrapper > label {
+.room-context > .checkbox-wrapper > label {
   color: #fff;
 }
 
 .room-context-comment {
   color: #707070;
 }
 
 .room-context-description,
 .room-context-comment {
   word-wrap: break-word;
 }
 
-.room-context-url {
-  color: #59A1D7;
+:not(input).room-context-url {
+  color: #0095dd;
   font-style: italic;
   text-decoration: none;
-  margin-bottom: 1em;
+  display: block;
+  cursor: pointer;
 }
 
 .room-context-url:hover {
   text-decoration: underline;
 }
 
-.room-context-content > form > textarea,
-.room-context-content > form > input[type="text"] {
+.room-context > form {
+  width: 100%;
+}
+
+.room-context > form > textarea,
+.room-context > form > input[type="text"] {
   display: block;
   background: rgba(0,0,0,.5);
-  color: #fff;
   font-family: "Helvetica Neue", Arial, sans;
-  font-size: 1em;
-  border: 1px solid #999;
+  border: 1px solid rgba(255,255,255,.2);
   width: 100%;
-  padding: .2em .4em;
+  padding: .5em;
   border-radius: 3px;
   resize: none;
+  color: #fff;
+}
+
+.room-context > form > textarea {
+  font-size: 1em;
+}
+
+.room-context > form > input:not([disabled]).room-context-url {
+  color: #0095dd;
 }
 
-.room-context-content > form > textarea:not(:last-of-type),
-.room-context-content > form > input[type="text"] {
+.room-context > form > input[disabled] {
+  background-color: rgba(255,255,255,.2);
+  color: rgba(255,255,255,.4);
+}
+
+.room-context > form > textarea:not(:last-of-type),
+.room-context > form > input[type="text"] {
   margin: 0 0 .5em 0;
 }
 
+.room-context > .btn {
+  margin: .5em 0 0;
+  font-size: 1.1em;
+  padding: 0 .5em;
+  align-self: flex-end;
+}
+
 .room-context-btn-close,
 .room-context-btn-edit {
   position: absolute;
-  right: 5px;
-  top: 5px;
+  right: 8px;
+  /* 8px offset + 2px border-top */
+  top: 10px;
   width: 8px;
   height: 8px;
   background-color: transparent;
-  background-image: url("../img/icons-10x10.svg#close");
+  background-image: url("../img/icons-10x10.svg#close-darkergrey");
   background-size: 8px 8px;
   background-repeat: no-repeat;
   border: 0;
   padding: 0;
   cursor: pointer;
 }
 
 .room-context-btn-edit {
-  right: 18px;
-  background-image: url("../img/icons-10x10.svg#edit");
+  right: 20px;
+  background-image: url("../img/icons-10x10.svg#edit-darkergrey");
 }
 
 .room-context-btn-edit:hover,
 .room-context-btn-edit:hover:active {
   background-image: url("../img/icons-10x10.svg#edit-active");
 }
 
 .room-context-btn-close:hover,
 .room-context-btn-close:hover:active {
   background-image: url("../img/icons-10x10.svg#close-active");
 }
 
 body[dir=rtl] .room-context-btn-close,
 body[dir=rtl] .room-context-btn-edit {
   right: auto;
-  left: 5px;
+  left: 8px;
 }
 
 body[dir=rtl] .room-context-btn-edit {
-  left: 18px;
+  left: 20px;
 }
 
 /* Standalone rooms */
 
 .standalone .room-conversation-wrapper {
   position: relative;
   height: 100%;
   background: #000;
--- a/browser/components/loop/content/shared/img/icons-10x10.svg
+++ b/browser/components/loop/content/shared/img/icons-10x10.svg
@@ -17,33 +17,38 @@
       fill: #0095dd;
     }
     use[id$="-white"] {
       fill: rgba(255,255,255,0.8);
     }
     use[id$="-disabled"] {
       fill: rgba(255,255,255,0.4);
     }
+    use[id$="-darkergrey"] {
+      fill: #999;
+    }
   </style>
   <defs>
     <polygon id="close-shape" points="10,1.717 8.336,0.049 5.024,3.369 1.663,0 0,1.668 3.36,5.037 0.098,8.307 1.762,9.975 5.025,6.705 8.311,10 9.975,8.332 6.688,5.037"/>
     <path id="dropdown-shape" fill-rule="evenodd" d="M9,3L4.984,7L1,3H9z"/>
     <polygon id="expand-shape" points="10,0 4.838,0 6.506,1.669 0,8.175 1.825,10 8.331,3.494 10,5.162"/>
     <path id="edit-shape" d="M5.493,1.762l2.745,2.745L2.745,10H0V7.255L5.493,1.762z M2.397,9.155l0.601-0.601L1.446,7.002L0.845,7.603 V8.31H1.69v0.845H2.397z M5.849,3.028c0-0.096-0.048-0.144-0.146-0.144c-0.044,0-0.081,0.015-0.112,0.046L2.014,6.508 C1.983,6.538,1.968,6.577,1.968,6.619c0,0.098,0.048,0.146,0.144,0.146c0.044,0,0.081-0.015,0.112-0.046l3.579-3.577 C5.834,3.111,5.849,3.073,5.849,3.028z M10,2.395c0,0.233-0.081,0.431-0.245,0.595L8.66,4.085L5.915,1.34L7.01,0.25 C7.168,0.083,7.366,0,7.605,0c0.233,0,0.433,0.083,0.601,0.25l1.55,1.544C9.919,1.966,10,2.166,10,2.395z"/>
     <rect id="minimize-shape" y="3.6" width="10" height="2.8"/>
   </defs>
   <use id="close" xlink:href="#close-shape"/>
   <use id="close-active" xlink:href="#close-shape"/>
   <use id="close-disabled" xlink:href="#close-shape"/>
+  <use id="close-darkergrey" xlink:href="#close-shape"/>
   <use id="dropdown" xlink:href="#dropdown-shape"/>
   <use id="dropdown-white" xlink:href="#dropdown-shape"/>
   <use id="dropdown-active" xlink:href="#dropdown-shape"/>
   <use id="dropdown-disabled" xlink:href="#dropdown-shape"/>
   <use id="edit" xlink:href="#edit-shape"/>
   <use id="edit-active" xlink:href="#edit-shape"/>
   <use id="edit-disabled" xlink:href="#edit-shape"/>
+  <use id="edit-darkergrey" xlink:href="#edit-shape"/>
   <use id="expand" xlink:href="#expand-shape"/>
   <use id="expand-active" xlink:href="#expand-shape"/>
   <use id="expand-disabled" xlink:href="#expand-shape"/>
   <use id="minimize" xlink:href="#minimize-shape"/>
   <use id="minimize-active" xlink:href="#minimize-shape"/>
   <use id="minimize-disabled" xlink:href="#minimize-shape"/>
 </svg>
--- a/browser/components/loop/content/shared/js/actions.js
+++ b/browser/components/loop/content/shared/js/actions.js
@@ -364,16 +364,22 @@ loop.shared.actions = (function() {
     /**
      * Updating the context data attached to a room error.
      */
     UpdateRoomContextError: Action.define("updateRoomContextError", {
       error: [Error, Object]
     }),
 
     /**
+     * Updating the context data attached to a room finished successfully.
+     */
+    UpdateRoomContextDone: Action.define("updateRoomContextDone", {
+    }),
+
+    /**
      * Copy a room url into the user's clipboard.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     CopyRoomUrl: Action.define("copyRoomUrl", {
       roomUrl: String
     }),
 
     /**
--- a/browser/components/loop/content/shared/js/activeRoomStore.js
+++ b/browser/components/loop/content/shared/js/activeRoomStore.js
@@ -430,17 +430,17 @@ loop.store.ActiveRoomStore = (function()
       // Reset the failure reason if necessary.
       if (this.getStoreState().failureReason) {
         this.setStoreState({failureReason: undefined});
       }
 
       // XXX Ideally we'd do this check before joining a room, but we're waiting
       // for the UX for that. See bug 1166824. In the meantime this gives us
       // additional information for analysis.
-      loop.shared.utils.hasAudioDevices(function(hasAudio) {
+      loop.shared.utils.hasAudioOrVideoDevices(function(hasAudio) {
         if (hasAudio) {
           // MEDIA_WAIT causes the views to dispatch sharedActions.SetupStreamElements,
           // which in turn starts the sdk obtaining the device permission.
           this.setStoreState({roomState: ROOM_STATES.MEDIA_WAIT});
         } else {
           this.dispatchAction(new sharedActions.ConnectionFailure({
             reason: FAILURE_DETAILS.NO_MEDIA
           }));
--- a/browser/components/loop/content/shared/js/utils.js
+++ b/browser/components/loop/content/shared/js/utils.js
@@ -307,34 +307,34 @@ var inChrome = typeof Components != "und
   };
 
   /**
    * Determines if the user has any audio devices installed.
    *
    * @param  {Function} callback Called with a boolean which is true if there
    *                             are audio devices present.
    */
-  function hasAudioDevices(callback) {
+  function hasAudioOrVideoDevices(callback) {
     // mediaDevices is the official API for the spec.
     if ("mediaDevices" in rootNavigator) {
       rootNavigator.mediaDevices.enumerateDevices().then(function(result) {
         function checkForInput(device) {
-          return device.kind === "audioinput";
+          return device.kind === "audioinput" || device.kind === "videoinput";
         }
 
         callback(result.some(checkForInput));
       }).catch(function() {
         callback(false);
       });
     // MediaStreamTrack is the older version of the API, implemented originally
     // by Google Chrome.
     } else if ("MediaStreamTrack" in rootObject) {
       rootObject.MediaStreamTrack.getSources(function(result) {
         function checkForInput(device) {
-          return device.kind === "audio";
+          return device.kind === "audio" || device.kind === "video";
         }
 
         callback(result.some(checkForInput));
       });
     } else {
       // We don't know, so assume true.
       callback(true);
     }
@@ -740,17 +740,17 @@ var inChrome = typeof Components != "und
     getOS: getOS,
     getOSVersion: getOSVersion,
     getPlatform: getPlatform,
     isChrome: isChrome,
     isFirefox: isFirefox,
     isFirefoxOS: isFirefoxOS,
     isOpera: isOpera,
     getUnsupportedPlatform: getUnsupportedPlatform,
-    hasAudioDevices: hasAudioDevices,
+    hasAudioOrVideoDevices: hasAudioOrVideoDevices,
     locationData: locationData,
     atob: atob,
     btoa: btoa,
     strToUint8Array: strToUint8Array,
     Uint8ArrayToStr: Uint8ArrayToStr,
     objectDiff: objectDiff,
     stripFalsyValues: stripFalsyValues
   };
--- a/browser/components/loop/content/shared/js/views.js
+++ b/browser/components/loop/content/shared/js/views.js
@@ -658,17 +658,17 @@ loop.shared.views = (function(_, l10n) {
         disabled: this.props.disabled
       };
       var checkClasses = {
         checkbox: true,
         checked: this.state.checked,
         disabled: this.props.disabled
       };
       if (this.props.additionalClass) {
-        checkClasses[this.props.additionalClass] = true;
+        wrapperClasses[this.props.additionalClass] = true;
       }
       return (
         React.createElement("div", {className: cx(wrapperClasses), 
              disabled: this.props.disabled, 
              onClick: this._handleClick}, 
           React.createElement("div", {className: cx(checkClasses)}), 
           this.props.label ?
             React.createElement("label", null, this.props.label) :
--- a/browser/components/loop/content/shared/js/views.jsx
+++ b/browser/components/loop/content/shared/js/views.jsx
@@ -658,17 +658,17 @@ loop.shared.views = (function(_, l10n) {
         disabled: this.props.disabled
       };
       var checkClasses = {
         checkbox: true,
         checked: this.state.checked,
         disabled: this.props.disabled
       };
       if (this.props.additionalClass) {
-        checkClasses[this.props.additionalClass] = true;
+        wrapperClasses[this.props.additionalClass] = true;
       }
       return (
         <div className={cx(wrapperClasses)}
              disabled={this.props.disabled}
              onClick={this._handleClick}>
           <div className={cx(checkClasses)} />
           {this.props.label ?
             <label>{this.props.label}</label> :
--- a/browser/components/loop/test/desktop-local/roomStore_test.js
+++ b/browser/components/loop/test/desktop-local/roomStore_test.js
@@ -639,39 +639,59 @@ describe("loop.store.RoomStore", functio
 
       sinon.assert.calledOnce(fakeMozLoop.rooms.get);
       sinon.assert.calledOnce(fakeMozLoop.rooms.update);
       sinon.assert.calledWith(fakeMozLoop.rooms.update, "42abc", {
         roomName: "silly name"
       });
     });
 
+    it("should flag the the store as saving context", function() {
+      expect(store.getStoreState().savingContext).to.eql(false);
+
+      sandbox.stub(fakeMozLoop.rooms, "update", function(roomToken, roomData, cb) {
+        expect(store.getStoreState().savingContext).to.eql(true);
+        cb();
+      });
+
+      dispatcher.dispatch(new sharedActions.UpdateRoomContext({
+        roomToken: "42abc",
+        newRoomName: "silly name"
+      }));
+
+      expect(store.getStoreState().savingContext).to.eql(false);
+    });
+
     it("should store any update-encountered error", function() {
       var err = new Error("fake");
       sandbox.stub(fakeMozLoop.rooms, "update", function(roomToken, roomData, cb) {
+        expect(store.getStoreState().savingContext).to.eql(true);
         cb(err);
       });
 
       dispatcher.dispatch(new sharedActions.UpdateRoomContext({
         roomToken: "42abc",
         newRoomName: "silly name"
       }));
 
-      expect(store.getStoreState().error).eql(err);
+      var state = store.getStoreState();
+      expect(state.error).eql(err);
+      expect(state.savingContext).to.eql(false);
     });
 
     it("should ensure only submitting a non-empty room name", function() {
       fakeMozLoop.rooms.update = sinon.spy();
 
       dispatcher.dispatch(new sharedActions.UpdateRoomContext({
         roomToken: "42abc",
         newRoomName: " \t  \t "
       }));
 
       sinon.assert.notCalled(fakeMozLoop.rooms.update);
+      expect(store.getStoreState().savingContext).to.eql(false);
     });
 
     it("should save updated context information", function() {
       fakeMozLoop.rooms.update = sinon.spy();
 
       dispatcher.dispatch(new sharedActions.UpdateRoomContext({
         roomToken: "42abc",
         // Room name doesn't need to change.
@@ -718,11 +738,12 @@ describe("loop.store.RoomStore", functio
           // Room name doesn't need to change.
           newRoomName: "sillier name",
           newRoomDescription: "",
           newRoomThumbnail: "",
           newRoomURL: ""
         }));
 
         sinon.assert.notCalled(fakeMozLoop.rooms.update);
+        expect(store.getStoreState().savingContext).to.eql(false);
       });
   });
 });
--- a/browser/components/loop/test/desktop-local/roomViews_test.js
+++ b/browser/components/loop/test/desktop-local/roomViews_test.js
@@ -91,17 +91,17 @@ describe("loop.roomViews", function () {
         render: function() { return React.DOM.div(); }
       });
 
       var testView = TestUtils.renderIntoDocument(
         React.createElement(TestView, {
           roomStore: roomStore
         }));
 
-      var expectedState = _.extend({foo: "bar"},
+      var expectedState = _.extend({foo: "bar", savingContext: false},
         activeRoomStore.getInitialStoreState());
 
       expect(testView.state).eql(expectedState);
     });
 
     it("should listen to store changes", function() {
       var TestView = React.createClass({
         mixins: [loop.roomViews.ActiveRoomStoreMixin],
@@ -671,20 +671,18 @@ describe("loop.roomViews", function () {
             roomContextUrls: [fakeContextURL]
           }
         });
 
         var node = view.getDOMNode();
         expect(node).to.not.eql(null);
         expect(node.querySelector(".room-context-thumbnail").src).to.
           eql(fakeContextURL.thumbnail);
-        expect(node.querySelector(".room-context-description").textContent).to.
-          eql(fakeContextURL.description);
-        expect(node.querySelector(".room-context-comment").textContent).to.
-          eql(view.props.roomData.roomDescription);
+        expect(node.querySelector(".room-context-description").firstChild.textContent).
+          to.eql(fakeContextURL.description);
       });
 
       it("should not render optional data", function() {
         view = mountTestComponent({
           roomData: { roomContextUrls: [fakeContextURL] }
         });
 
         expect(view.getDOMNode().querySelector(".room-context-comment")).to.
@@ -722,22 +720,23 @@ describe("loop.roomViews", function () {
         var node = view.getDOMNode();
         expect(node.querySelector("form")).to.not.eql(null);
         // Check the contents of the form fields.
         expect(node.querySelector(".room-context-name").value).to.eql(roomName);
         expect(node.querySelector(".room-context-url").value).to.eql(fakeContextURL.location);
         expect(node.querySelector(".room-context-comments").value).to.eql(fakeContextURL.description);
       });
 
-      it("should show the checkbox as disabled when no context is available", function() {
+      it("should show the checkbox as disabled when context is already set", function() {
         view = mountTestComponent({
           editMode: true,
           roomData: {
             roomToken: "fakeToken",
-            roomName: "fakeName"
+            roomName: "fakeName",
+            roomContextUrls: [fakeContextURL]
           }
         });
 
         var checkbox = view.getDOMNode().querySelector(".checkbox");
         expect(checkbox.classList.contains("disabled")).to.eql(true);
       });
 
       it("should render the editMode view when the edit button is clicked", function(next) {
@@ -753,23 +752,46 @@ describe("loop.roomViews", function () {
         // Switch to editMode via setting the prop, since we can control that
         // better.
         view.setProps({ editMode: true }, function() {
           // First check if availableContext is set correctly.
           expect(view.state.availableContext).to.not.eql(null);
           expect(view.state.availableContext.previewImage).to.eql(favicon);
 
           var node = view.getDOMNode();
+          expect(node.querySelector(".checkbox-wrapper").classList.contains("disabled")).to.eql(true);
           expect(node.querySelector(".room-context-name").value).to.eql(roomName);
           expect(node.querySelector(".room-context-url").value).to.eql(fakeContextURL.location);
           expect(node.querySelector(".room-context-comments").value).to.eql(fakeContextURL.description);
 
           next();
         });
       });
+
+      it("should hide the checkbox when no context data is stored or available", function(next) {
+        view = mountTestComponent({
+          roomData: {
+            roomToken: "fakeToken",
+            roomName: "Hello, is it me you're looking for?"
+          }
+        });
+
+        // Switch to editMode via setting the prop, since we can control that
+        // better.
+        view.setProps({ editMode: true }, function() {
+          // First check if availableContext is set correctly.
+          expect(view.state.availableContext).to.not.eql(null);
+          expect(view.state.availableContext.previewImage).to.eql(favicon);
+
+          var node = view.getDOMNode();
+          expect(node.querySelector(".checkbox-wrapper").classList.contains("hide")).to.eql(true);
+
+          next();
+        });
+      });
     });
 
     describe("Update Room", function() {
       var roomNameBox;
 
       beforeEach(function() {
         sandbox.stub(dispatcher, "dispatch");
 
@@ -780,23 +802,23 @@ describe("loop.roomViews", function () {
             roomName: "fakeName",
             roomContextUrls: [fakeContextURL]
           }
         });
 
         roomNameBox = view.getDOMNode().querySelector(".room-context-name");
       });
 
-      it("should dispatch a UpdateRoomContext action when the focus is lost",
+      it("should dispatch a UpdateRoomContext action when the save button is clicked",
         function() {
           React.addons.TestUtils.Simulate.change(roomNameBox, { target: {
             value: "reallyFake"
           }});
 
-          React.addons.TestUtils.Simulate.blur(roomNameBox);
+          React.addons.TestUtils.Simulate.click(view.getDOMNode().querySelector(".btn-info"));
 
           sinon.assert.calledOnce(dispatcher.dispatch);
           sinon.assert.calledWithExactly(dispatcher.dispatch,
             new sharedActions.UpdateRoomContext({
               roomToken: "fakeToken",
               newRoomName: "reallyFake",
               newRoomDescription: fakeContextURL.description,
               newRoomURL: fakeContextURL.location,
--- a/browser/components/loop/test/shared/activeRoomStore_test.js
+++ b/browser/components/loop/test/shared/activeRoomStore_test.js
@@ -635,33 +635,33 @@ describe("loop.store.ActiveRoomStore", f
       store.setStoreState({failureReason: "Test"});
 
       store.joinRoom();
 
       expect(store.getStoreState().failureReason).eql(undefined);
     });
 
     it("should set the state to MEDIA_WAIT if media devices are present", function() {
-      sandbox.stub(loop.shared.utils, "hasAudioDevices").callsArgWith(0, true);
+      sandbox.stub(loop.shared.utils, "hasAudioOrVideoDevices").callsArgWith(0, true);
 
       store.joinRoom();
 
       expect(store.getStoreState().roomState).eql(ROOM_STATES.MEDIA_WAIT);
     });
 
     it("should not set the state to MEDIA_WAIT if no media devices are present", function() {
-      sandbox.stub(loop.shared.utils, "hasAudioDevices").callsArgWith(0, false);
+      sandbox.stub(loop.shared.utils, "hasAudioOrVideoDevices").callsArgWith(0, false);
 
       store.joinRoom();
 
       expect(store.getStoreState().roomState).eql(ROOM_STATES.READY);
     });
 
     it("should dispatch `ConnectionFailure` if no media devices are present", function() {
-      sandbox.stub(loop.shared.utils, "hasAudioDevices").callsArgWith(0, false);
+      sandbox.stub(loop.shared.utils, "hasAudioOrVideoDevices").callsArgWith(0, false);
 
       store.joinRoom();
 
       sinon.assert.calledOnce(dispatcher.dispatch);
       sinon.assert.calledWithExactly(dispatcher.dispatch,
         new sharedActions.ConnectionFailure({
           reason: FAILURE_DETAILS.NO_MEDIA
         }));
--- a/browser/components/loop/test/shared/utils_test.js
+++ b/browser/components/loop/test/shared/utils_test.js
@@ -136,17 +136,17 @@ describe("loop.shared.utils", function()
       it("should return the localStorage value", function() {
         localStorage.setItem("test.true", true);
 
         expect(sharedUtils.getBoolPreference("test.true")).eql(true);
       });
     });
   });
 
-  describe("hasAudioDevices", function() {
+  describe("#hasAudioOrVideoDevices", function() {
     var fakeNavigatorObject, fakeWindowObject;
 
     beforeEach(function() {
       fakeNavigatorObject = {
         mediaDevices: {
           enumerateDevices: sinon.stub()
         }
       };
@@ -163,93 +163,126 @@ describe("loop.shared.utils", function()
     afterEach(function() {
       sharedUtils.setRootObjects();
     });
 
     it("should return true if no APIs to detect devices exist", function(done) {
       delete fakeNavigatorObject.mediaDevices;
       delete fakeWindowObject.MediaStreamTrack;
 
-      sharedUtils.hasAudioDevices(function(result) {
+      sharedUtils.hasAudioOrVideoDevices(function(result) {
         expect(result).eql(true);
         done();
       });
     });
 
-    it("should return false if no audio devices exist according to navigator.mediaDevices", function(done) {
+    it("should return false if no audio nor video devices exist according to navigator.mediaDevices", function(done) {
       delete fakeWindowObject.MediaStreamTrack;
 
       fakeNavigatorObject.mediaDevices.enumerateDevices.returns(Promise.resolve([]));
-      sharedUtils.hasAudioDevices(function(result) {
+
+      sharedUtils.hasAudioOrVideoDevices(function(result) {
         try {
           expect(result).eql(false);
           done();
         } catch (ex) {
           done(ex);
         }
       });
     });
 
     it("should return true if audio devices exist according to navigator.mediaDevices", function(done) {
       delete fakeWindowObject.MediaStreamTrack;
 
       fakeNavigatorObject.mediaDevices.enumerateDevices.returns(
         Promise.resolve([{
-          deviceId: "15234",
-          groupId: "",
-          kind: "videoinput",
-          label: ""
-        }, {
           deviceId: "54321",
           groupId: "",
           kind: "audioinput",
           label: ""
         }])
       );
 
-      sharedUtils.hasAudioDevices(function(result) {
+      sharedUtils.hasAudioOrVideoDevices(function(result) {
         try {
           expect(result).eql(true);
           done();
         } catch (ex) {
           done(ex);
         }
       });
     });
 
-    it("should return false if no audio devices exist according to window.MediaStreamTrack", function(done) {
+    it("should return true if video devices exist according to navigator.mediaDevices", function(done) {
+      delete fakeWindowObject.MediaStreamTrack;
+
+      fakeNavigatorObject.mediaDevices.enumerateDevices.returns(
+        Promise.resolve([{
+          deviceId: "15234",
+          groupId: "",
+          kind: "videoinput",
+          label: ""
+        }])
+      );
+
+      sharedUtils.hasAudioOrVideoDevices(function(result) {
+        try {
+          expect(result).eql(true);
+          done();
+        } catch (ex) {
+          done(ex);
+        }
+      });
+    });
+
+    it("should return false if no audio nor video devices exist according to window.MediaStreamTrack", function(done) {
       delete fakeNavigatorObject.mediaDevices;
 
       fakeWindowObject.MediaStreamTrack.getSources.callsArgWith(0, []);
-      sharedUtils.hasAudioDevices(function(result) {
+      sharedUtils.hasAudioOrVideoDevices(function(result) {
         try {
           expect(result).eql(false);
           done();
         } catch (ex) {
           done(ex);
         }
       });
     });
 
     it("should return true if audio devices exist according to window.MediaStreamTrack", function(done) {
       delete fakeNavigatorObject.mediaDevices;
 
       fakeWindowObject.MediaStreamTrack.getSources.callsArgWith(0, [{
         facing: "",
-        id: "15234",
-        kind: "video",
-        label: ""
-      }, {
-        facing: "",
         id: "54321",
         kind: "audio",
         label: ""
       }]);
 
-      sharedUtils.hasAudioDevices(function(result) {
+      sharedUtils.hasAudioOrVideoDevices(function(result) {
+        try {
+          expect(result).eql(true);
+          done();
+        } catch (ex) {
+          done(ex);
+        }
+      });
+    });
+
+    it("should return true if video devices exist according to window.MediaStreamTrack", function(done) {
+      delete fakeNavigatorObject.mediaDevices;
+
+      fakeWindowObject.MediaStreamTrack.getSources.callsArgWith(0, [{
+        facing: "",
+        id: "15234",
+        kind: "video",
+        label: ""
+      }]);
+
+      sharedUtils.hasAudioOrVideoDevices(function(result) {
         try {
           expect(result).eql(true);
           done();
         } catch (ex) {
           done(ex);
         }
       });
     });
new file mode 100644
--- /dev/null
+++ b/browser/devtools/.eslintignore
@@ -0,0 +1,15 @@
+# Ignore d3
+browser/devtools/shared/d3.js
+browser/devtools/webaudioeditor/lib/dagre-d3.js
+
+# Ignore codemirror
+browser/devtools/sourceeditor/codemirror/*.js
+browser/devtools/sourceeditor/codemirror/**/*.js
+
+# Ignore jquery test libs
+browser/devtools/markupview/test/lib_*
+
+# Ignore pre-processed files
+browser/devtools/framework/toolbox-process-window.js
+browser/devtools/performance/system.js
+browser/devtools/webide/webide-prefs.js
new file mode 100644
--- /dev/null
+++ b/browser/devtools/.eslintrc
@@ -0,0 +1,406 @@
+{
+  "env": {
+    "es6": true
+  },
+  "globals": {
+    "Cc": true,
+    "Ci": true,
+    "Components": true,
+    "console": true,
+    "Cr": true,
+    "Cu": true,
+    "devtools": true,
+    "dump": true,
+    "EventEmitter": true,
+    "exports": true,
+    "loader": true,
+    "module": true,
+    "require": true,
+    "Services": true,
+    "Task": true,
+    "XPCOMUtils": true,
+  },
+  "rules": {
+    // These are the rules that have been configured so far to match the
+    // devtools coding style.
+
+    // Disallow using variables outside the blocks they are defined (especially
+    // since only let and const are used, see "no-var").
+    "block-scoped-var": 2,
+    // Enforce one true brace style (opening brace on the same line) and avoid
+    // start and end braces on the same line.
+    "brace-style": [2, "1tbs", {"allowSingleLine": false}],
+    // Require camel case names
+    "camelcase": 2,
+    // Disallow trailing commas. Not valid JSON notation.
+    "comma-dangle": 1,
+    // Enforce spacing before and after comma
+    "comma-spacing": [2, {"before": false, "after": true}],
+    // Enforce one true comma style.
+    "comma-style": [2, "last"],
+    // Warn about cyclomatic complexity in functions.
+    "complexity": 1,
+    // Require return statements to either always or never specify values.
+    "consistent-return": 2,
+    // Don't warn for inconsistent naming when capturing this (not so important
+    // with auto-binding fat arrow functions).
+    "consistent-this": 0,
+    // Enforce curly brace conventions for all control statements.
+    "curly": 2,
+    // Don't require a default case in switch statements. Avoid being forced to
+    // add a bogus default when you know all possible cases are handled.
+    "default-case": 0,
+    // Don't enforce consistent newlines before or after dots. This depends on
+    // what gives the most readable code.
+    "dot-location": [1, "object"],
+    // Encourage the use of dot notation whenever possible.
+    "dot-notation": 2,
+    // Enforce newline at the end of file, with no multiple empty lines.
+    "eol-last": 2,
+    // Allow using == instead of ===, in the interest of landing something since
+    // the devtools codebase is split on convention here.
+    "eqeqeq": 0,
+    // Don't require function expressions to have a name.
+    // This makes the code more verbose and hard to read. Our engine already
+    // does a fantastic job assigning a name to the function, which includes
+    // the enclosing function name, and worst case you have a line number that
+    // you can just look up.
+    "func-names": 0,
+    // Allow use of function declarations and expressions.
+    "func-style": 0,
+    // Deprecated, will be removed in 1.0.
+    "generator-star": 0,
+    // Enforce the spacing around the * in generator functions.
+    "generator-star-spacing": [1, "after"],
+    // Deprecated, will be removed in 1.0.
+    "global-strict": 0,
+    // Only useful in a node environment.
+    "handle-callback-err": 0,
+    // Tab width.
+    "indent": [2, 2],
+    // Enforces spacing between keys and values in object literal properties.
+    "key-spacing": [1, {"beforeColon": false, "afterColon": true}],
+    // Allow mixed 'LF' and 'CRLF' as linebreaks.
+    "linebreak-style": 0,
+    // Don't enforce the maximum depth that blocks can be nested. The complexity
+    // rule is a better rule to check this.
+    "max-depth": 0,
+    // Maximum length of a line.
+    "max-len": [1, 80],
+    // Maximum depth callbacks can be nested.
+    "max-nested-callbacks": [2, 3],
+    // Don't limit the number of parameters that can be used in a function.
+    "max-params": 0,
+    // Don't limit the maximum number of statement allowed in a function. We
+    // already have the complexity rule that's a better measurement.
+    "max-statements": 0,
+    // Require a capital letter for constructors, only check if all new
+    // operators are followed by a capital letter. Don't warn when capitalized
+    // functions are used without the new operator.
+    "new-cap": [2, {"capIsNew": false}],
+    // Disallow the omission of parentheses when invoking a constructor with no
+    // arguments.
+    "new-parens": 2,
+    // Disallow use of the Array constructor.
+    "no-array-constructor": 2,
+    // Allow use of bitwise operators.
+    "no-bitwise": 0,
+    // Disallow use of arguments.caller or arguments.callee.
+    "no-caller": 2,
+    // Disallow the catch clause parameter name being the same as a variable in
+    // the outer scope, to avoid confusion.
+    "no-catch-shadow": 1,
+    // Deprecated, will be removed in 1.0.
+    "no-comma-dangle": 0,
+    // Disallow assignment in conditional expressions.
+    "no-cond-assign": 2,
+    // Allow using the console API.
+    "no-console": 0,
+    // Allow using constant expressions in conditions like while (true)
+    "no-constant-condition": 0,
+    // Allow use of the continue statement.
+    "no-continue": 0,
+    // Disallow control characters in regular expressions.
+    "no-control-regex": 2,
+    // Disallow use of debugger.
+    "no-debugger": 2,
+    // Disallow deletion of variables (deleting properties is fine).
+    "no-delete-var": 2,
+    // Allow division operators explicitly at beginning of regular expression.
+    "no-div-regex": 0,
+    // Disallow duplicate arguments in functions.
+    "no-dupe-args": 2,
+    // Disallow duplicate keys when creating object literals.
+    "no-dupe-keys": 2,
+    // Disallow a duplicate case label.
+    "no-duplicate-case": 2,
+    // Disallow else after a return in an if. The else around the second return
+    // here is useless:
+    // if (something) { return false; } else { return true; }
+    "no-else-return": 2,
+    // Disallow empty statements. This will report an error for:
+    // try { something(); } catch (e) {}
+    // but will not report it for:
+    // try { something(); } catch (e) { /* Silencing the error because ...*/ }
+    // which is a valid use case.
+    "no-empty": 2,
+    // Disallow the use of empty character classes in regular expressions.
+    "no-empty-class": 2,
+    // Disallow use of labels for anything other then loops and switches.
+    "no-empty-label": 2,
+    // Disallow use of eval(). We have other APIs to evaluate code in content.
+    "no-eval": 2,
+    // Disallow assigning to the exception in a catch block.
+    "no-ex-assign": 2,
+    // Disallow adding to native types
+    "no-extend-native": 2,
+    // Disallow unnecessary function binding.
+    "no-extra-bind": 2,
+    // Disallow double-negation boolean casts in a boolean context.
+    "no-extra-boolean-cast": 2,
+    // Allow unnecessary parentheses, as they may make the code more readable.
+    "no-extra-parens": 0,
+    // Disallow unnecessary semicolons.
+    "no-extra-semi": 2,
+    // Deprecated, will be removed in 1.0.
+    "no-extra-strict": 0,
+    // Disallow fallthrough of case statements, except if there is a comment.
+    "no-fallthrough": 2,
+    // Allow the use of leading or trailing decimal points in numeric literals.
+    "no-floating-decimal": 0,
+    // Disallow comments inline after code.
+    "no-inline-comments": 1,
+    // Disallow if as the only statement in an else block.
+    "no-lonely-if": 2,
+    // Allow mixing regular variable and require declarations (not a node env).
+    "no-mixed-requires": 0,
+    // Disallow mixed spaces and tabs for indentation.
+    "no-mixed-spaces-and-tabs": 2,
+    // Disallow use of multiple spaces (sometimes used to align const values,
+    // array or object items, etc.). It's hard to maintain and doesn't add that
+    // much benefit.
+    "no-multi-spaces": 1,
+    // Disallow use of multiline strings (use template strings instead).
+    "no-multi-str": 1,
+    // Disallow multiple empty lines.
+    "no-multiple-empty-lines": [1, {"max": 1}],
+    // Disallow reassignments of native objects.
+    "no-native-reassign": 2,
+    // Disallow nested ternary expressions, they make the code hard to read.
+    "no-nested-ternary": 2,
+    // Allow use of new operator with the require function.
+    "no-new-require": 0,
+    // Disallow use of octal literals.
+    "no-octal": 1,
+    // Allow reassignment of function parameters.
+    "no-param-reassign": 0,
+    // Allow string concatenation with __dirname and __filename (not a node env).
+    "no-path-concat": 0,
+    // Allow use of unary operators, ++ and --.
+    "no-plusplus": 0,
+    // Allow using process.env (not a node environment).
+    "no-process-env": 0,
+    // Allow using process.exit (not a node environment).
+    "no-process-exit": 0,
+    // Disallow usage of __proto__ property.
+    "no-proto": 2,
+    // Disallow declaring the same variable more than once (we use let anyway).
+    "no-redeclare": 2,
+    // Disallow multiple spaces in a regular expression literal.
+    "no-regex-spaces": 2,
+    // Allow reserved words being used as object literal keys.
+    "no-reserved-keys": 0,
+    // Don't restrict usage of specified node modules (not a node environment).
+    "no-restricted-modules": 0,
+    // Disallow use of assignment in return statement. It is preferable for a
+    // single line of code to have only one easily predictable effect.
+    "no-return-assign": 2,
+    // Allow use of javascript: urls.
+    "no-script-url": 0,
+    // Disallow comparisons where both sides are exactly the same.
+    "no-self-compare": 2,
+    // Disallow use of comma operator.
+    "no-sequences": 2,
+    // Warn about declaration of variables already declared in the outer scope.
+    // This isn't an error because it sometimes is useful to use the same name
+    // in a small helper function rather than having to come up with another
+    // random name.
+    // Still, making this a warning can help people avoid being confused.
+    "no-shadow": 1,
+    // Disallow shadowing of names such as arguments.
+    "no-shadow-restricted-names": 2,
+    // Deprecated, will be removed in 1.0.
+    "no-space-before-semi": 0,
+    // Disallow space between function identifier and application.
+    "no-spaced-func": 1,
+    // Disallow sparse arrays, eg. let arr = [,,2].
+    // Array destructuring is fine though:
+    // for (let [, breakpointPromise] of aPromises)
+    "no-sparse-arrays": 2,
+    // Allow use of synchronous methods (not a node environment).
+    "no-sync": 0,
+    // Allow the use of ternary operators.
+    "no-ternary": 0,
+    // Disallow throwing literals (eg. throw "error" instead of
+    // throw new Error("error")).
+    "no-throw-literal": 2,
+    // Disallow trailing whitespace at the end of lines.
+    "no-trailing-spaces": 2,
+    // Disallow use of undeclared variables unless mentioned in a /*global */
+    // block.
+    // This should really be a 2, but until we define all globals in comments
+    // and .eslintrc, keeping this as a 1.
+    "no-undef": 2,
+    // Allow dangling underscores in identifiers (for privates).
+    "no-underscore-dangle": 0,
+    // Allow use of undefined variable.
+    "no-undefined": 0,
+    // Disallow the use of Boolean literals in conditional expressions.
+    "no-unneeded-ternary": 2,
+    // Disallow unreachable statements after a return, throw, continue, or break
+    // statement.
+    "no-unreachable": 2,
+    // Disallow declaration of variables that are not used in the code
+    "no-unused-vars": 2,
+    // Allow using variables before they are defined.
+    "no-use-before-define": 0,
+    // Require let or const instead of var.
+    "no-var": 2,
+    // Allow using TODO/FIXME comments.
+    "no-warning-comments": 0,
+    // Disallow use of the with statement.
+    "no-with": 2,
+    // Don't require method and property shorthand syntax for object literals.
+    // We use this in the code a lot, but not consistently, and this seems more
+    // like something to check at code review time.
+    "object-shorthand": 0,
+    // Allow more than one variable declaration per function.
+    "one-var": 0,
+    // Disallow padding within blocks.
+    "padded-blocks": [1, "never"],
+    // Don't require quotes around object literal property names.
+    "quote-props": 0,
+    // Double quotes should be used.
+    "quotes": [1, "double"],
+    // Require use of the second argument for parseInt().
+    "radix": 2,
+    // Always require use of semicolons wherever they are valid.
+    "semi": [1, "always"],
+    // Enforce spacing after semicolons.
+    "semi-spacing": [1, {"before": false, "after": true}],
+    // Don't require to sort variables within the same declaration block.
+    // Anyway, one-var is disabled.
+    "sort-vars": 0,
+    // Deprecated, will be removed in 1.0.
+    "space-after-function-name": 0,
+    // Require a space after keywords.
+    "space-after-keywords": [1, "always"],
+    // Deprecated, will be removed in 1.0.
+    "space-after-function-name": 0,
+    // Require a space before the start brace of a block.
+    "space-before-blocks": [1, "always"],
+    // Deprecated, will be removed in 1.0.
+    "space-before-function-parentheses": 0,
+    // Disallow space before function opening parenthesis.
+    "space-before-function-paren": [1, "never"],
+    // Disable the rule that checks if spaces inside {} and [] are there or not.
+    // Our code is split on conventions, and it'd be nice to have 2 rules
+    // instead, one for [] and one for {}. So, disabling until we write them.
+    "space-in-brackets": 0,
+    // Disallow spaces inside parentheses.
+    "space-in-parens": [1, "never"],
+    // Require spaces around operators, except for a|0.
+    "space-infix-ops": [1, {"int32Hint": true}],
+    // Require a space after return, throw, and case.
+    "space-return-throw-case": 1,
+    // Require spaces before/after unary operators (words on by default,
+    // nonwords off by default).
+    "space-unary-ops": [1, { "words": true, "nonwords": false }],
+    // Deprecated, will be removed in 1.0.
+    "space-unary-word-ops": 0,
+    // Require a space immediately following the // in a line comment.
+    "spaced-line-comment": [1, "always"],
+    // Require "use strict" to be defined globally in the script.
+    "strict": [2, "global"],
+    // Disallow comparisons with the value NaN.
+    "use-isnan": 2,
+    // Warn about invalid JSDoc comments.
+    // Disabled for now because of https://github.com/eslint/eslint/issues/2270
+    // The rule fails on some jsdoc comments like in:
+    // browser/devtools/webconsole/console-output.js
+    "valid-jsdoc": 0,
+    // Ensure that the results of typeof are compared against a valid string.
+    "valid-typeof": 2,
+    // Allow vars to be declared anywhere in the scope.
+    "vars-on-top": 0,
+    // Don't require immediate function invocation to be wrapped in parentheses.
+    "wrap-iife": 0,
+    // Don't require regex literals to be wrapped in parentheses (which
+    // supposedly prevent them from being mistaken for division operators).
+    "wrap-regex": 0,
+    // Disallow Yoda conditions (where literal value comes first).
+    "yoda": 2,
+
+    // And these are the rules that haven't been discussed so far, and that are
+    // disabled for now until we introduce them, one at a time.
+
+    // Require for-in loops to have an if statement.
+    "guard-for-in": 0,
+    // allow/disallow an empty newline after var statement
+    "newline-after-var": 0,
+    // disallow the use of alert, confirm, and prompt
+    "no-alert": 0,
+    // disallow comparisons to null without a type-checking operator
+    "no-eq-null": 0,
+    // disallow overwriting functions written as function declarations
+    "no-func-assign": 0,
+    // disallow use of eval()-like methods
+    "no-implied-eval": 0,
+    // disallow function or variable declarations in nested blocks
+    "no-inner-declarations": 0,
+    // disallow invalid regular expression strings in the RegExp constructor
+    "no-invalid-regexp": 0,
+    // disallow irregular whitespace outside of strings and comments
+    "no-irregular-whitespace": 0,
+    // disallow usage of __iterator__ property
+    "no-iterator": 0,
+    // disallow labels that share a name with a variable
+    "no-label-var": 0,
+    // disallow use of labeled statements
+    "no-labels": 0,
+    // disallow unnecessary nested blocks
+    "no-lone-blocks": 0,
+    // disallow creation of functions within loops
+    "no-loop-func": 0,
+    // disallow negation of the left operand of an in expression
+    "no-negated-in-lhs": 0,
+    // disallow use of new operator when not part of the assignment or
+    // comparison
+    "no-new": 0,
+    // disallow use of new operator for Function object
+    "no-new-func": 0,
+    // disallow use of the Object constructor
+    "no-new-object": 0,
+    // disallows creating new instances of String,Number, and Boolean
+    "no-new-wrappers": 0,
+    // disallow the use of object properties of the global object (Math and
+    // JSON) as functions
+    "no-obj-calls": 0,
+    // disallow use of octal escape sequences in string literals, such as
+    // var foo = "Copyright \251";
+    "no-octal-escape": 0,
+    // disallow use of undefined when initializing variables
+    "no-undef-init": 0,
+    // disallow usage of expressions in statement position
+    "no-unused-expressions": 0,
+    // disallow use of void operator
+    "no-void": 0,
+    // disallow wrapping of non-IIFE statements in parens
+    "no-wrap-func": 0,
+    // require assignment operator shorthand where possible or prohibit it
+    // entirely
+    "operator-assignment": 0,
+    // enforce operators to be placed before or after line breaks
+    "operator-linebreak": 0,
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/.eslintrc.mochitests
@@ -0,0 +1,50 @@
+// Parent config file for all devtools browser mochitest files.
+{
+  "rules": {
+    // Only disallow non-global unused vars, so that things like the test
+    // function do not produce errors.
+    "no-unused-vars": [2, {"vars": "local"}],
+    // Allow using undefined variables so that tests can refer to functions
+    // and variables defined in head.js files, without having to maintain a
+    // list of globals in each .eslintrc file.
+    // Note that bug 1168340 will eventually help auto-registering globals
+    // from head.js files.
+    "no-undef": 0,
+    "block-scoped-var": 0
+  },
+  // All globals made available in the test environment.
+  "globals": {
+    "add_task": true,
+    "Assert": true,
+    "content": true,
+    "document": true,
+    "EventUtils": true,
+    "executeSoon": true,
+    "export_assertions": true,
+    "finish": true,
+    "gBrowser": true,
+    "gDevTools": true,
+    "getRootDirectory": true,
+    "getTestFilePath": true,
+    "gTestPath": true,
+    "info": true,
+    "is": true,
+    "isnot": true,
+    "navigator": true,
+    "ok": true,
+    "promise": true,
+    "registerCleanupFunction": true,
+    "requestLongerTimeout": true,
+    "setTimeout": true,
+    "SimpleTest": true,
+    "SpecialPowers": true,
+    "test": true,
+    "todo": true,
+    "todo_is": true,
+    "todo_isnot": true,
+    "waitForClipboard": true,
+    "waitForExplicitFinish": true,
+    "waitForFocus": true,
+    "window": true,
+  }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/.eslintrc.xpcshell
@@ -0,0 +1,51 @@
+// Parent config file for all devtools browser mochitest files.
+{
+  "rules": {
+    // Allow non-camelcase so that run_test doesn't produce a warning.
+    "camelcase": 0,
+    // Only disallow non-global unused vars, so that things like the test
+    // function do not produce errors.
+    "no-unused-vars": [2, {"vars": "local"}],
+    // Allow using undefined variables so that tests can refer to functions
+    // and variables defined in head.js files, without having to maintain a
+    // list of globals in each .eslintrc file.
+    // Note that bug 1168340 will eventually help auto-registering globals
+    // from head.js files.
+    "no-undef": 0,
+    "block-scoped-var": 0
+  },
+  // All globals made available in the test environment.
+  "globals": {
+    "add_task": true,
+    "add_test": true,
+    "Assert": true,
+    "deepEqual": true,
+    "do_check_eq": true,
+    "do_check_false": true,
+    "do_check_neq": true,
+    "do_check_null": true,
+    "do_check_true": true,
+    "do_execute_soon": true,
+    "do_get_cwd": true,
+    "do_get_file": true,
+    "do_get_idle": true,
+    "do_get_profile": true,
+    "do_load_module": true,
+    "do_parse_document": true,
+    "do_print": true,
+    "do_register_cleanup": true,
+    "do_test_finished": true,
+    "do_test_pending": true,
+    "do_throw": true,
+    "do_timeout": true,
+    "equal": true,
+    "load": true,
+    "notDeepEqual": true,
+    "notEqual": true,
+    "notStrictEqual": true,
+    "ok": true,
+    "run_next_test": true,
+    "run_test": true,
+    "strictEqual": true,
+  }
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/animationinspector/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/canvasdebugger/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
--- a/browser/devtools/commandline/test/browser.ini
+++ b/browser/devtools/commandline/test/browser.ini
@@ -58,16 +58,17 @@ support-files =
 [browser_cmd_highlight_02.js]
 [browser_cmd_inject.js]
 support-files =
  browser_cmd_inject.html
 [browser_cmd_csscoverage_util.js]
 [browser_cmd_jsb.js]
 support-files =
   browser_cmd_jsb_script.jsi
+[browser_cmd_listen.js]
 [browser_cmd_media.js]
 support-files =
   browser_cmd_media.html
 [browser_cmd_pagemod_export.js]
 support-files =
   browser_cmd_pagemod_export.html
 [browser_cmd_pref1.js]
 [browser_cmd_pref2.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/test/browser_cmd_listen.js
@@ -0,0 +1,79 @@
+/* Any copyright is dedicated to the Public Domain.
+* http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the listen/unlisten commands work as they should.
+
+const TEST_URI = "http://example.com/browser/browser/devtools/commandline/"+
+                 "test/browser_cmd_cookie.html";
+
+function test() {
+  return Task.spawn(testTask).then(finish, helpers.handleError);
+}
+
+let tests = {
+  testInput: function(options) {
+    return helpers.audit(options, [
+      {
+        setup:    'listen',
+        check: {
+          input:  'listen',
+          markup: 'VVVVVV',
+          status: 'VALID'
+        },
+      },
+      {
+        setup:    'unlisten',
+        check: {
+          input:  'unlisten',
+          markup: 'VVVVVVVV',
+          status: 'VALID'
+        },
+        exec: {
+          output: 'All TCP ports closed'
+        }
+      },
+      {
+        setup: function() {
+          return helpers.setInput(options, 'listen');
+        },
+        check: {
+          input:  'listen',
+          hints:        ' [port]',
+          markup: 'VVVVVV',
+          status: 'VALID'
+        },
+        exec: {
+          output: 'Listening on port 6080'
+        }
+      },
+      {
+        setup: function() {
+          return helpers.setInput(options, 'listen 8000');
+        },
+        exec: {
+          output: 'Listening on port 8000'
+        }
+      },
+      {
+        setup: function() {
+          return helpers.setInput(options, 'unlisten');
+        },
+        exec: {
+          output: 'All TCP ports closed'
+        }
+      }
+    ]);
+  },
+};
+
+function* testTask() {
+    Services.prefs.setBoolPref('devtools.debugger.remote-enabled', true);
+    let options = yield helpers.openTab(TEST_URI);
+    yield helpers.openToolbar(options);
+
+    yield helpers.runTests(options, tests);
+
+    yield helpers.closeToolbar(options);
+    yield helpers.closeTab(options);
+    Services.prefs.clearUserPref('devtools.debugger.remote-enabled');
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/debugger/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/eyedropper/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/fontinspector/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/inspector/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/layoutview/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/markupview/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/netmonitor/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
--- a/browser/devtools/performance/modules/global.js
+++ b/browser/devtools/performance/modules/global.js
@@ -99,16 +99,31 @@ const CATEGORY_MAPPINGS = {
  *          If you use a function for a label, it *must* handle the case where
  *          no marker is provided for a main label to describe all markers of
  *          this type.
  * - colorName: The label of the DevTools color used for this marker. If
  *              adding a new color, be sure to check that there's an entry
  *              for `.marker-details-bullet.{COLORNAME}` for the equivilent
  *              entry in ./browser/themes/shared/devtools/performance.inc.css
  *              https://developer.mozilla.org/en-US/docs/Tools/DevToolsColors
+ * - collapseFunc: A function determining how markers are collapsed together.
+ *                 Invoked with 3 arguments: the current parent marker, the
+ *                 current marker and a method for peeking i markers ahead. If
+ *                 nothing is returned, the marker is added as a standalone entry
+ *                 in the waterfall. Otherwise, an object needs to be returned
+ *                 with the following properties:
+ *                 - toParent: The parent marker name (needs to be an entry in
+ *                             the `TIMELINE_BLUEPRINT` itself).
+ *                 - withData: An object containing some properties to staple
+ *                             on the parent marker.
+ *                 - forceNew: True if a new parent marker needs to be created
+ *                             even though there is one currently available
+ *                             with the same name.
+ *                 - forceEnd: True if the current parent marker is full after
+ *                             this collapse operation and should be finalized.
  * - fields: An optional array of marker properties you wish to display in the
  *           marker details view. For example, a field in the array such as
  *           { property: "aCauseName", label: "Cause" } would render a string
  *           like `Cause: ${marker.aCauseName}` in the marker details view.
  *           Each `field` item may take the following properties:
  *           - property: The property that must exist on the marker to render,
  *                       and the value of the property will be displayed.
  *           - label: The name of the property that should be displayed.
@@ -122,85 +137,171 @@ const CATEGORY_MAPPINGS = {
  * Whenever this is changed, browser_timeline_waterfall-styles.js *must* be
  * updated as well.
  */
 const TIMELINE_BLUEPRINT = {
   /* Group 0 - Reflow and Rendering pipeline */
   "Styles": {
     group: 0,
     colorName: "graphs-purple",
+    collapseFunc: collapseConsecutiveIdentical,
     label: L10N.getStr("timeline.label.styles2"),
     fields: getStylesFields,
   },
   "Reflow": {
     group: 0,
     colorName: "graphs-purple",
-    label: L10N.getStr("timeline.label.reflow2")
+    collapseFunc: collapseConsecutiveIdentical,
+    label: L10N.getStr("timeline.label.reflow2"),
   },
   "Paint": {
     group: 0,
     colorName: "graphs-green",
-    label: L10N.getStr("timeline.label.paint")
+    collapseFunc: collapseConsecutiveIdentical,
+    label: L10N.getStr("timeline.label.paint"),
   },
 
   /* Group 1 - JS */
   "DOMEvent": {
     group: 1,
     colorName: "graphs-yellow",
+    collapseFunc: collapseDOMIntoDOMJS,
     label: L10N.getStr("timeline.label.domevent"),
     fields: getDOMEventFields,
   },
   "Javascript": {
     group: 1,
     colorName: "graphs-yellow",
+    collapseFunc: either(collapseJSIntoDOMJS, collapseConsecutiveIdentical),
     label: getJSLabel,
     fields: getJSFields,
   },
+  "meta::DOMEvent+JS": {
+    colorName: "graphs-yellow",
+    label: getDOMJSLabel,
+    fields: getDOMEventFields,
+  },
   "Parse HTML": {
     group: 1,
     colorName: "graphs-yellow",
-    label: L10N.getStr("timeline.label.parseHTML")
+    collapseFunc: collapseConsecutiveIdentical,
+    label: L10N.getStr("timeline.label.parseHTML"),
   },
   "Parse XML": {
     group: 1,
     colorName: "graphs-yellow",
-    label: L10N.getStr("timeline.label.parseXML")
+    collapseFunc: collapseConsecutiveIdentical,
+    label: L10N.getStr("timeline.label.parseXML"),
   },
   "GarbageCollection": {
     group: 1,
     colorName: "graphs-red",
+    collapseFunc: collapseAdjacentGC,
     label: getGCLabel,
     fields: [
       { property: "causeName", label: "Reason:" },
       { property: "nonincrementalReason", label: "Non-incremental Reason:" }
-    ]
+    ],
   },
 
   /* Group 2 - User Controlled */
   "ConsoleTime": {
     group: 2,
     colorName: "graphs-grey",
     label: sublabelForProperty(L10N.getStr("timeline.label.consoleTime"), "causeName"),
     fields: [{
       property: "causeName",
       label: L10N.getStr("timeline.markerDetail.consoleTimerName")
-    }]
+    }],
   },
   "TimeStamp": {
     group: 2,
     colorName: "graphs-blue",
     label: sublabelForProperty(L10N.getStr("timeline.label.timestamp"), "causeName"),
     fields: [{
       property: "causeName",
       label: "Label:"
-    }]
+    }],
   },
 };
 
 /**
+ * Helper for creating a function that returns the first defined result from
+ * a list of functions passed in as params, in order.
+ * @param ...function fun
+ * @return any
+ */
+function either(...fun) {
+  return function() {
+    for (let f of fun) {
+      let result = f.apply(null, arguments);
+      if (result !== undefined) return result;
+    }
+  }
+}
+
+/**
+ * A series of collapsers used by the blueprint. These functions are
+ * consecutively invoked on a moving window of two markers.
+ */
+
+function collapseConsecutiveIdentical(parent, curr, peek) {
+  // If there is a parent marker currently being filled and the current marker
+  // should go into the parent marker, make it so.
+  if (parent && parent.name == curr.name) {
+    return { toParent: parent.name };
+  }
+  // Otherwise if the current marker is the same type as the next marker type,
+  // create a new parent marker containing the current marker.
+  let next = peek(1);
+  if (next && curr.name == next.name) {
+    return { toParent: curr.name };
+  }
+}
+
+function collapseAdjacentGC(parent, curr, peek) {
+  let next = peek(1);
+  if (next && (next.start < curr.end || next.start - curr.end <= 10 /* ms */)) {
+    return collapseConsecutiveIdentical(parent, curr, peek);
+  }
+}
+
+function collapseDOMIntoDOMJS(parent, curr, peek) {
+  // If the next marker is a JavaScript marker, create a new meta parent marker
+  // containing the current marker.
+  let next = peek(1);
+  if (next && next.name == "Javascript") {
+    return {
+      forceNew: true,
+      toParent: "meta::DOMEvent+JS",
+      withData: {
+        type: curr.type,
+        eventPhase: curr.eventPhase
+      },
+    };
+  }
+}
+
+function collapseJSIntoDOMJS(parent, curr, peek) {
+  // If there is a parent marker currently being filled, and it's the one
+  // created from a `DOMEvent` via `collapseDOMIntoDOMJS`, then the current
+  // marker has to go into that one.
+  if (parent && parent.name == "meta::DOMEvent+JS") {
+    return {
+      forceEnd: true,
+      toParent: "meta::DOMEvent+JS",
+      withData: {
+        stack: curr.stack,
+        endStack: curr.endStack
+      },
+    };
+  }
+}
+
+/**
  * A series of formatters used by the blueprint.
  */
 
 function getGCLabel (marker={}) {
   let label = L10N.getStr("timeline.label.garbageCollection");
   // Only if a `nonincrementalReason` exists, do we want to label
   // this as a non incremental GC event.
   if ("nonincrementalReason" in marker) {
@@ -231,16 +332,20 @@ const JS_MARKER_MAP = {
 function getJSLabel (marker={}) {
   let generic = L10N.getStr("timeline.label.javascript2");
   if ("causeName" in marker) {
     return JS_MARKER_MAP[marker.causeName] || generic;
   }
   return generic;
 }
 
+function getDOMJSLabel (marker={}) {
+  return `Event (${marker.type})`;
+}
+
 /**
  * Returns a hash for computing a fields object for a JS marker. If the cause
  * is considered content (so an entry exists in the JS_MARKER_MAP), do not display it
  * since it's redundant with the label. Otherwise for Gecko code, either display
  * the cause, or "(Gecko)", depending on if "show-platform-data" is set.
  */
 function getJSFields (marker) {
   if ("causeName" in marker && !JS_MARKER_MAP[marker.causeName]) {
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/modules/logic/waterfall-utils.js
@@ -0,0 +1,122 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+/**
+ * Utility functions for collapsing markers into a waterfall.
+ */
+
+loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
+  "devtools/performance/global", true);
+
+/**
+ * Collapses markers into a tree-like structure. Currently, this only goes
+ * one level deep.
+ * @param object markerNode
+ * @param array markersList
+ */
+function collapseMarkersIntoNode({ markerNode, markersList }) {
+  let [getOrCreateParentNode, getCurrentParentNode, clearParentNode] = makeParentNodeFactory();
+
+  for (let i = 0, len = markersList.length; i < len; i++) {
+    let curr = markersList[i];
+    let blueprint = TIMELINE_BLUEPRINT[curr.name];
+
+    let parentNode = getCurrentParentNode();
+    let collapse = blueprint.collapseFunc || (() => null);
+    let peek = distance => markersList[i + distance];
+    let collapseInfo = collapse(parentNode, curr, peek);
+
+    if (collapseInfo) {
+      let { toParent, withData, forceNew, forceEnd } = collapseInfo;
+
+      // If the `forceNew` prop is set on the collapse info, then a new parent
+      // marker needs to be created even if there is one already available.
+      if (forceNew) {
+        clearParentNode();
+      }
+      // If the `toParent` prop is set on the collapse info, then this marker
+      // can be collapsed into a higher-level parent marker.
+      if (toParent) {
+        let parentNode = getOrCreateParentNode(markerNode, toParent, curr.start);
+        parentNode.end = curr.end;
+        parentNode.submarkers.push(curr);
+        for (let key in withData) {
+          parentNode[key] = withData[key];
+        }
+      }
+      // If the `forceEnd` prop is set on the collapse info, then the higher-level
+      // parent marker is full and should be finalized.
+      if (forceEnd) {
+        clearParentNode();
+      }
+    } else {
+      clearParentNode();
+      markerNode.submarkers.push(curr);
+    }
+  }
+}
+
+/**
+ * Creates an empty parent marker, which functions like a regular marker,
+ * but is able to hold additional child markers.
+ * @param string name
+ * @param number start [optional]
+ * @param number end [optional]
+ * @return object
+ */
+function makeEmptyMarkerNode(name, start, end) {
+  return {
+    name: name,
+    start: start,
+    end: end,
+    submarkers: []
+  };
+}
+
+/**
+ * Creates a factory for markers containing other markers.
+ * @return array[function]
+ */
+function makeParentNodeFactory() {
+  let marker;
+
+  return [
+    /**
+     * Gets the current parent marker for the given marker name. If it doesn't
+     * exist, it creates it and appends it to another parent marker.
+     * @param object owner
+     * @param string name
+     * @param number start
+     * @return object
+     */
+    function getOrCreateParentNode(owner, name, start) {
+      if (marker && marker.name == name) {
+        return marker;
+      } else {
+        marker = makeEmptyMarkerNode(name, start);
+        owner.submarkers.push(marker);
+        return marker;
+      }
+    },
+
+    /**
+     * Gets the current marker marker.
+     * @return object
+     */
+    function getCurrentParentNode() {
+      return marker;
+    },
+
+    /**
+     * Clears the current marker marker.
+     */
+    function clearParentNode() {
+      marker = null;
+    }
+  ];
+}
+
+exports.makeEmptyMarkerNode = makeEmptyMarkerNode;
+exports.collapseMarkersIntoNode = collapseMarkersIntoNode;
--- a/browser/devtools/performance/modules/widgets/marker-details.js
+++ b/browser/devtools/performance/modules/widgets/marker-details.js
@@ -3,17 +3,16 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 /**
  * This file contains the rendering code for the marker sidebar.
  */
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
-let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
 
 loader.lazyRequireGetter(this, "EventEmitter",
   "devtools/toolkit/event-emitter");
 loader.lazyRequireGetter(this, "L10N",
   "devtools/performance/global", true);
 loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
   "devtools/performance/global", true);
 loader.lazyRequireGetter(this, "MarkerUtils",
@@ -24,60 +23,62 @@ loader.lazyRequireGetter(this, "MarkerUt
  *
  * @param nsIDOMNode parent
  *        The parent node holding the view.
  * @param nsIDOMNode splitter
  *        The splitter node that the resize event is bound to.
  */
 function MarkerDetails(parent, splitter) {
   EventEmitter.decorate(this);
-  this._onClick = this._onClick.bind(this);
+
   this._document = parent.ownerDocument;
   this._parent = parent;
   this._splitter = splitter;
-  this._splitter.addEventListener("mouseup", () => this.emit("resize"));
+
+  this._onClick = this._onClick.bind(this);
+  this._onSplitterMouseUp = this._onSplitterMouseUp.bind(this);
+
   this._parent.addEventListener("click", this._onClick);
+  this._splitter.addEventListener("mouseup", this._onSplitterMouseUp);
 }
 
 MarkerDetails.prototype = {
   /**
-   * Removes any node references from this view.
+   * Sets this view's width.
+   * @param boolean
    */
-  destroy: function() {
-    this.empty();
-    this._parent.removeEventListener("click", this._onClick);
-    this._parent = null;
-    this._splitter = null;
+  set width(value) {
+    this._parent.setAttribute("width", value);
   },
 
   /**
-   * Clears the view.
+   * Clears the marker details from this view.
    */
   empty: function() {
     this._parent.innerHTML = "";
   },
 
   /**
    * Populates view with marker's details.
    *
    * @param object params
    *        An options object holding:
-   *        marker - The marker to display.
-   *        frames - Array of stack frame information; see stack.js.
+   *          - marker: The marker to display.
+   *          - frames: Array of stack frame information; see stack.js.
    */
   render: function({ marker, frames }) {
     this.empty();
 
     let elements = [];
     elements.push(MarkerUtils.DOM.buildTitle(this._document, marker));
     elements.push(MarkerUtils.DOM.buildDuration(this._document, marker));
-    MarkerUtils.DOM.buildFields(this._document, marker).forEach(field => elements.push(field));
+    MarkerUtils.DOM.buildFields(this._document, marker).forEach(f => elements.push(f));
 
     // Build a stack element -- and use the "startStack" label if
-    // we have both a star and endStack.
+    // we have both a startStack and endStack.
     if (marker.stack) {
       let type = marker.endStack ? "startStack" : "stack";
       elements.push(MarkerUtils.DOM.buildStackTrace(this._document, {
         frameIndex: marker.stack, frames, type
       }));
     }
 
     elements.forEach(el => this._parent.appendChild(el));
@@ -93,16 +94,23 @@ MarkerDetails.prototype = {
     if (!data) {
       return;
     }
 
     if (data.action === "view-source") {
       this.emit("view-source", data.url, data.line);
     }
   },
+
+  /**
+   * Handles the "mouseup" event on the marker details view splitter.
+   */
+  _onSplitterMouseUp: function() {
+    this.emit("resize");
+  }
 };
 
 /**
  * Take an element from an event `target`, and asend through
  * the DOM, looking for an element with a `data-action` attribute. Return
  * the parsed `data-action` value found, or null if none found before
  * reaching the parent `container`.
  *
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/modules/widgets/marker-view.js
@@ -0,0 +1,305 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+/**
+ * This file contains the "marker" view, essentially a detailed list
+ * of all the markers in the timeline data.
+ */
+
+const { Cc, Ci, Cu, Cr } = require("chrome");
+const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
+const { AbstractTreeItem } = require("resource:///modules/devtools/AbstractTreeItem.jsm");
+const { TIMELINE_BLUEPRINT: ORIGINAL_BP } = require("devtools/performance/global");
+
+loader.lazyRequireGetter(this, "MarkerUtils",
+  "devtools/performance/marker-utils");
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+
+const LEVEL_INDENT = 10; // px
+const ARROW_NODE_OFFSET = -15; // px
+const WATERFALL_MARKER_SIDEBAR_WIDTH = 175; // px
+const WATERFALL_MARKER_TIMEBAR_WIDTH_MIN = 5; // px
+
+/**
+ * A detailed waterfall view for the timeline data.
+ *
+ * @param MarkerView owner
+ *        The MarkerView considered the "owner" marker. This newly created
+ *        instance will be represent the "submarker". Should be null for root nodes.
+ * @param object marker
+ *        Details about this marker, like { name, start, end, submarkers } etc.
+ * @param number level [optional]
+ *        The indentation level in the waterfall tree. The root node is at level 0.
+ * @param boolean hidden [optional]
+ *        Whether this node should be hidden and not contribute to depth/level
+ *        calculations. Defaults to false.
+ */
+function MarkerView({ owner, marker, level, hidden }) {
+  AbstractTreeItem.call(this, {
+    parent: owner,
+    level: level|0 - (hidden ? 1 : 0)
+  });
+
+  this.marker = marker;
+  this.hidden = !!hidden;
+
+  this._onItemBlur = this._onItemBlur.bind(this);
+  this._onItemFocus = this._onItemFocus.bind(this);
+}
+
+MarkerView.prototype = Heritage.extend(AbstractTreeItem.prototype, {
+  /**
+   * Calculates and stores the available width for the waterfall.
+   * This should be invoked every time the container node is resized.
+   */
+  recalculateBounds: function() {
+    this.root._waterfallWidth = this.bounds.width - WATERFALL_MARKER_SIDEBAR_WIDTH;
+  },
+
+  /**
+   * Sets a list of names and colors used to paint markers.
+   * @see TIMELINE_BLUEPRINT in timeline/widgets/global.js
+   * @param object blueprint
+   */
+  set blueprint(blueprint) {
+    this.root._blueprint = blueprint;
+  },
+  get blueprint() {
+    return this.root._blueprint;
+  },
+
+  /**
+   * Sets the { startTime, endTime }, in milliseconds.
+   * @param object interval
+   */
+  set interval(interval) {
+    this.root._interval = interval;
+  },
+  get interval() {
+    return this.root._interval;
+  },
+
+  /**
+   * Gets the current waterfall width.
+   * @return number
+   */
+  getWaterfallWidth: function() {
+    return this._waterfallWidth;
+  },
+
+  /**
+   * Gets the data scale amount for the current width and interval.
+   * @return number
+   */
+  getDataScale: function() {
+    let startTime = this.root._interval.startTime|0;
+    let endTime = this.root._interval.endTime|0;
+    return this.root._waterfallWidth / (endTime - startTime);
+  },
+
+  /**
+   * Creates the view for this waterfall node.
+   * @param nsIDOMNode document
+   * @param nsIDOMNode arrowNode
+   * @return nsIDOMNode
+   */
+  _displaySelf: function(document, arrowNode) {
+    let targetNode = document.createElement("hbox");
+    targetNode.className = "waterfall-tree-item";
+
+    if (this == this.root) {
+      // Bounds are needed for properly positioning and scaling markers in
+      // the waterfall, but it's sufficient to make those calculations only
+      // for the root node.
+      this.root.recalculateBounds();
+      // The AbstractTreeItem propagates events to the root, so we don't
+      // need to listen them on descendant items in the tree.
+      this._addEventListeners();
+    } else {
+      // Root markers are an implementation detail and shouldn't be shown.
+      this._buildMarkerCells(document, targetNode, arrowNode);
+    }
+
+    if (this.hidden) {
+      targetNode.style.display = "none";
+    }
+
+    return targetNode;
+  },
+
+  /**
+   * Populates this node in the waterfall tree with the corresponding "markers".
+   * @param array:AbstractTreeItem children
+   */
+  _populateSelf: function(children) {
+    let submarkers = this.marker.submarkers;
+    if (!submarkers || !submarkers.length) {
+      return;
+    }
+    let blueprint = this.root._blueprint;
+    let startTime = this.root._interval.startTime;
+    let endTime = this.root._interval.endTime;
+    let newLevel = this.level + 1;
+
+    for (let i = 0, len = submarkers.length; i < len; i++) {
+      let marker = submarkers[i];
+
+      // If this marker isn't in the global timeline blueprint, don't display
+      // it, but dump a warning message to the console.
+      if (!(marker.name in blueprint)) {
+        if (!(marker.name in ORIGINAL_BP)) {
+          console.warn(`Marker not found in timeline blueprint: ${marker.name}.`);
+        }
+        continue;
+      }
+      if (!isMarkerInRange(marker, startTime|0, endTime|0)) {
+        continue;
+      }
+      children.push(new MarkerView({
+        owner: this,
+        marker: marker,
+        level: newLevel,
+        inverted: this.inverted
+      }));
+    }
+  },
+
+  /**
+   * Builds all the nodes representing a marker in the waterfall.
+   * @param nsIDOMNode document
+   * @param nsIDOMNode targetNode
+   * @param nsIDOMNode arrowNode
+   */
+  _buildMarkerCells: function(doc, targetNode, arrowNode) {
+    // Root markers are an implementation detail and shouldn't be shown.
+    let marker = this.marker;
+    if (marker.name == "(root)") {
+      return;
+    }
+
+    let style = this.root._blueprint[marker.name];
+    let startTime = this.root._interval.startTime;
+    let endTime = this.root._interval.endTime;
+
+    let sidebarCell = this._buildMarkerSidebar(
+      doc, style, marker);
+
+    let timebarCell = this._buildMarkerTimebar(
+      doc, style, marker, startTime, endTime, arrowNode);
+
+    targetNode.appendChild(sidebarCell);
+    targetNode.appendChild(timebarCell);
+
+    // Don't render an expando-arrow for leaf nodes.
+    let submarkers = this.marker.submarkers;
+    let hasDescendants = submarkers && submarkers.length > 0;
+    if (hasDescendants) {
+      targetNode.setAttribute("expandable", "");
+    } else {
+      arrowNode.setAttribute("invisible", "");
+    }
+
+    targetNode.setAttribute("level", this.level);
+  },
+
+  /**
+   * Functions creating each cell in this waterfall view.
+   * Invoked by `_displaySelf`.
+   */
+  _buildMarkerSidebar: function(doc, style, marker) {
+    let cell = doc.createElement("hbox");
+    cell.className = "waterfall-sidebar theme-sidebar";
+    cell.setAttribute("width", WATERFALL_MARKER_SIDEBAR_WIDTH);
+    cell.setAttribute("align", "center");
+
+    let bullet = doc.createElement("hbox");
+    bullet.className = `waterfall-marker-bullet marker-color-${style.colorName}`;
+    bullet.style.transform = `translateX(${this.level * LEVEL_INDENT}px)`;
+    bullet.setAttribute("type", marker.name);
+    cell.appendChild(bullet);
+
+    let name = doc.createElement("description");
+    let label = MarkerUtils.getMarkerLabel(marker);
+    name.className = "plain waterfall-marker-name";
+    name.style.transform = `translateX(${this.level * LEVEL_INDENT}px)`;
+    name.setAttribute("crop", "end");
+    name.setAttribute("flex", "1");
+    name.setAttribute("value", label);
+    name.setAttribute("tooltiptext", label);
+    cell.appendChild(name);
+
+    return cell;
+  },
+  _buildMarkerTimebar: function(doc, style, marker, startTime, endTime, arrowNode) {
+    let cell = doc.createElement("hbox");
+    cell.className = "waterfall-marker waterfall-background-ticks";
+    cell.setAttribute("align", "center");
+    cell.setAttribute("flex", "1");
+
+    let dataScale = this.getDataScale();
+    let offset = (marker.start - startTime) * dataScale;
+    let width = (marker.end - marker.start) * dataScale;
+
+    arrowNode.style.transform =`translateX(${offset + ARROW_NODE_OFFSET}px)`;
+    cell.appendChild(arrowNode);
+
+    let bar = doc.createElement("hbox");
+    bar.className = `waterfall-marker-bar marker-color-${style.colorName}`;
+    bar.style.transform = `translateX(${offset}px)`;
+    bar.setAttribute("type", marker.name);
+    bar.setAttribute("width", Math.max(width, WATERFALL_MARKER_TIMEBAR_WIDTH_MIN));
+    cell.appendChild(bar);
+
+    return cell;
+  },
+
+  /**
+   * Adds the event listeners for this particular tree item.
+   */
+  _addEventListeners: function() {
+    this.on("focus", this._onItemFocus);
+    this.on("blur", this._onItemBlur);
+  },
+
+  /**
+   * Handler for the "blur" event on the root item.
+   */
+  _onItemBlur: function() {
+    this.root.emit("unselected");
+  },
+
+  /**
+   * Handler for the "mousedown" event on the root item.
+   */
+  _onItemFocus: function(e, item) {
+    this.root.emit("selected", item.marker);
+  }
+});
+
+/**
+ * Checks if a given marker is in the specified time range.
+ *
+ * @param object e
+ *        The marker containing the { start, end } timestamps.
+ * @param number start
+ *        The earliest allowed time.
+ * @param number end
+ *        The latest allowed time.
+ * @return boolean
+ *         True if the marker fits inside the specified time range.
+ */
+function isMarkerInRange(e, start, end) {
+  let m_start = e.start|0;
+  let m_end = e.end|0;
+
+  return (m_start >= start && m_end <= end) || // bounds inside
+         (m_start < start && m_end > end) || // bounds outside
+         (m_start < start && m_end >= start && m_end <= end) || // overlap start
+         (m_end > end && m_start >= start && m_start <= end); // overlap end
+}
+
+exports.MarkerView = MarkerView;
+exports.WATERFALL_MARKER_SIDEBAR_WIDTH = WATERFALL_MARKER_SIDEBAR_WIDTH;
--- a/browser/devtools/performance/modules/widgets/markers-overview.js
+++ b/browser/devtools/performance/modules/widgets/markers-overview.js
@@ -14,16 +14,18 @@ const { AbstractCanvasGraph } = require(
 const { Heritage } = require("resource:///modules/devtools/ViewHelpers.jsm");
 
 loader.lazyRequireGetter(this, "colorUtils",
   "devtools/css-color", true);
 loader.lazyRequireGetter(this, "getColor",
   "devtools/shared/theme", true);
 loader.lazyRequireGetter(this, "L10N",
   "devtools/performance/global", true);
+loader.lazyRequireGetter(this, "TickUtils",
+  "devtools/performance/waterfall-ticks", true);
 
 const OVERVIEW_HEADER_HEIGHT = 14; // px
 const OVERVIEW_ROW_HEIGHT = 11; // px
 
 const OVERVIEW_SELECTION_LINE_COLOR = "#666";
 const OVERVIEW_CLIPHEAD_LINE_COLOR = "#555";
 
 const FIND_OPTIMAL_TICK_INTERVAL_MAX_ITERS = 100;
@@ -70,17 +72,17 @@ MarkersOverview.prototype = Heritage.ext
    * @see TIMELINE_BLUEPRINT in timeline/widgets/global.js
    */
   setBlueprint: function(blueprint) {
     this._paintBatches = new Map();
     this._lastGroup = 0;
 
     for (let type in blueprint) {
       this._paintBatches.set(type, { style: blueprint[type], batch: [] });
-      this._lastGroup = Math.max(this._lastGroup, blueprint[type].group);
+      this._lastGroup = Math.max(this._lastGroup, blueprint[type].group || 0);
     }
   },
 
   /**
    * Disables selection and empties this graph.
    */
   clearView: function() {
     this.selectionEnabled = false;
@@ -138,17 +140,22 @@ MarkersOverview.prototype = Heritage.ext
     ctx.fill();
 
     // Draw the timeline header ticks.
 
     let fontSize = OVERVIEW_HEADER_TEXT_FONT_SIZE * this._pixelRatio;
     let fontFamily = OVERVIEW_HEADER_TEXT_FONT_FAMILY;
     let textPaddingLeft = OVERVIEW_HEADER_TEXT_PADDING_LEFT * this._pixelRatio;
     let textPaddingTop = OVERVIEW_HEADER_TEXT_PADDING_TOP * this._pixelRatio;
-    let tickInterval = this._findOptimalTickInterval(dataScale);
+
+    let tickInterval = TickUtils.findOptimalTickInterval({
+      ticksMultiple: OVERVIEW_HEADER_TICKS_MULTIPLE,
+      ticksSpacingMin: OVERVIEW_HEADER_TICKS_SPACING_MIN,
+      dataScale: dataScale
+    });
 
     ctx.textBaseline = "middle";
     ctx.font = fontSize + "px " + fontFamily;
     ctx.fillStyle = this.headerTextColor;
     ctx.strokeStyle = this.headerTimelineStrokeColor;
     ctx.beginPath();
 
     for (let x = 0; x < canvasWidth; x += tickInterval) {
@@ -186,42 +193,16 @@ MarkersOverview.prototype = Heritage.ext
       // they will be sorted and drawn again.
       batch.length = 0;
     }
 
     return canvas;
   },
 
   /**
-   * Finds the optimal tick interval between time markers in this overview.
-   */
-  _findOptimalTickInterval: function(dataScale) {
-    let timingStep = OVERVIEW_HEADER_TICKS_MULTIPLE;
-    let spacingMin = OVERVIEW_HEADER_TICKS_SPACING_MIN * this._pixelRatio;
-    let maxIters = FIND_OPTIMAL_TICK_INTERVAL_MAX_ITERS;
-    let numIters = 0;
-
-    if (dataScale > spacingMin) {
-      return dataScale;
-    }
-
-    while (true) {
-      let scaledStep = dataScale * timingStep;
-      if (++numIters > maxIters) {
-        return scaledStep;
-      }
-      if (scaledStep < spacingMin) {
-        timingStep <<= 1;
-        continue;
-      }
-      return scaledStep;
-    }
-  },
-
-  /**
    * Sets the theme via `theme` to either "light" or "dark",
    * and updates the internal styling to match. Requires a redraw
    * to see the effects.
    */
   setTheme: function (theme) {
     this.theme = theme = theme || "light";
     this.backgroundColor = getColor("body-background", theme);
     this.selectionBackgroundColor = colorUtils.setAlpha(getColor("selection-background", theme), 0.25);
--- a/browser/devtools/performance/modules/widgets/tree-view.js
+++ b/browser/devtools/performance/modules/widgets/tree-view.js
@@ -51,21 +51,21 @@ const sum = vals => vals.reduce((a, b) =
  *       300.34 |   30.03% |  1500 |     ▼ bar                        Categ. 2
  *        10.56 |    0.01% |    42 |       ▶ call_with_children       Categ. 3
  *        90.78 |    0.09% |    25 |         call_without_children    Categ. 4
  *
  * Every instance of a `CallView` represents a row in the call tree. The same
  * parent node is used for all rows.
  *
  * @param CallView caller
- *        The CallView considered the "caller" frame. This instance will be
- *        represent the "callee". Should be null for root nodes.
+ *        The CallView considered the "caller" frame. This newly created
+ *        instance will be represent the "callee". Should be null for root nodes.
  * @param ThreadNode | FrameNode frame
  *        Details about this function, like { samples, duration, calls } etc.
- * @param number level
+ * @param number level [optional]
  *        The indentation level in the call tree. The root node is at level 0.
  * @param boolean hidden [optional]
  *        Whether this node should be hidden and not contribute to depth/level
  *        calculations. Defaults to false.
  * @param boolean inverted [optional]
  *        Whether the call tree has been inverted (bottom up, rather than
  *        top-down). Defaults to false.
  * @param function sortingPredicate [optional]
@@ -208,58 +208,58 @@ CallView.prototype = Heritage.extend(Abs
     children.sort(this.sortingPredicate.bind(this));
   },
 
   /**
    * Functions creating each cell in this call view.
    * Invoked by `_displaySelf`.
    */
   _createTimeCell: function(doc, duration, isSelf = false) {
-    let cell = doc.createElement("label");
+    let cell = doc.createElement("description");
     cell.className = "plain call-tree-cell";
     cell.setAttribute("type", isSelf ? "self-duration" : "duration");
     cell.setAttribute("crop", "end");
     cell.setAttribute("value", L10N.numberWithDecimals(duration, 2) + " " + MILLISECOND_UNITS);
     return cell;
   },
   _createExecutionCell: function(doc, percentage, isSelf = false) {
-    let cell = doc.createElement("label");
+    let cell = doc.createElement("description");
     cell.className = "plain call-tree-cell";
     cell.setAttribute("type", isSelf ? "self-percentage" : "percentage");
     cell.setAttribute("crop", "end");
     cell.setAttribute("value", L10N.numberWithDecimals(percentage, 2) + PERCENTAGE_UNITS);
     return cell;
   },
   _createAllocationsCell: function(doc, count, isSelf = false) {
-    let cell = doc.createElement("label");
+    let cell = doc.createElement("description");
     cell.className = "plain call-tree-cell";
     cell.setAttribute("type", isSelf ? "self-allocations" : "allocations");
     cell.setAttribute("crop", "end");
     cell.setAttribute("value", count || 0);
     return cell;
   },
   _createSamplesCell: function(doc, count) {
-    let cell = doc.createElement("label");
+    let cell = doc.createElement("description");
     cell.className = "plain call-tree-cell";
     cell.setAttribute("type", "samples");
     cell.setAttribute("crop", "end");
     cell.setAttribute("value", count || "");
     return cell;
   },
   _createFunctionCell: function(doc, arrowNode, frameName, frameInfo, frameLevel) {
     let cell = doc.createElement("hbox");
     cell.className = "call-tree-cell";
     cell.style.MozMarginStart = (frameLevel * CALL_TREE_INDENTATION) + "px";
     cell.setAttribute("type", "function");
     cell.appendChild(arrowNode);
 
     // Don't render a name label node if there's no function name. A different
     // location label node will be rendered instead.
     if (frameName) {
-      let nameNode = doc.createElement("label");
+      let nameNode = doc.createElement("description");
       nameNode.className = "plain call-tree-name";
       nameNode.setAttribute("flex", "1");
       nameNode.setAttribute("crop", "end");
       nameNode.setAttribute("value", frameName);
       cell.appendChild(nameNode);
     }
 
     // Don't render detailed labels for meta category frames
@@ -272,53 +272,53 @@ CallView.prototype = Heritage.extend(Abs
     if (!hasDescendants) {
       arrowNode.setAttribute("invisible", "");
     }
 
     return cell;
   },
   _appendFunctionDetailsCells: function(doc, cell, frameInfo) {
     if (frameInfo.fileName) {
-      let urlNode = doc.createElement("label");
+      let urlNode = doc.createElement("description");
       urlNode.className = "plain call-tree-url";
       urlNode.setAttribute("flex", "1");
       urlNode.setAttribute("crop", "end");
       urlNode.setAttribute("value", frameInfo.fileName);
       urlNode.setAttribute("tooltiptext", URL_LABEL_TOOLTIP + " → " + frameInfo.url);
       urlNode.addEventListener("mousedown", this._onUrlClick);
       cell.appendChild(urlNode);
     }
 
     if (frameInfo.line) {
-      let lineNode = doc.createElement("label");
+      let lineNode = doc.createElement("description");
       lineNode.className = "plain call-tree-line";
       lineNode.setAttribute("value", ":" + frameInfo.line);
       cell.appendChild(lineNode);
     }
 
     if (frameInfo.column) {
-      let columnNode = doc.createElement("label");
+      let columnNode = doc.createElement("description");
       columnNode.className = "plain call-tree-column";
       columnNode.setAttribute("value", ":" + frameInfo.column);
       cell.appendChild(columnNode);
     }
 
     if (frameInfo.host) {
-      let hostNode = doc.createElement("label");
+      let hostNode = doc.createElement("description");
       hostNode.className = "plain call-tree-host";
       hostNode.setAttribute("value", frameInfo.host);
       cell.appendChild(hostNode);
     }
 
     let spacerNode = doc.createElement("spacer");
     spacerNode.setAttribute("flex", "10000");
     cell.appendChild(spacerNode);
 
     if (frameInfo.categoryData.label) {
-      let categoryNode = doc.createElement("label");
+      let categoryNode = doc.createElement("description");
       categoryNode.className = "plain call-tree-category";
       categoryNode.style.color = frameInfo.categoryData.color;
       categoryNode.setAttribute("value", frameInfo.categoryData.label);
       cell.appendChild(categoryNode);
     }
   },
 
   /**
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/modules/widgets/waterfall-ticks.js
@@ -0,0 +1,187 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+/**
+ * This file contains the "waterfall ticks" view, a header for the
+ * markers displayed in the waterfall.
+ */
+
+loader.lazyRequireGetter(this, "L10N",
+  "devtools/performance/global", true);
+loader.lazyRequireGetter(this, "WATERFALL_MARKER_SIDEBAR_WIDTH",
+  "devtools/performance/marker-view", true);
+
+const HTML_NS = "http://www.w3.org/1999/xhtml";
+
+const FIND_OPTIMAL_TICK_INTERVAL_MAX_ITERS = 100;
+
+const WATERFALL_HEADER_TICKS_MULTIPLE = 5; // ms
+const WATERFALL_HEADER_TICKS_SPACING_MIN = 50; // px
+const WATERFALL_HEADER_TEXT_PADDING = 3; // px
+
+const WATERFALL_BACKGROUND_TICKS_MULTIPLE = 5; // ms
+const WATERFALL_BACKGROUND_TICKS_SCALES = 3;
+const WATERFALL_BACKGROUND_TICKS_SPACING_MIN = 10; // px
+const WATERFALL_BACKGROUND_TICKS_COLOR_RGB = [128, 136, 144];
+const WATERFALL_BACKGROUND_TICKS_OPACITY_MIN = 32; // byte
+const WATERFALL_BACKGROUND_TICKS_OPACITY_ADD = 32; // byte
+
+/**
+ * A header for a markers waterfall.
+ *
+ * @param MarkerView root
+ *        The root item of the waterfall tree.
+ */
+function WaterfallHeader(root) {
+  this.root = root;
+}
+
+WaterfallHeader.prototype = {
+  /**
+   * Creates and appends this header as the first element of the specified
+   * parent element.
+   *
+   * @param nsIDOMNode parentNode
+   *        The parent element for this header.
+   */
+  attachTo: function(parentNode) {
+    let document = parentNode.ownerDocument;
+    let startTime = this.root.interval.startTime;
+    let dataScale = this.root.getDataScale();
+    let waterfallWidth = this.root.getWaterfallWidth();
+
+    let header = this._buildNode(document, startTime, dataScale, waterfallWidth);
+    parentNode.insertBefore(header, parentNode.firstChild);
+
+    this._drawWaterfallBackground(document, dataScale, waterfallWidth);
+  },
+
+  /**
+   * Creates the node displaying this view.
+   */
+  _buildNode: function(doc, startTime, dataScale, waterfallWidth) {
+    let container = doc.createElement("hbox");
+    container.className = "waterfall-header-container";
+    container.setAttribute("flex", "1");
+
+    let sidebar = doc.createElement("hbox");
+    sidebar.className = "waterfall-sidebar theme-sidebar";
+    sidebar.setAttribute("width", WATERFALL_MARKER_SIDEBAR_WIDTH);
+    sidebar.setAttribute("align", "center");
+    container.appendChild(sidebar);
+
+    let name = doc.createElement("description");
+    name.className = "plain waterfall-header-name";
+    name.setAttribute("value", L10N.getStr("timeline.records"));
+    sidebar.appendChild(name);
+
+    let ticks = doc.createElement("hbox");
+    ticks.className = "waterfall-header-ticks waterfall-background-ticks";
+    ticks.setAttribute("align", "center");
+    ticks.setAttribute("flex", "1");
+    container.appendChild(ticks);
+
+    let tickInterval = findOptimalTickInterval({
+      ticksMultiple: WATERFALL_HEADER_TICKS_MULTIPLE,
+      ticksSpacingMin: WATERFALL_HEADER_TICKS_SPACING_MIN,
+      dataScale: dataScale
+    });
+
+    for (let x = 0; x < waterfallWidth; x += tickInterval) {
+      let left = x + WATERFALL_HEADER_TEXT_PADDING;
+      let time = Math.round(x / dataScale + startTime);
+      let label = L10N.getFormatStr("timeline.tick", time);
+
+      let node = doc.createElement("description");
+      node.className = "plain waterfall-header-tick";
+      node.style.transform = "translateX(" + left + "px)";
+      node.setAttribute("value", label);
+      ticks.appendChild(node);
+    }
+
+    return container;
+  },
+
+  /**
+   * Creates the background displayed on the marker's waterfall.
+   */
+  _drawWaterfallBackground: function(doc, dataScale, waterfallWidth) {
+    if (!this._canvas || !this._ctx) {
+      this._canvas = doc.createElementNS(HTML_NS, "canvas");
+      this._ctx = this._canvas.getContext("2d");
+    }
+    let canvas = this._canvas;
+    let ctx = this._ctx;
+
+    // Nuke the context.
+    let canvasWidth = canvas.width = waterfallWidth;
+    let canvasHeight = canvas.height = 1; // Awww yeah, 1px, repeats on Y axis.
+
+    // Start over.
+    let imageData = ctx.createImageData(canvasWidth, canvasHeight);
+    let pixelArray = imageData.data;
+
+    let buf = new ArrayBuffer(pixelArray.length);
+    let view8bit = new Uint8ClampedArray(buf);
+    let view32bit = new Uint32Array(buf);
+
+    // Build new millisecond tick lines...
+    let [r, g, b] = WATERFALL_BACKGROUND_TICKS_COLOR_RGB;
+    let alphaComponent = WATERFALL_BACKGROUND_TICKS_OPACITY_MIN;
+    let tickInterval = findOptimalTickInterval({
+      ticksMultiple: WATERFALL_BACKGROUND_TICKS_MULTIPLE,
+      ticksSpacingMin: WATERFALL_BACKGROUND_TICKS_SPACING_MIN,
+      dataScale: dataScale
+    });
+
+    // Insert one pixel for each division on each scale.
+    for (let i = 1; i <= WATERFALL_BACKGROUND_TICKS_SCALES; i++) {
+      let increment = tickInterval * Math.pow(2, i);
+      for (let x = 0; x < canvasWidth; x += increment) {
+        let position = x | 0;
+        view32bit[position] = (alphaComponent << 24) | (b << 16) | (g << 8) | r;
+      }
+      alphaComponent += WATERFALL_BACKGROUND_TICKS_OPACITY_ADD;
+    }
+
+    // Flush the image data and cache the waterfall background.
+    pixelArray.set(view8bit);
+    ctx.putImageData(imageData, 0, 0);
+    doc.mozSetImageElement("waterfall-background", canvas);
+  }
+};
+
+/**
+ * Finds the optimal tick interval between time markers in this timeline.
+ *
+ * @param number ticksMultiple
+ * @param number ticksSpacingMin
+ * @param number dataScale
+ * @return number
+ */
+function findOptimalTickInterval({ ticksMultiple, ticksSpacingMin, dataScale }) {
+  let timingStep = ticksMultiple;
+  let maxIters = FIND_OPTIMAL_TICK_INTERVAL_MAX_ITERS;
+  let numIters = 0;
+
+  if (dataScale > ticksSpacingMin) {
+    return dataScale;
+  }
+
+  while (true) {
+    let scaledStep = dataScale * timingStep;
+    if (++numIters > maxIters) {
+      return scaledStep;
+    }
+    if (scaledStep < ticksSpacingMin) {
+      timingStep <<= 1;
+      continue;
+    }
+    return scaledStep;
+  }
+}
+
+exports.WaterfallHeader = WaterfallHeader;
+exports.TickUtils = { findOptimalTickInterval };
deleted file mode 100644
--- a/browser/devtools/performance/modules/widgets/waterfall.js
+++ /dev/null
@@ -1,620 +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/. */
-"use strict";
-
-/**
- * This file contains the "waterfall" view, essentially a detailed list
- * of all the markers in the timeline data.
- */
-
-const { Cc, Ci, Cu, Cr } = require("chrome");
-
-loader.lazyRequireGetter(this, "promise");
-loader.lazyRequireGetter(this, "EventEmitter",
-  "devtools/toolkit/event-emitter");
-
-loader.lazyRequireGetter(this, "L10N",
-  "devtools/performance/global", true);
-loader.lazyRequireGetter(this, "MarkerUtils",
-  "devtools/performance/marker-utils");
-
-loader.lazyImporter(this, "setNamedTimeout",
-  "resource:///modules/devtools/ViewHelpers.jsm");
-loader.lazyImporter(this, "clearNamedTimeout",
-  "resource:///modules/devtools/ViewHelpers.jsm");
-
-const HTML_NS = "http://www.w3.org/1999/xhtml";
-
-const WATERFALL_SIDEBAR_WIDTH = 200; // px
-
-const WATERFALL_IMMEDIATE_DRAW_MARKERS_COUNT = 30;
-const WATERFALL_FLUSH_OUTSTANDING_MARKERS_DELAY = 75; // ms
-
-const FIND_OPTIMAL_TICK_INTERVAL_MAX_ITERS = 100;
-const WATERFALL_HEADER_TICKS_MULTIPLE = 5; // ms
-const WATERFALL_HEADER_TICKS_SPACING_MIN = 50; // px
-const WATERFALL_HEADER_TEXT_PADDING = 3; // px
-
-const WATERFALL_BACKGROUND_TICKS_MULTIPLE = 5; // ms
-const WATERFALL_BACKGROUND_TICKS_SCALES = 3;
-const WATERFALL_BACKGROUND_TICKS_SPACING_MIN = 10; // px
-const WATERFALL_BACKGROUND_TICKS_COLOR_RGB = [128, 136, 144];
-const WATERFALL_BACKGROUND_TICKS_OPACITY_MIN = 32; // byte
-const WATERFALL_BACKGROUND_TICKS_OPACITY_ADD = 32; // byte
-const WATERFALL_MARKER_BAR_WIDTH_MIN = 5; // px
-
-const WATERFALL_ROWCOUNT_ONPAGEUPDOWN = 10;
-
-/**
- * A detailed waterfall view for the timeline data.
- *
- * @param nsIDOMNode parent
- *        The parent node holding the waterfall.
- * @param nsIDOMNode container
- *        The container node that key events should be bound to.
- * @param Object blueprint
- *        List of names and colors defining markers.
- */
-function Waterfall(parent, container, blueprint) {
-  EventEmitter.decorate(this);
-
-  this._parent = parent;
-  this._document = parent.ownerDocument;
-  this._container = container;
-  this._fragment = this._document.createDocumentFragment();
-  this._outstandingMarkers = [];
-
-  this._headerContents = this._document.createElement("hbox");
-  this._headerContents.className = "waterfall-header-contents";
-  this._parent.appendChild(this._headerContents);
-
-  this._listContents = this._document.createElement("vbox");
-  this._listContents.className = "waterfall-list-contents";
-  this._listContents.setAttribute("flex", "1");
-  this._parent.appendChild(this._listContents);
-
-  this.setupKeys();
-
-  this._isRTL = this._getRTL();
-
-  // Lazy require is a bit slow, and these are hot objects.
-  this._l10n = L10N;
-  this._blueprint = blueprint;
-  this._setNamedTimeout = setNamedTimeout;
-  this._clearNamedTimeout = clearNamedTimeout;
-
-  // Selected row index. By default, we want the first
-  // row to be selected.
-  this._selectedRowIdx = 0;
-
-  // Default rowCount
-  this.rowCount = WATERFALL_ROWCOUNT_ONPAGEUPDOWN;
-}
-
-Waterfall.prototype = {
-  /**
-   * Removes any node references from this view.
-   */
-  destroy: function() {
-    this._parent = this._document = this._container = null;
-  },
-
-  /**
-   * Populates this view with the provided data source.
-   *
-   * @param object data
-   *        An object containing the following properties:
-   *          - markers: a list of markers received from the controller
-   *          - interval: the { startTime, endTime }, in milliseconds
-   */
-  setData: function({ markers, interval }) {
-    this.clearView();
-    this._markers = markers;
-    this._interval = interval;
-
-    let { startTime, endTime } = interval;
-    let dataScale = this._waterfallWidth / (endTime - startTime);
-    this._drawWaterfallBackground(dataScale);
-
-    this._buildHeader(this._headerContents, startTime, dataScale);
-    this._buildMarkers(this._listContents, markers, startTime, endTime, dataScale);
-    this.selectRow(this._selectedRowIdx);
-  },
-
-  /**
-   * List of names and colors used to paint markers.
-   * @see TIMELINE_BLUEPRINT in timeline/widgets/global.js
-   */
-  setBlueprint: function(blueprint) {
-    this._blueprint = blueprint;
-  },
-
-  /**
-   * Keybindings.
-   */
-  setupKeys: function() {
-    let pane = this._container;
-    pane.addEventListener("keydown", e => {
-      if (e.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_UP) {
-        e.preventDefault();
-        this.selectNearestRow(this._selectedRowIdx - 1);
-      }
-      if (e.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_DOWN) {
-        e.preventDefault();
-        this.selectNearestRow(this._selectedRowIdx + 1);
-      }
-      if (e.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_HOME) {
-        e.preventDefault();
-        this.selectNearestRow(0);
-      }
-      if (e.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_END) {
-        e.preventDefault();
-        this.selectNearestRow(this._listContents.children.length);
-      }
-      if (e.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP) {
-        e.preventDefault();
-        this.selectNearestRow(this._selectedRowIdx - this.rowCount);
-      }
-      if (e.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN) {
-        e.preventDefault();
-        this.selectNearestRow(this._selectedRowIdx + this.rowCount);
-      }
-    }, true);
-  },
-
-  /**
-   * Depopulates this view.
-   */
-  clearView: function() {
-    while (this._headerContents.hasChildNodes()) {
-      this._headerContents.firstChild.remove();
-    }
-    while (this._listContents.hasChildNodes()) {
-      this._listContents.firstChild.remove();
-    }
-    this._listContents.scrollTop = 0;
-    this._outstandingMarkers.length = 0;
-    this._clearNamedTimeout("flush-outstanding-markers");
-  },
-
-  /**
-   * Calculates and stores the available width for the waterfall.
-   * This should be invoked every time the container window is resized.
-   */
-  recalculateBounds: function() {
-    let bounds = this._parent.getBoundingClientRect();
-    this._waterfallWidth = bounds.width - WATERFALL_SIDEBAR_WIDTH;
-  },
-
-  /**
-   * Creates the header part of this view.
-   *
-   * @param nsIDOMNode parent
-   *        The parent node holding the header.
-   * @param number startTime
-   *        @see Waterfall.prototype.setData
-   * @param number dataScale
-   *        The time scale of the data source.
-   */
-  _buildHeader: function(parent, startTime, dataScale) {
-    let container = this._document.createElement("hbox");
-    container.className = "waterfall-header-container";
-    container.setAttribute("flex", "1");
-
-    let sidebar = this._document.createElement("hbox");
-    sidebar.className = "waterfall-sidebar theme-sidebar";
-    sidebar.setAttribute("width", WATERFALL_SIDEBAR_WIDTH);
-    sidebar.setAttribute("align", "center");
-    container.appendChild(sidebar);
-
-    let name = this._document.createElement("label");
-    name.className = "plain waterfall-header-name";
-    name.setAttribute("value", this._l10n.getStr("timeline.records"));
-    sidebar.appendChild(name);
-
-    let ticks = this._document.createElement("hbox");
-    ticks.className = "waterfall-header-ticks waterfall-background-ticks";
-    ticks.setAttribute("align", "center");
-    ticks.setAttribute("flex", "1");
-    container.appendChild(ticks);
-
-    let offset = this._isRTL ? this._waterfallWidth : 0;
-    let direction = this._isRTL ? -1 : 1;
-    let tickInterval = this._findOptimalTickInterval({
-      ticksMultiple: WATERFALL_HEADER_TICKS_MULTIPLE,
-      ticksSpacingMin: WATERFALL_HEADER_TICKS_SPACING_MIN,
-      dataScale: dataScale
-    });
-
-    for (let x = 0; x < this._waterfallWidth; x += tickInterval) {
-      let left = x + direction * WATERFALL_HEADER_TEXT_PADDING;
-      let time = Math.round(x / dataScale + startTime);
-      let label = this._l10n.getFormatStr("timeline.tick", time);
-
-      let node = this._document.createElement("label");
-      node.className = "plain waterfall-header-tick";
-      node.style.transform = "translateX(" + (left - offset) + "px)";
-      node.setAttribute("value", label);
-      ticks.appendChild(node);
-    }
-
-    parent.appendChild(container);
-  },
-
-  /**
-   * Creates the markers part of this view.
-   *
-   * @param nsIDOMNode parent
-   *        The parent node holding the markers.
-   * @param number startTime
-   *        @see Waterfall.prototype.setData
-   * @param number dataScale
-   *        The time scale of the data source.
-   */
-  _buildMarkers: function(parent, markers, startTime, endTime, dataScale) {
-    let rowsCount = 0;
-    let markerIdx = -1;
-
-    for (let marker of markers) {
-      markerIdx++;
-
-      if (!isMarkerInRange(marker, startTime, endTime)) {
-        continue;
-      }
-      if (!(marker.name in this._blueprint)) {
-        continue;
-      }
-
-      // Only build and display a finite number of markers initially, to
-      // preserve a snappy UI. After a certain delay, continue building the
-      // outstanding markers while there's (hopefully) no user interaction.
-      let arguments_ = [this._fragment, marker, startTime, dataScale, markerIdx, rowsCount];
-      if (rowsCount++ < WATERFALL_IMMEDIATE_DRAW_MARKERS_COUNT) {
-        this._buildMarker.apply(this, arguments_);
-      } else {
-        this._outstandingMarkers.push(arguments_);
-      }
-    }
-
-    // If there are no outstanding markers, add a dummy "spacer" at the end
-    // to fill up any remaining available space in the UI.
-    if (!this._outstandingMarkers.length) {
-      this._buildMarker(this._fragment, null);
-    }
-    // Otherwise prepare flushing the outstanding markers after a small delay.
-    else {
-      let delay = WATERFALL_FLUSH_OUTSTANDING_MARKERS_DELAY;
-      let func = () => this._buildOutstandingMarkers(parent);
-      this._setNamedTimeout("flush-outstanding-markers", delay, func);
-    }
-
-    parent.appendChild(this._fragment);
-  },
-
-  /**
-   * Finishes building the outstanding markers in this view.
-   * @see Waterfall.prototype._buildMarkers
-   */
-  _buildOutstandingMarkers: function(parent) {
-    if (!this._outstandingMarkers.length) {
-      return;
-    }
-    for (let args of this._outstandingMarkers) {
-      this._buildMarker.apply(this, args);
-    }
-    this._outstandingMarkers.length = 0;
-    parent.appendChild(this._fragment);
-    this.selectRow(this._selectedRowIdx);
-  },
-
-  /**
-   * Creates a single marker in this view.
-   *
-   * @param nsIDOMNode parent
-   *        The parent node holding the marker.
-   * @param object marker
-   *        The { name, start, end } marker in the data source.
-   * @param startTime
-   *        @see Waterfall.prototype.setData
-   * @param number dataScale
-   *        @see Waterfall.prototype._buildMarkers
-   * @param number markerIdx
-   *        Index of the marker in this._markers
-   * @param number rowIdx
-   *        Index of current row
-   */
-  _buildMarker: function(parent, marker, startTime, dataScale, markerIdx, rowIdx) {
-    let container = this._document.createElement("hbox");
-    container.setAttribute("markerIdx", markerIdx);
-    container.className = "waterfall-marker-container";
-
-    if (marker) {
-      this._buildMarkerSidebar(container, marker);
-      this._buildMarkerWaterfall(container, marker, startTime, dataScale, markerIdx);
-      container.onclick = () => this.selectRow(rowIdx);
-    } else {
-      this._buildMarkerSpacer(container);
-      container.setAttribute("flex", "1");
-      container.setAttribute("is-spacer", "");
-    }
-
-    parent.appendChild(container);
-  },
-
-  /**
-   * Select first row.
-   */
-  resetSelection: function() {
-    this.selectRow(0);
-  },
-
-  /**
-   * Select a marker in the waterfall.
-   *
-   * @param number idx
-   *        Index of the row to select. -1 clears the selection.
-   */
-  selectRow: function(idx) {
-    let prev = this._listContents.children[this._selectedRowIdx];
-    if (prev) {
-      prev.classList.remove("selected");
-    }
-
-    this._selectedRowIdx = idx;
-
-    let row = this._listContents.children[idx];
-    if (row && !row.hasAttribute("is-spacer")) {
-      row.focus();
-      row.classList.add("selected");
-
-      let markerIdx = row.getAttribute("markerIdx");
-      this.emit("selected", this._markers[markerIdx]);
-      this.ensureRowIsVisible(row);
-    } else {
-      this.emit("unselected");
-    }
-  },
-
-  /**
-   * Find a valid row to select.
-   *
-   * @param number idx
-   *        Index of the row to select.
-   */
-  selectNearestRow: function(idx) {
-    if (this._listContents.children.length == 0) {
-      return;
-    }
-    idx = Math.max(idx, 0);
-    idx = Math.min(idx, this._listContents.children.length - 1);
-    let row = this._listContents.children[idx];
-    if (row && row.hasAttribute("is-spacer")) {
-      if (idx > 0) {
-        return this.selectNearestRow(idx - 1);
-      } else {
-        return;
-      }
-    }
-    this.selectRow(idx);
-  },
-
-  /**
-   * Scroll waterfall to ensure row is in the viewport.
-   *
-   * @param number idx
-   *        Index of the row to select.
-   */
-  ensureRowIsVisible: function(row) {
-    let parent = row.parentNode;
-    let parentRect = parent.getBoundingClientRect();
-    let rowRect = row.getBoundingClientRect();
-    let yDelta = rowRect.top - parentRect.top;
-    if (yDelta < 0) {
-      parent.scrollTop += yDelta;
-    }
-    yDelta = parentRect.bottom - rowRect.bottom;
-    if (yDelta < 0) {
-      parent.scrollTop -= yDelta;
-    }
-  },
-
-  /**
-   * Creates the sidebar part of a marker in this view.
-   *
-   * @param nsIDOMNode container
-   *        The container node representing the marker in this view.
-   * @param object marker
-   *        @see Waterfall.prototype._buildMarker
-   */
-  _buildMarkerSidebar: function(container, marker) {
-    let blueprint = this._blueprint[marker.name];
-
-    let sidebar = this._document.createElement("hbox");
-    sidebar.className = "waterfall-sidebar theme-sidebar";
-    sidebar.setAttribute("width", WATERFALL_SIDEBAR_WIDTH);
-    sidebar.setAttribute("align", "center");
-
-    let bullet = this._document.createElement("hbox");
-    bullet.className = `waterfall-marker-bullet marker-color-${blueprint.colorName}`;
-    bullet.setAttribute("type", marker.name);
-    sidebar.appendChild(bullet);
-
-    let name = this._document.createElement("label");
-    name.setAttribute("crop", "end");
-    name.setAttribute("flex", "1");
-    name.className = "plain waterfall-marker-name";
-
-    let label = MarkerUtils.getMarkerLabel(marker);
-    name.setAttribute("value", label);
-    name.setAttribute("tooltiptext", label);
-    sidebar.appendChild(name);
-
-    container.appendChild(sidebar);
-  },
-
-  /**
-   * Creates the waterfall part of a marker in this view.
-   *
-   * @param nsIDOMNode container
-   *        The container node representing the marker.
-   * @param object marker
-   *        @see Waterfall.prototype._buildMarker
-   * @param startTime
-   *        @see Waterfall.prototype.setData
-   * @param number dataScale
-   *        @see Waterfall.prototype._buildMarkers
-   */
-  _buildMarkerWaterfall: function(container, marker, startTime, dataScale) {
-    let blueprint = this._blueprint[marker.name];
-
-    let waterfall = this._document.createElement("hbox");
-    waterfall.className = "waterfall-marker-item waterfall-background-ticks";
-    waterfall.setAttribute("align", "center");
-    waterfall.setAttribute("flex", "1");
-
-    let start = (marker.start - startTime) * dataScale;
-    let width = (marker.end - marker.start) * dataScale;
-    let offset = this._isRTL ? this._waterfallWidth : 0;
-
-    let bar = this._document.createElement("hbox");
-    bar.className = `waterfall-marker-bar marker-color-${blueprint.colorName}`;
-    bar.style.transform = "translateX(" + (start - offset) + "px)";
-    bar.setAttribute("type", marker.name);
-    bar.setAttribute("width", Math.max(width, WATERFALL_MARKER_BAR_WIDTH_MIN));
-    waterfall.appendChild(bar);
-
-    container.appendChild(waterfall);
-  },
-
-  /**
-   * Creates a dummy spacer as an empty marker.
-   *
-   * @param nsIDOMNode container
-   *        The container node representing the marker.
-   */
-  _buildMarkerSpacer: function(container) {
-    let sidebarSpacer = this._document.createElement("spacer");
-    sidebarSpacer.className = "waterfall-sidebar theme-sidebar";
-    sidebarSpacer.setAttribute("width", WATERFALL_SIDEBAR_WIDTH);
-
-    let waterfallSpacer = this._document.createElement("spacer");
-    waterfallSpacer.className = "waterfall-marker-item waterfall-background-ticks";
-    waterfallSpacer.setAttribute("flex", "1");
-
-    container.appendChild(sidebarSpacer);
-    container.appendChild(waterfallSpacer);
-  },
-
-  /**
-   * Creates the background displayed on the marker's waterfall.
-   *
-   * @param number dataScale
-   *        @see Waterfall.prototype._buildMarkers
-   */
-  _drawWaterfallBackground: function(dataScale) {
-    if (!this._canvas || !this._ctx) {
-      this._canvas = this._document.createElementNS(HTML_NS, "canvas");
-      this._ctx = this._canvas.getContext("2d");
-    }
-    let canvas = this._canvas;
-    let ctx = this._ctx;
-
-    // Nuke the context.
-    let canvasWidth = canvas.width = this._waterfallWidth;
-    let canvasHeight = canvas.height = 1; // Awww yeah, 1px, repeats on Y axis.
-
-    // Start over.
-    let imageData = ctx.createImageData(canvasWidth, canvasHeight);
-    let pixelArray = imageData.data;
-
-    let buf = new ArrayBuffer(pixelArray.length);
-    let view8bit = new Uint8ClampedArray(buf);
-    let view32bit = new Uint32Array(buf);
-
-    // Build new millisecond tick lines...
-    let [r, g, b] = WATERFALL_BACKGROUND_TICKS_COLOR_RGB;
-    let alphaComponent = WATERFALL_BACKGROUND_TICKS_OPACITY_MIN;
-    let tickInterval = this._findOptimalTickInterval({
-      ticksMultiple: WATERFALL_BACKGROUND_TICKS_MULTIPLE,
-      ticksSpacingMin: WATERFALL_BACKGROUND_TICKS_SPACING_MIN,
-      dataScale: dataScale
-    });
-
-    // Insert one pixel for each division on each scale.
-    for (let i = 1; i <= WATERFALL_BACKGROUND_TICKS_SCALES; i++) {
-      let increment = tickInterval * Math.pow(2, i);
-      for (let x = 0; x < canvasWidth; x += increment) {
-        let position = x | 0;
-        view32bit[position] = (alphaComponent << 24) | (b << 16) | (g << 8) | r;
-      }
-      alphaComponent += WATERFALL_BACKGROUND_TICKS_OPACITY_ADD;
-    }
-
-    // Flush the image data and cache the waterfall background.
-    pixelArray.set(view8bit);
-    ctx.putImageData(imageData, 0, 0);
-    this._document.mozSetImageElement("waterfall-background", canvas);
-  },
-
-  /**
-   * Finds the optimal tick interval between time markers in this timeline.
-   *
-   * @param number ticksMultiple
-   * @param number ticksSpacingMin
-   * @param number dataScale
-   * @return number
-   */
-  _findOptimalTickInterval: function({ ticksMultiple, ticksSpacingMin, dataScale }) {
-    let timingStep = ticksMultiple;
-    let maxIters = FIND_OPTIMAL_TICK_INTERVAL_MAX_ITERS;
-    let numIters = 0;
-
-    if (dataScale > ticksSpacingMin) {
-      return dataScale;
-    }
-
-    while (true) {
-      let scaledStep = dataScale * timingStep;
-      if (++numIters > maxIters) {
-        return scaledStep;
-      }
-      if (scaledStep < ticksSpacingMin) {
-        timingStep <<= 1;
-        continue;
-      }
-      return scaledStep;
-    }
-  },
-
-  /**
-   * Returns true if this is document is in RTL mode.
-   * @return boolean
-   */
-  _getRTL: function() {
-    let win = this._document.defaultView;
-    let doc = this._document.documentElement;
-    return win.getComputedStyle(doc, null).direction == "rtl";
-  }
-};
-
-/**
- * Checks if a given marker is in the specified time range.
- *
- * @param object e
- *        The marker containing the { start, end } timestamps.
- * @param number start
- *        The earliest allowed time.
- * @param number end
- *        The latest allowed time.
- * @return boolean
- *         True if the marker fits inside the specified time range.
- */
-function isMarkerInRange(e, start, end) {
-  return (e.start >= start && e.end <= end) || // bounds inside
-         (e.start < start && e.end > end) || // bounds outside
-         (e.start < start && e.end >= start && e.end <= end) || // overlap start
-         (e.end > end && e.start >= start && e.start <= end); // overlap end
-}
-
-exports.Waterfall = Waterfall;
--- a/browser/devtools/performance/moz.build
+++ b/browser/devtools/performance/moz.build
@@ -10,17 +10,19 @@ EXTRA_JS_MODULES.devtools.performance +=
     'modules/logic/frame-utils.js',
     'modules/logic/front.js',
     'modules/logic/io.js',
     'modules/logic/jit.js',
     'modules/logic/marker-utils.js',
     'modules/logic/recording-model.js',
     'modules/logic/recording-utils.js',
     'modules/logic/tree-model.js',
+    'modules/logic/waterfall-utils.js',
     'modules/widgets/graphs.js',
     'modules/widgets/marker-details.js',
+    'modules/widgets/marker-view.js',
     'modules/widgets/markers-overview.js',
     'modules/widgets/tree-view.js',
-    'modules/widgets/waterfall.js',
+    'modules/widgets/waterfall-ticks.js',
     'panel.js'
 ]
 
 BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
--- a/browser/devtools/performance/performance-controller.js
+++ b/browser/devtools/performance/performance-controller.js
@@ -20,22 +20,26 @@ loader.lazyRequireGetter(this, "L10N",
 loader.lazyRequireGetter(this, "TIMELINE_BLUEPRINT",
   "devtools/performance/global", true);
 loader.lazyRequireGetter(this, "RecordingUtils",
   "devtools/performance/recording-utils");
 loader.lazyRequireGetter(this, "RecordingModel",
   "devtools/performance/recording-model", true);
 loader.lazyRequireGetter(this, "GraphsController",
   "devtools/performance/graphs", true);
-loader.lazyRequireGetter(this, "Waterfall",
-  "devtools/performance/waterfall", true);
+loader.lazyRequireGetter(this, "WaterfallHeader",
+  "devtools/performance/waterfall-ticks", true);
+loader.lazyRequireGetter(this, "MarkerView",
+  "devtools/performance/marker-view", true);
 loader.lazyRequireGetter(this, "MarkerDetails",
   "devtools/performance/marker-details", true);
 loader.lazyRequireGetter(this, "MarkerUtils",
   "devtools/performance/marker-utils");
+loader.lazyRequireGetter(this, "WaterfallUtils",
+  "devtools/performance/waterfall-utils");
 loader.lazyRequireGetter(this, "CallView",
   "devtools/performance/tree-view", true);
 loader.lazyRequireGetter(this, "ThreadNode",
   "devtools/performance/tree-model", true);
 loader.lazyRequireGetter(this, "FrameNode",
   "devtools/performance/tree-model", true);
 loader.lazyRequireGetter(this, "JITOptimizations",
   "devtools/performance/jit", true);
--- a/browser/devtools/performance/performance.xul
+++ b/browser/devtools/performance/performance.xul
@@ -236,22 +236,23 @@
                      value="&profilerUI.bufferStatusFull;"/>
             </vbox>
 
             <!-- Detail views -->
             <deck id="details-pane" flex="1">
 
               <!-- Waterfall -->
               <hbox id="waterfall-view" flex="1">
-                <vbox id="waterfall-breakdown" flex="1" />
+                <vbox flex="1">
+                  <hbox id="waterfall-header" />
+                  <vbox id="waterfall-breakdown" flex="1" />
+                </vbox>
                 <splitter class="devtools-side-splitter"/>
                 <vbox id="waterfall-details"
-                      class="theme-sidebar"
-                      width="150"
-                      height="150"/>
+                      class="theme-sidebar"/>
               </hbox>
 
               <!-- JS Tree and JIT view -->
               <hbox id="js-profile-view" flex="1">
                 <vbox id="js-calltree-view" flex="1">
                   <hbox class="call-tree-headers-container">
                     <label class="plain call-tree-header"
                            type="duration"
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
--- a/browser/devtools/performance/test/browser.ini
+++ b/browser/devtools/performance/test/browser.ini
@@ -140,9 +140,11 @@ skip-if = e10s # GC events seem unreliab
 [browser_profiler_tree-view-07.js]
 [browser_profiler_tree-view-08.js]
 [browser_profiler_tree-view-09.js]
 [browser_profiler-frame-utils-01.js]
 [browser_timeline-blueprint.js]
 [browser_timeline-filters.js]
 [browser_timeline-waterfall-background.js]
 [browser_timeline-waterfall-generic.js]
+[browser_timeline-waterfall-rerender.js]
 [browser_timeline-waterfall-sidebar.js]
+[browser_waterfall-collapse.js]
--- a/browser/devtools/performance/test/browser_perf-front-basic-timeline-01.js
+++ b/browser/devtools/performance/test/browser_perf-front-basic-timeline-01.js
@@ -63,18 +63,21 @@ function* spawnTest() {
       ok(delta > lastTickDelta, "received `delta` in ticks event");
 
       // Timestamps aren't guaranteed to always contain tick events, since
       // they're dependent on the refresh driver, which may be blocked.
 
       counters.ticks.push({ delta, timestamps });
       lastTickDelta = delta;
     }
+    else if (name === "frames") {
+      // Nothing to do here.
+    }
     else {
-      throw new Error("unknown event " + name);
+      ok(false, `Received unknown event: ${name}`);
     }
 
     if (name === "markers" && counters[name].length === 1 ||
         name === "memory" && counters[name].length === 3 ||
         name === "ticks" && counters[name].length === 3) {
       deferreds[name].resolve();
     }
   };
--- a/browser/devtools/performance/test/browser_profiler_tree-abstract-01.js
+++ b/browser/devtools/performance/test/browser_profiler_tree-abstract-01.js
@@ -13,16 +13,21 @@ function* spawnTest() {
   let container = document.createElement("vbox");
   gBrowser.selectedBrowser.parentNode.appendChild(container);
 
   // Populate the tree and test the root item...
 
   let treeRoot = new MyCustomTreeItem(gDataSrc, { parent: null });
   treeRoot.attachTo(container);
 
+  ok(!treeRoot.expanded,
+    "The root node should not be expanded yet.");
+  ok(!treeRoot.populated,
+    "The root node should not be populated yet.");
+
   is(container.childNodes.length, 1,
     "The container node should have one child available.");
   is(container.childNodes[0], treeRoot.target,
     "The root node's target is a child of the container node.");
 
   is(treeRoot.root, treeRoot,
     "The root node has the correct root.");
   is(treeRoot.parent, null,
--- a/browser/devtools/performance/test/browser_profiler_tree-abstract-02.js
+++ b/browser/devtools/performance/test/browser_profiler_tree-abstract-02.js
@@ -11,24 +11,19 @@ let { Heritage } = Cu.import("resource:/
 
 function* spawnTest() {
   let container = document.createElement("vbox");
   gBrowser.selectedBrowser.parentNode.appendChild(container);
 
   // Populate the tree and test `expand`, `collapse` and `getChild`...
 
   let treeRoot = new MyCustomTreeItem(gDataSrc, { parent: null });
+  treeRoot.autoExpandDepth = 1;
   treeRoot.attachTo(container);
 
-  ok(!treeRoot.expanded,
-    "The root node should not be expanded yet.");
-  ok(!treeRoot.populated,
-    "The root node should not be populated yet.");
-
-  treeRoot.expand();
   ok(treeRoot.expanded,
     "The root node should now be expanded.");
   ok(treeRoot.populated,
     "The root node should now be populated.");
 
   let fooItem = treeRoot.getChild(0);
   let barItem = treeRoot.getChild(1);
   ok(!fooItem.expanded && !barItem.expanded,
--- a/browser/devtools/performance/test/browser_timeline-blueprint.js
+++ b/browser/devtools/performance/test/browser_timeline-blueprint.js
@@ -10,16 +10,25 @@ function* spawnTest() {
 
   ok(TIMELINE_BLUEPRINT,
     "A timeline blueprint should be available.");
 
   ok(Object.keys(TIMELINE_BLUEPRINT).length,
     "The timeline blueprint has at least one entry.");
 
   for (let [key, value] of Iterator(TIMELINE_BLUEPRINT)) {
-    ok("group" in value,
-      "Each entry in the timeline blueprint contains a `group` key.");
-    ok("colorName" in value,
-      "Each entry in the timeline blueprint contains a `colorName` key.");
-    ok("label" in value,
-      "Each entry in the timeline blueprint contains a `label` key.");
+    if (key.startsWith("meta::")) {
+      ok(!("group" in value),
+        "No meta entry in the timeline blueprint can contain a `group` key.");
+      ok("colorName" in value,
+        "Each meta entry in the timeline blueprint contains a `colorName` key.");
+      ok("label" in value,
+        "Each meta entry in the timeline blueprint contains a `label` key.");
+    } else {
+      ok("group" in value,
+        "Each entry in the timeline blueprint contains a `group` key.");
+      ok("colorName" in value,
+        "Each entry in the timeline blueprint contains a `colorName` key.");
+      ok("label" in value,
+        "Each entry in the timeline blueprint contains a `label` key.");
+    }
   }
 }
--- a/browser/devtools/performance/test/browser_timeline-filters.js
+++ b/browser/devtools/performance/test/browser_timeline-filters.js
@@ -2,94 +2,87 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests markers filtering mechanism.
  */
 
 function* spawnTest() {
   let { panel } = yield initPerformance(SIMPLE_URL);
-  let { $, $$, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
+  let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
   let { TimelineGraph } = devtools.require("devtools/performance/graphs");
   let { rowHeight: MARKERS_GRAPH_ROW_HEIGHT } = TimelineGraph.prototype;
 
   yield startRecording(panel);
   ok(true, "Recording has started.");
 
   yield waitUntil(() => {
     // Wait until we get 3 different markers.
     let markers = PerformanceController.getCurrentRecording().getMarkers();
     return markers.some(m => m.name == "Styles") &&
            markers.some(m => m.name == "Reflow") &&
            markers.some(m => m.name == "Paint");
   });
 
   yield stopRecording(panel);
 
-  let overview = OverviewView.graphs.get("timeline");
-  let waterfall = WaterfallView.waterfall;
-
   // Select everything
   OverviewView.setTimeInterval({ startTime: 0, endTime: Number.MAX_VALUE })
 
   $("#filter-button").click();
-
-  yield waitUntil(() => !waterfall._outstandingMarkers.length);
-
   let menuItem1 = $("menuitem[marker-type=Styles]");
   let menuItem2 = $("menuitem[marker-type=Reflow]");
   let menuItem3 = $("menuitem[marker-type=Paint]");
 
+  let overview = OverviewView.graphs.get("timeline");
   let originalHeight = overview.fixedHeight;
 
   ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (1)");
   ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (1)");
   ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (1)");
 
   let heightBefore = overview.fixedHeight;
   EventUtils.synthesizeMouseAtCenter(menuItem1, {type: "mouseup"}, panel.panelWin);
-  yield once(menuItem1, "command");
-
-  yield waitUntil(() => !waterfall._outstandingMarkers.length);
+  yield waitForOverviewAndCommand(overview, menuItem1);
 
   is(overview.fixedHeight, heightBefore, "Overview height hasn't changed");
   ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (2)");
   ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (2)");
   ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (2)");
 
   heightBefore = overview.fixedHeight;
   EventUtils.synthesizeMouseAtCenter(menuItem2, {type: "mouseup"}, panel.panelWin);
-  yield once(menuItem2, "command");
-
-  yield waitUntil(() => !waterfall._outstandingMarkers.length);
+  yield waitForOverviewAndCommand(overview, menuItem2);
 
   is(overview.fixedHeight, heightBefore, "Overview height hasn't changed");
   ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (3)");
   ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (3)");
   ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (3)");
 
   heightBefore = overview.fixedHeight;
   EventUtils.synthesizeMouseAtCenter(menuItem3, {type: "mouseup"}, panel.panelWin);
-  yield once(menuItem3, "command");
-
-  yield waitUntil(() => !waterfall._outstandingMarkers.length);
+  yield waitForOverviewAndCommand(overview, menuItem3);
 
   is(overview.fixedHeight, heightBefore - MARKERS_GRAPH_ROW_HEIGHT, "Overview is smaller");
   ok(!$(".waterfall-marker-bar[type=Styles]"), "No 'Styles' marker (4)");
   ok(!$(".waterfall-marker-bar[type=Reflow]"), "No 'Reflow' marker (4)");
   ok(!$(".waterfall-marker-bar[type=Paint]"), "No 'Paint' marker (4)");
 
   for (let item of [menuItem1, menuItem2, menuItem3]) {
     EventUtils.synthesizeMouseAtCenter(item, {type: "mouseup"}, panel.panelWin);
-    yield once(item, "command");
+    yield waitForOverviewAndCommand(overview, item);
   }
 
-  yield waitUntil(() => !waterfall._outstandingMarkers.length);
-
   ok($(".waterfall-marker-bar[type=Styles]"), "Found at least one 'Styles' marker (5)");
   ok($(".waterfall-marker-bar[type=Reflow]"), "Found at least one 'Reflow' marker (5)");
   ok($(".waterfall-marker-bar[type=Paint]"), "Found at least one 'Paint' marker (5)");
 
   is(overview.fixedHeight, originalHeight, "Overview restored");
 
   yield teardown(panel);
   finish();
 }
+
+function waitForOverviewAndCommand(overview, item) {
+  let overviewRendered = overview.once("refresh");
+  let menuitemCommandDispatched = once(item, "command");
+  return Promise.all([overviewRendered, menuitemCommandDispatched]);
+}
--- a/browser/devtools/performance/test/browser_timeline-waterfall-background.js
+++ b/browser/devtools/performance/test/browser_timeline-waterfall-background.js
@@ -20,34 +20,37 @@ function* spawnTest() {
     "The overview graphs were updated a bunch of times.");
   ok((yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length > 0)),
     "There are some markers available.");
 
   let rendered = Promise.all([
     DetailsView.selectView("waterfall"),
     once(WaterfallView, EVENTS.WATERFALL_RENDERED)
   ]);
+
   yield stopRecording(panel);
   ok(true, "Recording has ended.");
+
   yield rendered;
+  ok(true, "Recording has rendered.");
 
   // Test the waterfall background.
 
   let parentWidth = $("#waterfall-view").getBoundingClientRect().width;
   let sidebarWidth = $(".waterfall-sidebar").getBoundingClientRect().width;
   let detailsWidth = $("#waterfall-details").getBoundingClientRect().width;
-  let waterfallWidth = WaterfallView.waterfall._waterfallWidth;
+  let waterfallWidth = WaterfallView._markersRoot._waterfallWidth;
   is(waterfallWidth, parentWidth - sidebarWidth - detailsWidth,
     "The waterfall width is correct.")
 
-  ok(WaterfallView.waterfall._canvas,
+  ok(WaterfallView._waterfallHeader._canvas,
     "A canvas should be created after the recording ended.");
-  ok(WaterfallView.waterfall._ctx,
+  ok(WaterfallView._waterfallHeader._ctx,
     "A 2d context should be created after the recording ended.");
 
-  is(WaterfallView.waterfall._canvas.width, waterfallWidth,
+  is(WaterfallView._waterfallHeader._canvas.width, waterfallWidth,
     "The canvas width is correct.");
-  is(WaterfallView.waterfall._canvas.height, 1,
+  is(WaterfallView._waterfallHeader._canvas.height, 1,
     "The canvas height is correct.");
 
   yield teardown(panel);
   finish();
 }
--- a/browser/devtools/performance/test/browser_timeline-waterfall-generic.js
+++ b/browser/devtools/performance/test/browser_timeline-waterfall-generic.js
@@ -37,31 +37,27 @@ function* spawnTest() {
 
   // Test the header ticks (right).
 
   ok($(".waterfall-header-ticks"),
     "A header ticks node should have been created.");
   ok($$(".waterfall-header-ticks > .waterfall-header-tick").length > 0,
     "Some header tick labels should have been created inside the tick node.");
 
-  // Test the markers container.
-
-  ok($(".waterfall-marker-container"),
-    "A marker container should have been created.");
-
   // Test the markers sidebar (left).
 
-  ok($$(".waterfall-marker-container > .waterfall-sidebar").length,
+  ok($$(".waterfall-tree-item > .waterfall-sidebar").length,
     "Some marker sidebar nodes should have been created.");
-  ok($$(".waterfall-marker-container > .waterfall-sidebar:not(spacer) > .waterfall-marker-bullet").length,
+  ok($$(".waterfall-tree-item > .waterfall-sidebar > .waterfall-marker-bullet").length,
     "Some marker color bullets should have been created inside the sidebar.");
-  ok($$(".waterfall-marker-container > .waterfall-sidebar:not(spacer) > .waterfall-marker-name").length,
+  ok($$(".waterfall-tree-item > .waterfall-sidebar > .waterfall-marker-name").length,
     "Some marker name labels should have been created inside the sidebar.");
 
   // Test the markers waterfall (right).
 
-  ok($$(".waterfall-marker-item").length,
+  ok($$(".waterfall-tree-item > .waterfall-marker").length,
     "Some marker waterfall nodes should have been created.");
-  ok($$(".waterfall-marker-item:not(spacer) > .waterfall-marker-bar").length,
+  ok($$(".waterfall-tree-item > .waterfall-marker > .waterfall-marker-bar").length,
     "Some marker color bars should have been created inside the waterfall.");
+
   yield teardown(panel);
   finish();
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_timeline-waterfall-rerender.js
@@ -0,0 +1,57 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the waterfall remembers the selection when rerendering.
+ */
+
+function* spawnTest() {
+  let { target, panel } = yield initPerformance(SIMPLE_URL);
+  let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
+
+  yield startRecording(panel);
+  ok(true, "Recording has started.");
+
+  let updated = 0;
+  OverviewView.on(EVENTS.OVERVIEW_RENDERED, () => updated++);
+
+  ok((yield waitUntil(() => updated > 0)),
+    "The overview graphs were updated a bunch of times.");
+  ok((yield waitUntil(() => PerformanceController.getCurrentRecording().getMarkers().length > 0)),
+    "There are some markers available.");
+
+  yield stopRecording(panel);
+  ok(true, "Recording has ended.");
+
+  let initialBarsCount = $$(".waterfall-marker-bar").length;
+
+  // Select a portion of the overview.
+  let timeline = OverviewView.graphs.get("timeline");
+  let rerendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
+  timeline.setSelection({ start: 0, end: timeline.width / 2 })
+  yield rerendered;
+
+  // Focus the second item in the tree.
+  WaterfallView._markersRoot.getChild(1).focus();
+
+  let beforeResizeBarsCount = $$(".waterfall-marker-bar").length;
+  ok(beforeResizeBarsCount < initialBarsCount,
+    "A subset of the total markers was selected.");
+
+  is(Array.indexOf($$(".waterfall-tree-item"), $(".waterfall-tree-item:focus")), 2,
+    "The correct item was focused in the tree.");
+
+  rerendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
+  EventUtils.sendMouseEvent({ type: "mouseup" }, WaterfallView.detailsSplitter);
+  yield rerendered;
+
+  let afterResizeBarsCount = $$(".waterfall-marker-bar").length;
+  is(afterResizeBarsCount, beforeResizeBarsCount,
+    "The same subset of the total markers remained visible.");
+
+  is(Array.indexOf($$(".waterfall-tree-item"), $(".waterfall-tree-item:focus")), 2,
+    "The correct item is still focused in the tree.");
+
+  yield teardown(panel);
+  finish();
+}
--- a/browser/devtools/performance/test/browser_timeline-waterfall-sidebar.js
+++ b/browser/devtools/performance/test/browser_timeline-waterfall-sidebar.js
@@ -2,58 +2,71 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * Tests if the sidebar is properly updated when a marker is selected.
  */
 
 function* spawnTest() {
   let { target, panel } = yield initPerformance(SIMPLE_URL);
-  let { $, $$, EVENTS, PerformanceController, OverviewView } = panel.panelWin;
+  let { $, $$, EVENTS, PerformanceController, OverviewView, WaterfallView } = panel.panelWin;
   let { L10N, TIMELINE_BLUEPRINT } = devtools.require("devtools/performance/global");
   let { getMarkerLabel } = devtools.require("devtools/performance/marker-utils");
 
+  // Hijack the markers massaging part of creating the waterfall view,
+  // to prevent collapsing markers and allowing this test to verify
+  // everything individually. A better solution would be to just expand
+  // all markers first and then skip the meta nodes, but I'm lazy.
+  WaterfallView._prepareWaterfallTree = markers => {
+    return { submarkers: markers };
+  };
+
   yield startRecording(panel);
   ok(true, "Recording has started.");
 
   yield waitUntil(() => {
     // Wait until we get 3 different markers.
     let markers = PerformanceController.getCurrentRecording().getMarkers();
     return markers.some(m => m.name == "Styles") &&
            markers.some(m => m.name == "Reflow") &&
            markers.some(m => m.name == "Paint");
   });
 
   yield stopRecording(panel);
   ok(true, "Recording has ended.");
 
   // Select everything
-  OverviewView.graphs.get("timeline").setSelection({ start: 0, end: OverviewView.graphs.get("timeline").width })
+  let timeline = OverviewView.graphs.get("timeline");
+  let rerendered = WaterfallView.once(EVENTS.WATERFALL_RENDERED);
+  timeline.setSelection({ start: 0, end: timeline.width })
+  yield rerendered;
 
-  let bars = $$(".waterfall-marker-item:not(spacer) > .waterfall-marker-bar");
+  let bars = $$(".waterfall-marker-bar");
   let markers = PerformanceController.getCurrentRecording().getMarkers();
 
-  ok(bars.length > 2, "got at least 3 markers");
+  ok(bars.length > 2, "Got at least 3 markers (1)");
+  ok(markers.length > 2, "Got at least 3 markers (2)");
 
-  let sidebar = $("#waterfall-details");
   for (let i = 0; i < bars.length; i++) {
     let bar = bars[i];
-    bar.click();
     let m = markers[i];
+    EventUtils.sendMouseEvent({ type: "mousedown" }, bar);
 
     is($("#waterfall-details .marker-details-type").getAttribute("value"), getMarkerLabel(m),
-      "sidebar title matches markers name");
+      "Sidebar title matches markers name.");
 
     let tooltip = $(".marker-details-duration").getAttribute("tooltiptext");
-    let printedDuration = $(".marker-details-duration .marker-details-labelvalue").getAttribute("value");
+    let duration = $(".marker-details-duration .marker-details-labelvalue").getAttribute("value");
 
     let toMs = ms => L10N.getFormatStrWithNumbers("timeline.tick", ms);
 
     // Values are rounded. We don't use a strict equality.
-    is(toMs(m.end - m.start), printedDuration, "sidebar duration is valid");
+    is(toMs(m.end - m.start), duration, "Sidebar duration is valid.");
+
     // For some reason, anything that creates "→" here turns it into a "â" for some reason.
     // So just check that start and end time are in there somewhere.
-    ok(tooltip.indexOf(toMs(m.start)) !== -1, "tooltip has start time");
-    ok(tooltip.indexOf(toMs(m.end)) !== -1, "tooltip has end time");
+    ok(tooltip.indexOf(toMs(m.start)) !== -1, "Tooltip has start time.");
+    ok(tooltip.indexOf(toMs(m.end)) !== -1, "Tooltip has end time.");
   }
+
   yield teardown(panel);
   finish();
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/performance/test/browser_waterfall-collapse.js
@@ -0,0 +1,358 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests if the waterfall collapsing logic works properly.
+ */
+
+function test() {
+  const WaterfallUtils = devtools.require("devtools/performance/waterfall-utils");
+
+  let rootMarkerNode = WaterfallUtils.makeEmptyMarkerNode("(root)");
+
+  WaterfallUtils.collapseMarkersIntoNode({
+    markerNode: rootMarkerNode,
+    markersList: gTestMarkers
+  });
+
+  is(rootMarkerNode.toSource(), gExpectedOutput.toSource(),
+    "The markers didn't collapse properly.");
+
+  finish();
+}
+
+const gTestMarkers = [
+// Test collapsing Style markers
+{
+  start: 1,
+  end: 2,
+  name: "Styles"
+},
+{
+  start: 3,
+  end: 4,
+  name: "Styles"
+},
+// Test collapsing Reflow markers
+{
+  start: 5,
+  end: 6,
+  name: "Reflow"
+},
+{
+  start: 7,
+  end: 8,
+  name: "Reflow"
+},
+// Test collapsing Paint markers
+{
+  start: 9,
+  end: 10,
+  name: "Paint"
+}, {
+  start: 11,
+  end: 12,
+  name: "Paint"
+},
+// Test standalone DOMEvent markers followed by a different marker
+{
+  start: 13,
+  end: 14,
+  name: "DOMEvent",
+  eventPhase: 1,
+  type: "foo1"
+},
+{
+  start: 15,
+  end: 16,
+  name: "TimeStamp"
+},
+// Test a DOMEvent marker followed by a Javascript marker.
+{
+  start: 17,
+  end: 18,
+  name: "DOMEvent",
+  eventPhase: 2,
+  type: "foo2"
+}, {
+  start: 19,
+  end: 20,
+  name: "Javascript",
+  stack: 1,
+  endStack: 2
+},
+// Test another DOMEvent marker followed by a Javascript marker.
+{
+  start: 21,
+  end: 22,
+  name: "DOMEvent",
+  eventPhase: 3,
+  type: "foo3"
+}, {
+  start: 23,
+  end: 24,
+  name: "Javascript",
+  stack: 3,
+  endStack: 4
+},
+// Test a DOMEvent marker followed by multiple Javascript markers.
+{
+  start: 25,
+  end: 26,
+  name: "DOMEvent",
+  eventPhase: 4,
+  type: "foo4"
+}, {
+  start: 27,
+  end: 28,
+  name: "Javascript",
+  stack: 5,
+  endStack: 6
+}, {
+  start: 29,
+  end: 30,
+  name: "Javascript",
+  stack: 7,
+  endStack: 8
+}, {
+  start: 31,
+  end: 32,
+  name: "Javascript",
+  stack: 9,
+  endStack: 10
+},
+// Test multiple DOMEvent markers followed by multiple Javascript markers.
+{
+  start: 33,
+  end: 34,
+  name: "DOMEvent",
+  eventPhase: 5,
+  type: "foo5"
+}, {
+  start: 35,
+  end: 36,
+  name: "DOMEvent",
+  eventPhase: 6,
+  type: "foo6"
+}, {
+  start: 37,
+  end: 38,
+  name: "DOMEvent",
+  eventPhase: 7,
+  type: "foo6"
+}, {
+  start: 39,
+  end: 40,
+  name: "Javascript",
+  stack: 11,
+  endStack: 12
+}, {
+  start: 41,
+  end: 42,
+  name: "Javascript",
+  stack: 13,
+  endStack: 14
+}, {
+  start: 43,
+  end: 44,
+  name: "Javascript",
+  stack: 15,
+  endStack: 16
+},
+// Test a lonely marker at the end.
+{
+  start: 45,
+  end: 46,
+  name: "GarbageCollection"
+}
+];
+
+const gExpectedOutput = {
+  name: "(root)",
+  start: (void 0),
+  end: (void 0),
+  submarkers: [{
+    name: "Styles",
+    start: 1,
+    end: 4,
+    submarkers: [{
+      start: 1,
+      end: 2,
+      name: "Styles"
+    }, {
+      start: 3,
+      end: 4,
+      name: "Styles"
+    }]
+  }, {
+    name: "Reflow",
+    start: 5,
+    end: 8,
+    submarkers: [{
+      start: 5,
+      end: 6,
+      name: "Reflow"
+    }, {
+      start: 7,
+      end: 8,
+      name: "Reflow"
+    }]
+  }, {
+    name: "Paint",
+    start: 9,
+    end: 12,
+    submarkers: [{
+      start: 9,
+      end: 10,
+      name: "Paint"
+    }, {
+      start: 11,
+      end: 12,
+      name: "Paint"
+    }]
+  }, {
+    start: 13,
+    end: 14,
+    name: "DOMEvent",
+    eventPhase: 1,
+    type: "foo1"
+  }, {
+    start: 15,
+    end: 16,
+    name: "TimeStamp"
+  }, {
+    name: "meta::DOMEvent+JS",
+    start: 17,
+    end: 20,
+    submarkers: [{
+      start: 17,
+      end: 18,
+      name: "DOMEvent",
+      eventPhase: 2,
+      type: "foo2"
+    }, {
+      start: 19,
+      end: 20,
+      name: "Javascript",
+      stack: 1,
+      endStack: 2
+    }],
+    type: "foo2",
+    eventPhase: 2,
+    stack: 1,
+    endStack: 2
+  }, {
+    name: "meta::DOMEvent+JS",
+    start: 21,
+    end: 24,
+    submarkers: [{
+      start: 21,
+      end: 22,
+      name: "DOMEvent",
+      eventPhase: 3,
+      type: "foo3"
+    }, {
+      start: 23,
+      end: 24,
+      name: "Javascript",
+      stack: 3,
+      endStack: 4
+    }],
+    type: "foo3",
+    eventPhase: 3,
+    stack: 3,
+    endStack: 4
+  }, {
+    name: "meta::DOMEvent+JS",
+    start: 25,
+    end: 28,
+    submarkers: [{
+      start: 25,
+      end: 26,
+      name: "DOMEvent",
+      eventPhase: 4,
+      type: "foo4"
+    }, {
+      start: 27,
+      end: 28,
+      name: "Javascript",
+      stack: 5,
+      endStack: 6
+    }],
+    type: "foo4",
+    eventPhase: 4,
+    stack: 5,
+    endStack: 6
+  }, {
+    name: "Javascript",
+    start: 29,
+    end: 32,
+    submarkers: [{
+      start: 29,
+      end: 30,
+      name: "Javascript",
+      stack: 7,
+      endStack: 8
+    }, {
+      start: 31,
+      end: 32,
+      name: "Javascript",
+      stack: 9,
+      endStack: 10
+    }]
+  }, {
+    start: 33,
+    end: 34,
+    name: "DOMEvent",
+    eventPhase: 5,
+    type: "foo5"
+  }, {
+    start: 35,
+    end: 36,
+    name: "DOMEvent",
+    eventPhase: 6,
+    type: "foo6"
+  }, {
+    name: "meta::DOMEvent+JS",
+    start: 37,
+    end: 40,
+    submarkers: [{
+      start: 37,
+      end: 38,
+      name: "DOMEvent",
+      eventPhase: 7,
+      type: "foo6"
+    }, {
+      start: 39,
+      end: 40,
+      name: "Javascript",
+      stack: 11,
+      endStack: 12
+    }],
+    type: "foo6",
+    eventPhase: 7,
+    stack: 11,
+    endStack: 12
+  }, {
+    name: "Javascript",
+    start: 41,
+    end: 44,
+    submarkers: [{
+      start: 41,
+      end: 42,
+      name: "Javascript",
+      stack: 13,
+      endStack: 14
+    }, {
+      start: 43,
+      end: 44,
+      name: "Javascript",
+      stack: 15,
+      endStack: 16
+    }]
+  }, {
+    start: 45,
+    end: 46,
+    name: "GarbageCollection"
+  }]
+};
--- a/browser/devtools/performance/views/details-waterfall.js
+++ b/browser/devtools/performance/views/details-waterfall.js
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const MARKER_DETAILS_WIDTH = 300;
+const WATERFALL_RESIZE_EVENTS_DRAIN = 100; // ms
+const MARKER_DETAILS_WIDTH = 200;
 
 /**
  * Waterfall view containing the timeline markers, controlled by DetailsView.
  */
 let WaterfallView = Heritage.extend(DetailsSubview, {
 
   observedPrefs: [
     "hidden-markers"
@@ -21,101 +22,153 @@ let WaterfallView = Heritage.extend(Deta
   rangeChangeDebounceTime: 75, // ms
 
   /**
    * Sets up the view with event binding.
    */
   initialize: function () {
     DetailsSubview.initialize.call(this);
 
-    // TODO bug 1167093 save the previously set width, and ensure minimum width
-    $("#waterfall-details").setAttribute("width", MARKER_DETAILS_WIDTH);
-
-    this.waterfall = new Waterfall($("#waterfall-breakdown"), $("#waterfall-view"));
-    this.details = new MarkerDetails($("#waterfall-details"), $("#waterfall-view > splitter"));
-
     this._onMarkerSelected = this._onMarkerSelected.bind(this);
     this._onResize = this._onResize.bind(this);
     this._onViewSource = this._onViewSource.bind(this);
 
-    this.waterfall.on("selected", this._onMarkerSelected);
-    this.waterfall.on("unselected", this._onMarkerSelected);
+    this.headerContainer = $("#waterfall-header");
+    this.breakdownContainer = $("#waterfall-breakdown");
+    this.detailsContainer = $("#waterfall-details");
+    this.detailsSplitter = $("#waterfall-view > splitter");
+
+    this.details = new MarkerDetails($("#waterfall-details"), $("#waterfall-view > splitter"));
     this.details.on("resize", this._onResize);
     this.details.on("view-source", this._onViewSource);
+    window.addEventListener("resize", this._onResize);
 
-    let blueprint = PerformanceController.getTimelineBlueprint();
-    this.waterfall.setBlueprint(blueprint);
-    this.waterfall.recalculateBounds();
+    // TODO bug 1167093 save the previously set width, and ensure minimum width
+    this.details.width = MARKER_DETAILS_WIDTH;
   },
 
   /**
    * Unbinds events.
    */
   destroy: function () {
     DetailsSubview.destroy.call(this);
 
-    this.waterfall.off("selected", this._onMarkerSelected);
-    this.waterfall.off("unselected", this._onMarkerSelected);
     this.details.off("resize", this._onResize);
     this.details.off("view-source", this._onViewSource);
+    window.removeEventListener("resize", this._onResize);
   },
 
   /**
    * Method for handling all the set up for rendering a new waterfall.
    *
    * @param object interval [optional]
    *        The { startTime, endTime }, in milliseconds.
    */
   render: function(interval={}) {
     let recording = PerformanceController.getCurrentRecording();
     let startTime = interval.startTime || 0;
     let endTime = interval.endTime || recording.getDuration();
     let markers = recording.getMarkers();
-    this.waterfall.setData({ markers, interval: { startTime, endTime } });
+    let rootMarkerNode = this._prepareWaterfallTree(markers);
+
+    this._populateWaterfallTree(rootMarkerNode, { startTime, endTime });
     this.emit(EVENTS.WATERFALL_RENDERED);
   },
 
   /**
    * Called when a marker is selected in the waterfall view,
    * updating the markers detail view.
    */
   _onMarkerSelected: function (event, marker) {
     let recording = PerformanceController.getCurrentRecording();
-    // Race condition in tests due to lazy rendering of markers in the
-    // waterfall? intermittent bug 1157523
-    if (!recording) {
-      return;
-    }
     let frames = recording.getFrames();
 
     if (event === "selected") {
       this.details.render({ toolbox: gToolbox, marker, frames });
+      this._selected = marker;
     }
     if (event === "unselected") {
       this.details.empty();
+      this._selected = null;
     }
   },
 
   /**
    * Called when the marker details view is resized.
    */
   _onResize: function () {
-    this.waterfall.recalculateBounds();
-    this.render();
+    setNamedTimeout("waterfall-resize", WATERFALL_RESIZE_EVENTS_DRAIN, () => {
+      this._markersRoot.recalculateBounds();
+      this.render(OverviewView.getTimeInterval());
+    });
   },
 
   /**
    * Called whenever an observed pref is changed.
    */
   _onObservedPrefChange: function(_, prefName) {
     let blueprint = PerformanceController.getTimelineBlueprint();
-    this.waterfall.setBlueprint(blueprint);
+    this._markersRoot.blueprint = blueprint;
   },
 
   /**
    * Called when MarkerDetails view emits an event to view source.
    */
   _onViewSource: function (_, file, line) {
     gToolbox.viewSourceInDebugger(file, line);
   },
 
+  /**
+   * Called when the recording is stopped and prepares data to
+   * populate the waterfall tree.
+   */
+  _prepareWaterfallTree: function(markers) {
+    let rootMarkerNode = WaterfallUtils.makeEmptyMarkerNode("(root)");
+
+    WaterfallUtils.collapseMarkersIntoNode({
+      markerNode: rootMarkerNode,
+      markersList: markers
+    });
+
+    return rootMarkerNode;
+  },
+
+  /**
+   * Renders the waterfall tree.
+   */
+  _populateWaterfallTree: function(rootMarkerNode, interval) {
+    let root = new MarkerView({
+      marker: rootMarkerNode,
+      // The root node is irrelevant in a waterfall tree.
+      hidden: true,
+      // The waterfall tree should not expand by default.
+      autoExpandDepth: 0
+    });
+
+    let header = new WaterfallHeader(root);
+
+    this._markersRoot = root;
+    this._waterfallHeader = header;
+
+    let blueprint = PerformanceController.getTimelineBlueprint();
+    root.blueprint = blueprint;
+    root.interval = interval;
+    root.on("selected", this._onMarkerSelected);
+    root.on("unselected", this._onMarkerSelected);
+
+    this.breakdownContainer.innerHTML = "";
+    root.attachTo(this.breakdownContainer);
+
+    this.headerContainer.innerHTML = "";
+    header.attachTo(this.headerContainer);
+
+    // If an item was previously selected in this view, attempt to
+    // re-select it by traversing the newly created tree.
+    if (this._selected) {
+      let item = root.find(i => i.marker == this._selected);
+      if (item) {
+        item.focus();
+      }
+    }
+  },
+
   toString: () => "[object WaterfallView]"
 });
new file mode 100644
--- /dev/null
+++ b/browser/devtools/projecteditor/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/responsivedesign/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/scratchpad/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shadereditor/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/shared/test/unit/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the common devtools xpcshell eslintrc config.
+  "extends": "../../../.eslintrc.xpcshell"
+}
\ No newline at end of file
--- a/browser/devtools/shared/widgets/AbstractTreeItem.jsm
+++ b/browser/devtools/shared/widgets/AbstractTreeItem.jsm
@@ -1,21 +1,25 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const Cu = Components.utils;
+const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource://gre/modules/devtools/event-emitter.js");
-XPCOMUtils.defineLazyModuleGetter(this, "console", "resource://gre/modules/devtools/Console.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
+  "resource://gre/modules/devtools/event-emitter.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "console",
+  "resource://gre/modules/devtools/Console.jsm");
 
 this.EXPORTED_SYMBOLS = ["AbstractTreeItem"];
 
 /**
  * A very generic and low-level tree view implementation. It is not intended
  * to be used alone, but as a base class that you can extend to build your
  * own custom implementation.
  *
@@ -112,23 +116,22 @@ this.EXPORTED_SYMBOLS = ["AbstractTreeIt
  * @param number level
  *        The indentation level in the tree. The root item is at level 0.
  */
 function AbstractTreeItem({ parent, level }) {
   this._rootItem = parent ? parent._rootItem : this;
   this._parentItem = parent;
   this._level = level || 0;
   this._childTreeItems = [];
-  this._onArrowClick = this._onArrowClick.bind(this);
-  this._onClick = this._onClick.bind(this);
-  this._onDoubleClick = this._onDoubleClick.bind(this);
-  this._onKeyPress = this._onKeyPress.bind(this);
-  this._onFocus = this._onFocus.bind(this);
 
-  EventEmitter.decorate(this);
+  // Events are always propagated through the root item. Decorating every
+  // tree item as an event emitter is a very costly operation.
+  if (this == this._rootItem) {
+    EventEmitter.decorate(this);
+  }
 }
 
 AbstractTreeItem.prototype = {
   _containerNode: null,
   _targetNode: null,
   _arrowNode: null,
   _constructed: false,
   _populated: false,
@@ -145,29 +148,39 @@ AbstractTreeItem.prototype = {
    * inheriting classes to create the child node displayed in the tree.
    * Use `this.level` and the provided `arrowNode` as you see fit.
    *
    * @param nsIDOMNode document
    * @param nsIDOMNode arrowNode
    * @return nsIDOMNode
    */
   _displaySelf: function(document, arrowNode) {
-    throw "This method needs to be implemented by inheriting classes.";
+    throw new Error(
+      "The `_displaySelf` method needs to be implemented by inheriting classes.");
   },
 
   /**
    * Populates this tree item with child items, whenever it's expanded.
    * Implement this method in the inheriting classes to fill the provided
    * `children` array with AbstractTreeItem instances, which will then be
    * magically handled by this tree item.
    *
    * @param array:AbstractTreeItem children
    */
   _populateSelf: function(children) {
-    throw "This method needs to be implemented by inheriting classes.";
+    throw new Error(
+      "The `_populateSelf` method needs to be implemented by inheriting classes.");
+  },
+
+  /**
+   * Gets the this tree's owner document.
+   * @return Document
+   */
+  get document() {
+    return this._containerNode.ownerDocument;
   },
 
   /**
    * Gets the root item of this tree.
    * @return AbstractTreeItem
    */
   get root() {
     return this._rootItem;
@@ -217,27 +230,45 @@ AbstractTreeItem.prototype = {
    * Expanded items with no children aren't consudered `populated`.
    * @return boolean
    */
   get expanded() {
     return this._expanded;
   },
 
   /**
+   * Gets the bounds for this tree's container without flushing.
+   * @return object
+   */
+  get bounds() {
+    let win = this.document.defaultView;
+    let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+    return utils.getBoundsWithoutFlushing(this._containerNode);
+  },
+
+  /**
    * Creates and appends this tree item to the specified parent element.
    *
    * @param nsIDOMNode containerNode
    *        The parent element for this tree item (and every other tree item).
-   * @param nsIDOMNode beforeNode
-   *        The child element which should succeed this tree item.
+   * @param nsIDOMNode fragmentNode [optional]
+   *        An optional document fragment temporarily holding this tree item in
+   *        the current batch. Defaults to the `containerNode`.
+   * @param nsIDOMNode beforeNode [optional]
+   *        An optional child element which should succeed this tree item.
    */
-  attachTo: function(containerNode, beforeNode = null) {
+  attachTo: function(containerNode, fragmentNode = containerNode, beforeNode = null) {
     this._containerNode = containerNode;
     this._constructTargetNode();
-    containerNode.insertBefore(this._targetNode, beforeNode);
+
+    if (beforeNode) {
+      fragmentNode.insertBefore(this._targetNode, beforeNode);
+    } else {
+      fragmentNode.appendChild(this._targetNode);
+    }
 
     if (this._level < this.autoExpandDepth) {
       this.expand();
     }
   },
 
   /**
    * Permanently removes this tree item (and all subsequent children) from the
@@ -260,44 +291,73 @@ AbstractTreeItem.prototype = {
    * Expands this item in the tree.
    */
   expand: function() {
     if (this._expanded) {
       return;
     }
     this._expanded = true;
     this._arrowNode.setAttribute("open", "");
+    this._targetNode.setAttribute("expanded", "");
     this._toggleChildren(true);
     this._rootItem.emit("expand", this);
   },
 
   /**
    * Collapses this item in the tree.
    */
   collapse: function() {
     if (!this._expanded) {
       return;
     }
     this._expanded = false;
     this._arrowNode.removeAttribute("open");
+    this._targetNode.removeAttribute("expanded", "");
     this._toggleChildren(false);
     this._rootItem.emit("collapse", this);
   },
 
   /**
    * Returns the child item at the specified index.
    *
    * @param number index
    * @return AbstractTreeItem
    */
   getChild: function(index = 0) {
     return this._childTreeItems[index];
   },
 
   /**
+   * Calls the provided function on all the descendants of this item.
+   * If this item was never expanded, then no descendents exist yet.
+   * @param function cb
+   */
+  traverse: function(cb) {
+    for (let child of this._childTreeItems) {
+      cb(child);
+      child.bfs();
+    }
+  },
+
+  /**
+   * Calls the provided function on all descendants of this item until
+   * a truthy value is returned by the predicate.
+   * @param function predicate
+   * @return AbstractTreeItem
+   */
+  find: function(predicate) {
+    for (let child of this._childTreeItems) {
+      if (predicate(child) || child.find(predicate)) {
+        return child;
+      }
+    }
+    return null;
+  },
+
+  /**
    * Shows or hides all the children of this item in the tree. If neessary,
    * populates this item with children.
    *
    * @param boolean visible
    *        True if the children should be visible, false otherwise.
    */
   _toggleChildren: function(visible) {
     if (visible) {
@@ -310,60 +370,101 @@ AbstractTreeItem.prototype = {
       this._hideChildren();
     }
   },
 
   /**
    * Shows all children of this item in the tree.
    */
   _showChildren: function() {
-    let childTreeItems = this._childTreeItems;
-    let expandedChildTreeItems = childTreeItems.filter(e => e._expanded);
-    let nextNode = this._getSiblingAtDelta(1);
-
-    // First append the child items, and afterwards append any descendants.
-    // Otherwise, the tree will become garbled and nodes will intertwine.
-    for (let item of childTreeItems) {
-      item.attachTo(this._containerNode, nextNode);
+    // If this is the root item and we're not expanding any child nodes,
+    // it is safe to append everything at once.
+    if (this == this._rootItem && this.autoExpandDepth == 0) {
+      this._appendChildrenBatch();
     }
-    for (let item of expandedChildTreeItems) {
-      item._showChildren();
+    // Otherwise, append the child items and their descendants successively;
+    // if not, the tree will become garbled and nodes will intertwine,
+    // since all the tree items are sharing a single container node.
+    else {
+      this._appendChildrenSuccessive();
     }
   },
 
   /**
    * Hides all children of this item in the tree.
    */
   _hideChildren: function() {
     for (let item of this._childTreeItems) {
       item._targetNode.remove();
       item._hideChildren();
     }
   },
 
   /**
+   * Appends all children in a single batch.
+   * This only works properly for root nodes when no child nodes will expand.
+   */
+  _appendChildrenBatch: function() {
+    if (this._fragment === undefined) {
+      this._fragment = this.document.createDocumentFragment();
+    }
+
+    let childTreeItems = this._childTreeItems;
+
+    for (let i = 0, len = childTreeItems.length; i < len; i++) {
+      childTreeItems[i].attachTo(this._containerNode, this._fragment);
+    }
+
+    this._containerNode.appendChild(this._fragment);
+  },
+
+  /**
+   * Appends all children successively.
+   */
+  _appendChildrenSuccessive: function() {
+    let childTreeItems = this._childTreeItems;
+    let expandedChildTreeItems = childTreeItems.filter(e => e._expanded);
+    let nextNode = this._getSiblingAtDelta(1);
+
+    for (let i = 0, len = childTreeItems.length; i < len; i++) {
+      childTreeItems[i].attachTo(this._containerNode, undefined, nextNode);
+    }
+    for (let i = 0, len = expandedChildTreeItems.length; i < len; i++) {
+      expandedChildTreeItems[i]._showChildren();
+    }
+  },
+
+  /**
    * Constructs and stores the target node displaying this tree item.
    */
   _constructTargetNode: function() {
     if (this._constructed) {
       return;
     }
-    let document = this._containerNode.ownerDocument;
+    this._onArrowClick = this._onArrowClick.bind(this);
+    this._onClick = this._onClick.bind(this);
+    this._onDoubleClick = this._onDoubleClick.bind(this);
+    this._onKeyPress = this._onKeyPress.bind(this);
+    this._onFocus = this._onFocus.bind(this);
+    this._onBlur = this._onBlur.bind(this);
+
+    let document = this.document;
 
     let arrowNode = this._arrowNode = document.createElement("hbox");
     arrowNode.className = "arrow theme-twisty";
     arrowNode.addEventListener("mousedown", this._onArrowClick);
 
     let targetNode = this._targetNode = this._displaySelf(document, arrowNode);
     targetNode.style.MozUserFocus = "normal";
 
     targetNode.addEventListener("mousedown", this._onClick);
     targetNode.addEventListener("dblclick", this._onDoubleClick);
     targetNode.addEventListener("keypress", this._onKeyPress);
     targetNode.addEventListener("focus", this._onFocus);
+    targetNode.addEventListener("blur", this._onBlur);
 
     this._constructed = true;
   },
 
   /**
    * Gets the element displaying an item in the tree at the specified offset
    * relative to this item.
    *
@@ -429,17 +530,16 @@ AbstractTreeItem.prototype = {
    * Handler for the "dblclick" event on the element displaying this tree item.
    */
   _onDoubleClick: function(e) {
     // Ignore dblclick on the arrow as it has already recived and handled two
     // click events.
     if (!e.target.classList.contains("arrow")) {
       this._onArrowClick(e);
     }
-
     this.focus();
   },
 
   /**
    * Handler for the "keypress" event on the element displaying this tree item.
    */
   _onKeyPress: function(e) {
     // Prevent scrolling when pressing navigation keys.
@@ -472,10 +572,17 @@ AbstractTreeItem.prototype = {
     }
   },
 
   /**
    * Handler for the "focus" event on the element displaying this tree item.
    */
   _onFocus: function(e) {
     this._rootItem.emit("focus", this);
+  },
+
+  /**
+   * Handler for the "blur" event on the element displaying this tree item.
+   */
+  _onBlur: function(e) {
+    this._rootItem.emit("blur", this);
   }
 };
--- a/browser/devtools/shared/widgets/FlameGraph.js
+++ b/browser/devtools/shared/widgets/FlameGraph.js
@@ -1,26 +1,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
+const { Task } = require("resource://gre/modules/Task.jsm");
 const { ViewHelpers } = require("resource:///modules/devtools/ViewHelpers.jsm");
-const { AbstractCanvasGraph, GraphArea, GraphAreaDragger } = require("resource:///modules/devtools/Graphs.jsm");
-const { Promise } = require("resource://gre/modules/Promise.jsm");
-const { Task } = require("resource://gre/modules/Task.jsm");
-const { getColor } = require("devtools/shared/theme");
-const EventEmitter = require("devtools/toolkit/event-emitter");
-const FrameUtils = require("devtools/performance/frame-utils");
+const { setNamedTimeout, clearNamedTimeout } = require("resource:///modules/devtools/ViewHelpers.jsm");
+
+loader.lazyRequireGetter(this, "promise");
+loader.lazyRequireGetter(this, "EventEmitter",
+  "devtools/toolkit/event-emitter");
+
+loader.lazyRequireGetter(this, "getColor",
+  "devtools/shared/theme", true);
 
 loader.lazyRequireGetter(this, "CATEGORY_MAPPINGS",
   "devtools/performance/global", true);
+loader.lazyRequireGetter(this, "FrameUtils",
+  "devtools/performance/frame-utils");
+
+loader.lazyImporter(this, "AbstractCanvasGraph",
+  "resource:///modules/devtools/Graphs.jsm");
+loader.lazyImporter(this, "GraphArea",
+  "resource:///modules/devtools/Graphs.jsm");
+loader.lazyImporter(this, "GraphAreaDragger",
+  "resource:///modules/devtools/Graphs.jsm");
 
 const HTML_NS = "http://www.w3.org/1999/xhtml";
 const GRAPH_SRC = "chrome://browser/content/devtools/graphs-frame.xhtml";
+
 const L10N = new ViewHelpers.L10N();
 
 const GRAPH_RESIZE_EVENTS_DRAIN = 100; // ms
 
 const GRAPH_WHEEL_ZOOM_SENSITIVITY = 0.00035;
 const GRAPH_WHEEL_SCROLL_SENSITIVITY = 0.5;
 const GRAPH_MIN_SELECTION_WIDTH = 0.001; // ms
 
@@ -107,17 +120,17 @@ const COLOR_PALLETTE = Array.from(Array(
  *        The parent node holding the graph.
  * @param number sharpness [optional]
  *        Defaults to the current device pixel ratio.
  */
 function FlameGraph(parent, sharpness) {
   EventEmitter.decorate(this);
 
   this._parent = parent;
-  this._ready = Promise.defer();
+  this._ready = promise.defer();
 
   this.setTheme();
 
   AbstractCanvasGraph.createIframe(GRAPH_SRC, parent, iframe => {
     this._iframe = iframe;
     this._window = iframe.contentWindow;
     this._document = iframe.contentDocument;
     this._pixelRatio = sharpness || this._window.devicePixelRatio;
--- a/browser/devtools/shared/widgets/graphs-frame.xhtml
+++ b/browser/devtools/shared/widgets/graphs-frame.xhtml
@@ -10,16 +10,17 @@
   <link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
   <link rel="stylesheet" href="chrome://browser/skin/devtools/widgets.css" ype="text/css"/>
   <script type="application/javascript;version=1.8" src="theme-switching.js"/>
   <style>
     body {
       overflow: hidden;
       margin: 0;
       padding: 0;
+      font-size: 0;
     }
   </style>
 </head>
 <body role="application">
   <div id="graph-container">
     <canvas id="graph-canvas"></canvas>
   </div>
 </body>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/sourceeditor/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/storage/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
--- a/browser/devtools/styleinspector/rule-view.js
+++ b/browser/devtools/styleinspector/rule-view.js
@@ -2680,23 +2680,55 @@ RuleEditor.prototype = {
    *        True if the change should be applied.
    */
   _onSelectorDone: function(aValue, aCommit) {
     if (!aCommit || this.isEditing || aValue === "" ||
         aValue === this.rule.selectorText) {
       return;
     }
 
+    let ruleView = this.ruleView;
+    let elementStyle = ruleView._elementStyle;
+    let element = elementStyle.element;
+    let supportsUnmatchedRules =
+      this.rule.domRule.supportsModifySelectorUnmatched;
+
     this.isEditing = true;
 
-    this.rule.domRule.modifySelector(aValue).then(isModified => {
+    this.rule.domRule.modifySelector(element, aValue).then(response => {
       this.isEditing = false;
 
-      if (isModified) {
-        this.ruleView.refreshPanel();
+      if (!supportsUnmatchedRules) {
+        if (response) {
+          this.ruleView.refreshPanel();
+        }
+        return;
+      }
+
+      let {ruleProps, isMatching} = response;
+      if (!ruleProps) {
+        return;
+      }
+
+      let newRule = new Rule(elementStyle, ruleProps);
+      let editor = new RuleEditor(ruleView, newRule);
+      let rules = elementStyle.rules;
+
+      rules.splice(rules.indexOf(this.rule), 1);
+      rules.push(newRule);
+      elementStyle._changed();
+
+      editor.element.setAttribute("unmatched", !isMatching);
+      this.element.parentNode.replaceChild(editor.element, this.element);
+
+      // Remove highlight for modified selector
+      if (ruleView.highlightedSelector &&
+          ruleView.highlightedSelector == this.rule.selectorText) {
+        ruleView.toggleSelectorHighlighter(ruleView.lastSelectorIcon,
+          ruleView.highlightedSelector);
       }
     }).then(null, err => {
       this.isEditing = false;
       promiseWarn(err);
     });
   }
 };
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
--- a/browser/devtools/styleinspector/test/browser.ini
+++ b/browser/devtools/styleinspector/test/browser.ini
@@ -82,16 +82,19 @@ skip-if = e10s # Bug 1039528: "inspect e
 [browser_ruleview_edit-property-increments.js]
 [browser_ruleview_edit-property-order.js]
 [browser_ruleview_edit-property_01.js]
 [browser_ruleview_edit-property_02.js]
 [browser_ruleview_edit-property_03.js]
 [browser_ruleview_edit-selector-commit.js]
 [browser_ruleview_edit-selector_01.js]
 [browser_ruleview_edit-selector_02.js]
+[browser_ruleview_edit-selector_03.js]
+[browser_ruleview_edit-selector_04.js]
+[browser_ruleview_edit-selector_05.js]
 [browser_ruleview_eyedropper.js]
 [browser_ruleview_filtereditor-appears-on-swatch-click.js]
 [browser_ruleview_filtereditor-commit-on-ENTER.js]
 [browser_ruleview_filtereditor-revert-on-ESC.js]
 skip-if = (os == "win" && debug) || e10s # bug 963492: win. bug 1040653: e10s.
 [browser_ruleview_inherit.js]
 [browser_ruleview_keybindings.js]
 [browser_ruleview_keyframes-rule_01.js]
--- a/browser/devtools/styleinspector/test/browser_ruleview_add-rule_02.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_add-rule_02.js
@@ -21,45 +21,46 @@ add_task(function*() {
   yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(PAGE_CONTENT));
 
   info("Opening the rule-view");
   let {toolbox, inspector, view} = yield openRuleView();
 
   info("Selecting the test element");
   yield selectNode("#testid", inspector);
 
-  info("Waiting for rule view to change");
+  info("Waiting for rule view to update");
   let onRuleViewChanged = once(view, "ruleview-changed");
 
   info("Adding the new rule");
   view.addRuleButton.click();
 
   yield onRuleViewChanged;
 
   yield testEditSelector(view, "span");
 
-  info("Selecting the modified element");
+  info("Selecting the modified element with the new rule");
   yield selectNode("span", inspector);
   yield checkModifiedElement(view, "span");
 });
 
 function* testEditSelector(view, name) {
   info("Test editing existing selector field");
   let idRuleEditor = getRuleViewRuleEditor(view, 1);
   let editor = idRuleEditor.selectorText.ownerDocument.activeElement;
 
   info("Entering a new selector name and committing");
   editor.value = name;
 
-  info("Waiting for rule view to refresh");
-  let onRuleViewRefresh = once(view, "ruleview-refreshed");
+  info("Waiting for rule view to update");
+  let onRuleViewChanged = once(view, "ruleview-changed");
 
   info("Entering the commit key");
   EventUtils.synthesizeKey("VK_RETURN", {});
-  yield onRuleViewRefresh;
+  yield onRuleViewChanged;
 
-  is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
+  is(view._elementStyle.rules.length, 3, "Should have 3 rules.");
+  ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
 }
 
 function* checkModifiedElement(view, name) {
   is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
   ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_add-rule_03.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_add-rule_03.js
@@ -74,24 +74,24 @@ function* testEditSelector(view, name) {
   let editor = yield focusEditableField(idRuleEditor.selectorText);
 
   is(inplaceEditor(idRuleEditor.selectorText), editor,
     "The selector editor got focused");
 
   info("Entering a new selector name: " + name);
   editor.input.value = name;
 
-  info("Waiting for rule view to refresh");
-  let onRuleViewRefresh = once(view, "ruleview-refreshed");
+  info("Waiting for rule view to update");
+  let onRuleViewChanged = once(view, "ruleview-changed");
 
   info("Entering the commit key");
   EventUtils.synthesizeKey("VK_RETURN", {});
-  yield onRuleViewRefresh;
+  yield onRuleViewChanged;
 
-  is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
+  is(view._elementStyle.rules.length, 3, "Should have 3 rules.");
 }
 
 function* checkModifiedElement(view, name, index) {
   is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
   ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
 
   let idRuleEditor = getRuleViewRuleEditor(view, index);
   let textProps = idRuleEditor.rule.textProps;
--- a/browser/devtools/styleinspector/test/browser_ruleview_edit-selector-commit.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-selector-commit.js
@@ -43,22 +43,17 @@ const TEST_DATA = [
     value: ".testclass",
     commitKey: "VK_TAB",
     modifiers: {shiftKey: true},
     expected: ".testclass"
   }
 ];
 
 add_task(function*() {
-  yield addTab("data:text/html;charset=utf-8,test escaping selector change reverts back to original value");
-
-  info("Creating the test document");
-  content.document.body.innerHTML = PAGE_CONTENT;
-
-  info("Opening the rule-view");
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(PAGE_CONTENT));
   let {toolbox, inspector, view} = yield openRuleView();
 
   info("Iterating over the test data");
   for (let data of TEST_DATA) {
     yield runTestData(inspector, view, data);
   }
 });
 
@@ -83,16 +78,16 @@ function* runTestData(inspector, view, d
   info("Entering the commit key " + commitKey + " " + modifiers);
   EventUtils.synthesizeKey(commitKey, modifiers);
 
   if (commitKey === "VK_ESCAPE") {
     is(idRuleEditor.rule.selectorText, expected,
         "Value is as expected: " + expected);
     is(idRuleEditor.isEditing, false, "Selector is not being edited.")
   } else {
-    yield once(view, "ruleview-refreshed");
+    yield once(view, "ruleview-changed");
     ok(getRuleViewRule(view, expected),
         "Rule with " + name + " selector exists.");
   }
 
   info("Resetting page content");
   content.document.body.innerHTML = PAGE_CONTENT;
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_01.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_01.js
@@ -8,34 +8,29 @@
 
 let PAGE_CONTENT = [
   '<style type="text/css">',
   '  .testclass {',
   '    text-align: center;',
   '  }',
   '</style>',
   '<div id="testid" class="testclass">Styled Node</div>',
-  '<span id="testid2">This is a span</span>'
+  '<span>This is a span</span>',
 ].join("\n");
 
 add_task(function*() {
-  yield addTab("data:text/html;charset=utf-8,test rule view selector changes");
-
-  info("Creating the test document");
-  content.document.body.innerHTML = PAGE_CONTENT;
-
-  info("Opening the rule-view");
-  let {toolbox, inspector, view} = yield openRuleView();
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(PAGE_CONTENT));
+  let {inspector, view} = yield openRuleView();
 
   info("Selecting the test element");
   yield selectNode("#testid", inspector);
   yield testEditSelector(view, "span");
 
-  info("Selecting the modified element");
-  yield selectNode("#testid2", inspector);
+  info("Selecting the modified element with the new rule");
+  yield selectNode("span", inspector);
   yield checkModifiedElement(view, "span");
 });
 
 function* testEditSelector(view, name) {
   info("Test editing existing selector fields");
 
   let idRuleEditor = getRuleViewRuleEditor(view, 1);
 
@@ -43,24 +38,25 @@ function* testEditSelector(view, name) {
   let editor = yield focusEditableField(idRuleEditor.selectorText);
 
   is(inplaceEditor(idRuleEditor.selectorText), editor,
     "The selector editor got focused");
 
   info("Entering a new selector name and committing");
   editor.input.value = name;
 
-  info("Waiting for rule view to refresh");
-  let onRuleViewRefresh = once(view, "ruleview-refreshed");
+  info("Waiting for rule view to update");
+  let onRuleViewChanged = once(view, "ruleview-changed");
 
   info("Entering the commit key");
   EventUtils.synthesizeKey("VK_RETURN", {});
-  yield onRuleViewRefresh;
+  yield onRuleViewChanged;
 
-  is(view._elementStyle.rules.length, 1, "Should have 1 rule.");
-  is(getRuleViewRule(view, name), undefined,
-      name + " selector has been removed.");
+  is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
+  ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
+  ok(getRuleViewRuleEditor(view, 1).element.getAttribute("unmatched"),
+    "Rule with " + name + " does not match the current element.");
 }
 
 function* checkModifiedElement(view, name) {
   is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
   ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
 }
--- a/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_02.js
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_02.js
@@ -7,42 +7,37 @@
 // Testing selector inplace-editor behaviors in the rule-view with pseudo
 // classes.
 
 let PAGE_CONTENT = [
   '<style type="text/css">',
   '  .testclass {',
   '    text-align: center;',
   '  }',
-  '  #testid3:first-letter {',
+  '  #testid3::first-letter {',
   '    text-decoration: "italic"',
   '  }',
   '</style>',
   '<div id="testid">Styled Node</div>',
   '<span class="testclass">This is a span</span>',
   '<div class="testclass2">A</div>',
   '<div id="testid3">B</div>'
 ].join("\n");
 
 add_task(function*() {
-  yield addTab("data:text/html;charset=utf-8,test rule view selector changes");
-
-  info("Creating the test document");
-  content.document.body.innerHTML = PAGE_CONTENT;
-
-  info("Opening the rule-view");
-  let {toolbox, inspector, view} = yield openRuleView();
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(PAGE_CONTENT));
+  let {inspector, view} = yield openRuleView();
 
   info("Selecting the test element");
   yield selectNode(".testclass", inspector);
-  yield testEditSelector(view, "div:nth-child(2)");
+  yield testEditSelector(view, "div:nth-child(1)");
 
   info("Selecting the modified element");
   yield selectNode("#testid", inspector);
-  yield checkModifiedElement(view, "div:nth-child(2)");
+  yield checkModifiedElement(view, "div:nth-child(1)");
 
   info("Selecting the test element");
   yield selectNode("#testid3", inspector);
   yield testEditSelector(view, ".testclass2::first-letter");
 
   info("Selecting the modified element");
   yield selectNode(".testclass2", inspector);
   yield checkModifiedElement(view, ".testclass2::first-letter");
@@ -58,24 +53,28 @@ function* testEditSelector(view, name) {
   let editor = yield focusEditableField(idRuleEditor.selectorText);
 
   is(inplaceEditor(idRuleEditor.selectorText), editor,
     "The selector editor got focused");
 
   info("Entering a new selector name: " + name);
   editor.input.value = name;
 
-  info("Waiting for rule view to refresh");
-  let onRuleViewRefresh = once(view, "ruleview-refreshed");
+  info("Waiting for rule view to update");
+  let onRuleViewChanged = once(view, "ruleview-changed");
 
   info("Entering the commit key");
   EventUtils.synthesizeKey("VK_RETURN", {});
-  yield onRuleViewRefresh;
+  yield onRuleViewChanged;
+
+  is(view._elementStyle.rules.length, 2, "Should have 2 rule.");
+  ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
 
-  is(view._elementStyle.rules.length, 1, "Should have 1 rule.");
-  is(getRuleViewRule(view, name), undefined,
-      name + " selector has been removed.");
+  let newRuleEditor = getRuleViewRuleEditor(view, 1) ||
+    getRuleViewRuleEditor(view, 1, 0);
+  ok(newRuleEditor.element.getAttribute("unmatched"),
+    "Rule with " + name + " does not match the current element.");
 }
 
 function* checkModifiedElement(view, name) {
   is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
   ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_03.js
@@ -0,0 +1,46 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Testing selector inplace-editor behaviors in the rule-view with invalid
+// selectors
+
+let TEST_URI = [
+  '<style type="text/css">',
+  '  .testclass {',
+  '    text-align: center;',
+  '  }',
+  '</style>',
+  '<div class="testclass">Styled Node</div>',
+].join("\n");
+
+add_task(function*() {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  let {inspector, view} = yield openRuleView();
+  yield selectNode(".testclass", inspector);
+  yield testEditSelector(view, "asd@:::!");
+});
+
+function* testEditSelector(view, name) {
+  info("Test editing existing selector fields");
+
+  let ruleEditor = getRuleViewRuleEditor(view, 1);
+
+  info("Focusing an existing selector name in the rule-view");
+  let editor = yield focusEditableField(ruleEditor.selectorText);
+
+  is(inplaceEditor(ruleEditor.selectorText), editor,
+    "The selector editor got focused");
+
+  info("Entering a new selector name and committing");
+  editor.input.value = name;
+  EventUtils.synthesizeKey("VK_RETURN", {});
+
+  is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
+  is(getRuleViewRule(view, name), undefined,
+    "Rule with " + name + " selector should not exist.");
+  ok(getRuleViewRule(view, ".testclass"),
+    "Rule with .testclass selector exists.");
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_04.js
@@ -0,0 +1,67 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that the selector highlighter is removed when modifying a selector and
+// the selector highlighter works for the newly added unmatched rule.
+
+const TEST_URI = [
+  '<style type="text/css">',
+  '  p {',
+  '    background: red;',
+  '  }',
+  '</style>',
+  '<p>Test the selector highlighter</p>'
+].join("\n");
+
+add_task(function*() {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  let {inspector, view} = yield openRuleView();
+
+  ok(!view.selectorHighlighter, "No selectorhighlighter exist in the rule-view");
+
+  yield selectNode("p", inspector);
+  yield testSelectorHighlight(view, "p");
+  yield testEditSelector(view, "body");
+  yield testSelectorHighlight(view, "body");
+});
+
+function* testSelectorHighlight(view, name) {
+  info("Test creating selector highlighter");
+
+  info("Clicking on a selector icon");
+  let icon = getRuleViewSelectorHighlighterIcon(view, name);
+
+  let onToggled = view.once("ruleview-selectorhighlighter-toggled");
+  EventUtils.synthesizeMouseAtCenter(icon, {}, view.doc.defaultView);
+  let isVisible = yield onToggled;
+
+  ok(view.selectorHighlighter, "The selectorhighlighter instance was created");
+  ok(isVisible, "The toggle event says the highlighter is visible");
+}
+
+function* testEditSelector(view, name) {
+  info("Test editing existing selector fields");
+
+  let ruleEditor = getRuleViewRuleEditor(view, 1);
+
+  info("Focusing an existing selector name in the rule-view");
+  let editor = yield focusEditableField(ruleEditor.selectorText);
+
+  is(inplaceEditor(ruleEditor.selectorText), editor,
+    "The selector editor got focused");
+
+  info("Waiting for rule view to update");
+  let onToggled = view.once("ruleview-selectorhighlighter-toggled");
+
+  info("Entering a new selector name and committing");
+  editor.input.value = name;
+  EventUtils.synthesizeKey("VK_RETURN", {});
+
+  let isVisible = yield onToggled;
+
+  ok(!view.highlightedSelector, "The selectorhighlighter instance was removed");
+  ok(!isVisible, "The toggle event says the highlighter is not visible");
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser_ruleview_edit-selector_05.js
@@ -0,0 +1,108 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests that adding a new property of an unmatched rule works properly.
+
+let TEST_URI = [
+  '<style type="text/css">',
+  '  #testid {',
+  '  }',
+  '  .testclass {',
+  '    background-color: white;',
+  '  }',
+  '</style>',
+  '<div id="testid">Styled Node</div>',
+  '<span class="testclass">This is a span</span>'
+].join("\n");
+
+add_task(function*() {
+  yield addTab("data:text/html;charset=utf-8," + encodeURIComponent(TEST_URI));
+  let {inspector, view} = yield openRuleView();
+
+  info("Selecting the test element");
+  yield selectNode("#testid", inspector);
+  yield testEditSelector(view, "span");
+  yield testAddProperty(view);
+
+  info("Selecting the modified element with the new rule");
+  yield selectNode("span", inspector);
+  yield checkModifiedElement(view, "span");
+});
+
+function* testEditSelector(view, name) {
+  info("Test editing existing selector fields");
+
+  let ruleEditor = getRuleViewRuleEditor(view, 1);
+
+  info("Focusing an existing selector name in the rule-view");
+  let editor = yield focusEditableField(ruleEditor.selectorText);
+
+  is(inplaceEditor(ruleEditor.selectorText), editor,
+    "The selector editor got focused");
+
+  info("Entering a new selector name and committing");
+  editor.input.value = name;
+
+  info("Waiting for rule view to update");
+  let onRuleViewChanged = once(view, "ruleview-changed");
+
+  info("Entering the commit key");
+  EventUtils.synthesizeKey("VK_RETURN", {});
+  yield onRuleViewChanged;
+
+  is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
+  ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
+  ok(getRuleViewRuleEditor(view, 1).element.getAttribute("unmatched"),
+    "Rule with " + name + " does not match the current element.");
+}
+
+function* checkModifiedElement(view, name) {
+  is(view._elementStyle.rules.length, 3, "Should have 3 rules.");
+  ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
+}
+
+function* testAddProperty(view) {
+  info("Test creating a new property");
+
+  let ruleEditor = getRuleViewRuleEditor(view, 1);
+
+  info("Focusing a new property name in the rule-view");
+  let editor = yield focusEditableField(ruleEditor.closeBrace);
+
+  is(inplaceEditor(ruleEditor.newPropSpan), editor,
+    "The new property editor got focused");
+  let input = editor.input;
+
+  info("Entering text-align in the property name editor");
+  input.value = "text-align";
+
+  info("Pressing return to commit and focus the new value field");
+  let onValueFocus = once(ruleEditor.element, "focus", true);
+  let onModifications = ruleEditor.rule._applyingModifications;
+  EventUtils.synthesizeKey("VK_RETURN", {}, view.doc.defaultView);
+  yield onValueFocus;
+  yield onModifications;
+
+  // Getting the new value editor after focus
+  editor = inplaceEditor(view.doc.activeElement);
+  let textProp = ruleEditor.rule.textProps[0];
+
+  is(ruleEditor.rule.textProps.length,  1, "Created a new text property.");
+  is(ruleEditor.propertyList.children.length, 1, "Created a property editor.");
+  is(editor, inplaceEditor(textProp.editor.valueSpan),
+    "Editing the value span now.");
+
+  info("Entering a value and bluring the field to expect a rule change");
+  editor.input.value = "center";
+  let onBlur = once(editor.input, "blur");
+  onModifications = ruleEditor.rule._applyingModifications;
+  editor.input.blur();
+  yield onBlur;
+  yield onModifications;
+
+  is(textProp.value, "center", "Text prop should have been changed.");
+  is(textProp.overridden, false, "Property should not be overridden");
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/unit/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the common devtools xpcshell eslintrc config.
+  "extends": "../../../.eslintrc.xpcshell"
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/tilt/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webaudioeditor/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webide/test/.eslintrc
@@ -0,0 +1,4 @@
+{
+  // Extend from the shared list of defined globals for mochitests.
+  "extends": "../../.eslintrc.mochitests"
+}
--- a/browser/devtools/webide/themes/throbber.svg
+++ b/browser/devtools/webide/themes/throbber.svg
@@ -1,18 +1,22 @@
 <!-- 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="24" height="24" viewBox="0 0 64 64">
-  <rect x="30" y="4" width="4" height="15" transform="rotate(0, 32, 32)" fill="#bbb"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(30, 32, 32)" fill="#aaa"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(60, 32, 32)" fill="#999"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(90, 32, 32)" fill="#888"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(120, 32, 32)" fill="#777"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(150, 32, 32)" fill="#666"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(180, 32, 32)" fill="#555"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(210, 32, 32)" fill="#444"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(240, 32, 32)" fill="#333"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(270, 32, 32)" fill="#222"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(300, 32, 32)" fill="#111"/>
-  <rect x="30" y="4" width="4" height="15" transform="rotate(330, 32, 32)" fill="#000"/>
-  <animateTransform attributeName="transform" type="rotate" calcMode="discrete" dur="0.8s" repeatCount="indefinite" values="0 32 32;30 32 32;60 32 32;90 32 32;120 32 32;150 32 32;180 32 32;210 32 32;240 32 32;270 32 32;300 32 32;330 32 32"/>
+
+<svg  xmlns="http://www.w3.org/2000/svg"
+      width="24" height="24" viewBox="0 0 64 64">
+  <g>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(0, 32, 32)" fill="#BBB"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(30, 32, 32)" fill="#AAA"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(60, 32, 32)" fill="#999"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(90, 32, 32)" fill="#888"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(120, 32, 32)" fill="#777"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(150, 32, 32)" fill="#666"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(180, 32, 32)" fill="#555"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(210, 32, 32)" fill="#444"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(240, 32, 32)" fill="#333"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(270, 32, 32)" fill="#222"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(300, 32, 32)" fill="#111"/>
+    <rect x="30" y="4" width="4" height="15" transform="rotate(330, 32, 32)" fill="#000"/>
+    <animateTransform attributeName="transform" type="rotate" calcMode="discrete" values="0 32 32;30 32 32;60 32 32;90 32 32;120 32 32;150 32 32;180 32 32;210 32 32;240 32 32;270 32 32;300 32 32;330 32 32" dur="0.8s" repeatCount="indefinite"/>
+  </g>
 </svg>
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -483,26 +483,26 @@ dataReportingNotification.button.accessK
 # Process hang reporter
 processHang.message = A web page is causing %1$S to run slowly. What would you like to do?
 processHang.button.label = Options
 processHang.button.accessKey = O
 
 # Webapps notification popup
 webapps.install = Install
 webapps.install.accesskey = I
-#LOCALIZATION NOTE (webapps.requestInstall) %1$S is the web app name, %2$S is the site from which the web app is installed
-webapps.requestInstall = Do you want to install "%1$S" from this site (%2$S)?
+#LOCALIZATION NOTE (webapps.requestInstall2) %S is the web app name
+webapps.requestInstall2 = Do you want to install “%S” from this site?
 webapps.install.success = Application Installed
 webapps.install.inprogress = Installation in progress
 webapps.uninstall = Uninstall
 webapps.uninstall.accesskey = U
 webapps.doNotUninstall = Don't Uninstall
 webapps.doNotUninstall.accesskey = D
 #LOCALIZATION NOTE (webapps.requestUninstall) %1$S is the web app name
-webapps.requestUninstall = Do you want to uninstall "%1$S"?
+webapps.requestUninstall = Do you want to uninstall “%1$S”?
 
 # LOCALIZATION NOTE (fullscreen.entered): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.entered=%S is now fullscreen.
 # LOCALIZATION NOTE (fullscreen.rememberDecision): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.rememberDecision=Remember decision for %S
 
 # LOCALIZATION NOTE (fullscreenButton.tooltip): %S is the keyboard shortcut for full screen
 fullscreenButton.tooltip=Display the window in full screen (%S)
--- a/browser/modules/WebappManager.jsm
+++ b/browser/modules/WebappManager.jsm
@@ -202,57 +202,56 @@ this.WebappManager = {
         );
       }
     };
 
     let requestingURI = chromeWin.makeURI(aData.from);
     let app = aData.app;
     let manifest = new ManifestHelper(jsonManifest, app.origin, app.manifestURL);
 
-    let host;
+    let options = {};
     try {
-      host = requestingURI.host;
+      options.displayOrigin = requestingURI.host;
     } catch(e) {
-      host = requestingURI.spec;
+      options.displayOrigin = requestingURI.spec;
     }
 
-    let message = bundle.getFormattedString("webapps.requestInstall",
-                                            [manifest.name, host], 2);
+    let message = bundle.getFormattedString("webapps.requestInstall2",
+                                            [manifest.name]);
 
-    let eventCallback = null;
     let gBrowser = chromeWin.gBrowser;
     if (gBrowser) {
       let windowID = aData.oid;
 
       let listener = {
         onLocationChange(webProgress) {
           if (webProgress.DOMWindowID == windowID) {
             notification.remove();
           }
         }
       };
 
       gBrowser.addProgressListener(listener);
 
-      eventCallback = (event) => {
+      options.eventCallback = event => {
         if (event != "removed") {
           return;
         }
         // The notification was removed, so we should
         // remove our listener.
         gBrowser.removeProgressListener(listener);
-      }
+      };
     }
 
     notification = chromeWin.PopupNotifications.show(aBrowser,
                                                      "webapps-install",
                                                      message,
                                                      "webapps-notification-icon",
                                                      mainAction, [],
-                                                     eventCallback);
+                                                     options);
   },
 
   doUninstall: function(aData, aBrowser) {
     let chromeDoc = aBrowser.ownerDocument;
     let chromeWin = chromeDoc.defaultView;
 
     let bundle = chromeWin.gNavigatorBundle;
     let jsonManifest = aData.app.manifest;
@@ -279,46 +278,46 @@ this.WebappManager = {
 
     let manifest = new ManifestHelper(jsonManifest, aData.app.origin,
                                       aData.app.manifestURL);
 
     let message = bundle.getFormattedString("webapps.requestUninstall",
                                             [manifest.name]);
 
 
-    let eventCallback = null;
+    let options = {};
     let gBrowser = chromeWin.gBrowser;
     if (gBrowser) {
       let windowID = aData.oid;
 
       let listener = {
         onLocationChange(webProgress) {
           if (webProgress.DOMWindowID == windowID) {
             notification.remove();
           }
         }
       };
 
       gBrowser.addProgressListener(listener);
 
-      eventCallback = (event) => {
+      options.eventCallback = event => {
         if (event != "removed") {
           return;
         }
         // The notification was removed, so we should
         // remove our listener.
         gBrowser.removeProgressListener(listener);
-      }
+      };
     }
 
     notification = chromeWin.PopupNotifications.show(
                      aBrowser, "webapps-uninstall", message,
                      "webapps-notification-icon",
                      mainAction, [secondaryAction],
-                     eventCallback);
+                     options);
   }
 }
 
 function notifyInstallSuccess(aApp, aNativeApp, aBundle, aInPrivateBrowsing) {
   let launcher = {
     observe: function(aSubject, aTopic) {
       if (aTopic == "alertclickcallback") {
         WebappOSUtils.launch(aApp);
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -1018,26 +1018,16 @@ toolbarbutton[constrain-size="true"][cui
 
 %include ../shared/identity-block.inc.css
 
 #page-proxy-favicon {
   margin-top: 1px;
   margin-bottom: 1px;
   -moz-margin-start: 3px;
   -moz-margin-end: 1px;
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
-
-#identity-box:hover > #page-proxy-favicon {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-#identity-box:hover:active > #page-proxy-favicon,
-#identity-box[open=true] > #page-proxy-favicon {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
 }
 
 /* Identity popup icons */
 #identity-popup-icon {
   height: 64px;
   width: 64px;
   padding: 0;
   list-style-image: url("chrome://browser/skin/identity.png");
@@ -1376,16 +1366,62 @@ richlistitem[type~="action"][actiontype=
   -moz-image-region: rect(14px, 28px, 28px, 14px);
 }
 
 #urlbar-stop-button:hover:active {
   background-image: radial-gradient(circle closest-side, hsla(5,100%,75%,.1), transparent);
   -moz-image-region: rect(28px, 28px, 42px, 14px);
 }
 
+@media (min-resolution: 1.1dppx) {
+  #urlbar > toolbarbutton {
+    list-style-image: url("chrome://browser/skin/reload-stop-go@2x.png");
+  }
+
+  #urlbar-go-button {
+    -moz-image-region: rect(0, 84px, 28px, 56px);
+  }
+
+  #urlbar-go-button:hover {
+    -moz-image-region: rect(28px, 84px, 56px, 56px);
+  }
+
+  #urlbar-go-button:hover:active {
+    -moz-image-region: rect(56px, 84px, 84px, 56px);
+  }
+
+  #urlbar-reload-button {
+    -moz-image-region: rect(0, 28px, 28px, 0);
+  }
+
+  #urlbar-reload-button:not([disabled]):hover {
+    -moz-image-region: rect(28px, 28px, 56px, 0);
+  }
+
+  #urlbar-reload-button:not([disabled]):hover:active {
+    -moz-image-region: rect(56px, 28px, 84px, 0);
+  }
+
+  #urlbar-stop-button {
+    -moz-image-region: rect(0, 56px, 28px, 28px);
+  }
+
+  #urlbar-stop-button:not([disabled]):hover {
+    -moz-image-region: rect(28px, 56px, 56px, 28px);
+  }
+
+  #urlbar-stop-button:hover:active {
+    -moz-image-region: rect(56px, 56px, 84px, 28px);
+  }
+
+  #urlbar > toolbarbutton > .toolbarbutton-icon {
+    width: 14px;
+  }
+}
+
 /* Popup blocker button */
 #page-report-button {
   list-style-image: url("chrome://browser/skin/Info.png");
 }
 
 %include ../shared/readinglist/readinglist.inc.css
 
 /* Reader mode button */
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e7c041eff2ccc95f18c94b888acceceb5d34d035
GIT binary patch
literal 2269
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..93a615dde378f8af6b53dadd40a3f2ec94ad019f
GIT binary patch
literal 1560
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
KMNUMnLSTZP(fmIE
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cb3456e4872f2bbb0cd2e44a578cffdf3dca038b
GIT binary patch
literal 1889
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
bM-=}9!eA_DOtz#d00000NkvXXu0mjf0)VSl
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c79694fa3551a70ba7af9e7ab8f619ae4bc7cd06
GIT binary patch
literal 698
zc$@*c0!96aP)<h;3K|Lk000e1NJLTq003YB001Be1ONa4N6EF{0007kNkl<ZcmeIu
zziVDq7{Kw*O^=Zln${GGxkF>$bO}NbK@o?dgSa`V;17hhai~=^2Bk{dS5vXZs!c#a
z7c2N5I2Q-sw<$#g2OUHQ7b%Jk)};u2kJE*l94_3OGrSc1OlSE%oagbsF)K9l)oYfq
zW>uuSGPD1tMPGcR$)Oi~0(ix`&So<EL90G!FgF#?s`P!~Z=IA=vid>GK4`LJTICMQ
z&gdj&_L9ES0=?<Dr0!+w{?gh^W<Q+PvM)ZAqW7*hY_{s8*2>I&(7F#%s<%JB1pf4;
zNzd4e7hUkXR?5tNuwU!GI4{-vz%rtFKjB{Afi+87DKq;)hrW0}{eI~eJ8|6}z(|1`
z4*9Lc_cQxpr#@Z4!H=B)-0olOb{+7k<1H4*?1!ED5VwB+Kzv?hpKI8sa@49{HA9)%
z4-e?lrwhbWCRO&hhTSTYPCF(wu0CDh;9NXHZ2)QmdCq%&)~L+vhjY60=>oAYBm;J$
z67)T*(I~UmxesdYnvYMD4A`aaDd+qMshP}vV_xSz#Lf5Lp>8j@P2GgPC)JFpPZyY7
z7(IdX0#i17+&#XRC>LT@e|bUoUKpvw6%)yT^a2!CJSLIb+g4w!0A}xVRiUj1T&1qe
z>^HXAhX{yocgR`sC}7Ne@fMhU&}CcQblPV|jyP|JtqvPdDKq<xZTBI9_>R=NbKrt$
zr)+iBLtxB(aR##w`&#OL-vaLTgVZA~0cB=?C8G}zUq>pazf!Nd#JKwq;V@E1T~WOf
z^(toeGWr1VAG@R$u_ij<I8rxY+<l0M7o9|E(V}J-RWkdS(T9lGchfO<YVQx9>w_`(
g#hY$z6K-+;0p*1~lbB@Aga7~l07*qoM6N<$f|r6)&;S4c
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a4af07b5e93a97ddbadb5ab54dc99cd62b36b2f7
GIT binary patch
literal 1130
zc$@)h1eN=VP)<h;3K|Lk000e1NJLTq003YB001Be1ONa4N6EF{000CrNkl<Zcmc(j
zPiPcZ9LGO1v%5)G(g@k4-KL?`Lrb&tWQ*3a1f++GN5L*V2?lKG$x8&mh~#chIko;d
zdXSzf{X_7ghb>7@qEHHgA+kx$Au<1VXWp;oJ$%egW-}XR!0(q~!rT31e&3njyq$Rt
z8Eeh~9BU)724R04kay<DRF1Z54Gw~`7VT{K>;u??=kWAqN>C^Q{N2qKk)F2!GA>^q
zI<IX?0KvznrR@{g5>oOB0sbCkoKt)VJmq(O<_Y`i=<CDhDbPdV#pp&YsLC)n3*N&+
zcLtx(WQQiL4iO^!<I(?WJ5@Cd?n2MQp*xj$K0d%)f$MyaixrBWxX2bA_1Wvg_t4wy
zdp_yc+WFkw^0nR-w%M^Iv@67K^wlS~BYf}Oqt_0{@Gg5aTabJ5gSbM-u3V5`r66>&
zE+DsCK(lZDR_og+-#WW+v)M<FZVeZQs4TzU_u$sn9)9a={pNa<j}IU}%2z^+Ps(*6
z-k*mWVBxCzf*7e|3zHPc<LLsNP7PGQ>c{f_v3i7$4N$MB3kvOj)fv_Q%4c5vh4y!<
zqKI+m3@%lg-<UC(FHVe%jf@p1WZsN4YfF`+EAXhYX?U0)oH#LdVr*~%!?Rg?w1>|T
zk&NR3@DImX0pJ(zQ|DvAW1Nc}XCOU)tkuNT1J6dz6;}!1{h7_#`P=dV;I7r)c}xor
z9|wu!8-~YwcKlpP^T%eEXY02E%{OYFMtGNq)Yl5_%WB1*;T3gR@9n2iV<*5?)r=IU
zi))z4&o8bOr_E@qYNtnsuq?lAcm}3RmM^Uh7@qA29~a<=LVHFL@}FjJK8^ZIbN+Mz
z!LYFF(qDj>UV_2884ZR_0eEe9L5TMa&qr<iCx*w5@_Pf=ndYSs^19i_%|lgl1Dabf
zFL^Us+yGrt4iDbi6twf~TK~q{2(kP?8-KVXpCcm0!DSmDM?TE!k?8-;le0}AY5B+x
z+5J=8pv?YiaGu`?>7;{4fnE+hJ^gY@N(ot)-@bC>9vf`aBtQVmKRCTOr4o2|`Q0nk
z5T7F?m0UiQxxst!&oHZr<%5(~r})Fp<r3x_iRD93YJ~YnfHK{v+^L0v65Xg|TOh*w
zUGb`oZx4|2F}iEs-h%1*ECM*jxYBh2mPyTL5x^Fq4i-5RK7D{U%x4-PAe|&_03n^y
z^Kb472!iUGR|t}x&nkdus{<9F43(bGs)h8zN7uYwTgZfu1ZYquS&Ok}B%mcPWROHT
z%d`kI6XD$#stew2<K6bRF<BH6{9MkrkC+C)r`dmr<s_b^{t24+wvR*n&?P64cb10Q
z`1A`~_DRO9=a_d^+zy@V(=zKjc8Mw_pCb#2Zh<C(k7pmW;=dK(+m)U4eEKU8d8cx<
woel*EN;|OgNNPTt0N_}=fJ3|_;tcrz0X#uP0#e#Y7ytkO07*qoM6N<$f|E-wPyhe`
--- a/browser/themes/linux/jar.mn
+++ b/browser/themes/linux/jar.mn
@@ -43,30 +43,40 @@ browser.jar:
   skin/classic/browser/Geolocation-64.png
   skin/classic/browser/Push-16.png
   skin/classic/browser/Push-64.png
   skin/classic/browser/heartbeat-icon.svg                   (../shared/heartbeat-icon.svg)
   skin/classic/browser/heartbeat-star-lit.svg               (../shared/heartbeat-star-lit.svg)
   skin/classic/browser/heartbeat-star-off.svg               (../shared/heartbeat-star-off.svg)
   skin/classic/browser/identity.png
   skin/classic/browser/identity-icons-generic.png
+  skin/classic/browser/identity-icons-generic@2x.png
   skin/classic/browser/identity-icons-https.png
+  skin/classic/browser/identity-icons-https@2x.png
   skin/classic/browser/identity-icons-https-ev.png
+  skin/classic/browser/identity-icons-https-ev@2x.png
   skin/classic/browser/identity-icons-https-mixed-active.png
+  skin/classic/browser/identity-icons-https-mixed-active@2x.png
   skin/classic/browser/identity-icons-https-mixed-display.png
+  skin/classic/browser/identity-icons-https-mixed-display@2x.png
   skin/classic/browser/Info.png
   skin/classic/browser/magnifier.png                        (../shared/magnifier.png)
   skin/classic/browser/magnifier@2x.png                     (../shared/magnifier@2x.png)
   skin/classic/browser/mask.png                             (../shared/mask.png)
   skin/classic/browser/mask@2x.png                          (../shared/mask@2x.png)
   skin/classic/browser/menuPanel.png
+  skin/classic/browser/menuPanel@2x.png
   skin/classic/browser/menuPanel-customize.png
+  skin/classic/browser/menuPanel-customize@2x.png
   skin/classic/browser/menuPanel-exit.png
+  skin/classic/browser/menuPanel-exit@2x.png
   skin/classic/browser/menuPanel-help.png
+  skin/classic/browser/menuPanel-help@2x.png
   skin/classic/browser/menuPanel-small.png
+  skin/classic/browser/menuPanel-small@2x.png
   skin/classic/browser/bad-content-blocked-16.png           (../shared/bad-content-blocked-16.png)
   skin/classic/browser/bad-content-blocked-16@2x.png        (../shared/bad-content-blocked-16@2x.png)
   skin/classic/browser/bad-content-blocked-64.png           (../shared/bad-content-blocked-64.png)
   skin/classic/browser/bad-content-unblocked-16.png         (../shared/bad-content-unblocked-16.png)
   skin/classic/browser/bad-content-unblocked-64.png         (../shared/bad-content-unblocked-64.png)
   skin/classic/browser/monitor.png
   skin/classic/browser/monitor_16-10.png
   skin/classic/browser/notification-16.png
@@ -74,35 +84,36 @@ browser.jar:
 * skin/classic/browser/pageInfo.css
   skin/classic/browser/pageInfo.png
   skin/classic/browser/page-livemarks.png
   skin/classic/browser/pointerLock-16.png
   skin/classic/browser/pointerLock-64.png
   skin/classic/browser/Privacy-16.png
   skin/classic/browser/privatebrowsing-mask.png
   skin/classic/browser/reload-stop-go.png
+  skin/classic/browser/reload-stop-go@2x.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/search-pref.png                      (../shared/search/search-pref.png)
   skin/classic/browser/search-indicator.png                 (../shared/search/search-indicator.png)
-  skin/classic/browser/search-indicator-add-engine.png      (../shared/search/search-indicator-add-engine.png)
   skin/classic/browser/search-engine-placeholder.png        (../shared/search/search-engine-placeholder.png)
   skin/classic/browser/badge-add-engine.png                 (../shared/search/badge-add-engine.png)
   skin/classic/browser/search-indicator-badge-add.png       (../shared/search/search-indicator-badge-add.png)
   skin/classic/browser/search-history-icon.svg              (../shared/search/history-icon.svg)
   skin/classic/browser/Secure.png
   skin/classic/browser/Security-broken.png
   skin/classic/browser/setDesktopBackground.css
   skin/classic/browser/slowStartup-16.png
   skin/classic/browser/theme-switcher-icon.png              (../shared/theme-switcher-icon.png)
   skin/classic/browser/Toolbar.png
   skin/classic/browser/Toolbar-inverted.png
   skin/classic/browser/Toolbar-small.png
   skin/classic/browser/undoCloseTab.png                        (../shared/undoCloseTab.png)
   skin/classic/browser/update-badge.svg                        (../shared/update-badge.svg)
   skin/classic/browser/urlbar-arrow.png
+  skin/classic/browser/urlbar-arrow@2x.png
   skin/classic/browser/session-restore.svg                  (../shared/incontent-icons/session-restore.svg)
   skin/classic/browser/tab-crashed.svg                      (../shared/incontent-icons/tab-crashed.svg)
   skin/classic/browser/welcome-back.svg                     (../shared/incontent-icons/welcome-back.svg)
   skin/classic/browser/reader-tour.png                      (../shared/reader/reader-tour.png)
   skin/classic/browser/reader-tour@2x.png                   (../shared/reader/reader-tour@2x.png)
   skin/classic/browser/readerMode.svg                       (../shared/reader/readerMode.svg)
   skin/classic/browser/readinglist/icons.svg          (../shared/readinglist/icons.svg)
   skin/classic/browser/readinglist/readinglist-icon.svg (../shared/readinglist/readinglist-icon.svg)
@@ -127,16 +138,17 @@ browser.jar:
   skin/classic/browser/customizableui/customize-illustration.png  (../shared/customizableui/customize-illustration.png)
   skin/classic/browser/customizableui/customize-illustration-rtl.png  (../shared/customizableui/customize-illustration-rtl.png)
   skin/classic/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
   skin/classic/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
   skin/classic/browser/customizableui/customizeMode-separatorVertical.png  (customizableui/customizeMode-separatorVertical.png)
   skin/classic/browser/customizableui/customizeFavicon.ico  (../shared/customizableui/customizeFavicon.ico)
   skin/classic/browser/customizableui/info-icon-customizeTip.png  (../shared/customizableui/info-icon-customizeTip.png)
   skin/classic/browser/customizableui/menuPanel-customizeFinish.png  (../shared/customizableui/menuPanel-customizeFinish.png)
+  skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png  (../shared/customizableui/menuPanel-customizeFinish@2x.png)
   skin/classic/browser/customizableui/panelarrow-customizeTip.png  (../shared/customizableui/panelarrow-customizeTip.png)
 * skin/classic/browser/customizableui/panelUIOverlay.css (customizableui/panelUIOverlay.css)
   skin/classic/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
   skin/classic/browser/customizableui/subView-arrow-back-inverted-rtl.png  (../shared/customizableui/subView-arrow-back-inverted-rtl.png)
   skin/classic/browser/customizableui/whimsy.png  (../shared/customizableui/whimsy.png)
   skin/classic/browser/customizableui/whimsy@2x.png  (../shared/customizableui/whimsy@2x.png)
   skin/classic/browser/customizableui/whimsy-bw.png  (../shared/customizableui/whimsy-bw.png)
   skin/classic/browser/customizableui/whimsy-bw@2x.png  (../shared/customizableui/whimsy-bw@2x.png)
@@ -151,18 +163,21 @@ browser.jar:
   skin/classic/browser/feeds/feedIcon.png             (feeds/feedIcon.png)
   skin/classic/browser/feeds/feedIcon16.png           (feeds/feedIcon16.png)
   skin/classic/browser/feeds/subscribe.css            (feeds/subscribe.css)
   skin/classic/browser/feeds/subscribe-ui.css         (feeds/subscribe-ui.css)
 * skin/classic/browser/newtab/newTab.css              (newtab/newTab.css)
   skin/classic/browser/newtab/controls.svg            (../shared/newtab/controls.svg)
   skin/classic/browser/newtab/whimsycorn.png          (../shared/newtab/whimsycorn.png)
   skin/classic/browser/panic-panel/header.png         (../shared/panic-panel/header.png)
+  skin/classic/browser/panic-panel/header@2x.png      (../shared/panic-panel/header@2x.png)
   skin/classic/browser/panic-panel/header-small.png   (../shared/panic-panel/header-small.png)
+  skin/classic/browser/panic-panel/header-small@2x.png (../shared/panic-panel/header-small@2x.png)
   skin/classic/browser/panic-panel/icons.png          (../shared/panic-panel/icons.png)
+  skin/classic/browser/panic-panel/icons@2x.png       (../shared/panic-panel/icons@2x.png)
   skin/classic/browser/places/bookmarksMenu.png       (places/bookmarksMenu.png)
   skin/classic/browser/places/bookmarksToolbar.png    (places/bookmarksToolbar.png)
   skin/classic/browser/places/bookmarksToolbar-menuPanel.png (places/bookmarksToolbar-menuPanel.png)
   skin/classic/browser/places/bookmarks-notification-finish.png  (places/bookmarks-notification-finish.png)
   skin/classic/browser/places/bookmarks-menu-arrow.png           (places/bookmarks-menu-arrow.png)
   skin/classic/browser/places/calendar.png            (places/calendar.png)
 * skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
   skin/classic/browser/places/livemark-item.png       (places/livemark-item.png)
@@ -417,25 +432,28 @@ browser.jar:
   skin/classic/browser/devtools/search-clear-dark.svg                 (../shared/devtools/images/search-clear-dark.svg)
 #ifdef MOZ_SERVICES_SYNC
   skin/classic/browser/sync-16.png
   skin/classic/browser/sync-32.png
   skin/classic/browser/sync-bg.png
   skin/classic/browser/sync-128.png
   skin/classic/browser/sync-desktopIcon.png
   skin/classic/browser/sync-horizontalbar.png
+  skin/classic/browser/sync-horizontalbar@2x.png
   skin/classic/browser/sync-mobileIcon.png
   skin/classic/browser/sync-notification-24.png
   skin/classic/browser/syncProgress-menuPanel.png
+  skin/classic/browser/syncProgress-menuPanel@2x.png
   skin/classic/browser/syncProgress-toolbar.png
   skin/classic/browser/syncProgress-toolbar-inverted.png
   skin/classic/browser/syncSetup.css
   skin/classic/browser/syncCommon.css
   skin/classic/browser/syncQuota.css
   skin/classic/browser/syncProgress-horizontalbar.png
+  skin/classic/browser/syncProgress-horizontalbar@2x.png
 #endif
   skin/classic/browser/notification-pluginNormal.png  (../shared/plugins/notification-pluginNormal.png)
   skin/classic/browser/notification-pluginAlert.png   (../shared/plugins/notification-pluginAlert.png)
   skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png)
   skin/classic/browser/devtools/tooltip/arrow-horizontal-dark.png   (../shared/devtools/tooltip/arrow-horizontal-dark.png)
   skin/classic/browser/devtools/tooltip/arrow-horizontal-dark@2x.png   (../shared/devtools/tooltip/arrow-horizontal-dark@2x.png)
   skin/classic/browser/devtools/tooltip/arrow-vertical-dark.png   (../shared/devtools/tooltip/arrow-vertical-dark.png)
   skin/classic/browser/devtools/tooltip/arrow-vertical-dark@2x.png   (../shared/devtools/tooltip/arrow-vertical-dark@2x.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5ce3b766a1bb9b298120472bdf42b0bc63404918
GIT binary patch
literal 2193
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
T(vx8%00000NkvXXu0mjfiGEYE
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d48426546fa492f78bd3e22676184b7dece8bcb3
GIT binary patch
literal 1139
zc$@)q1dRKMP)<h;3K|Lk000e1NJLTq003YB001Be1^@s6?ZACh000C!Nkl<ZcmeI&
zOK4VS0>|OzBqo87(Ts^;4aFv{MrylIk_JlaP@FiKO-4~im~kPJ0WUM@wu?d$y6C2O
zmzH9os}M&=H%%2RxDiRHD{o-aEYu3#gD6o*GS4Sjd>q~rzf010;}0HQ5Ilc5=eS8u
z#cM^j@6gx(b*v{L*ChXABXiz=cK$2szBaRh3UW<xl>v&bVrt6YFQWa2znRLq*6;KH
zqVDVS>_0EQgowSWD)5F^Iu3A=Zz-o;yu-hlDDVxBy03(8ZgY`x>Y#~1CWB*vn?Jw~
zzT!<vZ5dy(g8?cFxcO1{m9U9+*3m$zEo3e2Y$C}T%x^Cn$W_l#5{j*g@2Ml#2KF&?
z@%R723UbxZLj}c_u%2q<nyx+L1Mv3$-Laee{zM<e_9^d^-!5!qzWq`6wUQ3<TS_Oz
z_94yW*TKr*190;f<PJi8K^uj(iq8nOp9O)NA9Y`~bQ9`h8Y#5Jd_<^jYD516K4B4|
zhPXwcUFSTZY}iT{f4`GDLfzsqh4z3OgtB2Puf*G5?c7PIYxETP4|q%u*9f(f>b$o<
z>b@#zC)7Rqc}Af<qn~?(YR9IO&_xsJrr5?9#Wuz^rbyRB7gGHFR_ZeLPclxijdL<%
zzmC@Q0|<4N3#2=qy6_~&Nq2#>gj$Cbf4`MbqueCjmDK(eS4el0Q9`}Ni>g>fr~yK4
zq|gRfOS=5c*!znKbvgT*1$UViq`+pvGD7`Cxn*7BZKU}73kfw!xs4L)kNFQ^KA~<<
zX5nk3He>JC5^9Vx3S1+wnUGZtF^j!l#hjNgMyS^*x8?%gjM)3*gsP|9{(z*=X2Nws
zbx>{}5GZdm{{90(Euq}rKvHNk;b%hqgL3;Pp)MlD-~WwJ?^15>5$bmS12{vdE;=c-
zPX0`wyv_LgBZO+DnNn+}g-|2u2XLQs6@15hifukesUY25P9w$NAK_`n{@<vj*lOv?
z*nh$=yeRRrnCH%eglgjy^%Pn?r&vL#!#vOXF?iH{O)x~LMz&Bxq1CX3CPEEkQ%cCS
zmpg=7!w{XktWJhlL#VshN)><q0#69FlwO*7S<Upalu$No<&{kTMDkJYAgeacbDCaS
zm`5FL^m3Z>v=Pn*j{?7kj=HaL2Fa?C?QCT=4OCK1BdgiUb{ffQknzmVQrw7xj$O<}
zhuBSKUWBOo`YRpGMMM1Xvfl~!ae~?I1bxh0{QV!f%53MFt{o^zy@3;s%^YF2I>Kfq
z3i#+N>b@p9#xS$hFvplI>dQDcV~b-SizuZ#^wD497jRMcwUTb?D5WP1a*5268E!zo
zV>x@cPodps56kJNq`Ux8_jQQ_oZ~5l_LOrR;L@yo8|r4vbF8C_c3Nm4*F%0~m^0I!
z&+_-6QTJ6z>$D{_P)n|H9&(G3X%oeNocpRMCA=zP{|9KfV(gRckq!U=002ovPDHLk
FV1k-`HGu#C
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b8f0a80fa168230973a6eb53f8bfe93d2cc981df
GIT binary patch
literal 5300
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
GLSTa6#BN0Z
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f3eb362267138163c3abceaf3028b7940954ee31
GIT binary patch
literal 3305
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..eb790b766e85d2e0e93f24e77aafbfa03ef62899
GIT binary patch
literal 40200
zc$`$4cQ{*r`1eC%uh=U{P{P-WRjY_ijTlAkS=8Q}*s-Z7Mb)U5F0*R1_9``7MQOz<
zwL=m6(cka6p6hzfAGuEcI_G@e_xpXn?sGn=C_`-;N)Ac@06?RwqhSI7kfCqR(d48z
zzndgMIsib)xUL4$ER1M-di<`LF%#K-;9l`<U$2z`O=Qz6&1=o}_>l4pntUNGwL(kp
zc-V8*9Eo6e5m7|!s!pOSNVGD^xGCrH+q5)2ejQSJb;aoMmA7gVUl6%_U1VbGrH6Ou
zcAcJ2sVpi7Pkb=63lOcWoRTJ(7_unqMW4if3l<%zH<Sr!F8X;t`$*x-tjN$A=KnjY
zdCO}K>9R>jd%r5rDDHW-e{*Y}UOW5tw58_V(&M(TK;g_#v!Y$%S$3KB#?ls6DOpeU
z$IMVhmvbmDZ^g)I7KeL+2La%UvWyqshrH{K0rUR9<JB7js<a<39!|Lp`lJk=|Bi3l
z;#j5J<RtxeJG)xtMAi13@#vIwQ^9RIxYJbVqlHimX`R$V{L>>#@dwNIM^qoXT7_V^
zJhq8pH<!95yS|o(CtM}nV@sqar>DQCPnwMUzt2$dYKeTc98`;A#3C8jo*#4Q<rqD9
zg$ya<*ho0lpbts#679HFAv1e_=SQBrlqC0q$j3ciwaG6@rM;d^d`o&+v>ElfX4!&<
zwDUEO6)M)(_$Q&EEtNTcO87z#mthr^!oBsLy*N`!WJFT5y~D!WBJpW6XX5vi53iC$
zZf<2#pqk_-+6{~b(@(xo1T>a0e-`|o1*rJsNB_WqBq+h$LE!TbvIZa|-nT5aFr^o2
zowC=t)cq<srt@`Gkc?@lGh&!U`ls9*<1Ob*g<tMwC12gE-~6e6R@Bz{3aRVNy}*xt
z)BWVRIG~s&H@ErCRjb^5$m~1m5UpA7MTbRVHP7BiTcRW$=sa=whAv@o`=^@&)ATPi
zK2L4KKov>!DJ_kO6H_gn`;K@j9nP|yHj5H+8cdGJf8ivKLC@Af&An1TO~RTc@^W%i
zp`Wj#$pdA+w6{wsdb{;T5mLJz-xp|q@<nPLQl0Q6X*PqV1+WSIO0<Z(TVglRIcC(Y
zqm&|EPyA#y;nPr`o=BhB0-D7iLcX<f%PVCTn;<VoJM8wTp44elq8hz-)cXvc80I2A
zh2ZQ(aSsQ_F=Y%|x!@GP^!2tdcrPyxud3Q_qusHZ1`-sp&bRy4LsoqC)flT)p<r^k
z3Pnk%a$ejn%70ZXlk!3(#euC<o1?i55I&0*M^M<JXopjX<6N2sM8jC@9q-i~+Q&b&
zOxFyfzrEDdqIk{ho^oQNU}S<hncx;Sv_%sq1S)fvGEyIRRw>^5<m2-?EkUsM)x<SL
zjobxEO;B&7$)8_~RR>L8HGiGr%%ZAvhC2lw#Rt@;^RGMuP@582w%f~dS1Jkb7cz%$
z>nUk#mcHg4zaO{$fb%)=yvf>Gt7thfnNw_L0=9w}VL{&rE0V7!56+RZK7rjwv!KXQ
zS=#byTHUGdX<^lQKBjtu(<SjNXZ^+i1;`eZcBBW7Ql4UP>ODu{#o3m2;*MIFgmJF~
zp`>Z`)U``i(kG*uUU311iB83XmqKA2nmKa!5<RjY)?~zSs!-svDLcyFi5LWDjsuS3
zA7WXHy}N%_6ETzbS%&}ZhpeiK3=ddutZk)3h`IKe`}pk3fo70D7~;J0#@pEQ_)DH6
zu2;75ht0#6+>5pz8$mSzqw^-gUa!oG+tgous<U|Y(MBZSp1y`4-2L4NVEBy$hrK3o
z;BI8dwtcc*JsgNHF-cl~_eHi&w86Ld*qf6H>=2t7w*gNnNhC!f%tgnv$fgHAfS>vr
zpF`PCFSHA1YH1l3kwMDnv_KgIOEHXgKCRuK9GiWI%KvkTBnw%A+UbOU7}Y#f*1M0d
z8pND(g(eJb>EP#18nrgEw)W-hdS4Q_{>!ZqLPJd(iPG^hzXpPMqMmvsS=Mn$A(S3$
zoq{%36fvbqgm!?5mWW1LwpKF<-`dS;@mei~d`w!b<7$_g$16Tq2`Sl4pnBW4ZU$-L
z3_wGPEqbLnSxY{pGd;7#%utCt7+}{$A40jr%Pba37OB5=U(RyJu6M?-*i&sT-P6hV
zm==Lj4pnM^39N-nK}BY-fA{VsnKHbli}kn5k1^7jzH67iS*e__Ub-Nh@@1A!#$M#{
zrg*AZ^!?|Qxy@4@fQ(1RT`a_Y3@vncOR6p<b4_qT>KEQ=RKoh3*1gte3%t{_EX}&Y
zjo#C<1JU!8Yqu{H&5{36_rGl+%YMk+1^?Usnbrm`HP8=S&8w&R&lwW;dW9^CO^{4C
zvyPf!KvFthxc5x8X9IL^AUGk>-wKlL&XdgrE?C3a@nmn_r}Ebo!)6C1&F(W|$ECGc
z`W!pUXw6E55(!@ft0BFN_tuw;qY`XV=r-<Uqyp3SnSC^(;WH#{4(aNG1A^+qg)gHe
z8bsNISjj<IT?s4&M)%WGt9d}UoMrJVQu-G9t9VQ4ac%qwN(sEoOQ1&y*mB<(Upv9s
zWARmdN*&{JgUy25^@WAsg{Nt(i@K8t=Vf`+E8>`B4G)r6$W!d}WhX_yW&D$(Tkrva
z+LO*2&gqT_!zvC|<r9PVM0r&M%#BswpVkCyG%3{_M&*8sK(6MnQZ#^Y53K;-wTKEz
zNv){5RO9hyomK!bnKM=;A6*v#S;nW~cBSpI^QaVW`9yE0`RAJ*-Y(Xj^`ofz=c7xp
zvfRDm#-;i{lY9}sdZxjlsy%+fSCnO%xY>UD$tVmZN_m>YTHo%^G{>uqGkS)B0+j0l
zuMXQ@zsH0fEq?Z43Ei619N8pARwYdKBk`KlAyn*CnO2)P-6(n;?*-6a?i`A1DPuDj
z#$Ac^Xm9XjxcF)E?jm#57jG9;fK3LNDum3~0&<LLJuzDd#!kmZ^=J9=vl%>i0j*`W
zYDrPcLmA-D%nyR^wAy9{zS6#}vO^11bFHi-$f6Ka0%OGcpK^d8`j)4o^m&2N46&X#
z<5hJv%OpO7tCD)jp2(Pn+6R=>HsCeQ>v=q5jJEmqSS-n4CrcGh2m@3`%dHAMyNbF)
z?=;znLb%0Vvo7;}>G=R&b<P&xiT6cN@l;HtU;2h6C|Hcvm<4V~#eQd#wtZ-S*Z~Q-
z)~mT4o&7EPoh5Cw-E&&{W)?*A@4E-%aNKa4aaWs1nE{!D_nDiMWVS`b-@Uu%l~VX8
z<e~v=^Ckt}3Rv&g{jv>jZzANxTM;`$2vwv$aR&CmVx6(6uX(l9d;I0DHu?O#mTRy1
z_DP0P3bEPBu76$P+1#n_X+3r3B`#qY^rR_by(Uve0!TX&EWgnYyM?IP{EYykE5DPU
zs0UrCeqsZCVDzJ5Q6QXt01qchO^O?yoR}}L>eKHODiGKz8s`T%y0X=Ws|OPp9nih3
zaid83KE8eeAhX<td1!x5=V^u<*G;GBuR)Ua?}ttJ4!*=Q#wL(QDI7pqMz!=HqWO(f
zrjx)UV?$G(I}*(8P}0ZH?tb>V7cj0!nE%6@UN~B{l1N!di}({7G_mu6za+u_lgc$S
z<k||w{7fO}LV;EWN_#ftc6aru*P+yNww-b%*VyZI=T>#rvz>u}yvq$uZJ^&<m??uN
z%~QO=Tjcm>$C()ZBSD{><gZj!SAo1KmAlkJsa@~YGl<`rMKJj_5w(2#JFekUQ_XW}
zt#H*qb2R&yZvySD81Mb2x0$;~w!llVmS~vj$LFEXvn2kyEW29F@Tc=oQb=a!8Toej
z#ZfGX+rwW&6Q-q>53^UN7C{SFc3{$j?J}qPPr%Oz^hXH*2&1SmAa&|*f?Sv#3kX*Y
z9|d8?Hrd3BCwj}tqY!2w-4<3&@W%uN|F+K16?q7at8N+1cl993{nwd$oar!Qs|2!1
zk|Qn!*gcZWNoG1H=DrvGs3IJwFq+FriN@~TR;3b<!8zoEcE4qVw&|vkrer)|Tjc~v
z3)a9XSkl#Rh+-2CQs<%Etu(`q6ou#tNrm%~x3uFS2ULB}Z&mx$y_pEWXnIt$f*cM-
zV(czACJ>&_OhnZo$FH*=bDUE<eI3_HJSeTYw11QSzLmg6w`5A*fi%E={nqyZ9F>-`
zj|d1hZe?T8Qs7YFK+|y^A6UPqs0psU)W|AnG0rNr;@7^zH?@C%jwdd)HaN8|ST*O?
zm&Y6=Z%A;IKcpvq1M6bW)=es7?axC0icdZvd{j|mtgKR=|CZyenC9&@)Z8#?5{U~8
z*r+RTQ*YIsPrc1Iv+~+G1?l0F#Ma0Y>&y}tjGtMjmzyk~WHN%*XXqdC2|OjbH_((+
zh|2hlQVxbp!IT@h1wlk|0;CmSrzw4Yu0BDf!-{h&8sa)6=ocohOzAs2Crow+A&1O~
z4+lS`PU*BTj}NN`m{ux;)9ZA>x8pXLmf4x+2pz^?R|41eq+2*IsWVMq1@W_(u~F?i
zqfwl(wLv`#++!IRKZ#Q7l@e+`0g-^Le7!Kb<=hjL5P4TefXeDM1@HbAIQ;>PeOQ||
zA?&#rws$uU>wls)_w7s1cvM0ewGCOlqfAzUq>$W|Oszsp{A?44;3l_)&A!yD^O$C%
zL$Mnvb}nNDAC>1|WWY+KRflXK&m8h3mjwz$9j&%v8|nU1K}Yyu`Q^(IdW%^8>sH^V
z5XDxVtS15ie}i)QDBjYP{#4m)<|aCp_-Qs#b<+uoNZZT+zXUY^$_|(I-e>DMm9f43
zi+{X$=4Ub9uElG9%}-~bDfS9m=J4C@Tl7_GPODrCB#2(0i_H6=@BQ}Av~g*L-cD(c
zJpE~oi`ba0=!LVQ8P<M~zsk4|UZay6PT{yu&8<lwVw|KCtY8`DBS|TfKU<E8^2O_Y
z6LseR;R;(QoO;f6C=J652|q8~Zeqzm11C~KQpHMUF%nD5+^wH5*#s<upx7CJr)<7*
zPwmS{f6213H~jd0LWB6jWtMbc$*d@t9epNmL8oUr{(Et2I`EI2lUSc1iz+)6h-g+y
zH%w4#Jz<!HXm${P8`I?tjS#a_vY|?e@bl47ni@(9e60v|waFTl2qA7(t#A<-E1{|P
zXgsaW#1UqmGl>MbNBmYmy(4pQaLkA;HB69msXs};iR@hS7?XF?=}ghEfJZe^3am)!
zr@@1{Dyk?pC#C?>tfT-Dz-<WrxF-1AVBA+?Ia)sAi+w=PSIvM6rrebm3>NB|4wq&V
zH!YxQhDeqZZK{@eHEnbW5xz2XRh;`iV8op76&Y=({@HU$1}UE!``XT*koh&{;z)sb
zYq@ru&(AxGDivyaBCwaCuLD}FkTruS&@fazM!EK}v&4Ha!g*@4gIToJemS~6q=dvx
zvXlmLZIThq2Cn7MA^ZaTdKkOR3iw<N3^ECHT`ze3xFf>+oK7?`2?MH0{xp56FtMb7
zE@7Pv5iPQ6)gfoRYmNkWANBd-?PVwPB9OjtB~i<}Pn~4cK6LYyvFT9d00yibl)MXZ
zz{Ichf`mx!H+NzplLjsu#`4hzcJ+NgJdAu;(;3FiPPJBNK1(iCDO-{MVZ9TO#}|06
z3aMLIIIaD+-k-t6FDfBeHzKw|YGxo8ly-}B?T+brEdAI(Aed>ztlH#-nzU$Hkd@Y~
z@5>6dcy>9?MTfhEPe4X}()`+7XgVIbTX+o7_*?fdyq8DNh|$z`XVO$qgASv#7;{{9
zgs}Z)=C$=^hGG7X4=;ydq0jYb%-W^yy~@(fA6_x3;vLR5%Ez{w++x>dG`U4jalY_W
zSPvLOx3iaLoHhT_Z;?_->y{aJ`?de;LxN0rsg;tOcWJxWydVF3MgQU>R5bDYkG~#u
zJA?Zi9Q#(spI$_Kl!Xhro60h&EoWR3wp{<OYqTs$Qyti|Ql{j`R--wQ{ZGPKYF*4-
z`^a+OpGemjg$T4xQ|2})2efxiFz{HpQ<D5LC+Iblri;0b%&Ck7oBcKci!Am>UXVHT
zlG~t(#FAgK!f3bHmQrRQ7>cBgm5FZ#;W=zV15H5XPN0PYD}RQ?B;zs?P?`#Qrk`}D
zF$097L$PY(fd9fvZIK%#yFiS85?SW7VQG_I6UJz?A_;kL`250Mzh8PG?QsWP7ZR}R
z>qv8yx{=I?y7!gM7BShAbRU=i*zP58YTznS)TvXiS(bgdE+~-#!|JVN+>$WvxvVy^
zonjT3>z8MQ>``{E*f>k+Z+-RKZs3#)7oWdwH-vkA-hvl-M(V9@BMTUI_Em?-E~X6n
z-)D;h1yLaq+~iBr=x2#1z0?GbA4=BihQ9Lw8EVSIKUSqLQ8;$|E_S?Iv!jzH4B!dI
zziH>BjnK^cw4^Bir#?#lR4A8ma{CXE&o9A0_U@;ffm8w<N6}yf5|}XO`)1DGuCic0
z!7G8ZcvMN<wUCYZvf_>}Xwi519j<zjub>oa3+Zl#yiV^No%@}4MP&!9)#TVO%4#Ew
zMwV?)i4%C-u(~w$luoya2Su)k=O@{QUEdn$(;WysR7)~uq|)zu{~hID(b^BZaw;Kb
zUbj*cf%o~NlqD#frmU+;*6NDFXq=`FU4!}(r_vkqxOvW_Ud_nlNDA{^0qg#dN0DNC
z2api+L}3(6$=UJFm#<}B3JkX$80@-VT4t$bYXfg5C}8gOPzi`(6(O8=$h$mIB*TKQ
z95Szgb>c#tzty9DbHdXVtS{ck6RqqQck6boS136yj^Gd$OR#j-uUrXtZ&;y7z3x`p
zzG9!ttX^LkTzRj#!W@jgbDN&Q931C+?7n)VCaut#(%wt*%yuC=Pn@X^J6`Ca>YN0P
zQ?D=S$eql1xor>l*PF@j6JL&Nqhe5Enm=IdAWW<8hX7eTlLIuOyleGzzqee;sp-0L
z0!+CUoN)302V6yZ4fm3@&3!T{=N+^M`0{=>1Na2Z%^z{l7Uo7S<Uboub+*tQ5lmnE
zCa7uni`9hU)hNYlgZJb%*DO6-Z);3Ya0PgPZaM8{J&ksqXw`~%cbiMGk>k9zlCj9>
z;9C~EJn3x}z7LaCzB368dhHyYY)+=ikC(JZCAX7XZc3Usk|)+EF5o^7Bj5E4=>1Tf
zoIxIOmF@r&qrGBu*>cwwsi3w)9g9y?B$?A>ItuZ9bamYp_AVu0E`Jt?Sc-=N+FwD&
z2F`Qf7x6^Z5Rk)o{#yX`0?Fj*=cU}V9b=IHtX?(Pu!+s)t1)nxgxQ}mdCB8q`@pPD
zaguct`i(7Cm6yPsFTr_ZN$#6zC_(9;!G7IXFp7W9GEb83Hf*kMyvkxpP=~3xT+s}4
z4^PTZ8M{JicAH+<XTZ>g5#%tVM1xqmV-^@r^Y=4tmd~>UE`KmO)PXiDiIOlz#+~s%
zN&1V<cfoQ9Hp2pnI3Rswd)9gtu2T}(9d|SlslF{)7=OWvp&Fwh_Ol%BvMJ^p%SOz}
z`3yuCW*&iAza$+D<%1b_(Nh_Tg?@Zk?Tq7Va`@;GINK%V$#92Ivj#yq*9C%3>A;&*
zItEsq8g%My>1qa?t?<6QgVeb7ytE>{i^kV5pEPmi4y-~%iK?s5-lMBoLg9W<ep+Xu
zr^n~!56d!5F>iE=7B5~)w{3XKC(n?(CdqyXFVD=oU+c(r#rS*Gg`o&%6_x6Q>BV02
z`PuX@=E5@qI4}_et<a;ktIfxr)XVNS41PLW50{oxjhsC3T(Sy%G<vdc2jN=rh_)zH
zI{hv+OwYQ=%X-%@_3l@!kLr6Upg4s1mpXT!+rd7!Avv+%4RmPXs2~>*8w&sKNEA#2
zZTVLLtNqXsYWF^-zv+aP<<us2wa{|wHLX~D7#RK4;LZ6wMJ1k3!;MHwyKp&zMZ-<u
zteB0xfcpmX=fXSFjks32JoN^5+>@E$-@3xXXu@T)*Hg3#cdu_3vyOa3k5z+`^xTso
zbBHEOxIhjT($expYr6aqb)*qQS?GqPFqcz8ycq=_)u1{_l&dH|<z;z=AKO*Kox6$k
zZ3K|hq?p&&?Rd+-sXzae_4X5GAQAjyOwJigo-*ch-G@ZakV*BR<@o7pCJ-*i4CFR{
z5#I5T>8bjkk__FUWVsCpoG!}eprYU9XXF8E`W|fS&EB=9j;iFlW52U&n-UMntIbcz
z&+CW?iFenz0=}Rv4vOqQ=~x-e^12x?$OGR}RKG0+YXQ?`Il^LHF2@aOZqbJw8Vc15
z86{*Yu%B{xN#vB9p83n>zqlhl57llE{ed0-QElHNGas!GMicPc`QqxGXpd)}^I7Mk
z(2M=n_vIDkBy9#c@VA4R)lPU^B;~Oxq#}wtZspdMz_Py%=*b54y<zrQuz>l~8ah`2
zWt&n}UM$@mUvOylpg&yNit4uEX!7h|5wnaNJVmj&UhJf)k$r!&`QX51L>&o`U9)sS
zMu~A|-V9|R9C$a-gESQnF3?Y$k|%RA{lGR#K0$R@N48v+k_)((oIhwP5c|SCk#y()
z4lqijbe5Kc3Aj`+GGz^9gMn1kj}4z}+y~GS`*~uFf|DBHQff`i)*0CaTR1vQ^o!>9
z7%<w_zca<NTCflzdIiAJ1Va5;(Q)!9qD44as>vn1a(gjHLe{#3;goJ6?T33Jg2nJ`
zefb{sKy1+ZHUplAdf@d?k_L>?d4l}CKh@(U)Yr<NJ>vs1Z0#_Ar`x0{bZy3&$x(pi
zoY&<&VUXoVkvEU^C=KU{A(6@<cZC7Aru#IQR3ZB^*b!Q7`aab~iG+y0F7E8dP{|+H
zToWX*>^8VVMmyEV@7%s=8t{8Ota#@mn=0}V{j82E+?}rKE2tPI@G<^*4p9p}sZro|
z>&6`q|F1k#SCdX2C)GOhgR9TLZ+K{;zEppEM6Qpy)1`I67$d`}H^O?K2l;3IfqU1A
zqhQc@=r;o|viXB+t;>f?A4WT7;*PT=o*q@JB+kGyQ^ty@nQ5rL+ORAmQ#u?t9ohSc
zgpcXvc2|5g8U20lWBx;FvqAKC2AEM*5I3jAaik`kM}7*&zh8_hnu%&>c^5p20@c?5
zw2|R&l0Uzm@Ij~bjMKj$F*j~oSlw7{yAfTQib3!J8Ic@$7fgD>-fV4R-GQYq`G{UD
zpiSV*=bu#jFGoG9AC);hSLW^u!H|8e?r%>f{8}ZE7|lhK7<Q(J^u1>R-^rtwV|1Dt
zCZ}%+1fwe-#14C3w{i?uJX0ziea_Bgvj28aaES4ym$qoU!H3Zt2@AZ)wDCM7#&h{Y
z(1GQ|9scC}dJnYyXL_9&iIAFqjLEdTGqp$IvA@}}Z7?*Z<@(^~T5?8Hr1Mba4>aDq
zHjsTFe_A@l0he6p2ha>#)VOGNs^v-#X3Hkevzu(NQ&q8er#y2M@FtX(MIAChJFHoN
zq!yu#RdRZD8I;^GdUj>h|JCu=%l{A@Zcuj0&uz2;JZ5Z+&>|&%Y(xg1$bkK)g4`fg
zfX}y3J*O3-T5si}SH918W(}tBj=7CI^nU<qbxo)C<S`eE;Hd2(GY@G!P9lf^v75v1
zy}5uPTMrX|n^#z#XTqODtMrx=&2-UioH~Hc0)A|}=k?AjBOS(FPQ;bZz@(QtUvpKG
z*hOj5<x;^+_tqbb?8j!)+6yg1+<We?ZhE{}_8-#x3`rtEDFH*%v@y;oWlR^%irmex
z@WD9CQm0!Qqx;pEThH`s-{%frV@~0LN0YPAO_mk@pG>5hq;cmUY(g3^W!W2}Zl@&*
zr^^f$>SNZFLsW@`kvQRUp#aVwl&OsOf05vzfWdkvc(K-8)RiFWR*wSW4vm)ng6E1_
z1y#Az8{q*(xvJ?Ml<SvP0i!zRvPz$yFeBo+ZnFv%wS7LVN)j_6ZRa*5n44=^nb9C?
zL#3w*pu}@jwrqCiODI8Z*$`vf#^~xD<rg>Pg-MA~mscXfPe@in0gAiQm^c_h;m;4s
zVcyhv05#o%Arpn4xkUb!q-~tO3ANLHf7p)w^1g2TzF%ng!w_^qO;aZF5IyciIuv32
zF=c8}x`*0v1giXAq^E7sAeVd1tw#eBSBm0pV{+>LiBh%UxlSvk8tmLddd(&gWsx|P
zQ7VT-wF<3&qD1&1%-DcXQUTRDSI28s^}5@`fsC23ss#}9K(O(b7=L0}q(~Tr?llO<
zC?4_B=n!`J{D>x2XC}3OY7LfaC?}{vu54P&(uSBk3iBFf25_FtQMkCv;%L--XyScN
z{m+5ECWU~K45nq@dp;x4F6uRdMA_*k<7D#Y^R(V=>%gA9x$~adV=DzC?4z0QXJ;y_
zeXzZuju~oKjr34YsDS7|J+1gFTWWvIfg|WR_CiL5A(HY@Z|#X^QH(9lMITWwX2VDK
z@=%^A8o@1vC!-XJ;VbeEpv0)`3k+297^+H|QA3imT4+u2Nh20|KHX~i1NSy?CTxZS
z0*v(UvMN>TtUF(YrKgT3ry&7ZI?MWCbOOLDxxu48Q-=M>l*=G#qlD7cp{`#j|9XG2
z>GOL8mnN;o<w)5untvhPDX%sX&XlEII!M%_WXASXdbrCSGo}ZjVIE)x1InKX_E!OH
z=!D0n0||k6_PyRx4`1Z{zx;j9jVNmTgar~1((er(@vOEka9NJ}vUBr)!Pb#m1-Sf(
z8qSqkNnV0c(_xB{ksI^}J+?YKkvc9Lo&2Cn`>FG#nn;A)@Chm;(Yf^pfn!<9zVhbu
z>o#14QMj<A6;40w?9?rbO-Vakv7Zbi5Kd4jk1yZ@-U7gVw=hO$8nJJB{!qic{&Iv;
zXfxLuO;OK-J-+6ptMM7k3%0#wO&y`P<v|fhJ$4_zQf)nty|4?C7`6AY#QVAlZsQ)o
za|KhoFV?13kh!}XS`s_)V^-w5)l}UEwMO{@x54N@kk!Ssi#vHsgN(gPX!#IX`iZs!
zaV@_}gBioK@!Uk#01X&XYPQ&a>|8cSyVBvYy0Ry8vG&}+AI?tBLQ1vL4>*hJM9=mk
zvshxnX{PQ)8r<P_IM)^}FfWL{B}iLzhjkdkV%7JYxteY*hhFRgT^+^pj{=%y$qgd?
zGw~6f1JvJ1ItFmX-^`mr<o?PcV>1Rt5+*$1Uyh%;tayF`#5xEJl#6rl%~egDSB<~u
zn~NWpV7E{NCr7GM+t4u|0;p|>5E3^{0STZ55y?@yAw`A;*ii~XXN+*;4Dd#R(-z-O
zRHe*S@+=B-w`|$cHtK<6#5{i#9bOLbUy6&GUMul%7jdO=ml%ly^GQjpH&rwQ9h=<X
z4q1gtD3W&}?yI@-Vs9O*Pg~!pe(Q?&x5~9{i6)LY2kzZx>`3Y&5_-1G8l6$+K#A>r
zp(-+)xC&oXkL0y+xzFvZ8nv8BZv4k&yMF(P#Khn_w67u#<sWnLUj*&qo)#wI1@to%
zkUl0ZM<<-9M__mA%@ni4iISFvI1FE|p$w&FukXT&%$m?WQMUYsvWNs5@oI@Sb?GE`
zE`ckbrc<dY7@0m%^l;f6yZ5`R`w<z7u=Pdp0Pga?HsFLR&Nc?)_r~4&RUcJA&%$h9
zNhh$Ni4w^5XY(I|em(Li<FUU*A*IR0P-<x_DH^mEIkkF6^vWj{9D7&A&9u2(UN6bs
zyJ_#rd+*(+$A@9I>x+YXgKIj)uVWtPk&TU^(=^(9++_L^m84ICFG#TCynYWMeT&MZ
zrrj<Tji*O3ne1<<7TBMVZj~O#HEigA>9U^%`cJ$>IerBCqljX9gPPEie?UqVoRgeJ
zfBBMmFb}z0SAZAPX8XDTS;f1(AEAJoZVv`I6lk|IS2Q9C)^w9*@sfX(b+9kg@1ux>
zP-4}I>kv#AuxuGM57(x=Q*B=aGX&Nt|9+sRDIXvw_2M5aypDpP8@=o`ERPLniR=E0
zNnm?hzWc~<Kq?MIH2ayb)eC@#(}%J2#RnIn11EWmtS$LYbm4gsND%@=S1j}IHN**N
zk-k?>mIJ8DL!ZMCA+d=&kzE6BJtdNC=yla3)|)%j`p}sz{D8P_Y|C+s29jx0T)CD{
zMXE+ktuDTRK@?U$K^G$?`lQ#B#Ip3S71ZV#7g9Cg&o_!DPEauYcx(WR8Jn9b3WG!`
zWO@(U|Ll^O-mEw=a+g^J%CEO|J|F+Y%L>+wtYqzOdZ|q6Ss72!9WX3Y6EO82gyTBc
zgFAdV7b>=YPk4QwF8<y26t5q%ns|4?e!CtM{&w7TZP;EXJ~XhykH-Nhc`S4^i#zQK
zY@`X0oIfxkOjr13n@oNXjM$0v-Uy`2CH&}2oDq4O{ArO%7_y^LS{RhyyVb^|Zc}#S
z+)M6Q?TQJ9oz#^#H^Clmi(9Gtf=dW^-alha?XRm{En%hRRUg|!;N6bHA|mzQ-GAiH
z8<8D%U;rTXK_G5<p8k{6@+Gly0>tH)wjLPWtJfq)jEl)*wPd!O?cl$lP3?KWuN8i4
zPicEvq~B{HtI?Qb7{)sHQRf}NO|?H2l#vxsRBw?BNHRsCl8N_4(&JV(3PCqW@Y12y
z7bt<^9FB+OBy=VG3v3olzs$ECg@rz*GU0e<1exOUzM6jO6z!Mp`tK{Xoy2}OE~d|6
zlV=@%&I&Ug)&#-}q*dRo@IA`Zo;8=?cHFAD(<0q7e&{<(_#&LWaHDo0U+Fa^v0pHg
zn$14nW^%Y;<@vqPu;&5gyNIU~^x@!ak@x5Fo{rb+8(M@?N+DO$NB)qAWm2UyW>}Vr
zWNu~Tw*Iy%y%;THtQ3^xlHs8_YC2-0op0XuB0uPpW71#2tmChLf3n`C7bcZ@+E5Y_
z{Hh5+&(ft;5@cEget0*2hm;0p@!heJC2sN7UvpkU!*MMfyMDcRzi4z3FL&DG9d}g4
zz2eQ?$eukKh@ST_bmg?Fm`@<nTD04+6+S!G>}=OOtK2&J@1MjeA8%6%QwOG70T&fp
zxVx&v$mG^^L0Q*?V$2|nUPRU4eCyK6j<rRAMU^*<cer-ctKfq@I{~o#Xj;H<!Y2W1
zJW@toLY!Jgu6-r}n33`a%-qoH=NnEA<$6v;;21(~_CNtC!43T~p?T%{EkufC72miR
zGU3^IzhwOn*8W>al7h(Xdix$0I&;w`9JF$T%?xOAtl`P})``NJ9<cP?dg{b*)8rSv
zo!70;VNZZi<DuU6LiA({U1J^ha=iY>loSMqGoGXQocCW;@Gu}x*{&9h0n7vVp|q7J
zVSN=M5Z^mjXR?6vJH#_;M19WlIZmE;?mDlO+sJY=RCRiHq_AkV)NMjs)Ri7(2J+f`
zY#aLRX3nX@PSrI~Nq2K;uH}kpcZPca(qA-);XC~g0{_si<%kU>gn2Pv0bSGaSK^5{
z=LD)J4P1l{^Nf*RNab8+=lk-%-<~8aM%I6I^$7Si6vVECbODnx=#rInijmrvCEatX
zYwD1^XJxMm7-Io&c7K})7>391X3sS^rm&#vX*~m5GjAk@5nDhnUM!sWUaal4&@|20
zl4Zku4=n}pg`;6!r9h=;FQz+oT6mAp8?Wg)fXAN%sC#hj<b5B_?HacucTnZ-m7)z$
zfuQ7ou3PZ5c66C0PLe71Kc}qJ*PD-aZu}ehkIQ5cm)e?eMoH%=lHcqI>Mq?`8llSO
zLQ2K~iz=aO5(hT>C<Mo_=Jbjjz^$OZ&Vp9Ppd>7kJs>ASfxOGnmMYc6w;HbBD3=z*
z&QE!}B@8wsps#7ouX^84Aw*T=j6oNrJU!Ke$Dgzbb#ccLqyZl!=%ZFtZuDyLy&2v|
z%0=XEr@5xTyIn}JB>hDL(f2}pl3ABNE0A<a8$%JQstE%!@NtTIWp`gXhY-1@83Fep
zL&$&g_l<{ZfpyRL{5ba#;;Lj?=(;iRtoZ=r-byNpP%V00EgYEam->Ia8AZNnL70($
z_$@;EAB6CwO`aCGKU0W4zZuOktjp9WiTBwsBa)NdJ*Pe0wAsYmWNT<21h-rR%OLXp
zgOAti$bB%wB)e%H`*N9+&6e85rOebDomV?$bS%N`%NBn^56xTsJ`N>;rpnnG#ycF+
zkfEN&EoNXJMc#X3JugIvR0~DfnWKi^XV7-!))hCa5Z4YWfJ0nq$Ui-@hu>NX<tD^_
z#*I$}CUwpb*M)S3_br-+iM)t-&{WHUzI#V-9_n32)nT<wlDyxRysSpeIk@BVL-?om
zh48tZq8a>$t`K4=6i!C1?RY^75+xpty?C4H3v=A=ml^wCl|89nxSfAr{p+5s?ls(V
zJB;*p1=Xhd6EoIzT!jAM%yDniAD%S3c&xFJ8haseDh|d&hKq#Je>8va?`0aNT9Tiv
zaxXXe@v@*zoCcNsp6i_Y4Q+WU@Kbt<WF#BJH8_ayQ;vrRsRfhxXmh21)!B)+4C2Jn
z*}5*x`nB#Z)`?O^bD(R{09U0O-NU?Ybl0WL2Ecoa!q~VfKTbT)&tzOtM34(pib~Mh
zI~J(3B9FVYFoWMKQ;v2fcVqqZiEPIQm?jiUc>MRCG(u%pt+G2i=(=Juy1a9#@Uyg#
z&4Z>9ab)-^bIQv~mb~Ul@5I268gRh{x{bc$U9)14$OU!Zb1M}0{0kLUE=@=jyYO=;
zU_3Fb44_`AWZ%L>aYkk4B{C?<IQ-(!7?4^|T>@}T#b3oz#FL2GuS!ztt;>1UvBz$y
z{(+E?RE=@}ojfSDxVWXRy*|9}Z?f!UBhAgm!b?e~mNH^;*K3#wO6A~ER}wRQ<?+P&
z=Z*2aoW%5aC8h$&JFGy-Ubt(E_1){k_f{gmk0rCun;}ok8Dfl95Jv0ushvtZ(mN;K
zgH<(NrW>=7^kUpp)HBqdL@gq+2zQS^g;b-O81<ZbMp3f18EP0ZEE&C=-HI<?!lcZT
zjqUD;PV*U(T^F!kK_$HzD1Tq7FHv8lCujj<$o(ex8wDSNYf%HC7n}Q;aW}XQVlr^y
z6R?w#ltWH>CI>i?#;Yevf<ZWf-yQ7OEz(786>>bgpQ{8(5IGWX)wB7dlUwd9zKRtM
z!T=8t{XI+ucf28Fduq<`XVvi*qFE81psJd*d@v6w&d^ayC+qvSL}7yyD;9?)lKT6=
z8x#w4VoLs@s(<!nX&v5UjAEG{jGz*vm{+@Rrrc8<_qrUyN*Fy8@ox^6td~xrRHuEA
zjGu|gd72%;Qh611IKF;PzCff1L-+x)G+&{lq{wg=a9@{nf!NtXW;qIGHeiG4{aqnx
zMy_5z-+gjn0nR(qv{c@(6&c)XAsU9QJBfx=)SkwPkgAZ85)sHS+Gz;VX>Y^D%lDb-
zLRcEsvMx6%>r!gh$Dc1d=@-@X!$?k69#Cr=l`vNfLOdSInxErOK1kp{sIVZBHDl_^
zKV!P{@2)<Yr&>Kg@D}W-^M5i6Ox5B^QM7*~{FJ=5xS5B|W!|>bN>YKa&H4CoA5N<F
zZeD0Cl-O-2yUnvcxvO0vWpN$&U*O4gsml7^sg%#T&%@@X4&}ElY3s*IEPT=7+a}%N
ziW8|j8%j#|s6KgB{(gk;Qt9&SdCFVhDc0&;@VC_|HHf{%Ps$8FK=m2uPU+e!LASCO
z0xyv18<xxHd`t6g**1Aa$!2e6v#o2;QHVd|t-CjG{1pviA7)bK^!(9h#v>K&*8NL_
zC7BSPc_DY4H>A_(uRp+tIu*)ylkhu<eYwHat}yPOWcP-3a}vxdp#bYE$hR%>wOmSL
zZmAc88;72B0+q5@-GWLsr)~=!bXxs@rI&wn<8M@z5*6M9U<VMYQo+XMw^6a>YyKj;
zfwkI<CI7TSEQxD3K1br0pF>lkhNB3UCe-pH`fFR4_4k)$?{{K!K#d6iNV4(8dmi+b
zyi$YpA03DWE^8>EuPa5z4;qGvt1MGG;K9UE*_0f;WLxREXcusN)GHOikNm^$P}2X5
zxy0%`98t6kmhMJ<WOs6Tkb8RQn>ETk4XS8l`4<4SH*H*??>PlZfo{IgR`dQhx=5&U
zBbR8ozSOVle(-2$VPg6ugEg$`8$!PB1tm7lx&BuYL6I$~>ZEg1d3EGtoP}7ye_E`=
z_d+o?;eyf@?poVYq%AgIFPFbD6n~&X8$hW?<P(>=Lz#7FwjMv$m~X5#%%kfNBzD`)
zZuiXXNZ2ptYfuWkuKhE2ejRn^*GltFi;?y2e9|D>kn__<ak+$b^l{02(@qQgUV8hF
z=3m_*p6|Zd1S?8gEHrC}jZQi57s#W^_p|eUBT?SJ@%c=2s^L6w(LAx|P#%T>;%|Rr
zKG~0K5zq7yC(tWI>)W(;5IZ>-W_(|~+pP@-##UtY=e1Zv{e5h)eD$(wymDXq8N(^W
z$Yy^c0nO0?p)@QG2>t<cN8%S+_-JX?=^&N5-$+_X>+*O2<og31rdO)r?su_{h{w<D
z=lyRnc#%;%UzR($!vjPOX}(W}*_teZa78RHAKOw)Ua;N%H;uhVZC?YZJ-6cTC2IK5
zVQFGj^@kcyKe?d0`;l*N0-)t*U;RT~Z11DG;eodC012s#&SPL*!)L<j1y`IRY<#A%
zlwI*hUwD!RJe$9W?I<FHY^38O7^Y$87U*CKdzb0AyGK%xl@tgQ+n`)SM1T8{3I+5!
zbe>OIqZA5|B13U$$zsqnBi9uXIG@1DHRX2vMrZa$q;VoUWdIbgklh(uW;h%7qV2La
zg4UK_{hgK2%r7xVTT>3i(Zj!x$5!#=k?2EA{kolgjwpMyHUFn~Ho~?kj2_z0KMyWG
zxJ$Ye0{rfp_GXOb{^Q1Lix~TZb)JA?pM_?slRuxM#akPz`L|0)R!UDg*XJn>#;IC=
zPMEbmXacmDueZ(92JO7nl>D2PKjk?z6Irf?Xx%^Hg>xDXJj_lWT1;Vr@A1{uuI%X~
z(7hMZIlhs0ev4SpS&~14H$&RLYDobTXQ7nUr7Q5V=)O;&-X>!%MXG7B-<w`O<bSPU
zyn9GECxZyj1sM?`n9+i!^mV%2&s>^Rsk3zZjwFbSGA*&6M*Ew=AS02uLNiGJ&@yj<
zw(~ccQ~9gp%sDZWG9~k00};#pY#h8T-Zug9{Tb7a3tnS$(x3hxqf;>?$s%mF4msdd
z=Bm7fNk335N+5)zGM0oHpVPe_O8-h-UTlJrI85Q}jDg%i=xhWzCU<qF0yvi;4o!8u
zxFiWKhoI*APVcQXQmOve&W(;ss%H0Tb4qs<WnEWGLNPvT4HFR&`$M)?FK*Cz3<ac*
zN7Gb&Wp&D3d-5<^jCF_W>_-F*2^iZ*h_(yLSl&}$UEZsLQ@`ihj4xmOT=$>($k05$
za5Uy!j;Qq-;K#G;z;;JI^ZbjLu6~b$Ig7crdFPQh<!ec6Qah|bbc)2=!?o9|1J;_T
zgUAh^+DrMCOb<R^p-1V*-ZMGA$7)Fq#~_?Ybq?`#?(YeBZ8Az3ru-5TQu29H>uWB~
z_#%3Ab!djK-0LCp%UsX@iqtiQ=opZia86kyZwqKx@*L&@ztT{Co-rF&>-VZZxX)ah
zK)w4<jwcdVRPsX$JRlq<L|xwsxK=+6&Z8{XKLadRWV*Wsgr_{)uBF>ey`EM2{)tx4
zjpca;2`&}<^w0kYagi}%pS@fbS|$?4?gXW(GzJP&7O3eHYLnIgVgnp`roA=rU~N)<
zJ@$=V+{*pf7+-#;x2aWZ!s_zR8&cP8QZzW96(1UpJ7oR{dl4jnT>>Z(4fEML6Qur%
zm?cSylXuBpa5+A1JvJ^?8OZ|sT_tqdDzp3o`ggaYxW9@Ux3D7reM=)U!&1WhdBtgg
zetfU-GY&7lrlTM}*RQYCO%BDl>aDbXn!#@`@&bG)R=yX<#U+>+3lI5_ChxnclfD>!
zTB-4lqeCy5MkoJn%Ja|THFJ-i3N=LM=?H|lU{-5cbAy&<E<4A64AstS#yF1RM#!o@
z_g}KjMdF3o6-`{+W4Q|kf4sVrtwl<+(8=}TCqKYvx^?Y0Fq7lGwpe@Aduq0WUfOC@
zMIo_z5>wwI50v&kdnGvp<WMHxTx?UT-U=rgx8gp1Xge=gEFjA%YD?LaqIUlQWd6V}
z{w|+iqqjjI+jUG*8ZI0&7QyJ*e?^_jC$63^2?@yg!+Il|Bus$0&w(_<7M$0tEkC_g
z{BO@`$7e>~K`RKdj&!X|$&b4M%5sOiN(!{R1)z4(q7SG=yPI3t@H8@7g>m1=XhT20
z3<s>27xf#{I++l4bZOY6al5C!kmC?skq%Px{Rl!VNl~i_mZY+{CknX7jj<)S<72ST
zva@drt@lCV`|GgdXN&*QsZxL3#3fCMBfZ96@sn<{zcuDuHzQ|URsaktUxoCF-9WZ8
z7^~UMH1XYg;13E`g0|Ps`r$*&-1BF4ySv`+MG}!-Al^0coMnX^PIoI=&aIdogll<9
z9MOD~PRVt@&1^Y?(NtAD+lg{RPxb{`dBEp_CeZFGKqS5Cdb$f%V=XS2{42^iE<+$I
ztAnD&HjqqpBIyCO82>;8|B%m5(5Ro<&aK3G&Xl*0=%Y>6eh_&a{D%xRiqjcuzAV2T
znxJ!~kbB2d!{zA8{xtgYv%Ll3hR_c~Ja2$e>Wk8?4WX|Vlw9&{LWp2b23O>1B{J3%
zz^UEMJAr)jHLdD_=WutQwwQv9mZ104+=O1OYVa33{5}UZ4th0U527WmJIbv)QEgrI
z$HaNN)2`Kx!7+KSpN+*gxXbg$GnRW*C&~+`xyq+kPTz`uFYxZ~XcE@=S#e9(azIo(
z4_;|goxO#MLHie?q@#A*^QM5#O+~hhTEd>o^HYwLiBzW!Y-AaSk=%vR!c|$}Kvtwk
z3)`^f=R$YC?wou!Kak`KKVX~^QFO8aUJ8xdmAl#ipIp*c2J@v_J2VL}#{c&}`$#$<
z%hv#}NEY;~Sqh=bF?8Ca&XY#OS~(xeLAY-|yDPisf_uKJA7Jx=nuo^_GXj8|6C&TK
z-+k_S!`kc?<-}O32z6@68a_kH2^Y^+^7V`MBKhD5aR1$|l9TMOegMCE(gfWpceIgC
z_Cb`Myls$o$_cFMBgI+{ha4~ksp&_nA;^UUBzH%AjtQc}j`f16rV;>N53gC(r5BeF
zHW@6lltNXs*wWp`-SC^#wRc?Jqk)t5?8V9i`E4%$Ck_MH7h5xgz?^*(A3z4OLAyPP
zoEp2yED<Luvzff}(iRL4Yj+I@JNd$u<SmH{kIIVg&W_G?)oz^({vxjMbv(NQ*pSDF
zpL(8LNB??!Nl!5P4(xazTD0J&oIR5_xP}PN0@{2}+1V%-KCu}L*$KQek7@S-3^*?+
zTS1c-0)l-$Z>*LBV=bwf(^wvrSZa%7I`KSl2>|LQDS3utb9l;6&w$k}50u!SKZoQW
zsn%8J_HPQ{iq`H{2@S<cNHzQ^T`G<Y4!o^4Tt?iK9DuaffjnVe?(;>gLXFX@P=NMd
z1V3egdibjB`PQBJ046O5qBJPWT7?icE}W${?VeaodM(6~PX1OOi5w4dnIFJIld2|Q
zrCKf!lUT@{_irDA%LRK1Q5e@NRn0&B4Jzk%!Dw4)cBh_smQLmWG!aEnMZohD;5Qn^
zb`|)_V9GxWNAkpuhi+U9iSVzu+awDSz%>MJ9w*^<UG*rjVp4<z`7mF?cE?F@A5v3b
z{QBM$9QdJPsQ2W87o+==`oYI=D!Ot?th#bi8CxwciJl;Zy?Rhb0ws*R>$t7Iz!Ehq
zjOqQs`3~>(iw+5peSa;rFWQ%A;m70C<M+4k{*cJgi7qTA#?Djfikq}5Pztoj%Qtmp
z(Mwt-_A!E>*Xq${-ul{XHEAI;(r@pmD;o6u9FKc%BH4CA>9p5OO;pD<!}w5}!OOQD
zYH)QH5_|DecVhJZVC@j!!LGpZt}g4Gw4inK=<wr;d*`v^&kj$1?8xqAcg4o$iH08Q
z=M|5;n&HE18ln^SmAYgl)LL8=x!a0%+O$@Q7Gg!`(<0}-M*>8tfw%2D@@uLrB<~#2
zQT;=z?_GLu#&`nfHT?~as<P&hozAGquZHCD+0U!CdO<0pIfBQM8a!T|3iW#_(tGl5
zk5`sg_}%7@zg?yu_MDouv*V^p$W!^gQop+p-HJ(}yul`;u!dcJ6xHx^&;?0qPi(nO
z0RQd>L|~7knGB*qn3JKZu?!L-E34*3Q2z3{_BG6(5glhJpe=HZsq}sqd{Mb>s(M3Z
zVmb>X4mhFo#-Z&bEFwA{u$?Lk&NFugFc=vAkq5kn33#b<!GQrerlbOWu7G3ZtK$Ip
z)tCkY)<{|+-0PeHt8Ev@Hl&%rc9n6P`LnFs>=TZJlZ!xb-X=2K%Nj$KD!j40w_-eQ
z$pOMWp?$Zv(4F+VTt%xo^^UoU^Npb+t~){9#Bbs(B}S46=b?o+qYf1`Y|j1q^%Ah-
zS;UU!i0kUUOu+cHns3eQIhrL(a2d9|$rtwb;i(&TuQ?iNo|kG({yy|rFR$~OHTJeA
zzM!sH8}~C`%mhsn*tk|{I<<Pp_|@f5#HT$?#oqSdWWligQh;|~EVo|+hhMMyys=yJ
zsI_!m=%{4o$VE}&k6!NJ{?I*MI{VRPr)8NlIQ2r<BuDFR&sv7lRgAD1T%guRL{cuC
zwQsS3`JbKtO8P%~&IT;^YWw1X+oWF0T~g*mSYl#Ov@MfU)6U<gGbC>P)keKw&mQLR
zcDz#?W`VXtiEYxR^4&)M`A8?P^N}9pKsJ*AI{qOi5Kc7wytJd3mc2Stuzs+dO7gFk
zTF^%&p#n4lo;X{l^d<FFYnI)J$kHvSkp5Gp!55Ax;>vmkCux}`w|}#ax-r`aBDNL^
zVZCwn;hbkVV35PiQ}n-WQ9Zzo#NOQMniRt@z<*F<HcD3!@-6{=%xl1Q^u?#Ha>99A
z_Oh=*2F6L+UhJW2>l@M#Eqtpav5fOy_I=nZE1R^XUbau`zDb2<T*J;u;HR!(;FFcm
zyHZl5L}716$3?3S>HA;>$Uio~dUqQz+F<WG9ITYcAJqK~{+;hxdH`&BkArpDm-x{>
z7<8C%tU^R+e_hMjprK`p6+4?f_p8C3vpEJcltLS>PSP&<qJ6uL|EZhgzy6Y<yP1Ds
zmml~0&DxC2^}ym!jbFiii=oypKBtVDxGquD9N=|59^qNGK(!24cIjQXm`9!du^_t!
zxb?2WZG(pI6iw@W@c2U=EmD<e`FR<&Ro&(te+W1ckE(%39VYz=xWwHG(7oP!mrMyO
zI-Mp{B|=_^p8s=eQMZ60?N1ulug*E-$7O=p!FNZxAh7{W6s?Ejazz0tik3536wKAg
zXF=C%m!h5clP1-<T{MeQJX<}N+_i^X2jbx&vE2Bk{Wf`5a@K)+-+kWWird&YrVE<X
zsn{~507@2X0{3?!;rIZS@2+Fo_u$13<%8meSft~pbbD@tdB|`Fs4M213bD7or<BI4
zV?*YEYlVw{Qzn+rkt_qdsge-M9ph*C##Ns%f*gwJE&s^L>(#wmI_$skYB2n&W3w^0
zGZtAP%{}b80yDPa>K#Xmqhy8&=bF@uhi+>6dgulyg-q@?{$xe!rV{0pFy&B<ba#vw
z#(*bLj;<hM4V>OaMl}2Pf4@5fmd?S+>-S9lZhe@~=u9_e6^=K8!li#)Z%$n;LSiq=
zI#<mrHi)`eLH6Mgqlc3xLiz#?hPRrtc-tgJ8(kQjk=TB#Q^Bj>^ge;#!T#?Hi#v;2
z(q;M<<=;-N{$w=0b<|gNaJRAQz&Ot={Q8^peIt<AENfi%&WW}IHmhq+N&9i~dcHL~
z^OtJpCow|vNkRpmI}vO~*tG6!yZ)_SZ}q9QWTM#5u9qG1+`^zhs%u~%eV;w{@*iwJ
z9YJ|TF*k@>u$L^bftdL|5TI9f6l-PtjHU{|c9-D|?C`0~LSZsjoPZ8U(Lg!t*V7!i
zCaRxh6@H*!J>29|2BfQQFvLE8mf9A)XZD#6da9KuAcu_`<Y0Q$Btc1VsfI%+yE)8~
z({S86*vA7KEq-xH#t&0b^nc?tJlL=_Z|g{x(eG}cH%ph$KS)HtNOJx|Z+04gvC@GM
z%*YQ_kFod`FTqlEdr0Q17csk-*z6mLXYUC*@b!`X{y$WGbwE_l`}NYbba!_xA>EB4
zt#r3Yx5UyNBB&q@DyT>!&C(zsAxd{6we-R+yYKS({quhBzZ>_?oaZ^`JTrG@IJxnA
zKJ!1IoM)|WF^pgsd(8XptcCSj<>f1ST|*^toN_ntqKnl(E9)0KgLGhAM2txpurO8G
z2~ljImHA}NYIKW!TkUm%N7X^^UXcF4I@$&N<BK=HRLe^v2wsd>GYx^wH<3Mx1-z_7
zWvnSzCbo`9(q~K)nUzH(!wOE+5Kn(cMjcCbpq?ND)KP0QKCB-^ZtUK{C;99mFN@Sn
zi?pmGaVKpahjO=Po~QyusGS?<MwHK_rI|-Kw|AXrjim37U*`Xnd%9a#D6m%8V0x}E
zn%gBz#Qpu&I4o<r$EQUnC#bQ}<!1E0WfJe^y|p{Jc`%e|fuY#s<Y+WF@X1?R5t@84
z>+OXn&S0RcJg=u1?2EA&toMok4hbf7q#N={J)z>BllnvFT}2cbSa>1xnIBEeAc+C%
z8Wt|R_U+hV8j_IO>5xtAoHv(fHD05RgkL0!1CC$bHUTYNfdy>a@TGYt3}h<=#-yqx
zfH;o`i9bWD6OYNVx>y|tc4>652gy0cZ(ql0z}WyDQdm8ke3iKJ<mF+Q0_hjR6Ec3v
zra;qy;n#dXF)`u`pXW-vLhU3S%m_UeLYGp;Zm0v`#Ml+fmn=GKkm)Eo*H0dVH>^gV
zhnM06u23V3CjAPtA{gyt11zQYJRY7o&Tv35?@w7Ch_Vrky0xnb!InSG<-|`~TcT_f
z4C7_@GZx#^kl{`wsS)SJ;JHtenTO2g|MY<7vM4lbta}#3`AsDLmR;C%UokKe9M@#C
zAWQ2`L^}vmxH4(1d^Uap)i&BvGfwik2_i*QyFhzY#-*>5<=IChR#BD!mIc%t?J&?n
z*a^P^C3@$0=Mw*{{2y@hA5mz^)GNH{AmG`fL$In;kxbf~Y=~vkN=oOm0qbhl?Ndg#
zk3XwTjCa1#JaHMO*KF7eB$v&A_*ihQ6*ZaeJ~DW_Q2FWS2b8A0FL;4~#o$~#es~q7
zu<*gJ=*DOGTmO7b+IA0Fx<@;mg12FNI&+hy_tDK^nqfB7rxD+=FE<W^{47TXHc(Zs
zPS5%;x2fXNxL&9%{OMW$_yW^3-BiOUT|10N&B9GK(S~@ZK?;UhV1y%({zQ?EAeb|C
ziwhYXpZZ%TF0Js@-OEcKH@+eoa>u}!-no}1BdX;NXa&2?8oWWMnWj5ZCAg>d>CG(=
zgpm>HC#GgUyf)(&*gc`5Lv?L#{_Pu~Ykn&<K$gZ4_oPpAKiZZrbu+eEU9I|HhT+0+
zI|ra3hTr2N4q(j^8d2pT8ZLmzhVXNdxE$KqkwuRMA|huOf!eBoANH}NSkU-9VU)`X
zkW1~>upxtgr4r_-AzsJKuY>^d0U~aTAya6Cb;-4MxH}MGijrtix#=Kx>`w$`*NC5p
zw|O6l14%C0@?tf~7`=g*pz<Zu6SfbmQ<#Jo>>nby!s)=2AcBjsDK%-ffG;WcwK(fh
z%0V3g>x6A-GIE*)o40Gz-Ig$BeS7YjZZ+pf;;rPGkRV+}Hsmgw87=stJ{1OE%=Zv)
z)O_)Ce=Q^r8K%S;rR-h)9V7kr>FvcX;$HWQcp88COiB;7{m(f~dv|iW)(*<0n0$3j
zTZrLfHR#yOwX~Oq7yS!J<BHfyhduzNFNE6PsidS`RkOSZL_>MKNmW&aeP)JnMuB!$
z)ic->Lt1=E+iHF80BTNNHOC_zzNEJjVjuh&U#Nzas>ff2d*;ay<Rm;cl(N~nz%NV-
zHl&I0*d$!7oTAc|!4*|;<cP5MjMjw_<-;gvrl<sBM_<ROV7x&S+~Uh*oHXC$ghyTP
z{(X+^#_wRGsg6#q$2FQD^DRzEn~+j3pJE;T=xUx`1fyiNC)9ERO$==4)P?rd_{C4J
z)RuZDJ5|50;~l~XZO$^7{cMg5!N+`<Dt<wd8>2P9`TJ(Wh0ph(US17d-<-G~<-iJ3
z*bQmWY;KGFT#lX$u2*7mCWj<JtF%%YHXmy^o#V7~k`^YfgZMzXZm(N(W*d=NBO7jE
z`$+fH&g7xc7SWqHK)O0}-rsdR(=4d%No+WX)Nae9Gd6sRC58M1jysUpC4&x%WN*}-
zr-n&-2vp%??yRAlwqx@zSa@hM3{HhDy3R~>*fJN2^2Es7FYtAP40@ih<cVYfSDuS6
z-pDGjav&zS>LxgvRtHCx!tral*`KF1w87o$r3}(q2JFJFswKm|<2c;>G0lGhh^oCs
z0uU)Q(aOCD9yluEBxN~sX<R|^>GRXH9>FI3^rH2%GEMvCwd`Y=BwvNRV+M{g^*Sj5
z*mUpG_G;9D_~*&ZN7b~20O}MeX_QDZ0mL#DsEWw=Z)mK@_BE(G)_+9wHAqfvP)AuO
zJt)z?7dts-uGH};tYuDhhJIrPzc5b9kj5)!fP5$R>1%OsSyOc8%KsdKM+&#AX+o7W
z_FVq-0h5WHN+U{12R@RP0u}bR8QkS~Wda>c9#u=XY1zrI{QPj3&9n)F=^mx)0&sCv
zZ>PxLp_pR<o#@JEG-I>;^-~h1y<b)M3FmY>_V}wA#fGYYMDXURTvM+E$?+kkLfWF?
zEE?BD0z)}P>voX6;w!qBaZ8D^RNzWZjM2S+3lX(Zt^r{^cd+qYHw|^ZA~pbH_&~yB
z=8Jj93xyBnP`2C{HUQSC`pY|8*2R}!qgx8Cq=fN%Xs*HJTzxp0%8B?W?fG=blm3CV
zFXXQBlvMdEC=_C{C=%6rvx@w-gMrDvVP^X$VNDwUs}IF<H%jw8lI%CIaOI6=E@Ta+
zf4xas^KJZ+&3r~|5Qk<M$KdS;1(nDAvkQ&y;39aBIY8%z6frl`#Q~cOFY#9CM}mnR
z;Z0<SA;TXXf%rplkrsQcq9!&s$Sqqwi6*RIv4dw9cv5JfApZe1jcXRlVB>XRr{L`P
z@sHkVC5My?kZY(W&cBy^B!P|&gPN1JppXZS&xc2>T{ig{E>Ag{SR~@Tq?bN~Z=Ix_
zz1u(8CaFVzV?h>OAw}zGB(_Qv5adqrBZ(B}hq}5~(yS90SI{Va#XM!tmmyd8R7H<Z
z-0%01JC$bGxebOGM8#V-FAb=%w+EVunHy4^XNd!J;yx>l_*}aKPI`C)Y@|>N#^~6;
zi7$~I7|1r{qls6A?r)`3NJikEERSQ{pa%~t+Gc1&k)(NkVub8cPcs?=KAJGgkg%rx
zGb;9EPP0xXo{61|CL15Vu@Q*~PLIxQAbe|$=$w$C=X@B|iIZVlDeKkMmJhZ4Y6Hxq
zv~BRixDTl58vcHYGFA8<{uGkvLH8D#k^%ds>{CSN`m@VXAw%*4ZpRu8M_6vHDhUSb
zalO%J$>qL-!f8~4NF1)bFb_N8XYrCD17^aAcbSl>*y9?qGun0-BM0UlD_u-T%rGSs
zhNrczy?DBoNqX04gQc-c>@1I0-xarTV$2@;uSY1X)u4TOE_^Vvz6<;v!zEGb?+#0{
zu0d-=v<XX=BgKnhFe0Pl0mO`6yvy(8HL)F5A-)9(@*GU~D_+nj6R~q~uA$;s|DTFH
zwc^LPJN217wG)wl_DmcW-X=UZlyXsLGEELQq83Ph2V2!H2{=_7Z8eJnFg0t<<J4~y
zgFFk<o}BpGTdwf)NhL2$mSN_`IF;ww9^&$0m7w_*UjWy&!2JC!UmSRC(P5Uqo8VA^
zsHcZfNg)Ov{NL-=2?^v1lj=fwE}NSvl=UQzy?a{97q|~aj~Oq4n>}#XQB2(E<Ie%d
z&Ww5)N?n%Iwe@?}R_p|_0-oUwK)!lCu)+v014NQfqqeL79L{bBCt)+CsD>`6!F~;x
zOR6z1C%WKnh~oDQv4m_iR>Yok{x#=o6dGtsD&ru+teco4!=u{J{S%*R?2@jkG=O0@
zye{KFm^(N<cB;0aI=8wtdjrM`?6reY1_3|kpr|MkT-Y~#C~Twm5eXvu_AV$^XhFEB
zIbyy)^7&Xrym4RcI9K5WN9hF5#|iGL3C`+nZTli+d(_C1_Unql`65B=Pn)$;uUhQs
z>+r(gr&5)>r|8sc(Od|^!2D|Ltwl#M!FCH7Z}1<sxcOkM_oBd(B1ZXSEcnU^J};$(
zHMaEfkm<**@Q?eadjAG5XS>YC?z?CVVp9`Se6U~DmSg7jzt|vJ`HAv;&4fCWX5l~^
z(V*_w_-ToO1fq&MY6>mf8ZFt#mlDb@A1k}#2Ii9tMZP%u6Q-f<@VSnBP6hXDhk~OA
z;9AYmS>96R76c&8;E?Rv%b9HRcrAXC%?7aYCmJY!R<*q`XC)_qt`UjK5gXz-qdman
z;=vuxnk0=4@hUnQCJS7XhQE?$vS4nC{-bYC>IZTFK!uHptLRBBzyE;GZYYhUD#>ay
zn)q$Px~8Ug#~f!36jTM^GH~{*ArxswhhuNRY;VR4vFi^YE-!-z`p*ak%5CP$7jWv`
zF-VdgCXRUi_PFZM=@)v^Z)}Ercv?k{y<T-1l1bFKu9&#XBPs>KD_|%2w|(X|fXSs=
zrpWb}x%73kSy5Eh(lRRTb+mKNY3*Z}P%6wySpyNtJ)o&<#!gRQ?%atY#)K+%fot!5
zPoFKZoEC|gz`cKe4o8OkIfYvy?pq-voXo~96dP~xiG-0avS}Kg5Vhb~j<0lN(S)Wo
z?Guqxp@^e|(Qq=OHF9PBjEj|<oK8MFjd!tu8P=4QtFcZBuP^$fg*EBYQF*n>WpJ(c
zUOT*IF?jM8!i-BzEX+|Ir?DX|8RtJDOa5bnG%y(jJ48LC@yubORH7P%Nbd)}xi3uV
z8hlOSt>06#g>=%tC;Cr^kx>%*^5>2vYMf!2C}+*K2t|j!WYmv2cK}4u3J^ZZK8%}e
z>tJ(P&OrN7uIV9yl8gRyp0Na(YO+0*1rPznC%00dq!|5Ssv)}YN15m8KOP*RW*5QN
znTqsEA^74>zH!(nYHUN=(<5I+NUeT+Y>>c=y&hNCP{x1KPs^^A=si^7Zhsd3i%kgM
z?`3`*s~CaXQnG+5fMin?4X1gGpdqmS;7q(-(pI(;BPCnfkYuzREtZVf1f28&kM9EV
zC)G9C@iq~+wQPXH@u0JaW5!lSX-6s^d!Bcy)}Xnq$>cS4y)YE#z{e7G>up5#@Y>v-
zrTHC*oRdRiT~sfSG!pT2NH2Nf%J2jE^BV|~^pASidux<)?cZ~%-oWe9KCsq(6ezm&
zvH5*`&mDi+Rek{S9q;0&QE*DFL5uF&FK(Yl0~O}vp4rMMKC|_HD^T04_cmYH*kzXg
zi}>EQX?}?D*UmYGXS>o)1Ku;H7E@f$Xo`DkGj1a(kxZwLwt|;kCsLNP;NuDj!ydg`
z&D(wkTW4WM2j9cGC5&Cp^A%7Qh=m34*j|?=jcw0$y%+11Q#kyTl~^G}rA$vr*#;So
zd=a*d_%x?((F^(2MnjT#y{Y>ru3_K2)BC*5O`cAH6533AHW!B<;Z7FKY}UVisDwki
zE}E<fDV6_P5Gt}$FGt48r-s8vt4J(%K>f$}z%kc@EXOwPT*n}b6G~Hvy)y%dz%k8T
zjmg_lt>XWNi-$4a@DH}q*AyZUe?~@|9@nrDn%2lbRgn<a=xR;qV*e~xIrl4_F20!6
zW5G1u;Jf@z^T3#I7<A@ws$z7+5nL?V<OA9m|1FvLnqo<!o!D<UGkpL?>%@SaM#o80
zZ*nn)p$MZr$Wf>KHPKET0oi-K=<|_hB!g?irK5FJLh+$T5+AW?V>G-(O>=GI_VX34
zzb9JC;It&Q+Sk*OZpg%06i|o(9Dk1)?&4sWS1L8I`H2u+DI(J6)9-d6J_SmdRq>~a
z@+au3wpJ@NW9uOp*x9S`&raXPzK4<*&t*`E*nQ1*VK@fQVB{SXQx+e!ad;78gbHk!
zGF}O?dYpx@$6Q@RR(MTL@^&IED8QAusgOxZcRLPb_v7lwB47CKmoMT4ui;Xw?Ekt^
z5WunqZS?J1fY7P*PVlcb#g?K-ikrPCA1Gbzk9EHr&GqLfE&F1#VxODJh(%7j?tk3p
z2{bXZmk#00{AHCl>p_JDA_her92wI+1co#gjPw{sLxTIM=RA902;f4faC=0Xkq<Ah
z|Aa2fu#qvwPQw@twzGnOG~Svz)A^^~s!1M07EhwH6jwtLfvl2p1^m|KvTr6ieq!R~
z3JZ2Pqv|VlM4Jsy-5F*mRfn|N+cP;!t*2;>hk{5j>x8u(hz8;l9Q1$x86rvU|11Og
zz3EplgW$)iU{Z)VbIs+f7*ih{Ics-1&^7#29klUL|4C;8$NRNYPbgdaI(}}PzsfVF
z)SPL`5GQuRBBa89YoxJM0kg8JY6u%v=`-3qEHPok9o+LZaHqk!I%YqD1Sh4BiH}w<
z`2r?SHCQYxO^N!)PPv(_$3(L8n)r3xfMwcn8CZRD;IxVg+kWYW5s(sqrJz7E-hV(Y
zVxO0#hsDY+)>ry%r<iGu@f6i<DEEczS029CsbD{h$W()n%2icz<#jaqNJAq^9l7!G
zf>xRxxvLOh+pYj!y?eu7LhF8ZL$vwNEPmGK)doWCwn4i%V&RcCP0-KmQ@I_Tf3mXY
zGYhikR!K~^jW(G=9yy$26QkMB+;&GkNccPVAILU*d6xOoBcF50YFlUa3*r?aWN+@N
z@GX4C-&wfD;;)?cyMPjISR--PT;{OX<krRfTFCaTT-lT2h_wpCZe@dcn(W$Ud_+D?
zjNQL_+v3Awk;zM)$*|4k!KbB1Q)-(L$;7uXiWxs%txc`;-T)X$IGYqO!)1PIc#TeL
zo%S`A9>#I116j#FeMPh10Ix{2zeVIntGp9usu${-2V~Y+)HF5SwWQQoMcH_My14q#
zgA^tCG7fUa2&n8FhVf7l1G-=J2Y4uHg`dR{ItUCn7|2TgTJ<4Idsl!^;^3+FbFkUX
zDRXqM7NO!&^FV^mx|$erafWd!RAT`T+5?v%!(Q*NuhAQ}EA=zwEb7ZbcHxY2wrJ4d
z2=Ta-iRC`w8Sp?TYK4?7TDhlENe)_(QL@C!C8sBZIt%5-*~T+***1tBj>{#Vnkzqy
zUpbku`MpR@8jcxcDN6E*7iM9ZGa#6O3KYnMgyNavKZ8EP7St1>3=l|V&x;{3-yT4c
z!f8z=Y{U=?EZ<ykIo;Pzn$?w-Xu+Z|X=K!z30KDc-Ao$?<eKcZv14SjhGVQfx%!B!
zVV5cU$}R2X5nDrZk&dfXHnUsGk%Eb{nP;|QWg1m8MfMD=nH!C!4I;|T(>nyWW$%a8
zk}vqAqgyd+*y;Px2pY^Z`HKjJIiD4csNJ@idE7|ssJ%|+bH};B{AsU8713tEB>&i8
zmtP#o28tQ+beY~W!*-$^b$Dme_&strsu7#d`LdqI!v>BGS={4)(NwP7Qc(J`WNJQJ
zksi?6kLiH64W`-usE{=U7G)HXC4C=0^J}1)ui>lc|D<$V=t;uAl?lYG<IK#cbDc!s
zo7uN$XZM?Y$hiDz3QaKN5sJz4r831XVl$${q*mu|pIRb$+&Hqn)-0Uc5euj`d02;-
zA@_f)pVs$A{Skj<Spr^Ti9uyGc<~;UDi{-6@U%P?#S8FN$Q|Puc!t0!PH=ZsPXIAe
z^u`(D<!g~;Nyhpc5>cs-wmLS|g+;MZZkkx7yJDq3EHZ42M0g6}l&Eixzb6sR*v|@>
zQXz6)QaWkuM(wE{MBo!R1jbw7*b<Y21xtByc?gtM43i~!Z@>ePh??QAKShI|ynj#d
z<zjL&r}oL<+Mmd?o6h^Q8`90wwSoCh18dX+3x5aJng<qvo2Rau$5I^LG-A?8RR!A1
zE6hBA)7_gegbhi{Pq`epU&$}8u)=EvmaOIv!`8h{qQ?UlK^tKm=ZKXB5*utJY*``f
z6VXxz{mOIw82>jvXqL^Cx;8m`5Bc>KlOOhNi$oA()~)I#6AOZ<-a7~nB<__eT$2nW
zK5C^iW5;srCo*J_CHeNSW!SIMh*DyIrs5y_^D^>hD75k-$^@2pO9F;fMqAb607rT1
zYI<d`SMgY<cO-V2NM1{IS@&<h7QAu^B-nT^>yc4c$0<K045>B=S4bloR&ZX63rLSn
zwvnQpmp(H&@^EzMH>nHikR1&e5H)N!*?co?3dy3Y#yO&;+~h&3g+wr%IR0~e4LXUF
z!)L}li+wW8MT)*R9@B?={{Bi6E9n?<vdLjcxf=>Lmum@AocIi=#o3|4(`K0Lf4t(p
z5o4YbX2=ty5u?2qc?n0AlkI`h*m23{b+{GMH2Ao-^rasVLNwKKb^h_XvUdF1nTZqs
z_w@1Lnq6`Ygwh_xffQjM65&PG{LVnGsCBOB5B%cU-K7Y+Xa;ne(MI3Az>q0Xp4^dI
zSPq6;EJKcC&{-0+9VT}cQ53c+q5y6IbNUJ_U0B>G<cE<gEy>#09<;wY+3VuQ81=CH
zQnFJaSTMxNo_J{eZ>x5Xd|vGVn;R2N*LBMk-SgDeg`uB&wP<+WXMDTVN({Yk;UseG
zEvG9qM+~~*DQK(Rj?j-J&gW)UYz1z=k0LhhQvZ%CMhmI=l>Utc+kV(4T`yfrEj|uz
znv`|>N>%pf?%o{*A7u?Xld@921*Ea_{7O8Jsbrf^cjoIPA=uFVs1oKZ_A&jAQUEAB
zvOfn9hL6``FyLcCulY7l{S5J9CfVh}r^!a0i0h>hmOb6#>>`_@hS<}l(S&7~T=5-c
zB*rbO3jU0_{S>~+scbHK<R>9e1k4CVxk(8rQw3cZn40F242t?ufJv{QGQR9@gvRUU
zIL0r3K4r4}W-F`Ng1T8Jt1`Crw}1Ehv3W91UUF78(e#m8*$jLQiYpObEsC<7`)fDO
zRn@(~Z$lHj#;*M0>_)o$uw<p_OG!`#SendJx_Ry?sv2iK7KG7S$_4P8Q7O4Sm7FSQ
zMd5l;`O0N=oEKtM#`0i}iLRtTY=TFQ8fRRd4+n--%={B|4YIOh85LfX&b6w;qu^Y+
z;>GOB>bZj*Mq*#{A#pM2bn5D6J!noesH;F<w`{l7%InBS)pcpKMvr<z<L2zJNG)M4
zE4VxLgn5K1^?ODHqe=RWvMy5sOw@ZO;E7}?%iV-qNx<JY)`(cZOCwG6zqCtcn6i8O
z!TKP)UN!2~diy}J4X>oiYW=wLn6Kt|s(bi{YI_v~xk)TZxkd)qygh*aM=E1V0iMyg
z;%qctfv~e9Wk}d5&e`0b{Wa+_$L(LObT~jgXe0v1UoRctO)^bS8ua=xC~RZdTd%*(
zJ(=)Bq73a!9iyXtTUuPC{t&Qwh()JxG45|(Oimfoa{^Hn$Cq*fDhp_f;`A3vKTz4-
z$8M-}#ilVs^EiM-BS1OV;90*+WLj!D&N7f%?Jd3pA+0_A`N}-%v-jomo2wmyo&YzA
zhF}rDtFD0AF`xGTfC-vWes77IV*{Mt*#TysVtr@Dv3@1s&QUjhT4%f4>;{+nIA+B>
zvo~?v(5;Y53zL44qRhq;&X}Z%v8rt!iMUe23}-;wZJ=ayUT#*Bk>Kb-U~#H=!}FVi
zSE3ytg61;4uSxty-AMDut<#JQvMetZWxf)5oFz6R%Z;<QSDSA(L5E&f59?P0Q~}q|
zDOTfK_p$J@unNjYHsPHvRGuWM1Q2z4b5b!6iClxrKQ?R<<mCa(xx*jI{@Z%h!WR<=
zg5bI%8k=$5OOpn-;8*(_>suC4QEB?B#l4fP!>Y_p72udzL$Tis6tor5F$CS2ke*?(
zUq@tRV(bIe<W6NI{>@^tYLYfC{_h$%>jl(+c}L%xEwHd0CAlxPE)yEi^}Z2bRwcWV
z1pQ7~#LMS-9u<50b8{J-S!#NgsdwxmTo!=dmb`>pzDq|`LH7pf-jlxNfZvs!zwnnr
zlB-WCt-z<2Tu+*&A%ZFO2cNW26wxhBlwNmkUiWqZ80J=Zt$!q^mcb?+Qx(yuf2Mq_
zO)lY!pT;^~QZ7mF470oe>~JG9Mjfbrgi5}(@TsEvmw43<WBi7H^bAc*peYhZd(mRm
zNWL^=oS9znYbAnF&LX{Tq}z1Q?uU=HA0qCB%N#%AvS=v{xP*mLJuBTDNSSxMSLvnP
zEMGO0Yk@-pY6w391!Gf<9SXHscPKN&aP7(fn{{@~=?n&Koh0BQKF194Is%FWe<gT~
z3=w}TmhotkPIPL_&)4Fv4F}noE+uCpBPwiD%pD~EvLPzrI)w*hN#voJrs-EiVo#$a
zOw}66&TjOp0MWR4RE~tVf~9)x3Ihpgq+7mK(Wj<^6)Z)l#grr?tkL#$*xYC2NaDae
z$z@V1R+hSCLaW$7TcTU(rUvo08W0h!qyrRN-=-H*6%+4VMH#JatOU$jUq&T8YQwg_
zeZ7CD34hv9j?TFtR3`H8XYlMSYK1mBrM)A$1E-P^*WQcS-iyH<%{aJOE#3W)ifD*;
zqpp%{+Od0%$i-64PnQmn*i`Ogm4jE+i84aev>fE4cmisJ=FFs9K4j4umA*nlLP@oC
zKHiRxYbd)E#O$GWYyP3H+H#;uT(J_Rj@2SOjvY@-uAdH+8TwVF{LCgzbGnRM)k=P%
zpY)raq~4t<_ld1g1?T#;qqu1<G9C3uIkHk*ZcC~&mi2X}^~)GG+I;gYZWzYJ83oTK
z?xmIl?dKkYUd&|OwDQ74A&d^@c6$ep+?hUZ^;-=^=S_u`_K_t=`BC*2)Yh8XM{|Y)
zI#hL5IuIMPay`<S6Kk@9#T0ZmH>Z?z{)M1B9ioDXF1~%`O?6_<_tR+Wct+_LNqQ+1
z;!bp831O=adC5ZW-@WRj4Ju`#VnSJ(k=Cj@ZePjB)5y{~+S8d9w)U4|b!J@~vj5Sr
ztiFMKlK*wux*LCcJTs%@x_!($FlUfbr`$4j=XQCj#c@otayi+ycn9f7=?G8mOlSvK
zkJN_OSy|!9+<?*i-wbBh7xoIX_M(E;dNpicNSJ5A^om(uYA+&44l>FRYH3Z!XVt&H
zdD3k86=G9+#;^gl$d2OoBR0=<{xm|L<;7K`vLsE|kQL#GK#)@A*wa6?o|W7~12A?M
z3!j5%PfL|Y)d$<0>ai(?LaK<Uu|!p@p|lkJOaK=(p-_5(^^~aBGJjb|->49NuArmn
z1*Ul#MgqiMlenxuPu4wExgE#vOf4h(g`>29GN|C2a8t<JO(S}S6{EsNch8uPiOU1y
zNB%SIwbr4-anNqU#YFdMR@g|8eOu~kw-SnaKf0Ek#Uj43Y*SA*j_AkS(DdYso&LZs
z#ZZD@Wqnl%C5Sqd@LKkl5=xpTyMSMnUNbFVEda8R49;zIJ=gf-Cy&>q=#27{cT)Ek
z`jG(dPeeU@%+Vn)W>nn#AjgY*>uXj%Ihx-?i)R(q=w$>W;e9_mYa9gjvH6r|w6HUK
zoI+V4PTb=4)PiS}yITa-=@q4z-ETaS%(6~n9Ol!7I=9ZGKc3`eG0#UU8M1T$m$EZR
zr>D0BztC{d7Ki~xE8qCxdiMh((wav!#IW<tlTM+ST3hIPO2A2AO9~OMu<b}*qe5t!
z&J^>A3{O~{GA`$dm9XAg0Jdq51lE~ZVS2jAfE^t^b=`NI;{L}}6@YJ01<M6QXBaDE
zHhrH~ju{s3I#0E#STLIjFP2ZKRPH3#y5eQhdKe$8M=Ea}b~u|-3nh4yKr)UH8#5-_
zM+=4fK;R5JCW>b)Qckqb9mN?`>CvD4l==4OwpP<TLyt=BbyhQsMs$m&Fw?oJmE1k+
z#-`o<hmLf)q-{}#TC%>_E7idia(0o~P$pu%adUW@-8JMG5B728tEF9&%?0$m+b1{h
z)7<++8Tj$R!MS3Y)cv^i&mZ*BbH&Ai9>TwOlHQ@_RwK1#pB;l)*L3RBm<K&iak`RI
zb;!vzOf@u2U#IOihp1qGQB~D6)zBP7(+M#nhfOM5*UjqZ7Cl#SiPEge@Y<kO!9#@3
zq_a5ecB|PHD9h`{>vS!<*LV}sxHh(+3@?h@nT^di^J0|yw6W`C@Az<V#YFWo`FwmQ
zowMVk?%_ys+(qqj#;8HLZR~{`p3cgk*BZ{s0VIj`lq5-Cs5Jh&wy6{{WML8$y+;91
zN&T1wgJrxBmwIo|+W`#oI7oKNDtRufHuhT`$6F;-{IUD1ieHcRted;m3h$Pr#<@Qh
zCE>*XNUMtngz!t*yt@tA-RXu9iHgEIF3*(-q6xsFsKe9Wufmbnw*OG_aO1VLf<sqi
z7h+8TBC=#Ndi}CR8i3sLzh1EqhtQjO)evz0clw4gz3ekRhMxaBBShzuDdk*+=#Zn5
z6enp1bJ%?PEnQl7E6XE?YZGaE${(e|dfdNp8KL&^V|LFp-<u*3V=k3Mj7Kl)>X6qr
zG`8JdW96^(0eX2IOo9Z#X5`SCZs)@_&-xR`sM!rjed?Oo`8*2KUZ`eRNn{PVx_Kwh
z*z><9t#G|*tX{zYy|rnB^t`!SGO+O*%+wbYSyFP|aakJv-X3_E`Y5R7b8VaRw>5(3
z8!|xnoOP!cW7c<b8#Jr#%`Q!QEVwKgB#{5ll?@d*h)Mh3J7L=Y?{{!|IR5|Z{ALY2
zr}5-+$bEc>X4|2Klhg_-uT>#!S<a&uMoxg@`kx=m64;1ganCbXP>idX6#_Yp7qINf
zvoq&Yyxg%aNCO_Z+6&Y~FBmXKgSY(B2TZFqc~UpDd1f6rR{NY<sh&A#XmIhrC>51*
zVsv!?+78^iS7rZ1@$EVBz3Wd};h#v_p-a7R5FmcI6GO;G<oKWnRT*FjM6EuJ`4|0T
z0Yj(sfP`)rz691mzF5)(5hbcJx~SapacbNwbxOMIQ93|cvSd)u8_ia#UDi$GxnF-2
z3W*v^sxqyhvcK!)wen#UEt@KN{^*#fbqt|%G0!jxrK8;d<lQI!>G92V4B>v3N-jgk
z<C2n`JfaDc9PM@Om}1rLLjyMbH*dFH>AC_x!A~G|jT+aW|1XH+EjNIMTo&-e5VNEL
zTfza!?pj8rnQ4pwnEYf;Se;K<3CE$waHE!sP}S-=CV8ERlwr`)(4Y_@MzXE_<UYy%
zi6IWcE%L+E`^5bSgwbJ?=m;}3*M%7}K||!oAK4qHq5))zA?G8OIpy=4{17ntjwlq_
zng<UhZ(~`i3s-I-p6lo8NrC+dDrv+|*!egTWOr#&h|l@vA4XmBh%ldK*%SVngoVjw
z;BTb3HLeK(b9(oP-&-O6MA22owwi^_HmLjatYn=&>S5@LHQ`NkiAN|VZ?CDqIc{(T
zUBX*yv0x_|y-_lBXi3xqJB%2P!-hv6G13&j@<^jeDzrRhqa#n5h+;vud&Q-g$UBz-
zxuLxUTuQm6Knr&~&NrhEk6}%Pd+_IT&(YrJe%g=sTlNC^hjk1tnT}L_1@;MiTKP_j
z-tp)gzy=X3#{y>5rP#_9HlO&mL}`0SSv%nbtcX^?=RPzbI!+%efSOP(r?d0FX_=7H
zvx|6hW<zQ%jq)vEC$!90c~9M=@Nc%QwnfvLg*VXJ;sto94BsVl&gAOOk_sIeO&SE9
zs=1})<5B-U;4h+1A2&^$8s_3+Lsq%?XHy=!fm<$6P&40&7Pp)x{o_Y7L*QxDXS&)R
zQ$BP=wqf4#Ww@+wl)HSpPK1OEu^>}N9$J2D@8~NNrAhyIJ!23B2cst8JFRv+g^@1b
zXp4q7pT&yn=?-$AYdrLXB&=^)vKY`<@`35|y(S$|&gKgTno+}8wa}buGH$;9W!U44
z)MOos$ImSiLTM}eb^gsa?oGa(j_SU}SuIjV$a#&LMB3f8BCnWjzXUl@hMUY%W|{nx
zVqN~)ukI6gEWPd2ak|_Y%Y24pUi{H(3PeA4nX(dzl_7-_tOGiK!JstU*2nCZ1mPfz
z?m~fh9uGTscjnlP2A@tG-25)6IDVvG^v$QOmWgLjsK*b)@rCRmp)!5{m=e^)FHB0N
zmfzF%eynP&XGf$M{&vIi=?w#Ma8NX>uLto@iX)XeQz-2PiV;_Hc1AdmxTFlk=15}=
z(>`{~&Tg_qEuFjFShs667~J$roLU{N6#H4)WmK!~!shM%8`FD|bsMM0gkVj95P%;4
zw#$2)5V+wOlI0N6QA=+<86sg+m7;7&Gx=L4>~@vet3%<8W>^YfmUX`|XSoBKY6o5z
zQhqK^LGxX<9mkPEBn-n<S%SUqnsy@~k1CMohjuuJ#?PGC@AARlop>hyV2EbXIT^%?
zyo|Vb68!nK@J3)%|E%c3@EvKG=VhziXZ_WN$T_)=r@6dJpXTXj<iH#p{(POf#_`6v
zWq?RSEG=U&@xIHqSz)E`wrRZ+zuwijXG-{Cf9)Okf}1&L;hxERGXX?8O*h>70aZZM
zYUt)NlncGfhg`g`Hn+zs)TBf<tcbC@4W=Zwlw&8hT;G_ZRtE1Qq$$f7^5}eE9S#>i
zp3zEs$;UhW%eZh@#_)|*Ur(WqR1_wR*3=M5^ZylZ{3mX~Kr*@EKB|y3M@_$P*M0Vo
zA4+q=aPez$i*fbO!C!Yb#JusFlF0k5$zWEa<z?YP*SB#r<S8U;9e-^;1?N1Z$BsLu
ziNgTnMD2_#%GGUKuGfc|31BkuwUnftCHQWq*zWUqA&cih3n4pNF1C!YeI$>1M0pWj
zSy&uEaMoZ%CxDaV3pGHx<EmI22EOwBb|7rSlDW0^lx^-}MK3<Ff+~S8dGK=K!c}(X
zUx}J<UNoQ;ZS>2j`W*yP`Oy4%%QH&yC&|a*no@ai3TXu5FUNH)r?RDrH#R*o0N>2i
zui;hW$N+9CWJOejnPOj5rN$W%(XLxACt*P6>HGTESno4xt3u6M=MreS^Rm?K(JG@L
ze|YXOIb{%hx{%`pG03T=bKx7bx<l50aLUH5IwO=Ys*h*n*H!YkzQqJz(;d|hKto*L
z=%Yc>PhiEF&TF(kVAY3(TTyMC`k6-?3#7V0FI4Erb&CLbL4Ly*jWjQo*0x|FTbl~X
zyMR{aQAc7he^ANI1h3Pu?2XE4Zy87zKl-~`?uJyJGv$Ni(hmCfkt+W?5^XGTdWl*9
z@!Pw9+&Jy~^o?fzd}2b^Kw47kX&xVQjMhHxWE-(}L^gR3Sc4Ap{ib5x2wDV$o0qDt
zz_yX6jkVyqMxnMdsgUEuUxNPr7cKs(1$Gncb+l;y@VCb2{6Y?BM4pgX#pXk@4~=j>
z$C|1>2^YG~dmzB%kDZm}#HOt$C42FZ<8mOFwhRqUA2EpI986_eYMd+kcncBI@|&&}
z>jfvJCSUUNdI;Cnv~8SH;7QyMt!H^$xINFw#Rbbb${&EE$FZv;H-4UMQCHG$>c3@u
zoRv$;+GkpK$iW}u*dLQ!(S5fnyAg(K#^o;D^R+6eawF`bUu+F|yJr_ho*CtdMfsl}
zajPIz@aCQMxI-M@1TmhSTd`&qDL74}Gkef8=2>Lh>C@J@jHp}XrB*VkigqGb-%kJw
z1who*gx-vjFSltQ(m})6%EMv-=6>fnAvU)pV1IelqD7As@mpzuo-ADK9fI)LIH;Kb
zaKnGl!Lw5rk=|mTd{B3)$0o&ZiAHI=rIS^M2->S*Y7oF013GM%4nJEe;We;qdiht)
zt*s*#`(jHl&-p*=<d(po`p9#&TsDvKv(WY}=<OfKM%INEj2=Y2%~nkyO_=$ntgQ=|
zm~jUir)BFkh}NCgp3l{RVo{S!k10JEs$u^5Pttc8OdfPH5yoU`L^ch4-%sbAVl7tr
zvDkl6+XZhEp57DX|0R^P&=aMAY2rr(*xLyYsXOtJwu+V2fJ6zuS|>dU&W~mR`F4=n
z*|&@>xzm1iZd2q5fBAo1VW#V`FzY^nh1Y$4oyX^fWXbvjXK0!bHx6(hQ_*<Ca`#+;
zvhQzAY7)6s_p6o7nSaf7&)&S+49qjcsDr<{`+*8(b`bRO6E1q&bGUD8jg<o|2bgPY
zciD5+9gUYgXJ&cTwZlvbBr>x6on+u3@THzlBPu<Dj=)6qu8-Awx0Vult$mL#GBq(k
zlH1ml1}ba?-nU<|o)bvK1aQ*bUt{W7YiLjb&4yE2v8C5lfziWq*PV%zit?~4qbJX+
zEsnnaCL>iIg>roD;VQvgXN@Y7N|<cbf34JoCtfd)ncqr-TZu=Iw!*Vs#RkryU2rl1
z2yt+{Y51ybMf`o?`^`Mtrx)=XKEgso&+F3{hCA#5Ny&Twt!R(><(4AZkd2qP9~X_U
zvew=6@G;lFO#xdf7!|_bcfzCk{`|Do-kXmc{z5imKU(k*;<DVPymH{5sbPVEE#?!8
zHMgo%8%Lw<*M6~brzQ?>j&z*M0k^#}E+z2wWqi@!QL6kAP`Okw`9<+hwOLG8Pph1W
zWUejI8u>;>zd0$*SMXJ@(_ct;zu-0IyXM!wDW~vgD)i#Q-f)2J=(ewByB{lG_`EM4
zH^NkofVRUh`w&1$b==W)ZSqbLO+Hon*%LwRAH#nx+RWC{H+_C`y?yY98JOGJsV=;h
zz42S7)K;0sq1mUqLb9%Ctf>H4?o5Y~R^i{rg5DJ22e9dJVSx15Sd=k@r-_Px*c68f
zO2~&au7C>>?m!ck2alrjs4&f7L%qA8=pLOFl}E&bPJVia`dK7<^_^rG`{sp7|3Gh5
zgd;N4wugTvW%)AcQ7EQyY~wZh9(=`_7+(u;;2;NyOV^}HTnEwI8NCYh#y(wp0@^{#
zePKSs-iH2V-0-{pJO5=-%EI%hv+FpQeT*Dy!f08$4lGwYL=;MVsdjIB+dJ=isk#KN
zD7}5$)8LAV{0Oh3{x&-v>^)9X&gGj?)6mc$)KL^(5Jp7vlo&s23@V#mpeXfUZS%!r
zWk`5fBYagG<|nGhr*NuKjZclV3|`=)>tW}BE1cT3x%U5lCA<iEIXP_7+np))=i<12
zNlGJ(8AP%wQ)ATCO3YK(1DOA1ab6>PS7h9ByZ-l3O7=K8pLWZBll>vdzHTWrX|kpd
zq3wDi#rA2M4R1{5cg6IIB4WxoMOJP;b#fXf;NAN3!lV}<>UC_%{tCJnj}hNyWs#ce
zN(b@P0d;pv{a)Wkn77PjT8IAX%3GVCy^>nTl#(bpsBVVHWUOC3xRLrqUCXMQtREjQ
zF6{ICc{$2KFnmdEgHVwdzg<Tj6tx}qmF8HI@iJD90%3GpzCT7fV~N-CoOb6;HuVW^
zCUKa}p?r8`ce$6;5%G^-q{;@c+2(i8B=S_=OL~PDKa_^qe*!hf<Vjti!KQoQc#||(
z7*LO_xnA5F=IK{r&kMv%)_ENe#f$iEjZr6$ow+Hu-YUa;Ox2TR9GJxg*xlnw?`>>l
zIyv083_XGoF(~_-77W`x6>oqKK9I&oxe0Cg%ig`3(z)+c++}jVJ6OZ7nJfP!_%Zpo
zVFv`rm<~US{moW;(C?V8<<m6SR`qVZ^hPXXic#ZB$GzWqf_r!vcK=)jpWeZq-$Xk#
z4?{|~tml)g?z7%JAI?zJNi@0z+rFa?HW{|iz^KcG5Qzr=O@5DO*vcn~+1uDX`lUXx
zp#YXWH_kta1in<3{rxZP+$;!sa62d1Vzf@YrkIM0I)1;GpS;<)h$NQMSwKIuhQ?kj
z-p=-}Plm&7*0JilUOCEdMhv<h2T!d+s-wxX0r>tCU|NzSU7YFSN%`R@GpZ#;64CQb
z({$s`n6D0)>&EZHT6_OyGQbRu(`xCPIE9^Tn1*)-w?G{4;27lDf?^a;*3~`GhCh+i
zmWoX@x0z8&v_j$#f6E{K`>iK!;t~rEv@gjqw^TA&O{fRonvk+A?Tq3xyJGA$ZQEnU
zy|+0Lp+?CZu>K}x;v5kEUXMnsQF}?ki=>vRmW%kbnjeQq7DCF5spGVR@^gEw;j2+m
zs5jA7_dQy8*U+`Bj(da~OFRRCtzhdT+<Bq}`T&~o%nDW^H8JlvUA~`7v`Q^6K&pis
zAO}f~aT`~-QyNGnZn${B2&DR_Q6dTJYnXEn_NMH!3fPhuI^o{@0kjgnUES3Tt1*kF
zc&TRBq$b~)$&_0P2;0yrx*g`CBPWPv!+>sp-iiQ%6MC|}Tihl~Aly*f@1&pTlKR!K
zdu)?PqjKex2H9(N-pbj|To*fh0+wf7wZ3F@(5Ob;b8u{q`wOQi?h_wBn30d1aN6`S
z0%q2KXTkf&PNazytq#ldNG|NIpCpNq?pTyV7}x-hGTYM&pW&>K_fa)ffcXaL6lJ92
za#q>()2gEWNh}8q4d;@~-Z?)1>K@wtm~Vb`dew#9D5Fr@sKfsH!T{%Ca!lHCB|S%-
zFuY2S1NtY|CjncZg)h9;h$%-aow^y07zU%{(x0T_K5)+Ys+%2{Ve3AFBDXzPBY<^x
zaO0FT0Uat;TzjKo-UQ1vJaM{2lo576$Uf!8S*l{LE4;^~!h2~ZvA)<Q#}Wa)lvW;i
zrKiv6*_VusOiI?_L13u5*_Io=aHeK9cgtgwt2S?p@{5(<z@+NS3fky1aPB9yJ5u!-
z#pzedwdd5MLuolAQzlz$l_|QpVSh3NSU01K#5?ly-9&!yZ+tBcjq3x!+{E>M(@V`r
zCbIsUprB>oWSjwM#99q6tM-@gPi0uNj5z>Ni(<H+yrJzA29G({1H5Lc&#@oc*B5lB
z2n0=Lp4ldn4rW&MeJFPXFa8Xw^&;lvz<{=3uD|0`v5gHgN)3`xjs?s!vw+hCFy<z-
zjn3-qyls1DWloY>;>o8A*f?TbK;ol<uOnR7zm-hI6p>JB9E)V#M74C<LSEjS5QBQ5
zg<r7?uiM(-oJvc~pfa*@B^rUt)gKaG!X+k@d8P!>4mXi+neE9wBYsMNL^wENyW$dK
zO=qDMe_Z5OHPlU0&gJ10m-mwuU90^3!f98X{aO4~gq+kA06PW_Xpo>vO+Vv?)ZoZU
zn#F*0KlbC5|1v(WYu4qaSkdAq3lMc5|0PFuP61C#19QEE1rTt*P|0-KwOfIG;J!&1
z&AD(wG8c65HX<vE_3&(JHVVXnf@^9xZ(gqP4lZqoRq$qjymubRc`@_fPbJZ)fsskG
z{Z=Fq<&aHKZP&5OV@)vhq|yoE#3~`>z0h4gZ}*1g)X$F`M8ZR7+c8>*^Th4A76aO3
zalz9QZ@exXq5MZF3Kq1;wOYyP;7I;r%@4OH2@Jp3CMdf$Sn7`TL!0PU%yxT1!(_)?
zT=NVT8L8CM<C&?$?BYqV3ZRHu9r7-TA}}c%HZUcPqUFXQWX2icCw=n1_6VPnFBL-j
zFhHvNmuz9=DbI=LC%eVYdlfh4r<@!cr(@3&J##d?hSL{MkG6LBNTaCA)#EYho<&pF
zSoAzQw2pit%5ykyY4c)<kn<d3r=fwoI(3cwar)SfQCHhh-J;Ke@p7V0_0(yS1PM)j
z7ednfi8)RNk0(7R&I`N{)I!=^+bbu&b>zADI=@b~+<u;g_mf0>KX$(-lghB1jJ&kZ
z1(F7N@_5o3{QUlTq=VYeF?3PgT(WT*DTT@Nd?zg6`jfO$sIVTO^C84Bdu*MDLLCl+
z5_)e#u_`s|MWBsc#o%KTx9``>eAF@%3E3ZUdVU$kI#RJ!PVFrz1l^6Zes`5#xh;n?
zO&~iWi<<+?7AfGJ?vWBFl{}yrV{x<vB+up<(G>H~@z}1a9r8PwW*T~mHdagFao1=5
z?;cp%?4e8IaZfCIf*nowkJZ-jsBhOqIXD7^=IoZ6j$fx&7iMh8y?N^?CB!2W8O7@0
zC5oW^?#DebKn^081G<$eS#H^0#`7BfrxsB&vpXA^Gq{WK1)_CNP4YmCQeB_MJUeNZ
zuHQrFa2KT%T1tfV_`1tCugb3fI;{)d^bb^7W33ODFfYrFk6(H{49EZ?v}g5taB4`o
z`4UL`{q(Tep$Gf$yAdP1MxeS-?Qy@UX-xJ<?4B*7<d=sz(@x5bdoE>U0G~xTVn@&n
z<;t4YOOI~8$bZfMJn}6WI=5OOcXT-x9+2tFmtKJO)2`w(&*7nOsLFDUVI|r|YVEa$
zuWr{_dG)itSXO!orjMYa$jQr`zGUKg{oKWO?c4os0rA+a-+T0O3%kp09Y4?CUuL4`
z?YOD;7=D%Vkr<nFUQ>ECvD8$s+V)qF15+%oWfR1Q&S9VAI@=_Fhc>iDvbC&27;+CH
zi6=;a#2lBcPKp>@dSFt1GlXZ}>_(zZ>MT(+N*RR^WPAvQXjKDk9w^5gk@Dm0M7SZh
z9)5(#T^4e;vcxgssq$j4P8(j2c3+Z^=jdg=vdqR&j{CL@9gm@r-`P;t67=TBxRNNY
z_NTyy+JfVkfB+)sYjM}Q9v6tCL6k6>z)9jwgwGE$?rfzst9>{L&lI|9WTYSSe1E)J
zM8dg=;NZZNso-V}a_#dbp3dK{z-BEI(0gM#Xr9ZaJby-R@8kd2SUEY)o+FT|eZ~J~
z%ZG*<F6f0nuG{y+b7@6>9CuNMiHAu)UR?e7A`{+Gf=l@gG>lNttIo@avd+8jFhFQ%
zV8<n8D7;x{Ss*w`>g4l7L|Zzjtv|`H-^gzXy<MiW6=eNph^6KDhBDqymbq=D!8SZ#
z8!sZ5whw#jWlo%swvxW+-d3>0!|X`S2Toee5#7&49{HY!w&6=-g&~1z)O6$vEsy<c
z3b)?%9Q$YIIOAk1z2BinMH5^u%qd@|odpFrXe^T^C)2s{oKns;Ls01Eo&aZ3-mVLq
z>Ken~x~=Gloy)L9?LAwB>ZI?0Gka&4S&q(rG*0;HyErOKxDIryGPalV=y71KpJ3T4
zk?=fsK)!oC#hnRRh*M*hZ$Qg5cFpM|wdbs;KoXLV7A<yyB18d98OP@&LMwGViE{#d
zoFL;U4CwCnrHMVaU0X_?r{O>zDz|7eDRE}mP)`WKLs9$@=UjjTQ3P=wWUc(`DK`J*
zRWMn4@&FA$5Kt3(kiS6WfSFOEP~j;AFJCmHNgq*Sr6MONBzWSnuA{d8-eJ^;x-)}<
zDjr`sWS(L|swcCND@a&D{a`b@hJu~{7w+uw>ERvC@G7%*zlMPI!r>>ux!J^&zqD%^
ztgNm-%tik7XpFrB5#Mz8pxqY$dT)2!HzW-iAZ}_4zeXHj2NJv`RX(2*&;VHDv@9rf
zHdPBLj?RtrzcNkAJ|~DiZga4(SO|`qtm|Cu%W{a_ki99#r?1B9Ttx;_X&T*D(Et1F
z{9l~Tu`4fZh|Zywio>sp#3qcXNH;)e_oazZcPJ;ZQ}<^Rn5SZ0d6Vj5cWtYbt}_KD
zBlmOdyKX()a9iErITMkO<4nfPEmhW&rB9{U#*-(pYG`}9H@sHY`zSL$#l-9K)yKUH
zRvC8RU;#mX;V1A1m8~zK&rC|u()UIt8p129gKhH6nZst^DuO>;E^R}QcY+clo>Yzm
zB(W*K7e+`Di3WZ>$TsF(bjN!AgqQDD+T7ahI@J3<DdG}s>WA-@z(0?w3#}``$rdE3
z>zWs2?7l$?GTXmMA?X{B2&W0O%HJ`^`{DI4N_iJkl5Nv$3Ww;rEvJ=iXcrTMPa|8G
zJTaDbd$ZQ2nSa?c1x>GH<0_wIoVTv%{WpgoNL7lzP~R|Srg>*=#lM?DIuv1Y*vB&|
zzgKhY$EFv`VXQmxwsD1`nR%|;>S*iBi{CzwtOSClpy8Sj#|5*fm=MZzoe?nAfBn{3
zYlXTw!aOIB@3C>9cnNrHNOpAPrLuBX#^ST|`<DzZkE*^F>tj0b`1pP<am=yX#rh1^
zT1(6${rHsGA>k$3q*uh4n<Sw6%||tfl{?I&ofBXm!gIO7`f9xKcDk1MHbZNSEi|s{
z9k*mn+IFGWgCgHSh_1<QN2+tjS>Qx!J>;C7kv1MbCQJ2{TX1$fOUik-m8M@Ou$(~u
z6kI(_gwPAwE|-bNbOrhx9*0do=Lu^#$O!4|`8h!7wxmF%T?*oq_$HWcmGEEf?9bVG
zmI(O~e=)r$8Cr87Y-1aKTx2k;Uo7T!_b~569$LNF>9zM54*!!6*4tyc^sM|{Fg#66
z+pF;yEs8!%`9FRuv7}uUv<NrO^@aP{1vEw~WZ#j7eG}DVQ#-UUIvx&UHRXE4o09Ae
zEQz-@xDGq30I^rma);vcs1}pZA{U_-tCe>dP22@WL_EFv+9gq<U9zbQ-z>h+{J)~U
zJ1Xh_`ybO(oZ-q%jvTotb1PY*Wg%MDyDS%)V!1W9IB~DEG|H8uG%I(G+~U?8X^wD{
zntLOP;1Bzp^ZP#kg>!h_=Y8J$cs!nu`#Mm659B*GiGkhY2j;CHWmpy0p*9HJ)@K?Y
zVw%<5YpQvM7t7FA@M&W7n8US0l5I*`XH7aAeGgaOo?@cl%n%ddQAPq|4R2B%Zq_w8
z>san$<xiWx)v={#qN12Xm1=VrGW9He-4vhGqsO)lvsw3Y@c6F(NCuBvt6gAF^k8c0
zszR1z9y;Qzgd>PsUuJ5SeNcG$KY0+ymVToIZi9dacld<3e}4IoQ$EJAg3E1HT(@^>
z?*oPY%3CeO42IXR{j!Eh3bKT(H(V$C%KNhgE)beGCA5H@&@376TsC@}cP(q}gqv5a
z)uhuXm*4v{#@~V&bAfU^wRq84BF9GsVz)_;Ben>tSaq-K!1|ol0croHtsM43cP_Yw
zh7iTlpAfEePnMx7`)qc%40&SqD)teYGTfG=*T8qNYN@5I7s!`YDS>V}eD;&!fDBYx
z%oT)7K5A0`V>nr3^)WG&hWO*^cjQL&P;4Qc#UjV6l@q4Ramsn}OcwEK$S~xIPonVt
zFQ2=_xLOjxphp1!Wf67UsT3fTmwTq|`aZruCP`<bHG2FkjYlF|T4?H9OKu#Rv@_^9
zg~y|R2M6pY_{{ha?{aqN)4A=?YH~6oddp{{)y^|xt6GPn`ECu5S}ylSC;BfY-9%~n
zwySt90Bg5w^XNJAqcVHS{Qw2wS;Hb8^;8}L>hpz~&D9-JcvqZVFhP2N#AP5kFC7~_
zc$g6r6dsu%Ou#goUH2X0ltSpuvJ*8`kJtB)9kVs(mSiCdYiIVVFG4bR-thJWF%m0E
zvw{6#F`dfvR%q>!)uF|}AS$brW&Lzc4O7;sLQzwYaLioYkKK}lGbApJd+3P-Y@Uxi
z2s?EyHIQ51{<0gB$=@4OlT!(SNjD{#+8wxZv(@LvcLj;vef<{T?V!2%mr!9Tn-t!*
z(Cg52<w5Q&h-mX&h~oNO%piRsJAto#=G4zmu9@OGN40NXIXJvyuQj*ntPYUUfaRxT
z$f0U4KCgQ?O&#ZU)a~`M7rka2S?2Tzzx5GO^1bN4c0om@FMjrvf^k%8$Uu=`iGXMK
zbNqk&$%R?+;y0vUh#ujS4RdY`z73XNVdPHIU`^v-;|+oytY`(`29%L0f4KHgz<2Jv
z0@U9J(*h!+VA@$(C9w)xJy=tk0L^=OZeN9qtDg_}F_=9T6hsrO6qv@41>KykW?}@8
z0AyefnLz#1ge){c5kvSQGRZ>eFPd37TgP{g2W<vjoDVriX-h?03PUgTK(ByBkn<k_
zHQv~udXQ*H=Le7?2AHENIM;n4$5kSO&h~-BKSXoB%kN6k3Yea6m~+*NXzG^A1(1q_
zHos4+<j4y8`3`vLjC3QOyQdlS#Gd808U5|}?8(`deX}V}*Du_WkE)g#Y4NL_1La5*
zg;TxJVb+;HW|0!$kQgR9)PXg5=51PS2QYXb!m!+*zxl>-y4)oIVxZ4*3De|d&6Q6)
zz9_ed(TExE8W4m4*}{xFB(_Ezho}qBDi)1U-qq~E4ZieJnCHU7?@T)DUo8AST+q}r
zhrtkSw*UN$qHjXy^@p+#-EKxxb5@WAR#Z~)9(*YPdSy>+1_y(MF@BQA4{}NA%K{J_
zw9MmY^~B0;+Ao~EMUVm<^)XGfqd%^=S&iJSvU3l7!#lSULiq(N@jig=|L5&89qDk;
z30S$fq~=5sC)f0<kPjsDC78^H%AG5nBS10FBtXd(B~A~r%?brtG}HeR5&h00C3@hs
zI&*29+UvcEAk61*!1W6~_Z1!vQ{jmpZmdo0q69x&Rth)d2>^A#KOeMa-16N9z{Mxh
zj~(Ktw;+SFzXUw_;9mB`EKcsWsX2o-c9HEN2h_>O$>`{=>wnG3^Nx(pGpUW5vG)e!
zOfJGs+^EeDr$t5VQscFQMlms&_JE2;YA;0gHl5ocHwaWKqE7=HbNqn%e4m^X312ne
zY6Sv%Bn{<b;ngr_REgOPnDWENJurL0RvF=D^n968609b4l}H8>Y7rBBF4xR7YK7KP
zg8C2UCDdhRm5V~3ZHdeARV4%*$Z`!Eh>Ig+-Xy@QZ&;oF<1-gL15ps)(SIS+SCx9!
z^t$2=zAJLKR1u+u`H#=5)(&f!b+d`HYPny9YcRA#<*6LCcy>~z>b6KUNnaSF&_d-<
z7@Z#vI<gy^VmEDs!7!WaE2M$cubOOjhN0^qA}YdxH`l80#>}2NdU#aksLOnkMdI?b
ze9MMTz-aBA7X>c`yW(HQyo;taJs_ARS>W?bQ1*!suf-Y{XZ8K3Bsp=Gkgsx&rw<uY
z8I<RlL($lXcXVT4q-TM?P9MTg`~2L)YlvgJ?pT%GbtiMJ;j!Xi7jVG)x+NWH(*Ap8
z4j?J8$c862S;Y2mi4AYSe@F6T0u07%@5<pF))cf`^#LgO?7rvC#~nr1*Ci{gOF};}
zGsIQn35B<WJG~$=Pwza(gB+2T__!ow4{N8p<l{WfL{^XaBgOhIw#CkvVQI}()%5&x
zpyU<b!Qv^Q_K=V6$RkW#qtG?G8&}bia|=<BIm76K%iwk7Jrn1%%?mUkmTxQGYE@VN
zikn(>ofk`M4lE%pWVeO#2dj&n+f!)~Hhs<RbmXt0AOF%B^C#sceqP(X&QE{M<D~#A
zUiJUSAoFlY=@Ckq)(E;GE$SkFKJ#PptizB-zb9HOqxN~TLOwAIm}v|=cme1W?4yyf
z?zG#DrQ1I!>wT-t2=9$h!yD%U6(^;?W}3u*F|jLu8==|-l!%Xxh6UQra>X}a;t>OX
z-cnuB-<q=E)-el5TVl|U=@2a6;JUkbs#ceozqm4&JZ~9DN*l=CUxGtIK4A!r59r)#
z&w)V84B+~%_+PKzdKPHRZT?^h*5?5fm;eH0D%@rgcC(x~V$1l9EXdaYsCmK3n1CUH
z>UqJ8$V<fo3orU2!G2xwsm|%nw1+uk4T>@Iw<rFkbtxJY2c02wG>L>Zc7@F(CyJ^w
zbgaLTRc>M-YGO(^o9~|sFc;vB8JI<5VHFaiPG%_(X<k1WT~@55W9*qf5pOA4F;(VF
z+*#4l>ULgHdHmE1vD>N~EZk?ZgN^V3mU#>h{4p2P!N7{9#Z@(D3$FHdSJ8e9P_OmP
zUn<Xod-4FP0bMDLFt>UkU?i>O>X`z~IakMsCh<=aT@?LSHdiLO8bmhrJK67-z)hIV
zF%R7&;jcOLjsLVJnLq95sp_s`H#jwv+Ab>1XlXry91=UNh*1-9og8h1ak^`<$xAYk
z;B@zEMYy&7?l&`>G<fc7%VahMvD8QGUeW~EcWm6p!U(%Mr2IR@%h~A<OU3#w^ITy1
zflSE<U76K4fCNI*5e=0Q7N!JdEUltsjwu2`q?b|hPu0s`vVxDXVS>mTcn;-7d6Gg3
zG@*#y6eoYzZA2?Oo+1?+bcNNzx;4dZ)An-Y$3g$*hj{=2&=usVLO9RU5*Po-2&?HB
z%T1lm-+Bn6bBkqcE`a{rJv`tx$-FECB_)TxaT9~{qjJGjElJ{kE+~s85e4@`orV6F
zMAnO8)eJP~9u4ji8L#t2qrR{*2kj=uu-%l}p%0totr1~rW)oH23AHXE$X&8zHw9t+
z%JXvRXLD^%{INUMy(xSAq@GTY@J%rmH#N9M9lf6n%s__5?L1%GpBU)FUMO2L$0kR`
zLp<)rgOF!t^IYp!=a7iyMYkOjRw=BICUjDvCuoNrJ1E&YfKMuMSBIZ{9&gcg_n%V=
zImlI?-tsyABk(F?>%f4PQ(2lqj8phg@3vf2OQYl-MsDS!v!;9Pw!Xq>2utsr&y@5)
z^c&|mXYT(6c!0@~Do>s>_|#b$_pY)wdd9UQH-zJBGw<<tyIep}C%C3~Vf{djxr$xw
z^}4Exb;_5t&lKJ;BHmWLFk^K3Yhr;E;spI1OXz}$9h1(fAi36<>w(u;^r#}p{;&@f
z>O_}9I_|XS=%anl*@P?idksJ<k;}%vou;ci%`oITt-i(;(@!>fJak)Jv>0R41%tlm
zky)_pfh?8=AeLm%+0#qS>r+uSJQpPXyJmFcEWY$ywDKNFE;Zzg_1R{W`Or>(4mIVc
zbH67cHAb5>%bC}ubN!NN6?>IJl@Wy2qx2=Gxg&eSyzX86V5jB1IiW1~-gH-7t|ukI
zlBA$nw){G1l6Ss#2`6c$_mC`in@=%Bw%{BogP`PaJV~@zmXlCVJ3}gCw=fZrLi`#8
zrq3lky}DDp*Y~Sn#2JdUZ30MXgFx<K-|G2qYBmXeRMOa>49x_d@1_<OZv)|wDz?4)
z_TJzmkM|>?5HUjojE9NvIfiRdi-id*5TKiSBCfp#gx+Qi+z7S)XZz24qr_Whz|x45
zU%=p!ha|a_avnh4R@UU@*#%H`>M-TE`JcSzWLj~GNhCW7IX$ta3AVUflPqZcOxz1-
z`(=hEmkAlz<tt%1JYJ62r#(tr&^E_{f-`4!@YX%7*$3?2JOZn9uJO5&g<!`m^~BJa
zpLc!v<t!WxP?#qNV*=Zw98y=r#ao-dMwAi9oa$JlUfWks59_3$hdPU+fD5~>oxz}m
zh=caiaOCOtQ@(Ve72lsKB}qjT1BP3GHLW<q)3o4bBsjnlx3p$Vo=M)Tm@&qFS37nF
zN{D}w>uR9&ou5-Zj#|^NBnBOSx+3;*x4T5^oaqxoK&MCBy|=5!PXi|NHdH=e+TbtR
z&VGp)X((m+!ncT_IgpS3G!7pXZC~fQfT%L!_9AnlEd5y-Z{N!x^dJjr4#MAwROeP0
z5^DNhrKHRFQ%{!o#>sj3a9d4%G%8PyLaUwozsEt2*Pfy#S~0DTSKk|(3AIo?+%CZ(
zO7&FBCK;yNULnb|Hpgqq$xKSICK<Z=TP<<gPbG9XXg~;~CV^yhzq1E8N3SkonwMJw
z)q;AI`aMg+L7!gp0J2NL49(wcCi@$e&i@WoT2*y1GoNUkIn~l-oi2EQ#Hpdm6?Sf~
z&ex^QZfWtWkhasGzhl#fdw1-IUE-AiB4=O0X>5pl-s$A`b(}$>faZLjlEX=)FHxVL
zq5=2wFi6(<l}kb6u)um~tPt+7Y?8<OYeceWV&)<K`*0pj9r013)j%LIhDkwMkZ+!a
z0NaDq2Cx;@{uuO4A*{9Nx=NwN)y~d$EhWvj+=8ixV~S+U^(3rHqsVD|XJ$*9s7Ev3
z8kDg|-oi;m{R8-QFYi()aWz|NgFX03bM*bkEFn#LUvCQo#yWh4T$WfuUA3E#tLJ?_
z+7*}MA21RhtzX95M*T}Bkf5-q5c9#)rq1YTmX%iCEA7!3uXoUs7OZQN+$ExGj9s?h
z;q(NgyA3|hTUHfJBIh-+I5k<=`ur&@X-vqY1UJ7{OWb$Zt6BSwx0+5)E4vbDHtBcj
ztiHjb4#&B(BGtV7BWzb=9z%v`x~uVy?aEljZDB|2)<aU9dp2zRAx9W+F~!kE=Z#rA
z2n-Id3Zf;Kf3nIxm_20pO8I}d(@}DO8#J||x=Fis<C_R_a&U-RhaU$AQ6_2&hJ+3B
z@0kM3G4nhr8<F#n*m<^)&$+$rMtF|018q4yl4DY;Z6nhI<iA49Mer3tOeGb1cH;0*
z@=+()_!B;`)H8XDL9ye*UzP#0{U;60%s;oiKN?&mE6OV1*<Q)l+p8G#L@F4rDH<Qs
zFf`Z|w-G`dyFS&he(iK9(JGO=u;hRr*sX4nr0?`&%PR6hzFI2i%h39kYwU|PB0f2F
z9RBnj>xfGEi;G|J>&U>$Jt<urgkjwZ{fD$tD0iRD-^5z4g-8Zig4%UIorQ2sDw*0N
zCavgaV}^rIc>iTR#PRq<fo^9vU%<$EQVO2=YkaCYh`LV7&L9i^u!ddIIomuTQ`AQ1
zb~n0PQY!Ww>6~_8$AW^@qdMfScpdsuxn1_a={+FvkvsE0crpCb-P$B>L8x{**vO<c
zfTPc*DXrlfHLWU|pEQeGmA4=jsIHP>d*j4hVI*H-h+&FyvH()Oj)2dWKC!{AhY+n6
zp9ia$*H%-`t2Q2f*nWkA=RUQ+x_*sON+5%)m$PNqaj?{w*7?#?(B(L`(u9A=s>7%q
zFL64euIe*6(*Ul}{b}>)M2(UqO>P8mbD%rECa=8;vODd~oZl$AJoN2Vv?8dU8FRi6
zj?WkfK0)H!W~!L}ZHe`--wCW|j`{`;&CW{c@`|2_m%55jei&cV9Ge?!j=uGwt{|Og
z%!Sh#(A$3bb+k+Ot?VanG_H9?mN=dfkQ3D!Ed$_7#)xApC3KZrC*ANW&ZG6q4=d|E
z3q9QjSrhKkOGSqdvNg;-^YC1H7@Xbo)Sf{tU)h97O28qw!cCeVGp6MnZBe36ev?T&
zfJxks0?zARox)QY)m{X)_q#1LObRUS|8$pym#gRO8wH?T@GoZ~DGTUaoZ}kFeSR;7
zPPrTZUXw<U+dibOSLaeJv!DUfFRB{oq%xxX+3Mw6RU&+7J@6h|dY*YC?TZZSV<pvU
z+{9|Y`2VQisU4^MqAiM!@{u!}a7K9k_*fX4|Kz?GUWjVRE+L+pr2JBKJv*cYCxpyh
zn9Obv%A)E`3oaBvABgc+*8LET(~+7C5C30rv^r0gH+Yry|BC#!%cqo$wjh(EG&1jj
zE2GOL+mSVNl-XyeZ91*kTubeKLF2R4M1M$ksS6?PiC$&!*qUD)>guV9h9CzJ9t$&Y
z=jgfV9JLM?;q*$B9(~{Ok!GGL_^Rb?!T!ogc*f6HFzfr+G;zm=Pyl~Fxt|8hu5>T|
z_G<%gHgkFk0jCrE^S+}6;2Qs_k7tvE)Lh^1@!UBxKGgXQ*^12HaaWyWueLg>W5b$w
zc<esB>7UWBTl5@4mg-;HbPuMc3fSTK##Pq?Vwg|gb2yIg)lxDmv)^n;bK<EJ6ME)t
zD7W;u9vB~eA2D^rc^LiDvxzg5wLU_~`3cfy4jx!bC#qG8qOl}pxl6|j-%w}aknf;h
z);$rY^J=vvPfp@8y`B%Bnb^7h8YDRP;ud8{@Md${Uzy2Rx~&&}xdU2XJWIzZ-&Nft
zC86w60;0=@fjaiN)NCUD<?qN}2r_w&QJ8}}@0~+9b?b$1X=gNg3i~auSra-!aKgsU
zV(<!sOrlR>|4g)$1eenYqXu!@M#rqeQ3xM*SF82MhO)J8i&r5Xjer5Y=tCzwO;Oa#
zDkJYD;#hcx*ZsGgJeA=X4vR+rDX=%$<k2f{9k|SEu&~gxU>kBu^M~`2g+l8~uBb3P
zopb8GeUc7QR(T1bQ-&B`a!$7<8q&^{V(G7MYu^HNna!icdBpMmsRf|_6qfbx``Yq@
zK8<|G?Q(8kg=Z+jlzc`1Zuq%|ds=A<tc5rhIW#O)E|{4!n@;~5#(%5C5gg36a9(ZV
z?OS5UbKR(`fOU6yc-Y8|o4#L)DUpF)?0@_)aZj9=Q>K;JPDcC^4O1!@IfXQ&nwslc
z8kzchv%C&$2O7BtsZZQ_;9<g1_{)H-sBFItihl2ZKV)eTWzRUGSwNA--7m!r3hT_3
zB|-~YJTt*);(8MF#3h5B6|2)Y(&&mIJ~@bFCHfdFx?5IwcK6k?7ATkdX0VgjjU4JY
zZz^3?8rxT(3F%9kINZBZ*NL6}J!QxBgKrIoD6(+fRl4xt>8gR2hP#Q-Vh_JwElcyN
z=d{fosijbTDw6P?v~$RzMcI*_KD|j%m9OeV4FD&}<x9+-=M~ev?!Hp>o(Q407S9_v
z`G`nj17Gv&$dCV$p+c-M-X9#}fWv#c9@{0=dKKI};OMA((h_`&My($V(q*9-8;{CF
zMqD=CP0H+|beNvXMs$x=HlSR+Dhwdv_m(pg3g#vTyl@kzeD!yW?bM8O^Q{1*C!*o@
z>(KSabw`HE4<Z~<hK#3Z?*Z}05q7{Mk+RYSv!cG{{!)G-<9b6(qHhuxgkjm3{;eAA
zIC|tgm`X;H)|R~X<&^}E8pyK+qtktPYzxp9tBl#MJ5=;-^<|NYkKBS4(!*(=xX@Ti
zY9C;dXQ(!ZhSnp^B3leYocq?)IT#FqYuI|k?(&z^6J^^df|9N)T{G!JmQIas;5K?U
zhBxr;N{A>!)qhV1^nZU|Q?gc1Q^;q|>_z7x#L)Zl_gtpm(teB^%Qf5svxYuo(>^+N
z0rnxr6a9yKZ6P6mCZP?Sf&<3%(u>hV+D~`<@a3W(<TTD@M})-;f&NAp3=Ojz6H=H_
zU#{vtWNWVYyZlq6dhQ&yuxq<UG${wHEnBQ6+OmK7>!BQN$Cq*?{NF2OwI%#}g$R%l
znHU;wKTtHY5>ar}xF>dpm*OC&?=sQo`1b32J2}&d*xPB8DX9I)4`?TJ%*D3ai`{-b
zde}Ne@82N!|E*g_<`E~k*JvA>bTWTw1oKHf_n&+5e~Y8l%pr_e12)c;KGN`?H=Il&
iI)qiYorC*<4o~>h3!4Pa^lbuY%TONyE52bJ_WuB9;<B*-
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..38b27bf0cd4499bedab1ee01c8b1c38268955a0e
GIT binary patch
literal 3661
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
--- a/browser/themes/linux/searchbar.css
+++ b/browser/themes/linux/searchbar.css
@@ -130,18 +130,23 @@ searchbar[oneoffui] .search-go-button:-m
   padding: 3px 5px;
   color: #666;
 }
 
 .search-panel-tree[collapsed=true] + .search-panel-header {
   border-top: none;
 }
 
+.search-panel-header > label {
+  margin-top: 2px !important;
+  margin-bottom: 1px !important;
+}
+
 .search-panel-current-input > label {
-  margin: 0 0 !important;
+  margin: 2px 0 1px !important;
 }
 
 .search-panel-input-value {
   color: black;
 }
 
 .search-panel-one-offs {
   margin: 0 -1px !important;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fadb57586afa5d5b28ac08099cb9dc4d02ad8ea2
GIT binary patch
literal 1376
zc$@)X1)utfP)<h;3K|Lk000e1NJLTq001BW001Be1^@s6b9#F8000FiNkl<Zc-rk&
zS!i5U7;Z{!ixd<^K?N6l7DEMtpbym-L6N?>A;pK(v`J>4yUpG2Y{_hCmZpf0`XVBg
zs0bwweR4r4LaR{JDo7(0tJFX&S&rX#W^TM>?xbeyV=sK%Ip_S#_iyLUu3OL6C#kx7
zfI;9W&;mY8>;9M7Lh*;3S^7P1magUitS_fE?|Yno0W1J_-xLA~)!hv|pP*6A+fbZ}
zFoK$}N=;#xTbnRT4WW4xB5ec$vZs648u(vi@>c1HS*i<v@`NbXXGEzn8v=XN!U74%
zfPiy2s)zMmz(>GY;E}$Zr*-c|BbfYy&dbd?QJtCxP7(YqN!XPp2`t0OzKHV!z`3kh
zl;mLND%OW~RtCj+U9~Ig4pLpL&5BAB&ReI%1f92tdF;;!vsf1yBRI1~_ie>4%QG8g
zGyF+`ep$i(v;WEYxMDw(HG}JgVvVUsq;tr?$qwcS8ND|#C3N&aQgecc?&FAf4VjbY
zL2X*Tu?A89Pn<uxz4N@iKc%@B4G#vYa9)SQ#!0?q#Qwyz+;=Ne!YVcdBZbbZ5&cCF
z5Cy*mS?bR+gHm31K^8p$ncdqEu!i$?30>X*do~>$*BR{zHXPHrj;P<)z3Q6clraIm
zfX+}v{}6B<XRy&^2B^=s)X!N(%D>i=KuUElgwc~d!AQ)YE)=W0jJbb-a!JL>0Af66
z5%))JV7(u9PU~(Jk++yRW&t))3XfTEzk^Koc#h@FgV{pB=HZBuIo^!C&Td{C%UjQF
zk$(>mz`ht;dy$>5*nsQ-jxcS~HhfTLD2{;7nmSA!SpyCt&=3haxEdpWJ8&*s$DBWb
ztYH#RPB^Dc+QxK|KsB!WKczFL+G=+%qBk)Kn26=koOwr_6YSr2gS+JO=tR&qeZbdZ
zmoRGj6UWL$t;m*du2Ihq`o7llb`cJlNoFCm$!YktOBkEiBmuDW!Irn2ithkwulMPn
z85(X+M1wY^ZQbYH;jYJJ;2LL@oy&%?H|u33`Xw-yHAfU%_5p3ub|(YwO57drqv}=|
zIqOf>VFqUU^iP}fv_V_6N!#$j9$4y5SGMq(VwL3Bc}SH5CC+k6b1oiB>pefKIJ>vU
z{$AXwOS;D%Xws&%O&{>J7^mQIMhoa#){5Y7?j6e*FKt601w6HN|9G~5X)DIsgM78y
zP)a+PQXNEHk<q(gZG*Aqlu<MLXPn;yu{ga+;2Yq!$lhaV&HanE?Cy*ToIf3Bi>%Lw
zteG~}j=%F(k-hNsNJ{HUH}*aT1T)y_{3n_E_9wYUI|P5r{|7j~1o`+65)NKLv@&W7
z3S`X)4Ae1WcyzJ^nKytvo1`=PWn_-$YuSSTPR<NgRX8tT+@hIe^vH^Uu1mdM1P0*b
z44u&_6$!JGh4Gw81HS+VI`V@gtl*3e__3j5k`JBp%{>rf^D%%sw;i3glInw_S>sC9
z@YxSkmT#`Hzk&0^|3+`jai7lVG$c%?VfLs`@)$`0-Iqh%8<7|S+vT+GlDTxAXd4J3
zG7lvc`)}1QF+*X*A-I<NC<m|Jw(d@zqX~6rB&l5)%@k03V*_g|ayD>0ZG4i^!{`}x
zGYam>Gsvt$KOO4skc9F8umBv{vTq>$Fzzuz_6ws8A=9qm2F%HCf8otu_WLC@42Y4W
zDiVst?q``;=MY?zT)XZGWd-s#m&EXReh^TB1$6Z#WaBz|W)%>l8Dkmi-$qjEw>Uow
iybE~1!@F)hG0#8pJffBMs&yp*0000<MNUMnLSTZ1u9vs~
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..e1de4763d47b1b536c1ad9c7e78adb74119d22ed
GIT binary patch
literal 9668
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
VF2}dkg!;##wuXWFON2e<{{dD^?9>1N
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..04b2cae005b3707f9c7267bb100bf39e5221d373
GIT binary patch
literal 55953
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..91d9f8d8b3b7b7d3282f0fceec952822b0fce91f
GIT binary patch
literal 324
zc%17D@N?(olHy`uVBq!ia0vp^0zj<8!2%?YIeoBUU|{6-ba4!+V4Qo!-s`A?h}*}{
z8#V?8D7w_H2+mgjcB^}@w}ANru{#YrSgJSn3nnEVQTowU;&>r^DaXIo85@Itd@wRt
zSwG?7nYq@xJ_ld(w><d6P2Mi~S@qeEDGcwWwI;c5^I>4seb-Seyl0Z}Z&SY)JPf9$
zrzNY^Bu-Qwe_Nc&kfAx_{Uug5W(U{9Kbo9{zodMrOP<Znd|=9?qv>J345~tL2i1k*
z7&9tZA?Q!r{<QD)3J*mWfRVz(a*+iOogb+F6K{0hcE{-YQtvNrE2Qrgu*V!*YNqGC
z?)MDi4eV)$((as)bY5K;IdS9l9e3Pq_8xdVb%(}<9fsN(8;<;YbWHcs1+9OKAvd0t
UN%1S61BMQRr>mdKI;Vst0M6};DgXcg
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -37,19 +37,16 @@
   --toolbarbutton-combined-backgroundimage: linear-gradient(hsla(0,0%,0%,.15) 0, hsla(0,0%,0%,.15) 18px);
 
   --urlbar-dropmarker-url: url("chrome://browser/skin/urlbar-history-dropmarker.png");
   --urlbar-dropmarker-region: rect(0, 11px, 14px, 0);
   --urlbar-dropmarker-active-region: rect(0, 22px, 14px, 11px);
   --urlbar-dropmarker-2x-url: url("chrome://browser/skin/urlbar-history-dropmarker@2x.png");
   --urlbar-dropmarker-2x-region: rect(0, 22px, 28px, 0);
   --urlbar-dropmarker-active-2x-region: rect(0, 44px, 28px, 22px);
-
-  --menupanel-list-style-image-2x: url(chrome://browser/skin/menuPanel@2x.png);
-  --menupanel-small-list-style-image-2x: url(chrome://browser/skin/menuPanel-small@2x.png);
 }
 
 #urlbar:-moz-lwtheme:not([focused="true"]),
 .searchbar-textbox:-moz-lwtheme:not([focused="true"]) {
   opacity: .9;
 }
 
 #navigator-toolbox::after {
@@ -720,20 +717,19 @@ toolbar .toolbarbutton-1 > .toolbarbutto
   margin-bottom: 0;
   padding-top: 1px;
   padding-bottom: 1px;
   -moz-margin-start: 9px;
   -moz-margin-end: 7px;
 }
 
 %include ../shared/toolbarbuttons.inc.css
+%include ../shared/menupanel.inc.css
 
 @media not all and (min-resolution: 1.1dppx) {
-%include ../shared/menupanel.inc.css
-
   #back-button:hover:active:not([disabled="true"]) {
     -moz-image-region: rect(18px, 36px, 36px, 18px);
   }
 
   #forward-button:hover:active:not([disabled="true"]) {
     -moz-image-region: rect(18px, 72px, 36px, 54px);
   }
 
@@ -1066,246 +1062,16 @@ toolbar .toolbarbutton-1 > .toolbarbutto
   }
 
   :-moz-any(@primaryToolbarButtons@) > .toolbarbutton-icon,
   :-moz-any(@primaryToolbarButtons@) > .toolbarbutton-badge-container > .toolbarbutton-icon,
   :-moz-any(@primaryToolbarButtons@) > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
     width: 18px;
   }
 
-  /* Menu panel and palette styles */
-
-  toolbaritem[sdkstylewidget="true"] > toolbarbutton,
-  :-moz-any(@primaryToolbarButtons@)[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > :-moz-any(@primaryToolbarButtons@) {
-    list-style-image: var(--menupanel-list-style-image-2x);
-  }
-
-  #home-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #home-button {
-    -moz-image-region: rect(0px, 256px, 64px, 192px);
-  }
-
-  #bookmarks-menu-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #bookmarks-menu-button {
-    -moz-image-region: rect(0px, 384px, 64px, 320px);
-  }
-
-  #bookmarks-menu-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(64px, 384px, 128px, 320px);
-  }
-
-  #history-panelmenu[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #history-panelmenu {
-    -moz-image-region: rect(0px, 448px, 64px, 384px);
-  }
-
-  #history-panelmenu[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(64px, 448px, 128px, 384px);
-  }
-
-  #downloads-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #downloads-button {
-    -moz-image-region: rect(0px, 512px, 64px, 448px);
-  }
-
-  #add-ons-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #add-ons-button {
-    -moz-image-region: rect(0px, 576px, 64px, 512px);
-  }
-
-  #open-file-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #open-file-button {
-    -moz-image-region: rect(0px, 640px, 64px, 576px);
-  }
-
-  #save-page-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #save-page-button {
-    -moz-image-region: rect(0px, 704px, 64px, 640px);
-  }
-
-  #sync-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #sync-button {
-    -moz-image-region: rect(0px, 768px, 64px, 704px);
-  }
-
-  #sync-button[cui-areatype="menu-panel"][status="active"] {
-    list-style-image: url(chrome://browser/skin/syncProgress-menuPanel@2x.png);
-    -moz-image-region: rect(0px, 64px, 64px, 0px);
-  }
-
-  #feed-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #feed-button {
-    -moz-image-region: rect(0px, 832px, 64px, 768px);
-  }
-
-  #feed-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(64px, 832px, 128px, 768px);
-  }
-
-  #social-share-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #social-share-button {
-    -moz-image-region: rect(0px, 896px, 64px, 832px);
-  }
-
-  #characterencoding-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #characterencoding-button {
-    -moz-image-region: rect(0, 960px, 64px, 896px);
-  }
-
-  #characterencoding-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(64px, 960px, 128px, 896px);
-  }
-
-  #new-window-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #new-window-button {
-    -moz-image-region: rect(0px, 1024px, 64px, 960px);
-  }
-
-  #e10s-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #e10s-button {
-    -moz-image-region: rect(0px, 1024px, 64px, 960px);
-  }
-
-  #webide-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #webide-button {
-    -moz-image-region: rect(0px, 1920px, 64px, 1856px);
-  }
-
-  #pocket-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #pocket-button {
-    -moz-image-region: rect(0px, 1984px, 64px, 1920px);
-  }
-
-  #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(64px, 1984px, 128px, 1920px);
-  }
-
-  #new-tab-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #new-tab-button {
-    -moz-image-region: rect(0px, 1088px, 64px, 1024px);
-  }
-
-  #privatebrowsing-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #privatebrowsing-button {
-    -moz-image-region: rect(0px, 1152px, 64px, 1088px);
-  }
-
-  #tabview-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #tabview-button {
-    -moz-image-region: rect(0px, 1216px, 64px, 1152px);
-  }
-
-  #find-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #find-button {
-    -moz-image-region: rect(0px, 1280px, 64px, 1216px);
-  }
-
-  #print-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #print-button {
-    -moz-image-region: rect(0px, 1344px, 64px, 1280px);
-  }
-
-  #fullscreen-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #fullscreen-button {
-    -moz-image-region: rect(0px, 1408px, 64px, 1344px);
-  }
-
-  #developer-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #developer-button {
-    -moz-image-region: rect(0px, 1472px, 64px, 1408px);
-  }
-
-  #developer-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(64px, 1472px, 128px, 1408px);
-  }
-
-  #preferences-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #preferences-button {
-    -moz-image-region: rect(0px, 1536px, 64px, 1472px);
-  }
-
-  #email-link-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #email-link-button {
-    -moz-image-region: rect(0px, 1600px, 64px, 1536px);
-  }
-
-  #sidebar-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #sidebar-button {
-    -moz-image-region: rect(0px, 1728px, 64px, 1664px);
-  }
-
-  #panic-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #panic-button {
-    -moz-image-region: rect(0, 1792px, 64px, 1728px);
-  }
-
-  #panic-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(64px, 1792px, 128px, 1728px);
-  }
-
-  #web-apps-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #web-apps-button {
-    -moz-image-region: rect(0, 1856px, 64px, 1792px);
-  }
-
-  toolbaritem[sdkstylewidget="true"] > toolbarbutton {
-    -moz-image-region: rect(0, 1664px, 64px, 1600px);
-  }
-
-  /* Footer and wide panel control icons */
-  #edit-controls@inAnyPanel@ > toolbarbutton,
-  #zoom-controls@inAnyPanel@ > toolbarbutton,
-  toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton,
-  toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton {
-    list-style-image: var(--menupanel-small-list-style-image-2x);
-  }
-
-  /* Wide items like the Cut/Copy/Paste and Zoom controls are special in that their icons
-     are 16x16 when in the panel, but 18x18 when in a toolbar. */
-  #edit-controls@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon,
-  #zoom-controls@inAnyPanel@ > toolbarbutton > .toolbarbutton-icon,
-  toolbarpaletteitem[place="palette"] > #edit-controls > toolbarbutton > .toolbarbutton-icon,
-  toolbarpaletteitem[place="palette"] > #zoom-controls > toolbarbutton > .toolbarbutton-icon {
-    width: 16px;
-  }
-
-  #edit-controls@inAnyPanel@ > #cut-button,
-  toolbarpaletteitem[place="palette"] > #edit-controls > #cut-button {
-    -moz-image-region: rect(0px, 64px, 32px, 32px);
-  }
-
-  #edit-controls@inAnyPanel@ > #copy-button,
-  toolbarpaletteitem[place="palette"] > #edit-controls > #copy-button {
-    -moz-image-region: rect(0px, 96px, 32px, 64px);
-  }
-
-  #edit-controls@inAnyPanel@ > #paste-button,
-  toolbarpaletteitem[place="palette"] > #edit-controls > #paste-button {
-    -moz-image-region: rect(0px, 128px, 32px, 96px);
-  }
-
-  #zoom-controls@inAnyPanel@ > #zoom-out-button,
-  toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button {
-    -moz-image-region: rect(0px, 160px, 32px, 128px);
-  }
-
-  #zoom-controls@inAnyPanel@ > #zoom-in-button,
-  toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
-    -moz-image-region: rect(0px, 192px, 32px, 160px);
-  }
-
-  #PanelUI-update-status > .toolbarbutton-icon,
-  #PanelUI-fxa-status > .toolbarbutton-icon,
-  #PanelUI-quit > .toolbarbutton-icon,
-  #PanelUI-customize > .toolbarbutton-icon,
-  #PanelUI-help > .toolbarbutton-icon {
-    width: 16px;
-  }
-
   #add-share-provider {
     list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
     -moz-image-region: rect(0px, 192px, 32px, 160px);
   }
 
   #loop-button > .toolbarbutton-badge-container {
     list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
     -moz-image-region: rect(0, 36px, 36px, 0);
@@ -2073,61 +1839,33 @@ toolbarbutton[constrain-size="true"][cui
   min-width: calc(54px + 11ch);
 }
 
 %include ../shared/identity-block.inc.css
 
 #page-proxy-favicon {
   margin: 0px;
   padding: 0px;
-  -moz-image-region: rect(0, 16px, 16px, 0);
-}
-
-#identity-box:hover:active > #page-proxy-favicon,
-#identity-box[open=true] > #page-proxy-favicon {
-  -moz-image-region: rect(0, 32px, 16px, 16px);
-}
-
-/* The chromeUI identity-icon set includes three states,
-   but OS X only uses two of them. */
-#identity-box.chromeUI:hover:active > #page-proxy-favicon,
-#identity-box.chromeUI[open=true] > #page-proxy-favicon {
-  -moz-image-region: rect(0, 48px, 16px, 32px);
-}
-
-@media (min-resolution: 2dppx) {
-  #page-proxy-favicon {
-    list-style-image: url(chrome://browser/skin/identity-icons-generic@2x.png);
-    -moz-image-region: rect(0, 32px, 32px, 0);
+}
+
+@media not all and (min-resolution: 1.1dppx) {
+  #identity-box:hover:active > #page-proxy-favicon,
+  #identity-box[open=true] > #page-proxy-favicon {
+    -moz-image-region: rect(0, 32px, 16px, 16px);
   }
 
-  .chromeUI > #page-proxy-favicon[pageproxystate="valid"] {
-    list-style-image: url(chrome://branding/content/identity-icons-brand@2x.png);
-  }
-
-  .verifiedDomain > #page-proxy-favicon[pageproxystate="valid"] {
-    list-style-image: url(chrome://browser/skin/identity-icons-https@2x.png);
-  }
-
-  .verifiedIdentity > #page-proxy-favicon[pageproxystate="valid"] {
-    list-style-image: url(chrome://browser/skin/identity-icons-https-ev@2x.png);
+  /* The chromeUI identity-icon set includes three states,
+     but OS X only uses two of them. */
+  #identity-box.chromeUI:hover:active > #page-proxy-favicon,
+  #identity-box.chromeUI[open=true] > #page-proxy-favicon {
+    -moz-image-region: rect(0, 48px, 16px, 32px);
   }
-
-  .mixedActiveContent > #page-proxy-favicon[pageproxystate="valid"] {
-    list-style-image: url(chrome://browser/skin/identity-icons-https-mixed-active@2x.png);
-  }
-
-  .mixedDisplayContent > #page-proxy-favicon[pageproxystate="valid"] {
-    list-style-image: url(chrome://browser/skin/identity-icons-https-mixed-display@2x.png);
-  }
-
-  .mixedDisplayContentLoadedActiveBlocked > #page-proxy-favicon[pageproxystate="valid"] {
-    list-style-image: url(chrome://browser/skin/identity-icons-https-mixed-display@2x.png);
-  }
-
+}
+
+@media (min-resolution: 1.1dppx) {
   #identity-box:hover:active > #page-proxy-favicon,
   #identity-box[open=true] > #page-proxy-favicon {
     -moz-image-region: rect(0, 64px, 32px, 32px);
   }
 
   /* The chromeUI identity-icon set includes three states,
      but OS X only uses two of them. */
   #identity-box.chromeUI:hover:active > #page-proxy-favicon,
@@ -4117,25 +3855,16 @@ window > chatbox {
 
 #main-window[customize-entered] #TabsToolbar {
   background-clip: padding-box;
   border-right: 3px solid transparent;
   border-left: 3px solid transparent;
 }
 
 @media (min-resolution: 2dppx) {
-  #customization-titlebar-visibility-button {
-    list-style-image: url("chrome://browser/skin/customizableui/customize-titleBar-toggle@2x.png");
-    -moz-image-region: rect(0, 48px, 48px, 0);
-  }
-
-  #customization-titlebar-visibility-button[checked] {
-    -moz-image-region: rect(0, 96px, 48px, 48px);
-  }
-
   .customization-tipPanel-infoBox {
     background-image: url(chrome://browser/skin/customizableui/info-icon-customizeTip@2x.png);
     background-size: 25px 25px;
   }
 
   .customization-tipPanel-contentImage {
     list-style-image: url(chrome://browser/skin/customizableui/customize-illustration@2x.png);
   }
--- a/browser/themes/osx/customizableui/panelUIOverlay.css
+++ b/browser/themes/osx/customizableui/panelUIOverlay.css
@@ -3,118 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 %include ../../shared/customizableui/panelUIOverlay.inc.css
 
 .panel-subviews {
   background-color: hsla(0,0%,100%,.97);
 }
 
-@media (min-resolution: 2dppx) {
-  #PanelUI-help[panel-multiview-anchor="true"]::after,
-  toolbarbutton[panel-multiview-anchor="true"] {
-    background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted@2x.png),
-                      linear-gradient(rgba(255,255,255,0.3), transparent);
-    background-size: 16px, auto;
-  }
-
-  #PanelUI-help[panel-multiview-anchor="true"]:-moz-locale-dir(rtl)::after,
-  toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
-    background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl@2x.png),
-                      linear-gradient(rgba(255,255,255,0.3), transparent);
-  }
-
-  #PanelUI-update-status {
-    list-style-image: url(chrome://branding/content/icon32.png);
-  }
-
-  #PanelUI-fxa-status {
-    list-style-image: url(chrome://browser/skin/sync-horizontalbar@2x.png);
-  }
-
-  #PanelUI-fxa-status[syncstatus="active"] {
-    list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar@2x.png);
-  }
-
-  #PanelUI-fxa-status[fxastatus="migrate-signup"],
-  #PanelUI-fxa-status[fxastatus="migrate-verify"] {
-    list-style-image: url(chrome://browser/skin/warning16@2x.png);
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  #PanelUI-customize {
-    list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png);
-  }
-
-  #main-window[customize-entered] #PanelUI-customize {
-    list-style-image: url(chrome://browser/skin/customizableui/menuPanel-customizeFinish@2x.png);
-  }
-
-  #PanelUI-help {
-    list-style-image: url(chrome://browser/skin/menuPanel-help@2x.png);
-  }
-
-  #PanelUI-quit {
-    list-style-image: url(chrome://browser/skin/menuPanel-exit@2x.png);
-  }
-
-  #PanelUI-fxa-status,
-  #PanelUI-customize,
-  #PanelUI-help,
-  #PanelUI-quit {
-    -moz-image-region: rect(0, 32px, 32px, 0);
-  }
-
-  #PanelUI-customize:hover,
-  #PanelUI-help:not([disabled]):hover,
-  #PanelUI-quit:not([disabled]):hover {
-    -moz-image-region: rect(0, 64px, 32px, 32px);
-  }
-
-  #PanelUI-customize:hover:active,
-  #PanelUI-help:not([disabled]):hover:active,
-  #PanelUI-quit:not([disabled]):hover:active {
-    -moz-image-region: rect(0, 96px, 32px, 64px);
-  }
-
-  #PanelUI-help[panel-multiview-anchor="true"] {
-    -moz-image-region: rect(0, 128px, 32px, 96px);
-    background-size: auto;
-  }
-
-  .subviewbutton[checked="true"] {
-    background-image: url("chrome://global/skin/menu/shared-menu-check@2x.png");
-  }
-
-  #panic-button-success-icon,
-  #PanelUI-panic-timeframe-icon {
-    list-style-image: url(chrome://browser/skin/panic-panel/header@2x.png);
-  }
-
-  #PanelUI-panic-timeframe-icon-small {
-    list-style-image: url(chrome://browser/skin/panic-panel/header-small@2x.png);
-  }
-
-  #PanelUI-panic-actionlist-cookies {
-    background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 32, 32, 0);
-  }
-
-  #PanelUI-panic-actionlist-history {
-    background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 64, 32, 32);
-  }
-
-  #PanelUI-panic-actionlist-windows {
-    background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 96, 32, 64);
-  }
-
-  #PanelUI-panic-actionlist-newwindow {
-    background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 128, 32, 96);
-  }
-}
-
 .panelUI-grid .toolbarbutton-1 {
   margin-right: 0;
   margin-left: 0;
   margin-bottom: 0;
 }
 
 .subviewbutton > .toolbarbutton-text {
   margin: 2px 0 !important; /* !important for overriding toolbarbutton.css */
@@ -168,16 +66,11 @@ menu.subviewbutton > .menu-right > image
   -moz-margin-start: 4px;
 }
 
 .PanelUI-subView menuseparator,
 .cui-widget-panelview menuseparator {
   padding: 0 !important;
 }
 
-toolbarpaletteitem:-moz-any([place="palette"], [place="panel"]) > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-1 > .toolbarbutton-icon {
-  width: 32px;
-  height: 32px;
-}
-
 toolbarpaletteitem[place="palette"] > .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   padding: 3px 1px;
 }
\ No newline at end of file
--- a/browser/themes/osx/jar.mn
+++ b/browser/themes/osx/jar.mn
@@ -117,18 +117,16 @@ browser.jar:
   skin/classic/browser/searchbar-dropmarker.png
   skin/classic/browser/searchbar-dropmarker@2x.png
   skin/classic/browser/searchbar.css
   skin/classic/browser/Search.png
   skin/classic/browser/Search@2x.png
   skin/classic/browser/search-pref.png                         (../shared/search/search-pref.png)
   skin/classic/browser/search-indicator.png                    (../shared/search/search-indicator.png)
   skin/classic/browser/search-indicator@2x.png                 (../shared/search/search-indicator@2x.png)
-  skin/classic/browser/search-indicator-add-engine.png         (../shared/search/search-indicator-add-engine.png)
-  skin/classic/browser/search-indicator-add-engine@2x.png      (../shared/search/search-indicator-add-engine@2x.png)
   skin/classic/browser/search-engine-placeholder.png           (../shared/search/search-engine-placeholder.png)
   skin/classic/browser/search-engine-placeholder@2x.png        (../shared/search/search-engine-placeholder@2x.png)
   skin/classic/browser/badge-add-engine.png                    (../shared/search/badge-add-engine.png)
   skin/classic/browser/badge-add-engine@2x.png                 (../shared/search/badge-add-engine@2x.png)
   skin/classic/browser/search-indicator-badge-add.png          (../shared/search/search-indicator-badge-add.png)
   skin/classic/browser/search-indicator-badge-add@2x.png       (../shared/search/search-indicator-badge-add@2x.png)
   skin/classic/browser/search-history-icon.svg                 (../shared/search/history-icon.svg)
   skin/classic/browser/Secure-Glyph.png
--- a/browser/themes/osx/searchbar.css
+++ b/browser/themes/osx/searchbar.css
@@ -155,18 +155,23 @@ searchbar[oneoffui] .search-go-button:-m
   padding: 3px 6px;
   color: #666;
 }
 
 .search-panel-tree[collapsed=true] + .search-panel-header {
   border-top: none;
 }
 
+.search-panel-header > label {
+  margin-top: 2px !important;
+  margin-bottom: 1px !important;
+}
+
 .search-panel-current-input > label {
-  margin: 0 0 !important;
+  margin: 2px 0 1px !important;
 }
 
 .search-panel-input-value {
   color: black;
 }
 
 .search-panel-one-offs {
   border-top: 1px solid #ccc;
--- a/browser/themes/shared/customizableui/customizeMode.inc.css
+++ b/browser/themes/shared/customizableui/customizeMode.inc.css
@@ -174,16 +174,27 @@
 #customization-titlebar-visibility-button > .button-box > .button-icon {
   vertical-align: middle;
 }
 
 #customization-titlebar-visibility-button[checked] {
   -moz-image-region: rect(0, 48px, 24px, 24px);
 }
 
+@media (min-resolution: 1.1dppx) {
+  #customization-titlebar-visibility-button {
+    list-style-image: url("chrome://browser/skin/customizableui/customize-titleBar-toggle@2x.png");
+    -moz-image-region: rect(0, 48px, 48px, 0);
+  }
+
+  #customization-titlebar-visibility-button[checked] {
+    -moz-image-region: rect(0, 96px, 48px, 48px);
+  }
+}
+
 #main-window[customize-entered] #customization-panel-container {
   background-image: url("chrome://browser/skin/customizableui/customizeMode-separatorHorizontal.png"),
                     url("chrome://browser/skin/customizableui/customizeMode-separatorVertical.png"),
                     url("chrome://browser/skin/customizableui/customizeMode-gridTexture.png"),
                     url("chrome://browser/skin/customizableui/background-noise-toolbar.png"),
                     linear-gradient(to bottom, #3e86ce, #3878ba);
   background-position: center top, left center, left top, left top, left top;
   background-repeat: no-repeat, no-repeat, repeat, repeat, no-repeat;
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -314,16 +314,21 @@ toolbarpaletteitem[place="panel"]:not([h
 toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-icon,
 toolbarpaletteitem[place="palette"] > toolbarbutton[constrain-size="true"] > .toolbarbutton-badge-container > .toolbarbutton-icon,
 toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-icon,
 toolbarbutton[constrain-size="true"][cui-areatype="menu-panel"] > .toolbarbutton-badge-container > .toolbarbutton-icon {
   height: 32px;
   width: 32px;
 }
 
+toolbarpaletteitem:-moz-any([place="palette"], [place="panel"]) > toolbaritem[sdkstylewidget="true"] > .toolbarbutton-1 > .toolbarbutton-icon {
+  width: 32px;
+  height: 32px;
+}
+
 .customization-palette .toolbarbutton-1 {
   -moz-appearance: none;
   -moz-box-orient: vertical;
 }
 
 .panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button {
   -moz-appearance: none;
   -moz-box-orient: vertical;
@@ -427,16 +432,18 @@ toolbaritem[cui-areatype="menu-panel"][s
 .panelUI-grid .toolbarbutton-1 > .toolbarbutton-icon,
 .panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-container,
 .customization-palette .toolbarbutton-1 > .toolbarbutton-menubutton-button > .toolbarbutton-icon,
 .customization-palette .toolbarbutton-1 > .toolbarbutton-icon,
 .customization-palette .toolbarbutton-1 > .toolbarbutton-badge-container,
 .panelUI-grid #bookmarks-toolbar-placeholder > .toolbarbutton-icon,
 .customization-palette #bookmarks-toolbar-placeholder > .toolbarbutton-icon,
 .panel-customization-placeholder-child > .toolbarbutton-icon {
+  width: 32px;
+  height: 32px;
   min-width: 32px;
   min-height: 32px;
   /* Explanation for the below formula (A / B - C)
      A
        Each button is @menuPanelButtonWidth@ wide
      B
        Each button has two margins.
      C (46px / 2 = 23px)
@@ -446,17 +453,17 @@ toolbaritem[cui-areatype="menu-panel"][s
        Total width of button's icon + button padding should therefore be 46px,
        which means each horizontal margin should be the half the button's width - (46/2) px.
   */
   margin: 4px calc(@menuPanelButtonWidth@ / 2 - 23px);
 }
 
 /* above we treat the container as the icon for the margins, that is so the
 /* badge itself is positioned correctly. Here we make sure that the icon itself
-/* has the minum size we want, but no padding/margin. */
+/* has the minimum size we want, but no padding/margin. */
 .panelUI-grid .toolbarbutton-1 > .toolbarbutton-badge-container > .toolbarbutton-icon,
 .customization-palette .toolbarbutton-1 > .toolbarbutton-badge-container > .toolbarbutton-icon {
   min-width: 32px;
   min-height: 32px;
   margin: 0;
   padding: 0;
 }
 
@@ -1375,8 +1382,118 @@ menuitem[checked="true"].subviewbutton >
   background-color: #dedede;
   border-color: #bbb;
 }
 
 #panic-button-success-closebutton:hover:active {
   background-color: #d0d0d0;
   border-color: #aaa;
 }
+
+@media (min-resolution: 1.1dppx) {
+  #PanelUI-help[panel-multiview-anchor="true"]::after,
+  toolbarbutton[panel-multiview-anchor="true"] {
+    background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted@2x.png),
+                      linear-gradient(rgba(255,255,255,0.3), transparent);
+    background-size: 16px, auto;
+  }
+
+  #PanelUI-help[panel-multiview-anchor="true"]:-moz-locale-dir(rtl)::after,
+  toolbarbutton[panel-multiview-anchor="true"]:-moz-locale-dir(rtl) {
+    background-image: url(chrome://browser/skin/customizableui/subView-arrow-back-inverted-rtl@2x.png),
+                      linear-gradient(rgba(255,255,255,0.3), transparent);
+  }
+
+  #PanelUI-update-status {
+    list-style-image: url(chrome://branding/content/icon32.png);
+  }
+
+  #PanelUI-fxa-status {
+    list-style-image: url(chrome://browser/skin/sync-horizontalbar@2x.png);
+  }
+
+  #PanelUI-fxa-status[syncstatus="active"] {
+    list-style-image: url(chrome://browser/skin/syncProgress-horizontalbar@2x.png);
+  }
+
+  #PanelUI-fxa-status[fxastatus="migrate-signup"],
+  #PanelUI-fxa-status[fxastatus="migrate-verify"] {
+    list-style-image: url(chrome://browser/skin/warning16@2x.png);
+    -moz-image-region: rect(0, 64px, 32px, 32px);
+  }
+
+  #PanelUI-customize {
+    list-style-image: url(chrome://browser/skin/menuPanel-customize@2x.png);
+  }
+
+  #customization-panelHolder #PanelUI-customize {
+    list-style-image: url(chrome://browser/skin/customizableui/menuPanel-customizeFinish@2x.png);
+  }
+
+  #PanelUI-help {
+    list-style-image: url(chrome://browser/skin/menuPanel-help@2x.png);
+  }
+
+  #PanelUI-quit {
+    list-style-image: url(chrome://browser/skin/menuPanel-exit@2x.png);
+  }
+
+  #PanelUI-fxa-status,
+  #PanelUI-customize,
+  #PanelUI-help,
+  #PanelUI-quit {
+    -moz-image-region: rect(0, 32px, 32px, 0);
+  }
+
+  #PanelUI-update-status > .toolbarbutton-icon,
+  #PanelUI-fxa-status > .toolbarbutton-icon,
+  #PanelUI-customize > .toolbarbutton-icon,
+  #PanelUI-help > .toolbarbutton-icon,
+  #PanelUI-quit > .toolbarbutton-icon {
+    width: 16px;
+  }
+
+  #PanelUI-customize:hover,
+  #PanelUI-help:not([disabled]):hover,
+  #PanelUI-quit:not([disabled]):hover {
+    -moz-image-region: rect(0, 64px, 32px, 32px);
+  }
+
+  #PanelUI-customize:hover:active,
+  #PanelUI-help:not([disabled]):hover:active,
+  #PanelUI-quit:not([disabled]):hover:active {
+    -moz-image-region: rect(0, 96px, 32px, 64px);
+  }
+
+  #PanelUI-help[panel-multiview-anchor="true"] {
+    -moz-image-region: rect(0, 128px, 32px, 96px);
+    background-size: auto;
+  }
+
+  .subviewbutton[checked="true"] {
+    background-image: url("chrome://global/skin/menu/shared-menu-check@2x.png");
+  }
+
+  #panic-button-success-icon,
+  #PanelUI-panic-timeframe-icon {
+    list-style-image: url(chrome://browser/skin/panic-panel/header@2x.png);
+  }
+
+  #PanelUI-panic-timeframe-icon-small {
+    list-style-image: url(chrome://browser/skin/panic-panel/header-small@2x.png);
+  }
+
+  #PanelUI-panic-actionlist-cookies {
+    background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 32, 32, 0);
+  }
+
+  #PanelUI-panic-actionlist-history {
+    background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 64, 32, 32);
+  }
+
+  #PanelUI-panic-actionlist-windows {
+    background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 96, 32, 64);
+  }
+
+  #PanelUI-panic-actionlist-newwindow {
+    background-image: -moz-image-rect(url(chrome://browser/skin/panic-panel/icons@2x.png), 0, 128, 32, 96);
+  }
+}
--- a/browser/themes/shared/devtools/performance.inc.css
+++ b/browser/themes/shared/devtools/performance.inc.css
@@ -1,23 +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/. */
 
 /* CSS Variables specific to this panel that aren't defined by the themes */
 .theme-dark {
   --cell-border-color: rgba(255,255,255,0.15);
+  --cell-border-color-light: rgba(255,255,255,0.1);
   --focus-cell-border-color: rgba(255,255,255,0.5);
   --row-alt-background-color: rgba(29,79,115,0.15);
   --row-hover-background-color: rgba(29,79,115,0.25);
 }
 
 .theme-light {
   --cell-border-color: rgba(0,0,0,0.15);
+  --cell-border-color-light: rgba(0,0,0,0.1);
   --focus-cell-border-color: rgba(0,0,0,0.3);
   --row-alt-background-color: rgba(76,158,217,0.1);
   --row-hover-background-color: rgba(76,158,217,0.2);
 }
 
 /* Toolbar */
 
 #performance-toolbar-control-other {
@@ -178,18 +180,16 @@
 
 #details-pane-container[buffer-status="full"] .buffer-status-message-full {
   display: initial;
 }
 
 /* Profile call tree */
 
 .call-tree-cells-container {
-  /* Hack: force hardware acceleration */
-  transform: translateZ(1px);
   overflow: auto;
 }
 
 .call-tree-cells-container[categories-hidden] .call-tree-category {
   display: none;
 }
 
 .call-tree-header {
@@ -251,33 +251,33 @@
 .call-tree-cell:not(:last-child) {
   text-align: end;
 }
 
 .call-tree-header {
   background-color: var(--theme-tab-toolbar-background);
 }
 
-.call-tree-item:last-child:not(:focus) {
+.call-tree-item:last-child {
   border-bottom: 1px solid var(--cell-border-color);
 }
 
 .call-tree-item:nth-child(2n) {
   background-color: var(--row-alt-background-color);
 }
 
 .call-tree-item:hover {
   background-color: var(--row-hover-background-color);
 }
 
 .call-tree-item:focus {
   background-color: var(--theme-selection-background);
 }
 
-.call-tree-item:focus label {
+.call-tree-item:focus description {
   color: var(--theme-selection-color) !important;
 }
 
 .call-tree-item:focus .call-tree-cell {
   -moz-border-end-color: var(--focus-cell-border-color);
 }
 
 .call-tree-item:not([origin="content"]) .call-tree-name,
@@ -320,129 +320,209 @@
 }
 
 .call-tree-category {
   transform: scale(0.75);
   transform-origin: center right;
 }
 
 /**
- * Details Waterfall Styles
+ * Waterfall ticks header
  */
 
-#waterfall-breakdown {
-  overflow: auto;
-}
-
-.waterfall-list-contents {
-  /* Hack: force hardware acceleration */