merge fx-team to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 29 Apr 2016 11:48:06 +0200
changeset 295528 8c3fd523d75bd30f691ca2d6cfdad18d576392a1
parent 295507 6adc822f5e27a55551faeb6c47a9bd8b0859a23b (current diff)
parent 295527 0e049ed7092053c46c959e9e2e276fce84a13870 (diff)
child 295529 6ce48a7c22d55187daa471ff10d136b7ab02a5ee
push id75951
push userkwierso@gmail.com
push dateFri, 29 Apr 2016 23:01:24 +0000
treeherdermozilla-inbound@f8896b71e9bc [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone49.0a1
first release with
nightly linux32
8c3fd523d75b / 49.0a1 / 20160429030215 / files
nightly linux64
8c3fd523d75b / 49.0a1 / 20160429030215 / files
nightly mac
8c3fd523d75b / 49.0a1 / 20160429030215 / files
nightly win32
8c3fd523d75b / 49.0a1 / 20160429030215 / files
nightly win64
8c3fd523d75b / 49.0a1 / 20160429030215 / 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 mozilla-central a=merge
--- a/.eslintignore
+++ b/.eslintignore
@@ -103,16 +103,17 @@ devtools/client/shadereditor/**
 devtools/client/shared/**
 devtools/client/sourceeditor/**
 devtools/client/webaudioeditor/**
 devtools/client/webconsole/**
 !devtools/client/webconsole/panel.js
 !devtools/client/webconsole/jsterm.js
 devtools/client/webide/**
 devtools/server/**
+!devtools/server/actors/webbrowser.js
 devtools/shared/*.js
 !devtools/shared/css-color.js
 devtools/shared/*.jsm
 devtools/shared/apps/**
 devtools/shared/client/**
 devtools/shared/discovery/**
 devtools/shared/gcli/**
 devtools/shared/heapsnapshot/**
--- a/browser/themes/linux/linuxShared.inc
+++ b/browser/themes/linux/linuxShared.inc
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 %filter substitution
 
-%define toolbarHighlight hsla(0,0%,100%,.05)
+%define toolbarHighlight hsla(0,0%,100%,.15)
 %define toolbarHighlightLWT rgba(255,255,255,.4)
 /* navbarInsetHighlight is tightly coupled to the toolbarHighlight constant. */
 %define navbarInsetHighlight hsla(0,0%,100%,.4)
 %define fgTabTexture linear-gradient(transparent 2px, @toolbarHighlight@ 2px, @toolbarHighlight@)
 %define fgTabTextureLWT linear-gradient(transparent 2px, @toolbarHighlightLWT@ 2px, @toolbarHighlightLWT@)
 %define fgTabBackgroundColor -moz-dialog
--- a/build.gradle
+++ b/build.gradle
@@ -28,17 +28,17 @@ buildscript {
         }
         // For android-sdk-manager SNAPSHOT releases.
         maven {
             url "file://${gradle.mozconfig.topsrcdir}/mobile/android/gradle/m2repo"
         }
     }
 
     dependencies {
-        classpath 'com.android.tools.build:gradle:1.5.0'
+        classpath 'com.android.tools.build:gradle:2.0.0'
         classpath('com.stanfy.spoon:spoon-gradle-plugin:1.0.4') {
             // Without these, we get errors linting.
             exclude module: 'guava'
         }
         // Provided in tree.
         classpath 'com.jakewharton.sdkmanager:gradle-plugin:1.5.0-SNAPSHOT'
     }
 }
--- a/devtools/client/debugger/test/mochitest/browser.ini
+++ b/devtools/client/debugger/test/mochitest/browser.ini
@@ -456,16 +456,17 @@ skip-if = e10s && debug
 skip-if = e10s # Bug 1093535
 [browser_dbg_sources-cache.js]
 [browser_dbg_sources-contextmenu-01.js]
 [browser_dbg_sources-contextmenu-02.js]
 skip-if = e10s && debug
 [browser_dbg_sources-eval-01.js]
 skip-if = true # non-named eval sources turned off for now, bug 1124106
 [browser_dbg_sources-eval-02.js]
+[browser_dbg_sources-iframe-reload.js]
 [browser_dbg_sources-keybindings.js]
 skip-if = e10s && debug
 [browser_dbg_sources-labels.js]
 skip-if = e10s && debug
 [browser_dbg_sources-large.js]
 [browser_dbg_sources-sorting.js]
 skip-if = e10s && debug
 [browser_dbg_sources-bookmarklet.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_sources-iframe-reload.js
@@ -0,0 +1,35 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* 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/ */
+
+/**
+ * Make sure iframe scripts don't disappear after few reloads (bug 1259743)
+ */
+
+"use strict";
+
+const IFRAME_URL = "data:text/html;charset=utf-8," +
+  "<script>function fn() { console.log('hello'); }</script>" +
+  "<div onclick='fn()'>hello</div>";
+const TAB_URL = `data:text/html;charset=utf-8,<iframe src="${IFRAME_URL}"/>`;
+
+add_task(function* () {
+  let [,, panel] = yield initDebugger("about:blank");
+  let dbg = panel.panelWin;
+  let newSource;
+
+  newSource = waitForDebuggerEvents(panel, dbg.EVENTS.NEW_SOURCE);
+  reload(panel, TAB_URL);
+  yield newSource;
+  ok(true, "Source event fired on initial load");
+
+  for (let i = 0; i < 5; i++) {
+    newSource = waitForDebuggerEvents(panel, dbg.EVENTS.NEW_SOURCE);
+    reload(panel);
+    yield newSource;
+    ok(true, `Source event fired after ${i + 1} reloads`);
+  }
+
+  yield closeDebuggerAndFinish(panel);
+});
--- a/devtools/client/jsonview/main.js
+++ b/devtools/client/jsonview/main.js
@@ -7,17 +7,17 @@
 
 "use strict";
 
 const { Cu } = require("chrome");
 const Services = require("Services");
 
 const { XPCOMUtils } = Cu.import("resource://gre/modules/XPCOMUtils.jsm", {});
 
-XPCOMUtils.defineLazyGetter(this, "JsonViewService", function () {
+XPCOMUtils.defineLazyGetter(this, "JsonViewUtils", function () {
   return require("devtools/client/jsonview/utils");
 });
 
 /**
  * Singleton object that represents the JSON View in-content tool.
  * It has the same lifetime as the browser. Initialization done by
  * DevTools() object from devtools/client/framework/devtools.js
  */
--- a/devtools/client/jsonview/test/browser.ini
+++ b/devtools/client/jsonview/test/browser.ini
@@ -17,8 +17,9 @@ support-files =
   !/devtools/client/framework/test/shared-head.js
 
 [browser_jsonview_copy_headers.js]
 [browser_jsonview_copy_json.js]
 [browser_jsonview_copy_rawdata.js]
 [browser_jsonview_filter.js]
 [browser_jsonview_invalid_json.js]
 [browser_jsonview_valid_json.js]
+[browser_jsonview_save_json.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/jsonview/test/browser_jsonview_save_json.js
@@ -0,0 +1,38 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const TEST_JSON_URL = URL_ROOT + "valid_json.json";
+
+let { MockFilePicker } = SpecialPowers;
+
+MockFilePicker.init(window);
+MockFilePicker.returnValue = MockFilePicker.returnCancel;
+
+registerCleanupFunction(function () {
+  MockFilePicker.cleanup();
+});
+
+add_task(function* () {
+  info("Test save JSON started");
+
+  yield addJsonViewTab(TEST_JSON_URL);
+
+  let promise = new Promise((resolve) => {
+    MockFilePicker.showCallback = () => {
+      MockFilePicker.showCallback = null;
+      ok(true, "File picker was opened");
+      resolve();
+    };
+  });
+
+  let browser = gBrowser.selectedBrowser;
+  yield BrowserTestUtils.synthesizeMouseAtCenter(
+    ".jsonPanelBox button.save",
+    {}, browser);
+
+  yield promise;
+});
--- a/devtools/server/actors/inspector.js
+++ b/devtools/server/actors/inspector.js
@@ -45,26 +45,25 @@
  * the client - when a node is disconnected from the DOM tree we want to be
  * able to free the client objects for all the children nodes.
  *
  * So to be able to answer "all the children of a given node that we have
  * seen on the client side", we guarantee that every time we've seen a node,
  * we connect it up through its parents.
  */
 
-const {Cc, Ci, Cu, Cr} = require("chrome");
+const {Cc, Ci, Cu} = require("chrome");
 const Services = require("Services");
 const protocol = require("devtools/server/protocol");
 const {Arg, Option, method, RetVal, types} = protocol;
 const {LongStringActor, ShortLongString} = require("devtools/server/actors/string");
 const promise = require("promise");
 const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
 const object = require("sdk/util/object");
 const events = require("sdk/event/core");
-const {Unknown} = require("sdk/platform/xpcom");
 const {Class} = require("sdk/core/heritage");
 const {WalkerSearch} = require("devtools/server/actors/utils/walker-search");
 const {PageStyleActor, getFontPreviewData} = require("devtools/server/actors/styles");
 const {
   HighlighterActor,
   CustomHighlighterActor,
   isTypeRegistered,
 } = require("devtools/server/actors/highlighters");
@@ -84,17 +83,18 @@ const {EventParsers} = require("devtools
 
 const FONT_FAMILY_PREVIEW_TEXT = "The quick brown fox jumps over the lazy dog";
 const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20;
 const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
 const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__";
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const IMAGE_FETCHING_TIMEOUT = 500;
-const RX_FUNC_NAME = /((var|const|let)\s+)?([\w$.]+\s*[:=]\s*)*(function)?\s*\*?\s*([\w$]+)?\s*$/;
+const RX_FUNC_NAME =
+  /((var|const|let)\s+)?([\w$.]+\s*[:=]\s*)*(function)?\s*\*?\s*([\w$]+)?\s*$/;
 
 // The possible completions to a ':' with added score to give certain values
 // some preference.
 const PSEUDO_SELECTORS = [
   [":active", 1],
   [":hover", 1],
   [":focus", 1],
   [":visited", 0],
@@ -118,52 +118,61 @@ const PSEUDO_SELECTORS = [
   [":empty", 0],
   [":target", 0],
   [":enabled", 0],
   [":disabled", 0],
   [":checked", 1],
   ["::selection", 0]
 ];
 
-var HELPER_SHEET = ".__fx-devtools-hide-shortcut__ { visibility: hidden !important } ";
-HELPER_SHEET += ":-moz-devtools-highlighted { outline: 2px dashed #F06!important; outline-offset: -2px!important } ";
+var HELPER_SHEET = `
+  .__fx-devtools-hide-shortcut__ {
+    visibility: hidden !important;
+  }
+
+  :-moz-devtools-highlighted {
+    outline: 2px dashed #F06!important;
+    outline-offset: -2px !important;
+  }
+`;
 
 loader.lazyRequireGetter(this, "DevToolsUtils",
                          "devtools/shared/DevToolsUtils");
 
 loader.lazyRequireGetter(this, "AsyncUtils", "devtools/shared/async-utils");
 
-loader.lazyGetter(this, "DOMParser", function() {
-  return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
+loader.lazyGetter(this, "DOMParser", function () {
+  return Cc["@mozilla.org/xmlextras/domparser;1"]
+           .createInstance(Ci.nsIDOMParser);
 });
 
-loader.lazyGetter(this, "eventListenerService", function() {
+loader.lazyGetter(this, "eventListenerService", function () {
   return Cc["@mozilla.org/eventlistenerservice;1"]
            .getService(Ci.nsIEventListenerService);
 });
 
 loader.lazyGetter(this, "CssLogic", () => require("devtools/shared/inspector/css-logic").CssLogic);
 
 // XXX: A poor man's makeInfallible until we move it out of transport.js
 // Which should be very soon.
 function makeInfallible(handler) {
-  return function(...args) {
+  return function (...args) {
     try {
       return handler.apply(this, args);
     } catch(ex) {
       console.error(ex);
     }
     return undefined;
-  }
+  };
 }
 
 // A resolve that hits the main loop first.
 function delayedResolve(value) {
   let deferred = promise.defer();
-  Services.tm.mainThread.dispatch(makeInfallible(function delayedResolveHandler() {
+  Services.tm.mainThread.dispatch(makeInfallible(() => {
     deferred.resolve(value);
   }), 0);
   return deferred.promise;
 }
 
 types.addDictType("imageData", {
   // The image data
   data: "nullable:longstring",
@@ -173,68 +182,69 @@ types.addDictType("imageData", {
 
 /**
  * We only send nodeValue up to a certain size by default.  This stuff
  * controls that size.
  */
 exports.DEFAULT_VALUE_SUMMARY_LENGTH = 50;
 var gValueSummaryLength = exports.DEFAULT_VALUE_SUMMARY_LENGTH;
 
-exports.getValueSummaryLength = function() {
+exports.getValueSummaryLength = function () {
   return gValueSummaryLength;
 };
 
-exports.setValueSummaryLength = function(val) {
+exports.setValueSummaryLength = function (val) {
   gValueSummaryLength = val;
 };
 
 // When the user selects a node to inspect in e10s, the parent process
 // has a CPOW that wraps the node being inspected.  It uses the
 // message manager to send this node to the child, which stores the
 // node in gInspectingNode. Then a findInspectingNode request is sent
 // over the remote debugging protocol, and gInspectingNode is returned
 // to the parent as a NodeFront.
 var gInspectingNode = null;
 
 // We expect this function to be called from the child.js frame script
 // when it receives the node to be inspected over the message manager.
-exports.setInspectingNode = function(val) {
+exports.setInspectingNode = function (val) {
   gInspectingNode = val;
 };
 
 /**
  * Server side of the node actor.
  */
 var NodeActor = exports.NodeActor = protocol.ActorClass({
   typeName: "domnode",
 
-  initialize: function(walker, node) {
+  initialize: function (walker, node) {
     protocol.Actor.prototype.initialize.call(this, null);
     this.walker = walker;
     this.rawNode = node;
     this._eventParsers = new EventParsers().parsers;
 
     // Storing the original display of the node, to track changes when reflows
     // occur
     this.wasDisplayed = this.isDisplayed;
   },
 
-  toString: function() {
-    return "[NodeActor " + this.actorID + " for " + this.rawNode.toString() + "]";
+  toString: function () {
+    return "[NodeActor " + this.actorID + " for " +
+      this.rawNode.toString() + "]";
   },
 
   /**
    * Instead of storing a connection object, the NodeActor gets its connection
    * from its associated walker.
    */
   get conn() {
     return this.walker.conn;
   },
 
-  isDocumentElement: function() {
+  isDocumentElement: function () {
     return this.rawNode.ownerDocument &&
            this.rawNode.ownerDocument.documentElement === this.rawNode;
   },
 
   destroy: function () {
     protocol.Actor.prototype.destroy.call(this);
 
     if (this.mutationObserver) {
@@ -243,17 +253,17 @@ var NodeActor = exports.NodeActor = prot
       }
       this.mutationObserver = null;
     }
     this.rawNode = null;
     this.walker = null;
   },
 
   // Returns the JSON representation of this object over the wire.
-  form: function(detail) {
+  form: function (detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
 
     let parentNode = this.walker.parentNode(this);
     let singleTextChild = this.walker.singleTextChild(this);
 
     let form = {
@@ -289,17 +299,18 @@ var NodeActor = exports.NodeActor = prot
     if (this.isDocumentElement()) {
       form.isDocumentElement = true;
     }
 
     if (this.rawNode.nodeValue) {
       // We only include a short version of the value if it's longer than
       // gValueSummaryLength
       if (this.rawNode.nodeValue.length > gValueSummaryLength) {
-        form.shortValue = this.rawNode.nodeValue.substring(0, gValueSummaryLength);
+        form.shortValue = this.rawNode.nodeValue
+          .substring(0, gValueSummaryLength);
         form.incompleteValue = true;
       } else {
         form.shortValue = this.rawNode.nodeValue;
       }
     }
 
     // Add an extra API for custom properties added by other
     // modules/extensions.
@@ -319,38 +330,38 @@ var NodeActor = exports.NodeActor = prot
 
     return form;
   },
 
   /**
    * Watch the given document node for mutations using the DOM observer
    * API.
    */
-  watchDocument: function(callback) {
+  watchDocument: function (callback) {
     let node = this.rawNode;
     // Create the observer on the node's actor.  The node will make sure
     // the observer is cleaned up when the actor is released.
     let observer = new node.defaultView.MutationObserver(callback);
     observer.mergeAttributeRecords = true;
     observer.observe(node, {
       nativeAnonymousChildList: true,
       attributes: true,
       characterData: true,
       childList: true,
       subtree: true
     });
     this.mutationObserver = observer;
   },
 
   get isBeforePseudoElement() {
-    return this.rawNode.nodeName === "_moz_generated_content_before"
+    return this.rawNode.nodeName === "_moz_generated_content_before";
   },
 
   get isAfterPseudoElement() {
-    return this.rawNode.nodeName === "_moz_generated_content_after"
+    return this.rawNode.nodeName === "_moz_generated_content_after";
   },
 
   // Estimate the number of children that the walker will return without making
   // a call to children() if possible.
   get numChildren() {
     // For pseudo elements, childNodes.length returns 1, but the walker
     // will return 0.
     if (this.isBeforePseudoElement || this.isAfterPseudoElement) {
@@ -391,55 +402,55 @@ var NodeActor = exports.NodeActor = prot
         this.isAfterPseudoElement ||
         this.isBeforePseudoElement) {
       return true;
     }
 
     let style = this.computedStyle;
     if (!style) {
       return true;
-    } else {
-      return style.display !== "none";
     }
+
+    return style.display !== "none";
   },
 
   /**
    * Are there event listeners that are listening on this node? This method
    * uses all parsers registered via event-parsers.js.registerEventParser() to
    * check if there are any event listeners.
    */
   get _hasEventListeners() {
     let parsers = this._eventParsers;
-    for (let [,{hasListeners}] of parsers) {
+    for (let [, {hasListeners}] of parsers) {
       try {
         if (hasListeners && hasListeners(this.rawNode)) {
           return true;
         }
       } catch(e) {
         // An object attached to the node looked like a listener but wasn't...
         // do nothing.
       }
     }
     return false;
   },
 
-  writeAttrs: function() {
+  writeAttrs: function () {
     if (!this.rawNode.attributes) {
       return undefined;
     }
 
     // The NamedNodeMap implementation in Firefox (returned by
     // node.attributes) gives attributes in the reverse order compared
     // to the source file when iterated. So reverse the list here.
     return [...this.rawNode.attributes].reverse().map(attr => {
       return {namespace: attr.namespace, name: attr.name, value: attr.value };
     });
   },
 
-  writePseudoClassLocks: function() {
+  writePseudoClassLocks: function () {
     if (this.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
       return undefined;
     }
     let ret = undefined;
     for (let pseudo of PSEUDO_CLASSES) {
       if (DOMUtils.hasPseudoClassLock(this.rawNode, pseudo)) {
         ret = ret || [];
         ret.push(pseudo);
@@ -449,22 +460,22 @@ var NodeActor = exports.NodeActor = prot
   },
 
   /**
    * Gets event listeners and adds their information to the events array.
    *
    * @param  {Node} node
    *         Node for which we are to get listeners.
    */
-  getEventListeners: function(node) {
+  getEventListeners: function (node) {
     let parsers = this._eventParsers;
     let dbg = this.parent().tabActor.makeDebugger();
     let events = [];
 
-    for (let [,{getListeners, normalizeHandler}] of parsers) {
+    for (let [, {getListeners, normalizeHandler}] of parsers) {
       try {
         let eventInfos = getListeners(node);
 
         if (!eventInfos) {
           continue;
         }
 
         for (let eventInfo of eventInfos) {
@@ -511,17 +522,17 @@ var NodeActor = exports.NodeActor = prot
    *             tags: tags,
    *             DOM0: true,
    *             capturing: true,
    *             hide: {
    *               dom0: true
    *             }
    *           }
    */
-  processHandlerForEvent: function(node, events, dbg, eventInfo) {
+  processHandlerForEvent: function (node, events, dbg, eventInfo) {
     let type = eventInfo.type || "";
     let handler = eventInfo.handler;
     let tags = eventInfo.tags || "";
     let hide = eventInfo.hide || {};
     let override = eventInfo.override || {};
     let global = Cu.getGlobalForObject(handler);
     let globalDO = dbg.addDebuggee(global);
     let listenerDO = globalDO.makeDebuggeeValue(handler);
@@ -610,51 +621,51 @@ var NodeActor = exports.NodeActor = prot
     events.push(eventObj);
 
     dbg.removeDebuggee(globalDO);
   },
 
   /**
    * Returns a LongStringActor with the node's value.
    */
-  getNodeValue: method(function() {
+  getNodeValue: method(function () {
     return new LongStringActor(this.conn, this.rawNode.nodeValue || "");
   }, {
     request: {},
     response: {
       value: RetVal("longstring")
     }
   }),
 
   /**
    * Set the node's value to a given string.
    */
-  setNodeValue: method(function(value) {
+  setNodeValue: method(function (value) {
     this.rawNode.nodeValue = value;
   }, {
     request: { value: Arg(0) },
     response: {}
   }),
 
   /**
    * Get a unique selector string for this node.
    */
-  getUniqueSelector: method(function() {
+  getUniqueSelector: method(function () {
     return CssLogic.findCssSelector(this.rawNode);
   }, {
     request: {},
     response: {
       value: RetVal("string")
     }
   }),
 
   /**
    * Scroll the selected node into view.
    */
-  scrollIntoView: method(function() {
+  scrollIntoView: method(function () {
     this.rawNode.scrollIntoView(true);
   }, {
     request: {},
     response: {}
   }),
 
   /**
    * Get the node's image data if any (for canvas and img nodes).
@@ -662,32 +673,32 @@ var NodeActor = exports.NodeActor = prot
    * and a size json object.
    * The image data is transmitted as a base64 encoded png data-uri.
    * The method rejects if the node isn't an image or if the image is missing
    *
    * Accepts a maxDim request parameter to resize images that are larger. This
    * is important as the resizing occurs server-side so that image-data being
    * transfered in the longstring back to the client will be that much smaller
    */
-  getImageData: method(function(maxDim) {
+  getImageData: method(function (maxDim) {
     return imageToImageData(this.rawNode, maxDim).then(imageData => {
       return {
         data: LongStringActor(this.conn, imageData.data),
         size: imageData.size
       };
     });
   }, {
     request: {maxDim: Arg(0, "nullable:number")},
     response: RetVal("imageData")
   }),
 
   /**
    * Get all event listeners that are listening on this node.
    */
-  getEventListenerInfo: method(function() {
+  getEventListenerInfo: method(function () {
     if (this.rawNode.nodeName.toLowerCase() === "html") {
       return this.getEventListeners(this.rawNode.ownerGlobal);
     }
     return this.getEventListeners(this.rawNode);
   }, {
     request: {},
     response: {
       events: RetVal("json")
@@ -702,54 +713,54 @@ var NodeActor = exports.NodeActor = prot
    *   attributeNamespace: <optional string>
    *   newValue: <optional string> - If null or undefined, the attribute
    *     will be removed.
    * }
    *
    * Returns when the modifications have been made.  Mutations will
    * be queued for any changes made.
    */
-  modifyAttributes: method(function(modifications) {
+  modifyAttributes: method(function (modifications) {
     let rawNode = this.rawNode;
     for (let change of modifications) {
       if (change.newValue == null) {
         if (change.attributeNamespace) {
-          rawNode.removeAttributeNS(change.attributeNamespace, change.attributeName);
+          rawNode.removeAttributeNS(change.attributeNamespace,
+                                    change.attributeName);
         } else {
           rawNode.removeAttribute(change.attributeName);
         }
+      } else if (change.attributeNamespace) {
+        rawNode.setAttributeNS(change.attributeNamespace, change.attributeName,
+                               change.newValue);
       } else {
-        if (change.attributeNamespace) {
-          rawNode.setAttributeNS(change.attributeNamespace, change.attributeName, change.newValue);
-        } else {
-          rawNode.setAttribute(change.attributeName, change.newValue);
-        }
+        rawNode.setAttribute(change.attributeName, change.newValue);
       }
     }
   }, {
     request: {
       modifications: Arg(0, "array:json")
     },
     response: {}
   }),
 
   /**
    * Given the font and fill style, get the image data of a canvas with the
    * preview text and font.
    * Returns an imageData object with the actual data being a LongStringActor
    * and the width of the text as a string.
    * The image data is transmitted as a base64 encoded png data-uri.
    */
-  getFontFamilyDataURL: method(function(font, fillStyle="black") {
+  getFontFamilyDataURL: method(function (font, fillStyle = "black") {
     let doc = this.rawNode.ownerDocument;
     let options = {
       previewText: FONT_FAMILY_PREVIEW_TEXT,
       previewFontSize: FONT_FAMILY_PREVIEW_TEXT_SIZE,
       fillStyle: fillStyle
-    }
+    };
     let { dataURL, size } = getFontPreviewData(font, doc, options);
 
     return { data: LongStringActor(this.conn, dataURL), size: size };
   }, {
     request: {font: Arg(0, "string"), fillStyle: Arg(1, "nullable:string")},
     response: RetVal("imageData")
   })
 });
@@ -764,35 +775,39 @@ var NodeActor = exports.NodeActor = prot
  * Children are stored in a doubly-linked list, to make addition/removal
  * and traversal quick.
  *
  * Due to the order/incompleteness of the child list, it is safe to use
  * the parent node from clients, but the `children` request should be used
  * to traverse children.
  */
 var NodeFront = protocol.FrontClass(NodeActor, {
-  initialize: function(conn, form, detail, ctx) {
-    this._parent = null; // The parent node
-    this._child = null;  // The first child of this node.
-    this._next = null;   // The next sibling of this node.
-    this._prev = null;   // The previous sibling of this node.
+  initialize: function (conn, form, detail, ctx) {
+    // The parent node
+    this._parent = null;
+    // The first child of this node.
+    this._child = null;
+    // The next sibling of this node.
+    this._next = null;
+    // The previous sibling of this node.
+    this._prev = null;
     protocol.Front.prototype.initialize.call(this, conn, form, detail, ctx);
   },
 
   /**
    * Destroy a node front.  The node must have been removed from the
    * ownership tree before this is called, unless the whole walker front
    * is being destroyed.
    */
-  destroy: function() {
+  destroy: function () {
     protocol.Front.prototype.destroy.call(this);
   },
 
   // Update the object given a form representation off the wire.
-  form: function(form, detail, ctx) {
+  form: function (form, detail, ctx) {
     if (detail === "actorid") {
       this.actorID = form;
       return;
     }
     // Shallow copy of the form.  We could just store a reference, but
     // eventually we'll want to update some of the data.
     this._form = object.merge(form);
     this._form.attrs = this._form.attrs ? this._form.attrs.slice() : [];
@@ -811,27 +826,27 @@ var NodeFront = protocol.FrontClass(Node
     } else {
       this.singleTextChild = undefined;
     }
   },
 
   /**
    * Returns the parent NodeFront for this NodeFront.
    */
-  parentNode: function() {
+  parentNode: function () {
     return this._parent;
   },
 
   /**
    * Process a mutation entry as returned from the walker's `getMutations`
    * request.  Only tries to handle changes of the node's contents
    * themselves (character data and attribute changes), the walker itself
    * will keep the ownership tree up to date.
    */
-  updateMutation: function(change) {
+  updateMutation: function (change) {
     if (change.type === "attributes") {
       // We'll need to lazily reparse the attributes after this change.
       this._attrMap = undefined;
 
       // Update any already-existing attributes.
       let found = false;
       for (let i = 0; i < this.attributes.length; i++) {
         let attr = this.attributes[i];
@@ -843,17 +858,17 @@ var NodeFront = protocol.FrontClass(Node
             this.attributes.splice(i, 1);
           }
           found = true;
           break;
         }
       }
       // This is a new attribute. The null check is because of Bug 1192270,
       // in the case of a newly added then removed attribute
-      if (!found && change.newValue !== null)  {
+      if (!found && change.newValue !== null) {
         this.attributes.push({
           name: change.attributeName,
           namespace: change.attributeNamespace,
           value: change.newValue
         });
       }
     } else if (change.type === "characterData") {
       this._form.shortValue = change.newValue;
@@ -876,28 +891,28 @@ var NodeFront = protocol.FrontClass(Node
   },
   get namespaceURI() {
     return this._form.namespaceURI;
   },
   get nodeName() {
     return this._form.nodeName;
   },
   get doctypeString() {
-    return '<!DOCTYPE ' + this._form.name +
-     (this._form.publicId ? ' PUBLIC "' +  this._form.publicId + '"': '') +
-     (this._form.systemId ? ' "' + this._form.systemId + '"' : '') +
-     '>';
+    return "<!DOCTYPE " + this._form.name +
+     (this._form.publicId ? " PUBLIC \"" + this._form.publicId + "\"" : "") +
+     (this._form.systemId ? " \"" + this._form.systemId + "\"" : "") +
+     ">";
   },
 
   get baseURI() {
     return this._form.baseURI;
   },
 
   get className() {
-    return this.getAttribute("class") || '';
+    return this.getAttribute("class") || "";
   },
 
   get hasChildren() {
     return this._form.numChildren > 0;
   },
   get numChildren() {
     return this._form.numChildren;
   },
@@ -940,38 +955,38 @@ var NodeFront = protocol.FrontClass(Node
   },
   get publicId() {
     return this._form.publicId;
   },
   get systemId() {
     return this._form.systemId;
   },
 
-  getAttribute: function(name) {
+  getAttribute: function (name) {
     let attr = this._getAttribute(name);
     return attr ? attr.value : null;
   },
-  hasAttribute: function(name) {
+  hasAttribute: function (name) {
     this._cacheAttributes();
     return (name in this._attrMap);
   },
 
   get hidden() {
     let cls = this.getAttribute("class");
     return cls && cls.indexOf(HIDDEN_CLASS) > -1;
   },
 
   get attributes() {
     return this._form.attrs;
   },
 
   get pseudoClassLocks() {
     return this._form.pseudoClassLocks || [];
   },
-  hasPseudoClassLock: function(pseudo) {
+  hasPseudoClassLock: function (pseudo) {
     return this.pseudoClassLocks.some(locked => locked === pseudo);
   },
 
   get isDisplayed() {
     // The NodeActor's form contains the isDisplayed information as a boolean
     // starting from FF32. Before that, the property is missing
     return "isDisplayed" in this._form ? this._form.isDisplayed : true;
   },
@@ -982,68 +997,68 @@ var NodeFront = protocol.FrontClass(Node
       if (!parent.isDisplayed) {
         return false;
       }
       parent = parent.parentNode();
     }
     return true;
   },
 
-  getNodeValue: protocol.custom(function() {
+  getNodeValue: protocol.custom(function () {
     if (!this.incompleteValue) {
       return delayedResolve(new ShortLongString(this.shortValue));
-    } else {
-      return this._getNodeValue();
     }
+
+    return this._getNodeValue();
   }, {
     impl: "_getNodeValue"
   }),
 
   // Accessors for custom form properties.
 
-  getFormProperty: function(name) {
+  getFormProperty: function (name) {
     return this._form.props ? this._form.props[name] : null;
   },
 
-  hasFormProperty: function(name) {
+  hasFormProperty: function (name) {
     return this._form.props ? (name in this._form.props) : null;
   },
 
   get formProperties() {
     return this._form.props;
   },
 
   /**
    * Return a new AttributeModificationList for this node.
    */
-  startModifyingAttributes: function() {
+  startModifyingAttributes: function () {
     return AttributeModificationList(this);
   },
 
-  _cacheAttributes: function() {
-    if (typeof(this._attrMap) != "undefined") {
+  _cacheAttributes: function () {
+    if (typeof this._attrMap != "undefined") {
       return;
     }
     this._attrMap = {};
     for (let attr of this.attributes) {
       this._attrMap[attr.name] = attr;
     }
   },
 
-  _getAttribute: function(name) {
+  _getAttribute: function (name) {
     this._cacheAttributes();
     return this._attrMap[name] || undefined;
   },
 
   /**
    * Set this node's parent.  Note that the children saved in
    * this tree are unordered and incomplete, so shouldn't be used
    * instead of a `children` request.
    */
-  reparent: function(parent) {
+  reparent: function (parent) {
     if (this._parent === parent) {
       return;
     }
 
     if (this._parent && this._parent._child === this) {
       this._parent._child = this._next;
     }
     if (this._prev) {
@@ -1064,64 +1079,65 @@ var NodeFront = protocol.FrontClass(Node
       this._next._prev = this;
     }
     parent._child = this;
   },
 
   /**
    * Return all the known children of this node.
    */
-  treeChildren: function() {
+  treeChildren: function () {
     let ret = [];
     for (let child = this._child; child != null; child = child._next) {
       ret.push(child);
     }
     return ret;
   },
 
   /**
    * Do we use a local target?
    * Useful to know if a rawNode is available or not.
    *
    * This will, one day, be removed. External code should
    * not need to know if the target is remote or not.
    */
-  isLocal_toBeDeprecated: function() {
+  isLocal_toBeDeprecated: function () {
     return !!this.conn._transport._serverConnection;
   },
 
   /**
    * Get an nsIDOMNode for the given node front.  This only works locally,
    * and is only intended as a stopgap during the transition to the remote
    * protocol.  If you depend on this you're likely to break soon.
    */
-  rawNode: function(rawNode) {
+  rawNode: function (rawNode) {
     if (!this.conn._transport._serverConnection) {
       console.warn("Tried to use rawNode on a remote connection.");
       return null;
     }
     let actor = this.conn._transport._serverConnection.getActor(this.actorID);
     if (!actor) {
       // Can happen if we try to get the raw node for an already-expired
       // actor.
       return null;
     }
     return actor.rawNode;
   }
 });
 
 /**
- * Returned from any call that might return a node that isn't connected to root by
- * nodes the child has seen, such as querySelector.
+ * Returned from any call that might return a node that isn't connected to root
+ * by nodes the child has seen, such as querySelector.
  */
 types.addDictType("disconnectedNode", {
   // The actual node to return
   node: "domnode",
 
-  // Nodes that are needed to connect the node to a node the client has already seen
+  // Nodes that are needed to connect the node to a node the client has already
+  // seen
   newParents: "array:domnode"
 });
 
 types.addDictType("disconnectedNodeArray", {
   // The actual node list to return
   nodes: "array:domnode",
 
   // Nodes that are needed to connect those nodes to the root.
@@ -1138,114 +1154,117 @@ types.addDictType("searchresult", {
 });
 
 /**
  * Server side of a node list as returned by querySelectorAll()
  */
 var NodeListActor = exports.NodeListActor = protocol.ActorClass({
   typeName: "domnodelist",
 
-  initialize: function(walker, nodeList) {
+  initialize: function (walker, nodeList) {
     protocol.Actor.prototype.initialize.call(this);
     this.walker = walker;
     this.nodeList = nodeList || [];
   },
 
-  destroy: function() {
+  destroy: function () {
     protocol.Actor.prototype.destroy.call(this);
   },
 
   /**
    * Instead of storing a connection object, the NodeActor gets its connection
    * from its associated walker.
    */
   get conn() {
     return this.walker.conn;
   },
 
   /**
    * Items returned by this actor should belong to the parent walker.
    */
-  marshallPool: function() {
+  marshallPool: function () {
     return this.walker;
   },
 
   // Returns the JSON representation of this object over the wire.
-  form: function() {
+  form: function () {
     return {
       actor: this.actorID,
       length: this.nodeList ? this.nodeList.length : 0
-    }
+    };
   },
 
   /**
    * Get a single node from the node list.
    */
-  item: method(function(index) {
+  item: method(function (index) {
     return this.walker.attachElement(this.nodeList[index]);
   }, {
     request: { item: Arg(0) },
     response: RetVal("disconnectedNode")
   }),
 
   /**
    * Get a range of the items from the node list.
    */
-  items: method(function(start=0, end=this.nodeList.length) {
-    let items = Array.prototype.slice.call(this.nodeList, start, end).map(item => this.walker._ref(item));
+  items: method(function (start = 0, end = this.nodeList.length) {
+    let items = Array.prototype.slice.call(this.nodeList, start, end)
+      .map(item => this.walker._ref(item));
     return this.walker.attachElements(items);
   }, {
     request: {
       start: Arg(0, "nullable:number"),
       end: Arg(1, "nullable:number")
     },
     response: RetVal("disconnectedNodeArray")
   }),
 
-  release: method(function() {}, { release: true })
+  release: method(function () {}, { release: true })
 });
 
 /**
  * Client side of a node list as returned by querySelectorAll()
  */
-var NodeListFront = exports.NodeListFront = protocol.FrontClass(NodeListActor, {
-  initialize: function(client, form) {
+var NodeListFront = protocol.FrontClass(NodeListActor, {
+  initialize: function (client, form) {
     protocol.Front.prototype.initialize.call(this, client, form);
   },
 
-  destroy: function() {
+  destroy: function () {
     protocol.Front.prototype.destroy.call(this);
   },
 
-  marshallPool: function() {
+  marshallPool: function () {
     return this.parent();
   },
 
   // Update the object given a form representation off the wire.
-  form: function(json) {
+  form: function (json) {
     this.length = json.length;
   },
 
-  item: protocol.custom(function(index) {
+  item: protocol.custom(function (index) {
     return this._item(index).then(response => {
       return response.node;
     });
   }, {
     impl: "_item"
   }),
 
-  items: protocol.custom(function(start, end) {
+  items: protocol.custom(function (start, end) {
     return this._items(start, end).then(response => {
       return response.nodes;
     });
   }, {
     impl: "_items"
   })
 });
 
+exports.NodeListFront = NodeListFront;
+
 // Some common request/response templates for the dom walker
 
 var nodeArrayMethod = {
   request: {
     node: Arg(0, "domnode"),
     maxNodes: Option(1),
     center: Option(1, "domnode"),
     start: Option(1, "domnode"),
@@ -1259,17 +1278,17 @@ var nodeArrayMethod = {
 var traversalMethod = {
   request: {
     node: Arg(0, "domnode"),
     whatToShow: Option(1)
   },
   response: {
     node: RetVal("nullable:domnode")
   }
-}
+};
 
 /**
  * Server side of the DOM walker.
  */
 var WalkerActor = protocol.ActorClass({
   typeName: "domwalker",
 
   events: {
@@ -1306,17 +1325,17 @@ var WalkerActor = protocol.ActorClass({
     }
   },
 
   /**
    * Create the WalkerActor
    * @param DebuggerServerConnection conn
    *    The server connection.
    */
-  initialize: function(conn, tabActor, options) {
+  initialize: function (conn, tabActor, options) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
     this.rootWin = tabActor.window;
     this.rootDoc = this.rootWin.document;
     this._refMap = new Map();
     this._pendingMutations = [];
     this._activePseudoClassLocks = new Set();
     this.showAllAnonymousContent = options.showAllAnonymousContent;
@@ -1354,17 +1373,17 @@ var WalkerActor = protocol.ActorClass({
     eventListenerService.addListenerChangeListener(this._onEventListenerChange);
   },
 
   /**
    * Callback for eventListenerService.addListenerChangeListener
    * @param nsISimpleEnumerator changesEnum
    *    enumerator of nsIEventListenerChange
    */
-  _onEventListenerChange: function(changesEnum) {
+  _onEventListenerChange: function (changesEnum) {
     let changes = changesEnum.enumerate();
     while (changes.hasMoreElements()) {
       let current = changes.getNext().QueryInterface(Ci.nsIEventListenerChange);
       let target = current.target;
 
       if (this._refMap.has(target)) {
         let actor = this.getNode(target);
         let mutation = {
@@ -1373,48 +1392,48 @@ var WalkerActor = protocol.ActorClass({
           hasEventListeners: actor._hasEventListeners
         };
         this.queueMutation(mutation);
       }
     }
   },
 
   // Returns the JSON representation of this object over the wire.
-  form: function() {
+  form: function () {
     return {
       actor: this.actorID,
       root: this.rootNode.form(),
       traits: {
         // FF42+ Inspector starts managing the Walker, while the inspector also
         // starts cleaning itself up automatically on client disconnection.
         // So that there is no need to manually release the walker anymore.
         autoReleased: true,
         // XXX: It seems silly that we need to tell the front which capabilities
-        // its actor has in this way when the target can use actorHasMethod.  If
-        // this was ported to the protocol (Bug 1157048) we could call that inside
-        // of custom front methods and not need to do traits for this.
+        // its actor has in this way when the target can use actorHasMethod. If
+        // this was ported to the protocol (Bug 1157048) we could call that
+        // inside of custom front methods and not need to do traits for this.
         multiFrameQuerySelectorAll: true,
         textSearch: true,
       }
-    }
+    };
   },
 
-  toString: function() {
+  toString: function () {
     return "[WalkerActor " + this.actorID + "]";
   },
 
-  getDocumentWalker: function(node, whatToShow) {
+  getDocumentWalker: function (node, whatToShow) {
     // Allow native anon content (like <video> controls) if preffed on
     let nodeFilter = this.showAllAnonymousContent
                         ? allAnonymousContentTreeWalkerFilter
                         : standardTreeWalkerFilter;
     return new DocumentWalker(node, this.rootWin, whatToShow, nodeFilter);
   },
 
-  destroy: function() {
+  destroy: function () {
     if (this._destroyed) {
       return;
     }
     this._destroyed = true;
     protocol.Actor.prototype.destroy.call(this);
     try {
       this.clearPseudoClassLocks();
       this._activePseudoClassLocks = null;
@@ -1447,52 +1466,51 @@ var WalkerActor = protocol.ActorClass({
       this.onMutations = null;
 
       this.tabActor = null;
 
       events.emit(this, "destroyed");
     } catch(e) {
       console.error(e);
     }
-
   },
 
-  release: method(function() {}, { release: true }),
-
-  unmanage: function(actor) {
+  release: method(function () {}, { release: true }),
+
+  unmanage: function (actor) {
     if (actor instanceof NodeActor) {
       if (this._activePseudoClassLocks &&
           this._activePseudoClassLocks.has(actor)) {
         this.clearPseudoClassLocks(actor);
       }
       this._refMap.delete(actor.rawNode);
     }
     protocol.Actor.prototype.unmanage.call(this, actor);
   },
 
   /**
    * Determine if the walker has come across this DOM node before.
    * @param {DOMNode} rawNode
    * @return {Boolean}
    */
-  hasNode: function(rawNode) {
+  hasNode: function (rawNode) {
     return this._refMap.has(rawNode);
   },
 
   /**
    * If the walker has come across this DOM node before, then get the
    * corresponding node actor.
    * @param {DOMNode} rawNode
    * @return {NodeActor}
    */
-  getNode: function(rawNode) {
+  getNode: function (rawNode) {
     return this._refMap.get(rawNode);
   },
 
-  _ref: function(node) {
+  _ref: function (node) {
     let actor = this.getNode(node);
     if (actor) {
       return actor;
     }
 
     actor = new NodeActor(this, node);
 
     // Add the node actor as a child of this walker actor, assigning
@@ -1501,17 +1519,17 @@ var WalkerActor = protocol.ActorClass({
     this._refMap.set(node, actor);
 
     if (node.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) {
       actor.watchDocument(this.onMutations);
     }
     return actor;
   },
 
-  _onReflows: function(reflows) {
+  _onReflows: function (reflows) {
     // Going through the nodes the walker knows about, see which ones have
     // had their display changed and send a display-change event if any
     let changes = [];
     for (let [node, actor] of this._refMap) {
       if (Cu.isDeadWrapper(node)) {
         continue;
       }
 
@@ -1526,17 +1544,17 @@ var WalkerActor = protocol.ActorClass({
     if (changes.length) {
       events.emit(this, "display-change", changes);
     }
   },
 
   /**
    * When the browser window gets resized, relay the event to the front.
    */
-  _onResize: function() {
+  _onResize: function () {
     events.emit(this, "resize");
   },
 
   /**
    * This is kept for backward-compatibility reasons with older remote targets.
    * Targets prior to bug 916443.
    *
    * pick/cancelPick are used to pick a node on click on the content
@@ -1548,41 +1566,46 @@ var WalkerActor = protocol.ActorClass({
    *
    * As for highlight, the new highlighter actor is used instead of the walker's
    * highlight method. Same here though, the client-side uses the highlightable
    * trait to dertermine which to use.
    *
    * Keeping these actor methods for now allows newer client-side debuggers to
    * inspect fxos 1.2 remote targets or older firefox desktop remote targets.
    */
-  pick: method(function() {}, {request: {}, response: RetVal("disconnectedNode")}),
-  cancelPick: method(function() {}),
-  highlight: method(function(node) {}, {request: {node: Arg(0, "nullable:domnode")}}),
+  pick: method(function () {}, {
+    request: {},
+    response: RetVal("disconnectedNode")
+  }),
+  cancelPick: method(function () {}),
+  highlight: method(function (node) {}, {
+    request: {node: Arg(0, "nullable:domnode")}
+  }),
 
   /**
    * Ensures that the node is attached and it can be accessed from the root.
    *
    * @param {(Node|NodeActor)} nodes The nodes
    * @return {Object} An object compatible with the disconnectedNode type.
    */
-  attachElement: function(node) {
+  attachElement: function (node) {
     let { nodes, newParents } = this.attachElements([node]);
     return {
       node: nodes[0],
       newParents: newParents
     };
   },
 
   /**
    * Ensures that the nodes are attached and they can be accessed from the root.
    *
    * @param {(Node[]|NodeActor[])} nodes The nodes
    * @return {Object} An object compatible with the disconnectedNodeArray type.
    */
-  attachElements: function(nodes) {
+  attachElements: function (nodes) {
     let nodeActors = [];
     let newParents = new Set();
     for (let node of nodes) {
       if (!(node instanceof NodeActor)) {
         // If an anonymous node was passed in and we aren't supposed to know
         // about it, then consult with the document walker as the source of
         // truth about which elements exist.
         if (!this.showAllAnonymousContent && isAnonymous(node)) {
@@ -1606,32 +1629,32 @@ var WalkerActor = protocol.ActorClass({
 
   /**
    * Return the document node that contains the given node,
    * or the root node if no node is specified.
    * @param NodeActor node
    *        The node whose document is needed, or null to
    *        return the root.
    */
-  document: method(function(node) {
+  document: method(function (node) {
     let doc = isNodeDead(node) ? this.rootDoc : nodeDocument(node.rawNode);
     return this._ref(doc);
   }, {
     request: { node: Arg(0, "nullable:domnode") },
     response: { node: RetVal("domnode") },
   }),
 
   /**
    * Return the documentElement for the document containing the
    * given node.
    * @param NodeActor node
    *        The node whose documentElement is requested, or null
    *        to use the root document.
    */
-  documentElement: method(function(node) {
+  documentElement: method(function (node) {
     let elt = isNodeDead(node)
               ? this.rootDoc.documentElement
               : nodeDocument(node.rawNode).documentElement;
     return this._ref(elt);
   }, {
     request: { node: Arg(0, "nullable:domnode") },
     response: { node: RetVal("domnode") },
   }),
@@ -1643,31 +1666,33 @@ var WalkerActor = protocol.ActorClass({
    *    The node whose parents are requested.
    * @param object options
    *    Named options, including:
    *    `sameDocument`: If true, parents will be restricted to the same
    *      document as the node.
    *    `sameTypeRootTreeItem`: If true, this will not traverse across
    *     different types of docshells.
    */
-  parents: method(function(node, options={}) {
+  parents: method(function (node, options = {}) {
     if (isNodeDead(node)) {
       return [];
     }
 
     let walker = this.getDocumentWalker(node.rawNode);
     let parents = [];
     let cur;
     while((cur = walker.parentNode())) {
-      if (options.sameDocument && nodeDocument(cur) != nodeDocument(node.rawNode)) {
+      if (options.sameDocument &&
+          nodeDocument(cur) != nodeDocument(node.rawNode)) {
         break;
       }
 
       if (options.sameTypeRootTreeItem &&
-          nodeDocshell(cur).sameTypeRootTreeItem != nodeDocshell(node.rawNode).sameTypeRootTreeItem) {
+          nodeDocshell(cur).sameTypeRootTreeItem !=
+          nodeDocshell(node.rawNode).sameTypeRootTreeItem) {
         break;
       }
 
       parents.push(this._ref(cur));
     }
     return parents;
   }, {
     request: {
@@ -1675,32 +1700,32 @@ var WalkerActor = protocol.ActorClass({
       sameDocument: Option(1),
       sameTypeRootTreeItem: Option(1)
     },
     response: {
       nodes: RetVal("array:domnode")
     },
   }),
 
-  parentNode: function(node) {
+  parentNode: function (node) {
     let walker = this.getDocumentWalker(node.rawNode);
     let parent = walker.parentNode();
     if (parent) {
       return this._ref(parent);
     }
     return null;
   },
 
   /**
    * If the given NodeActor only has a single text node as a child,
    * return that child's NodeActor.
    *
    * @param NodeActor node
    */
-  singleTextChild: function(node) {
+  singleTextChild: function (node) {
     // Quick checks to prevent creating a new walker if possible.
     if (node.isBeforePseudoElement ||
         node.isAfterPseudoElement ||
         node.rawNode.nodeType != Ci.nsIDOMNode.ELEMENT_NODE ||
         node.rawNode.children.length > 0) {
       return undefined;
     }
 
@@ -1730,42 +1755,42 @@ var WalkerActor = protocol.ActorClass({
    *
    * Retained nodes can be deleted by providing the `force` option to
    * `releaseNode`.  They will also be released when their document
    * has been destroyed.
    *
    * Retaining a node makes no promise about its children;  They can
    * still be removed by normal means.
    */
-  retainNode: method(function(node) {
+  retainNode: method(function (node) {
     node.retained = true;
   }, {
     request: { node: Arg(0, "domnode") },
     response: {}
   }),
 
   /**
    * Remove the 'retained' mark from a node.  If the node was a
    * retained orphan, release it.
    */
-  unretainNode: method(function(node) {
+  unretainNode: method(function (node) {
     node.retained = false;
     if (this._retainedOrphans.has(node)) {
       this._retainedOrphans.delete(node);
       this.releaseNode(node);
     }
   }, {
     request: { node: Arg(0, "domnode") },
     response: {},
   }),
 
   /**
    * Release actors for a node and all child nodes.
    */
-  releaseNode: method(function(node, options={}) {
+  releaseNode: method(function (node, options = {}) {
     if (isNodeDead(node)) {
       return;
     }
 
     if (node.retained && !options.force) {
       this._retainedOrphans.add(node);
       return;
     }
@@ -1793,17 +1818,17 @@ var WalkerActor = protocol.ActorClass({
       force: Option(1)
     }
   }),
 
   /**
    * Add any nodes between `node` and the walker's root node that have not
    * yet been seen by the client.
    */
-  ensurePathToRoot: function(node, newParents=new Set()) {
+  ensurePathToRoot: function (node, newParents = new Set()) {
     if (!node) {
       return newParents;
     }
     let walker = this.getDocumentWalker(node.rawNode);
     let cur;
     while ((cur = walker.parentNode())) {
       let parent = this.getNode(cur);
       if (!parent) {
@@ -1836,34 +1861,34 @@ var WalkerActor = protocol.ActorClass({
    *    `whatToShow`: A bitmask of node types that should be included.  See
    *       https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter.
    *
    * @returns an object with three items:
    *    hasFirst: true if the first child of the node is included in the list.
    *    hasLast: true if the last child of the node is included in the list.
    *    nodes: Child nodes returned by the request.
    */
-  children: method(function(node, options={}) {
+  children: method(function (node, options = {}) {
     if (isNodeDead(node)) {
       return { hasFirst: true, hasLast: true, nodes: [] };
     }
 
     if (options.center && options.start) {
       throw Error("Can't specify both 'center' and 'start' options.");
     }
     let maxNodes = options.maxNodes || -1;
     if (maxNodes == -1) {
       maxNodes = Number.MAX_VALUE;
     }
 
     // We're going to create a few document walkers with the same filter,
     // make it easier.
-    let getFilteredWalker = (node) => {
+    let getFilteredWalker = node => {
       return this.getDocumentWalker(node, options.whatToShow);
-    }
+    };
 
     // Need to know the first and last child.
     let rawNode = node.rawNode;
     let firstChild = getFilteredWalker(rawNode).firstChild();
     let lastChild = getFilteredWalker(rawNode).lastChild();
 
     if (!firstChild) {
       // No children, we're done.
@@ -1934,22 +1959,23 @@ var WalkerActor = protocol.ActorClass({
    *    `whatToShow`: A bitmask of node types that should be included.  See
    *       https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter.
    *
    * @returns an object with three items:
    *    hasFirst: true if the first child of the node is included in the list.
    *    hasLast: true if the last child of the node is included in the list.
    *    nodes: Child nodes returned by the request.
    */
-  siblings: method(function(node, options={}) {
+  siblings: method(function (node, options = {}) {
     if (isNodeDead(node)) {
       return { hasFirst: true, hasLast: true, nodes: [] };
     }
 
-    let parentNode = this.getDocumentWalker(node.rawNode, options.whatToShow).parentNode();
+    let parentNode = this.getDocumentWalker(node.rawNode, options.whatToShow)
+                         .parentNode();
     if (!parentNode) {
       return {
         hasFirst: true,
         hasLast: true,
         nodes: [node]
       };
     }
 
@@ -1964,17 +1990,17 @@ var WalkerActor = protocol.ActorClass({
    * Get the next sibling of a given node.  Getting nodes one at a time
    * might be inefficient, be careful.
    *
    * @param object options
    *    Named options:
    *    `whatToShow`: A bitmask of node types that should be included.  See
    *       https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter.
    */
-  nextSibling: method(function(node, options={}) {
+  nextSibling: method(function (node, options = {}) {
     if (isNodeDead(node)) {
       return null;
     }
 
     let walker = this.getDocumentWalker(node.rawNode, options.whatToShow);
     let sibling = walker.nextSibling();
     return sibling ? this._ref(sibling) : null;
   }, traversalMethod),
@@ -1983,45 +2009,45 @@ var WalkerActor = protocol.ActorClass({
    * Get the previous sibling of a given node.  Getting nodes one at a time
    * might be inefficient, be careful.
    *
    * @param object options
    *    Named options:
    *    `whatToShow`: A bitmask of node types that should be included.  See
    *       https://developer.mozilla.org/en-US/docs/Web/API/NodeFilter.
    */
-  previousSibling: method(function(node, options={}) {
+  previousSibling: method(function (node, options = {}) {
     if (isNodeDead(node)) {
       return null;
     }
 
     let walker = this.getDocumentWalker(node.rawNode, options.whatToShow);
     let sibling = walker.previousSibling();
     return sibling ? this._ref(sibling) : null;
   }, traversalMethod),
 
   /**
    * Helper function for the `children` method: Read forward in the sibling
    * list into an array with `count` items, including the current node.
    */
-  _readForward: function(walker, count) {
+  _readForward: function (walker, count) {
     let ret = [];
     let node = walker.currentNode;
     do {
       ret.push(this._ref(node));
       node = walker.nextSibling();
     } while (node && --count);
     return ret;
   },
 
   /**
    * Helper function for the `children` method: Read backward in the sibling
    * list into an array with `count` items, including the current node.
    */
-  _readBackward: function(walker, count) {
+  _readBackward: function (walker, count) {
     let ret = [];
     let node = walker.currentNode;
     do {
       ret.push(this._ref(node));
       node = walker.previousSibling();
     } while(node && --count);
     ret.reverse();
     return ret;
@@ -2029,44 +2055,44 @@ var WalkerActor = protocol.ActorClass({
 
   /**
    * Return the node that the parent process has asked to
    * inspect. This node is expected to be stored in gInspectingNode
    * (which is set by a message manager message to the child.js frame
    * script). The node is returned over the remote debugging protocol
    * as a NodeFront.
    */
-  findInspectingNode: method(function() {
+  findInspectingNode: method(function () {
     let node = gInspectingNode;
     if (!node) {
-      return {}
-    };
+      return {};
+    }
 
     return this.attachElement(node);
   }, {
     request: {},
     response: RetVal("disconnectedNode")
   }),
 
   /**
    * Return the first node in the document that matches the given selector.
    * See https://developer.mozilla.org/en-US/docs/Web/API/Element.querySelector
    *
    * @param NodeActor baseNode
    * @param string selector
    */
-  querySelector: method(function(baseNode, selector) {
+  querySelector: method(function (baseNode, selector) {
     if (isNodeDead(baseNode)) {
       return {};
     }
 
     let node = baseNode.rawNode.querySelector(selector);
     if (!node) {
-      return {}
-    };
+      return {};
+    }
 
     return this.attachElement(node);
   }, {
     request: {
       node: Arg(0, "domnode"),
       selector: Arg(1)
     },
     response: RetVal("disconnectedNode")
@@ -2074,17 +2100,17 @@ var WalkerActor = protocol.ActorClass({
 
   /**
    * Return a NodeListActor with all nodes that match the given selector.
    * See https://developer.mozilla.org/en-US/docs/Web/API/Element.querySelectorAll
    *
    * @param NodeActor baseNode
    * @param string selector
    */
-  querySelectorAll: method(function(baseNode, selector) {
+  querySelectorAll: method(function (baseNode, selector) {
     let nodeList = null;
 
     try {
       nodeList = baseNode.rawNode.querySelectorAll(selector);
     } catch(e) {
       // Bad selector. Do nothing as the selector can come from a searchbox.
     }
 
@@ -2100,17 +2126,17 @@ var WalkerActor = protocol.ActorClass({
   }),
 
   /**
    * Get a list of nodes that match the given selector in all known frames of
    * the current content page.
    * @param {String} selector.
    * @return {Array}
    */
-  _multiFrameQuerySelectorAll: function(selector) {
+  _multiFrameQuerySelectorAll: function (selector) {
     let nodes = [];
 
     for (let {document} of this.tabActor.windows) {
       try {
         nodes = [...nodes, ...document.querySelectorAll(selector)];
       } catch(e) {
         // Bad selector. Do nothing as the selector can come from a searchbox.
       }
@@ -2119,17 +2145,17 @@ var WalkerActor = protocol.ActorClass({
     return nodes;
   },
 
   /**
    * Return a NodeListActor with all nodes that match the given selector in all
    * frames of the current content page.
    * @param {String} selector
    */
-  multiFrameQuerySelectorAll: method(function(selector) {
+  multiFrameQuerySelectorAll: method(function (selector) {
     return new NodeListActor(this, this._multiFrameQuerySelectorAll(selector));
   }, {
     request: {
       selector: Arg(0)
     },
     response: {
       list: RetVal("domnodelist")
     }
@@ -2140,24 +2166,24 @@ var WalkerActor = protocol.ActorClass({
    * Results will be searched with the walker-search module (searches through
    * tag names, attribute names and values, and text contents).
    *
    * @returns {searchresult}
    *            - {NodeList} list
    *            - {Array<Object>} metadata. Extra information with indices that
    *                              match up with node list.
    */
-  search: method(function(query) {
+  search: method(function (query) {
     let results = this.walkerSearch.search(query);
     let nodeList = new NodeListActor(this, results.map(r => r.node));
 
     return {
       list: nodeList,
       metadata: []
-    }
+    };
   }, {
     request: {
       query: Arg(0),
     },
     response: {
       list: RetVal("searchresult"),
     }
   }),
@@ -2167,37 +2193,36 @@ var WalkerActor = protocol.ActorClass({
    *
    * @param string query
    *        The selector query being completed
    * @param string completing
    *        The exact token being completed out of the query
    * @param string selectorState
    *        One of "pseudo", "id", "tag", "class", "null"
    */
-  getSuggestionsForQuery: method(function(query, completing, selectorState) {
+  getSuggestionsForQuery: method(function (query, completing, selectorState) {
     let sugs = {
-      classes: new Map,
-      tags: new Map,
-      ids: new Map
+      classes: new Map(),
+      tags: new Map(),
+      ids: new Map()
     };
     let result = [];
     let nodes = null;
     // Filtering and sorting the results so that protocol transfer is miminal.
     switch (selectorState) {
       case "pseudo":
         result = PSEUDO_SELECTORS.filter(item => {
           return item[0].startsWith(":" + completing);
         });
         break;
 
       case "class":
         if (!query) {
           nodes = this._multiFrameQuerySelectorAll("[class]");
-        }
-        else {
+        } else {
           nodes = this._multiFrameQuerySelectorAll(query);
         }
         for (let node of nodes) {
           for (let className of node.classList) {
             sugs.classes.set(className, (sugs.classes.get(className)|0) + 1);
           }
         }
         sugs.classes.delete("");
@@ -2211,35 +2236,33 @@ var WalkerActor = protocol.ActorClass({
             result.push(["." + CSS.escape(className), count, selectorState]);
           }
         }
         break;
 
       case "id":
         if (!query) {
           nodes = this._multiFrameQuerySelectorAll("[id]");
-        }
-        else {
+        } else {
           nodes = this._multiFrameQuerySelectorAll(query);
         }
         for (let node of nodes) {
           sugs.ids.set(node.id, (sugs.ids.get(node.id)|0) + 1);
         }
         for (let [id, count] of sugs.ids) {
           if (id.startsWith(completing)) {
             result.push(["#" + CSS.escape(id), count, selectorState]);
           }
         }
         break;
 
       case "tag":
         if (!query) {
           nodes = this._multiFrameQuerySelectorAll("*");
-        }
-        else {
+        } else {
           nodes = this._multiFrameQuerySelectorAll(query);
         }
         for (let node of nodes) {
           let tag = node.tagName.toLowerCase();
           sugs.tags.set(tag, (sugs.tags.get(tag)|0) + 1);
         }
         for (let [tag, count] of sugs.tags) {
           if ((new RegExp("^" + completing + ".*", "i")).test(tag)) {
@@ -2247,18 +2270,20 @@ var WalkerActor = protocol.ActorClass({
           }
         }
 
         // For state 'tag' (no preceding # or .) and when there's no query (i.e.
         // only one word) then search for the matching classes and ids
         if (!query) {
           result = [
             ...result,
-            ...this.getSuggestionsForQuery(null, completing, "class").suggestions,
-            ...this.getSuggestionsForQuery(null, completing, "id").suggestions
+            ...this.getSuggestionsForQuery(null, completing, "class")
+                   .suggestions,
+            ...this.getSuggestionsForQuery(null, completing, "id")
+                   .suggestions
           ];
         }
 
         break;
 
       case "null":
         nodes = this._multiFrameQuerySelectorAll(query);
         for (let node of nodes) {
@@ -2284,40 +2309,36 @@ var WalkerActor = protocol.ActorClass({
         for (let [className, count] of sugs.classes) {
           className && result.push(["." + className, count]);
         }
     }
 
     // Sort by count (desc) and name (asc)
     result = result.sort((a, b) => {
       // Computed a sortable string with first the inverted count, then the name
-      let sortA = (10000-a[1]) + a[0];
-      let sortB = (10000-b[1]) + b[0];
+      let sortA = (10000 - a[1]) + a[0];
+      let sortB = (10000 - b[1]) + b[0];
 
       // Prefixing ids, classes and tags, to group results
       let firstA = a[0].substring(0, 1);
       let firstB = b[0].substring(0, 1);
 
       if (firstA === "#") {
         sortA = "2" + sortA;
-      }
-      else if (firstA === ".") {
+      } else if (firstA === ".") {
         sortA = "1" + sortA;
-      }
-      else {
+      } else {
         sortA = "0" + sortA;
       }
 
       if (firstB === "#") {
         sortB = "2" + sortB;
-      }
-      else if (firstB === ".") {
+      } else if (firstB === ".") {
         sortB = "1" + sortB;
-      }
-      else {
+      } else {
         sortB = "0" + sortB;
       }
 
       // String compare
       return sortA.localeCompare(sortB);
     });
 
     result.slice(0, 25);
@@ -2346,17 +2367,17 @@ var WalkerActor = protocol.ActorClass({
    * @param options
    *    Options object:
    *    `parents`: True if the pseudo-class should be added
    *      to parent nodes.
    *
    * @returns An empty packet.  A "pseudoClassLock" mutation will
    *    be queued for any changed nodes.
    */
-  addPseudoClassLock: method(function(node, pseudo, options={}) {
+  addPseudoClassLock: method(function (node, pseudo, options = {}) {
     if (isNodeDead(node)) {
       return;
     }
 
     this._addPseudoClassLock(node, pseudo);
 
     if (!options.parents) {
       return;
@@ -2372,60 +2393,60 @@ var WalkerActor = protocol.ActorClass({
     request: {
       node: Arg(0, "domnode"),
       pseudoClass: Arg(1),
       parents: Option(2)
     },
     response: {}
   }),
 
-  _queuePseudoClassMutation: function(node) {
+  _queuePseudoClassMutation: function (node) {
     this.queueMutation({
       target: node.actorID,
       type: "pseudoClassLock",
       pseudoClassLocks: node.writePseudoClassLocks()
     });
   },
 
-  _addPseudoClassLock: function(node, pseudo) {
+  _addPseudoClassLock: function (node, pseudo) {
     if (node.rawNode.nodeType !== Ci.nsIDOMNode.ELEMENT_NODE) {
       return false;
     }
     DOMUtils.addPseudoClassLock(node.rawNode, pseudo);
     this._activePseudoClassLocks.add(node);
     this._queuePseudoClassMutation(node);
     return true;
   },
 
-  _installHelperSheet: function(node) {
+  _installHelperSheet: function (node) {
     if (!this.installedHelpers) {
-      this.installedHelpers = new WeakMap;
+      this.installedHelpers = new WeakMap();
     }
     let win = node.rawNode.ownerDocument.defaultView;
     if (!this.installedHelpers.has(win)) {
       let { Style } = require("sdk/stylesheet/style");
       let { attach } = require("sdk/content/mod");
       let style = Style({source: HELPER_SHEET, type: "agent" });
       attach(style, win);
       this.installedHelpers.set(win, style);
     }
   },
 
-  hideNode: method(function(node) {
+  hideNode: method(function (node) {
     if (isNodeDead(node)) {
       return;
     }
 
     this._installHelperSheet(node);
     node.rawNode.classList.add(HIDDEN_CLASS);
   }, {
     request: { node: Arg(0, "domnode") }
   }),
 
-  unhideNode: method(function(node) {
+  unhideNode: method(function (node) {
     if (isNodeDead(node)) {
       return;
     }
 
     node.rawNode.classList.remove(HIDDEN_CLASS);
   }, {
     request: { node: Arg(0, "domnode") }
   }),
@@ -2439,17 +2460,17 @@ var WalkerActor = protocol.ActorClass({
    * @param options
    *    Options object:
    *    `parents`: True if the pseudo-class should be removed
    *      from parent nodes.
    *
    * @returns An empty response.  "pseudoClassLock" mutations
    *    will be emitted for any changed nodes.
    */
-  removePseudoClassLock: method(function(node, pseudo, options={}) {
+  removePseudoClassLock: method(function (node, pseudo, options = {}) {
     if (isNodeDead(node)) {
       return;
     }
 
     this._removePseudoClassLock(node, pseudo);
 
     if (!options.parents) {
       return;
@@ -2465,34 +2486,34 @@ var WalkerActor = protocol.ActorClass({
     request: {
       node: Arg(0, "domnode"),
       pseudoClass: Arg(1),
       parents: Option(2)
     },
     response: {}
   }),
 
-  _removePseudoClassLock: function(node, pseudo) {
+  _removePseudoClassLock: function (node, pseudo) {
     if (node.rawNode.nodeType != Ci.nsIDOMNode.ELEMENT_NODE) {
       return false;
     }
     DOMUtils.removePseudoClassLock(node.rawNode, pseudo);
     if (!node.writePseudoClassLocks()) {
       this._activePseudoClassLocks.delete(node);
     }
 
     this._queuePseudoClassMutation(node);
     return true;
   },
 
   /**
    * Clear all the pseudo-classes on a given node or all nodes.
    * @param {NodeActor} node Optional node to clear pseudo-classes on
    */
-  clearPseudoClassLocks: method(function(node) {
+  clearPseudoClassLocks: method(function (node) {
     if (node && isNodeDead(node)) {
       return;
     }
 
     if (node) {
       DOMUtils.clearPseudoClassLocks(node.rawNode);
       this._activePseudoClassLocks.delete(node);
       this._queuePseudoClassMutation(node);
@@ -2508,17 +2529,17 @@ var WalkerActor = protocol.ActorClass({
       node: Arg(0, "nullable:domnode")
     },
     response: {}
   }),
 
   /**
    * Get a node's innerHTML property.
    */
-  innerHTML: method(function(node) {
+  innerHTML: method(function (node) {
     let html = "";
     if (!isNodeDead(node)) {
       html = node.rawNode.innerHTML;
     }
     return LongStringActor(this.conn, html);
   }, {
     request: {
       node: Arg(0, "domnode")
@@ -2529,39 +2550,40 @@ var WalkerActor = protocol.ActorClass({
   }),
 
   /**
    * Set a node's innerHTML property.
    *
    * @param {NodeActor} node The node.
    * @param {string} value The piece of HTML content.
    */
-  setInnerHTML: method(function(node, value) {
+  setInnerHTML: method(function (node, value) {
     if (isNodeDead(node)) {
       return;
     }
 
     let rawNode = node.rawNode;
-    if (rawNode.nodeType !== rawNode.ownerDocument.ELEMENT_NODE)
+    if (rawNode.nodeType !== rawNode.ownerDocument.ELEMENT_NODE) {
       throw new Error("Can only change innerHTML to element nodes");
+    }
     rawNode.innerHTML = value;
   }, {
     request: {
       node: Arg(0, "domnode"),
       value: Arg(1, "string"),
     },
     response: {}
   }),
 
   /**
    * Get a node's outerHTML property.
    *
    * @param {NodeActor} node The node.
    */
-  outerHTML: method(function(node) {
+  outerHTML: method(function (node) {
     let outerHTML = "";
     if (!isNodeDead(node)) {
       outerHTML = node.rawNode.outerHTML;
     }
     return LongStringActor(this.conn, outerHTML);
   }, {
     request: {
       node: Arg(0, "domnode")
@@ -2572,17 +2594,17 @@ var WalkerActor = protocol.ActorClass({
   }),
 
   /**
    * Set a node's outerHTML property.
    *
    * @param {NodeActor} node The node.
    * @param {string} value The piece of HTML content.
    */
-  setOuterHTML: method(function(node, value) {
+  setOuterHTML: method(function (node, value) {
     if (isNodeDead(node)) {
       return;
     }
 
     let parsedDOM = DOMParser.parseFromString(value, "text/html");
     let rawNode = node.rawNode;
     let parentNode = rawNode.parentNode;
 
@@ -2636,19 +2658,19 @@ var WalkerActor = protocol.ActorClass({
   /**
    * Insert adjacent HTML to a node.
    *
    * @param {Node} node
    * @param {string} position One of "beforeBegin", "afterBegin", "beforeEnd",
    *                          "afterEnd" (see Element.insertAdjacentHTML).
    * @param {string} value The HTML content.
    */
-  insertAdjacentHTML: method(function(node, position, value) {
+  insertAdjacentHTML: method(function (node, position, value) {
     if (isNodeDead(node)) {
-      return {node: [], newParents: []}
+      return {node: [], newParents: []};
     }
 
     let rawNode = node.rawNode;
     // Don't insert anything adjacent to the document element,
     // the head or the body.
     if (node.isDocumentElement()) {
       throw new Error("Can't insert adjacent element to the root.");
     }
@@ -2680,25 +2702,26 @@ var WalkerActor = protocol.ActorClass({
     switch (position) {
       case "beforeBegin":
         rawParentNode.insertBefore(docFrag, rawNode);
         break;
       case "afterEnd":
         // Note: if the second argument is null, rawParentNode.insertBefore
         // behaves like rawParentNode.appendChild.
         rawParentNode.insertBefore(docFrag, rawNode.nextSibling);
+        break;
       case "afterBegin":
         rawNode.insertBefore(docFrag, rawNode.firstChild);
         break;
       case "beforeEnd":
         rawNode.appendChild(docFrag);
         break;
       default:
-        throw new Error('Invalid position value. Must be either ' +
-          '"beforeBegin", "beforeEnd", "afterBegin" or "afterEnd".');
+        throw new Error("Invalid position value. Must be either " +
+          "'beforeBegin', 'beforeEnd', 'afterBegin' or 'afterEnd'.");
     }
 
     return this.attachElements(newRawNodes);
   }, {
     request: {
       node: Arg(0, "domnode"),
       position: Arg(1, "string"),
       value: Arg(2, "string")
@@ -2706,45 +2729,45 @@ var WalkerActor = protocol.ActorClass({
     response: RetVal("disconnectedNodeArray")
   }),
 
   /**
    * Duplicate a specified node
    *
    * @param {NodeActor} node The node to duplicate.
    */
-  duplicateNode: method(function({rawNode}) {
+  duplicateNode: method(function ({rawNode}) {
     let clonedNode = rawNode.cloneNode(true);
     rawNode.parentNode.insertBefore(clonedNode, rawNode.nextSibling);
   }, {
     request: {
       node: Arg(0, "domnode")
     },
     response: {}
   }),
 
   /**
    * Test whether a node is a document or a document element.
    *
    * @param {NodeActor} node The node to remove.
    * @return {boolean} True if the node is a document or a document element.
    */
-  isDocumentOrDocumentElementNode: function(node) {
-      return ((node.rawNode.ownerDocument &&
-        node.rawNode.ownerDocument.documentElement === this.rawNode) ||
-        node.rawNode.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE);
+  isDocumentOrDocumentElementNode: function (node) {
+    return ((node.rawNode.ownerDocument &&
+      node.rawNode.ownerDocument.documentElement === this.rawNode) ||
+      node.rawNode.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE);
   },
 
   /**
    * Removes a node from its parent node.
    *
    * @param {NodeActor} node The node to remove.
    * @returns The node's nextSibling before it was removed.
    */
-  removeNode: method(function(node) {
+  removeNode: method(function (node) {
     if (isNodeDead(node) || this.isDocumentOrDocumentElementNode(node)) {
       throw Error("Cannot remove document, document elements or dead nodes.");
     }
 
     let nextSibling = this.nextSibling(node);
     node.rawNode.remove();
     // Mutation events will take care of the rest.
     return nextSibling;
@@ -2757,17 +2780,17 @@ var WalkerActor = protocol.ActorClass({
     }
   }),
 
   /**
    * Removes an array of nodes from their parent node.
    *
    * @param {NodeActor[]} nodes The nodes to remove.
    */
-  removeNodes: method(function(nodes) {
+  removeNodes: method(function (nodes) {
     // Check that all nodes are valid before processing the removals.
     for (let node of nodes) {
       if (isNodeDead(node) || this.isDocumentOrDocumentElementNode(node)) {
         throw Error("Cannot remove document, document elements or dead nodes");
       }
     }
 
     for (let node of nodes) {
@@ -2779,17 +2802,17 @@ var WalkerActor = protocol.ActorClass({
       node: Arg(0, "array:domnode")
     },
     response: {}
   }),
 
   /**
    * Insert a node into the DOM.
    */
-  insertBefore: method(function(node, parent, sibling) {
+  insertBefore: method(function (node, parent, sibling) {
     if (isNodeDead(node) ||
         isNodeDead(parent) ||
         (sibling && isNodeDead(sibling))) {
       return null;
     }
 
     let rawNode = node.rawNode;
     let rawParent = parent.rawNode;
@@ -2798,17 +2821,17 @@ var WalkerActor = protocol.ActorClass({
     // Don't bother inserting a node if the document position isn't going
     // to change. This prevents needless iframes reloading and mutations.
     if (rawNode.parentNode === rawParent) {
       let currentNextSibling = this.nextSibling(node);
       currentNextSibling = currentNextSibling ? currentNextSibling.rawNode :
                                                 null;
 
       if (rawNode === rawSibling || currentNextSibling === rawSibling) {
-        return;
+        return null;
       }
     }
 
     rawParent.insertBefore(rawNode, rawSibling);
   }, {
     request: {
       node: Arg(0, "domnode"),
       parent: Arg(1, "domnode"),
@@ -2818,36 +2841,37 @@ var WalkerActor = protocol.ActorClass({
   }),
 
   /**
    * Editing a node's tagname actually means creating a new node with the same
    * attributes, removing the node and inserting the new one instead.
    * This method does not return anything as mutation events are taking care of
    * informing the consumers about changes.
    */
-  editTagName: method(function(node, tagName) {
+  editTagName: method(function (node, tagName) {
     if (isNodeDead(node)) {
-      return;
+      return null;
     }
 
     let oldNode = node.rawNode;
 
     // Create a new element with the same attributes as the current element and
     // prepare to replace the current node with it.
     let newNode;
     try {
       newNode = nodeDocument(oldNode).createElement(tagName);
     } catch(x) {
       // Failed to create a new element with that tag name, ignore the change,
       // and signal the error to the front.
-      return Promise.reject(new Error("Could not change node's tagName to " + tagName));
+      return Promise.reject(new Error("Could not change node's tagName to " +
+        tagName));
     }
 
     let attrs = oldNode.attributes;
-    for (let i = 0; i < attrs.length; i ++) {
+    for (let i = 0; i < attrs.length; i++) {
       newNode.setAttribute(attrs[i].name, attrs[i].value);
     }
 
     // Insert the new node, and transfer the old node's children.
     oldNode.parentNode.insertBefore(newNode, oldNode);
     while (oldNode.firstChild) {
       newNode.appendChild(oldNode.firstChild);
     }
@@ -2901,17 +2925,17 @@ var WalkerActor = protocol.ActorClass({
    * or by being removed from the tree entirely), and is considered
    * 'orphaned'.
    *
    * Keep in mind that if a node that the client hasn't seen is moved
    * into or out of the target node, it will not be included in the
    * removedNodes and addedNodes list, so if the client is interested
    * in the new set of children it needs to issue a `children` request.
    */
-  getMutations: method(function(options={}) {
+  getMutations: method(function (options = {}) {
     let pending = this._pendingMutations || [];
     this._pendingMutations = [];
 
     if (options.cleanup) {
       for (let node of this._orphaned) {
         // Release the orphaned node.  Nodes or children that have been
         // retained will be moved to this._retainedOrphans.
         this.releaseNode(node);
@@ -2924,17 +2948,17 @@ var WalkerActor = protocol.ActorClass({
     request: {
       cleanup: Option(0)
     },
     response: {
       mutations: RetVal("array:dommutation")
     }
   }),
 
-  queueMutation: function(mutation) {
+  queueMutation: function (mutation) {
     if (!this.actorID || this._destroyed) {
       // We've been destroyed, don't bother queueing this mutation.
       return;
     }
     // We only send the `new-mutations` notification once, until the client
     // fetches mutations with the `getMutations` packet.
     let needEvent = this._pendingMutations.length === 0;
 
@@ -2946,17 +2970,17 @@ var WalkerActor = protocol.ActorClass({
   },
 
   /**
    * Handles mutations from the DOM mutation observer API.
    *
    * @param array[MutationRecord] mutations
    *    See https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver#MutationRecord
    */
-  onMutations: function(mutations) {
+  onMutations: function (mutations) {
     // Notify any observers that want *all* mutations (even on nodes that aren't
     // referenced).  This is not sent over the protocol so can only be used by
     // scripts running in the server process.
     events.emit(this, "any-mutation");
 
     for (let change of mutations) {
       let targetActor = this.getNode(change.target);
       if (!targetActor) {
@@ -2972,17 +2996,18 @@ var WalkerActor = protocol.ActorClass({
       if (type === "attributes") {
         mutation.attributeName = change.attributeName;
         mutation.attributeNamespace = change.attributeNamespace || undefined;
         mutation.newValue = targetNode.hasAttribute(mutation.attributeName) ?
                             targetNode.getAttribute(mutation.attributeName)
                             : null;
       } else if (type === "characterData") {
         if (targetNode.nodeValue.length > gValueSummaryLength) {
-          mutation.newValue = targetNode.nodeValue.substring(0, gValueSummaryLength);
+          mutation.newValue = targetNode.nodeValue
+            .substring(0, gValueSummaryLength);
           mutation.incompleteValue = true;
         } else {
           mutation.newValue = targetNode.nodeValue;
         }
       } else if (type === "childList" || type === "nativeAnonymousChildList") {
         // Get the list of removed and added actors that the client has seen
         // so that it can keep its ownership tree up to date.
         let removedActors = [];
@@ -3021,17 +3046,17 @@ var WalkerActor = protocol.ActorClass({
         if (singleTextChild) {
           mutation.singleTextChild = singleTextChild.form();
         }
       }
       this.queueMutation(mutation);
     }
   },
 
-  onFrameLoad: function({ window, isTopLevel }) {
+  onFrameLoad: function ({ window, isTopLevel }) {
     if (!this.rootDoc && isTopLevel) {
       this.rootDoc = window.document;
       this.rootNode = this.document();
       this.queueMutation({
         type: "newRoot",
         target: this.rootNode.form()
       });
       return;
@@ -3048,32 +3073,32 @@ var WalkerActor = protocol.ActorClass({
     });
 
     // Send a childList mutation on the frame.
     this.queueMutation({
       type: "childList",
       target: frameActor.actorID,
       added: [],
       removed: []
-    })
+    });
   },
 
   // Returns true if domNode is in window or a subframe.
-  _childOfWindow: function(window, domNode) {
+  _childOfWindow: function (window, domNode) {
     let win = nodeDocument(domNode).defaultView;
     while (win) {
       if (win === window) {
         return true;
       }
       win = getFrameElement(win);
     }
     return false;
   },
 
-  onFrameUnload: function({ window }) {
+  onFrameUnload: function ({ window }) {
     // Any retained orphans that belong to this document
     // or its children need to be released, and a mutation sent
     // to notify of that.
     let releasedOrphans = [];
 
     for (let retained of this._retainedOrphans) {
       if (Cu.isDeadWrapper(retained.rawNode) ||
           this._childOfWindow(window, retained.rawNode)) {
@@ -3126,17 +3151,17 @@ var WalkerActor = protocol.ActorClass({
   },
 
   /**
    * Check if a node is attached to the DOM tree of the current page.
    * @param {nsIDomNode} rawNode
    * @return {Boolean} false if the node is removed from the tree or within a
    * document fragment
    */
-  _isInDOMTree: function(rawNode) {
+  _isInDOMTree: function (rawNode) {
     let walker = this.getDocumentWalker(rawNode);
     let current = walker.currentNode;
 
     // Reaching the top of tree
     while (walker.parentNode()) {
       current = walker.currentNode;
     }
 
@@ -3149,31 +3174,32 @@ var WalkerActor = protocol.ActorClass({
 
     // Otherwise the top of the tree is rootDoc, hence rawNode is in rootDoc
     return true;
   },
 
   /**
    * @see _isInDomTree
    */
-  isInDOMTree: method(function(node) {
+  isInDOMTree: method(function (node) {
     if (isNodeDead(node)) {
       return false;
     }
     return this._isInDOMTree(node.rawNode);
   }, {
     request: { node: Arg(0, "domnode") },
     response: { attached: RetVal("boolean") }
   }),
 
   /**
    * Given an ObjectActor (identified by its ID), commonly used in the debugger,
-   * webconsole and variablesView, return the corresponding inspector's NodeActor
+   * webconsole and variablesView, return the corresponding inspector's
+   * NodeActor
    */
-  getNodeActorFromObjectActor: method(function(objectActorID) {
+  getNodeActorFromObjectActor: method(function (objectActorID) {
     let actor = this.conn.getActor(objectActorID);
     if (!actor) {
       return null;
     }
 
     let debuggerObject = this.conn.getActor(objectActorID).obj;
     let rawNode = debuggerObject.unsafeDereference();
 
@@ -3198,17 +3224,17 @@ var WalkerActor = protocol.ActorClass({
   }),
 
   /**
    * Given a StyleSheetActor (identified by its ID), commonly used in the
    * style-editor, get its ownerNode and return the corresponding walker's
    * NodeActor.
    * Note that getNodeFromActor was added later and can now be used instead.
    */
-  getStyleSheetOwnerNode: method(function(styleSheetActorID) {
+  getStyleSheetOwnerNode: method(function (styleSheetActorID) {
     return this.getNodeFromActor(styleSheetActorID, ["ownerNode"]);
   }, {
     request: {
       styleSheetActorID: Arg(0, "string")
     },
     response: {
       ownerNode: RetVal("nullable:disconnectedNode")
     }
@@ -3236,19 +3262,20 @@ var WalkerActor = protocol.ActorClass({
    *   toolbox.getPanel("inspector").selection.setNodeFront(nodeFront);
    * });
    *
    * @param {String} actorID The ID for the actor that has a reference to the
    * DOM node.
    * @param {Array} path Where, on the actor, is the DOM node stored. If in the
    * scope of the actor, the node is available as `this.data.node`, then this
    * should be ["data", "node"].
-   * @return {NodeActor} The attached NodeActor, or null if it couldn't be found.
+   * @return {NodeActor} The attached NodeActor, or null if it couldn't be
+   * found.
    */
-  getNodeFromActor: method(function(actorID, path) {
+  getNodeFromActor: method(function (actorID, path) {
     let actor = this.conn.getActor(actorID);
     if (!actor) {
       return null;
     }
 
     let obj = actor;
     for (let name of path) {
       if (!(name in obj)) {
@@ -3267,80 +3294,80 @@ var WalkerActor = protocol.ActorClass({
       node: RetVal("nullable:disconnectedNode")
     }
   })
 });
 
 /**
  * Client side of the DOM walker.
  */
-var WalkerFront = exports.WalkerFront = protocol.FrontClass(WalkerActor, {
+var WalkerFront = protocol.FrontClass(WalkerActor, {
   // Set to true if cleanup should be requested after every mutation list.
   autoCleanup: true,
 
   /**
    * This is kept for backward-compatibility reasons with older remote target.
    * Targets previous to bug 916443
    */
-  pick: protocol.custom(function() {
+  pick: protocol.custom(function () {
     return this._pick().then(response => {
       return response.node;
     });
   }, {impl: "_pick"}),
 
-  initialize: function(client, form) {
+  initialize: function (client, form) {
     this._createRootNodePromise();
     protocol.Front.prototype.initialize.call(this, client, form);
     this._orphaned = new Set();
     this._retainedOrphans = new Set();
   },
 
-  destroy: function() {
+  destroy: function () {
     protocol.Front.prototype.destroy.call(this);
   },
 
   // Update the object given a form representation off the wire.
-  form: function(json) {
+  form: function (json) {
     this.actorID = json.actor;
     this.rootNode = types.getType("domnode").read(json.root, this);
     this._rootNodeDeferred.resolve(this.rootNode);
     // FF42+ the actor starts exposing traits
     this.traits = json.traits || {};
   },
 
   /**
    * Clients can use walker.rootNode to get the current root node of the
    * walker, but during a reload the root node might be null.  This
    * method returns a promise that will resolve to the root node when it is
    * set.
    */
-  getRootNode: function() {
+  getRootNode: function () {
     return this._rootNodeDeferred.promise;
   },
 
   /**
    * Create the root node promise, triggering the "new-root" notification
    * on resolution.
    */
-  _createRootNodePromise: function() {
+  _createRootNodePromise: function () {
     this._rootNodeDeferred = promise.defer();
     this._rootNodeDeferred.promise.then(() => {
       events.emit(this, "new-root");
     });
   },
 
   /**
    * When reading an actor form off the wire, we want to hook it up to its
    * parent front.  The protocol guarantees that the parent will be seen
    * by the client in either a previous or the current request.
    * So if we've already seen this parent return it, otherwise create
    * a bare-bones stand-in node.  The stand-in node will be updated
    * with a real form by the end of the deserialization.
    */
-  ensureParentFront: function(id) {
+  ensureParentFront: function (id) {
     let front = this.get(id);
     if (front) {
       return front;
     }
 
     return types.getType("domnode").read({ actor: id }, this, "standin");
   },
 
@@ -3359,79 +3386,79 @@ var WalkerFront = exports.WalkerFront = 
    * node, this request will fail with noSuchActor, but the ownership tree
    * will stay in a consistent state.
    *
    * Because the protocol guarantees that requests will be processed and
    * responses received in the order they were sent, we get the right
    * semantics by setting our local retained flag on the node only AFTER
    * a SUCCESSFUL retainNode call.
    */
-  retainNode: protocol.custom(function(node) {
+  retainNode: protocol.custom(function (node) {
     return this._retainNode(node).then(() => {
       node.retained = true;
     });
   }, {
     impl: "_retainNode",
   }),
 
-  unretainNode: protocol.custom(function(node) {
+  unretainNode: protocol.custom(function (node) {
     return this._unretainNode(node).then(() => {
       node.retained = false;
       if (this._retainedOrphans.has(node)) {
         this._retainedOrphans.delete(node);
         this._releaseFront(node);
       }
     });
   }, {
     impl: "_unretainNode"
   }),
 
-  releaseNode: protocol.custom(function(node, options={}) {
+  releaseNode: protocol.custom(function (node, options = {}) {
     // NodeFront.destroy will destroy children in the ownership tree too,
     // mimicking what the server will do here.
     let actorID = node.actorID;
     this._releaseFront(node, !!options.force);
     return this._releaseNode({ actorID: actorID });
   }, {
     impl: "_releaseNode"
   }),
 
-  findInspectingNode: protocol.custom(function() {
+  findInspectingNode: protocol.custom(function () {
     return this._findInspectingNode().then(response => {
       return response.node;
     });
   }, {
     impl: "_findInspectingNode"
   }),
 
-  querySelector: protocol.custom(function(queryNode, selector) {
+  querySelector: protocol.custom(function (queryNode, selector) {
     return this._querySelector(queryNode, selector).then(response => {
       return response.node;
     });
   }, {
     impl: "_querySelector"
   }),
 
-  getNodeActorFromObjectActor: protocol.custom(function(objectActorID) {
+  getNodeActorFromObjectActor: protocol.custom(function (objectActorID) {
     return this._getNodeActorFromObjectActor(objectActorID).then(response => {
       return response ? response.node : null;
     });
   }, {
     impl: "_getNodeActorFromObjectActor"
   }),
 
-  getStyleSheetOwnerNode: protocol.custom(function(styleSheetActorID) {
+  getStyleSheetOwnerNode: protocol.custom(function (styleSheetActorID) {
     return this._getStyleSheetOwnerNode(styleSheetActorID).then(response => {
       return response ? response.node : null;
     });
   }, {
     impl: "_getStyleSheetOwnerNode"
   }),
 
-  getNodeFromActor: protocol.custom(function(actorID, path) {
+  getNodeFromActor: protocol.custom(function (actorID, path) {
     return this._getNodeFromActor(actorID, path).then(response => {
       return response ? response.node : null;
     });
   }, {
     impl: "_getNodeFromActor"
   }),
 
   /*
@@ -3498,17 +3525,17 @@ var WalkerFront = exports.WalkerFront = 
       node: node,
       resultsLength: nodeList.length,
       resultsIndex: searchData.index,
     };
   }), {
     impl: "_search"
   }),
 
-  _releaseFront: function(node, force) {
+  _releaseFront: function (node, force) {
     if (node.retained && !force) {
       node.reparent(null);
       this._retainedOrphans.add(node);
       return;
     }
 
     if (node.retained) {
       // Forcing a removal.
@@ -3523,17 +3550,17 @@ var WalkerFront = exports.WalkerFront = 
     // All children will have been removed from the node by this point.
     node.reparent(null);
     node.destroy();
   },
 
   /**
    * Get any unprocessed mutation records and process them.
    */
-  getMutations: protocol.custom(function(options={}) {
+  getMutations: protocol.custom(function (options = {}) {
     return this._getMutations(options).then(mutations => {
       let emitMutations = [];
       for (let change of mutations) {
         // The target is only an actorID, get the associated front.
         let targetID;
         let targetFront;
 
         if (change.type === "newRoot") {
@@ -3542,47 +3569,51 @@ var WalkerFront = exports.WalkerFront = 
           targetID = this.rootNode.actorID;
           targetFront = this.rootNode;
         } else {
           targetID = change.target;
           targetFront = this.get(targetID);
         }
 
         if (!targetFront) {
-          console.trace("Got a mutation for an unexpected actor: " + targetID + ", please file a bug on bugzilla.mozilla.org!");
+          console.trace("Got a mutation for an unexpected actor: " + targetID +
+            ", please file a bug on bugzilla.mozilla.org!");
           continue;
         }
 
         let emittedMutation = object.merge(change, { target: targetFront });
 
-        if (change.type === "childList" || change.type === "nativeAnonymousChildList") {
+        if (change.type === "childList" ||
+            change.type === "nativeAnonymousChildList") {
           // Update the ownership tree according to the mutation record.
           let addedFronts = [];
           let removedFronts = [];
           for (let removed of change.removed) {
             let removedFront = this.get(removed);
             if (!removedFront) {
-              console.error("Got a removal of an actor we didn't know about: " + removed);
+              console.error("Got a removal of an actor we didn't know about: " +
+                removed);
               continue;
             }
             // Remove from the ownership tree
             removedFront.reparent(null);
 
             // This node is orphaned unless we get it in the 'added' list
             // eventually.
             this._orphaned.add(removedFront);
             removedFronts.push(removedFront);
           }
           for (let added of change.added) {
             let addedFront = this.get(added);
             if (!addedFront) {
-              console.error("Got an addition of an actor we didn't know about: " + added);
+              console.error("Got an addition of an actor we didn't know " +
+                "about: " + added);
               continue;
             }
-            addedFront.reparent(targetFront)
+            addedFront.reparent(targetFront);
 
             // The actor is reconnected to the ownership tree, unorphan
             // it.
             this._orphaned.delete(addedFront);
             addedFronts.push(addedFront);
           }
 
           if (change.singleTextChild) {
@@ -3595,26 +3626,27 @@ var WalkerFront = exports.WalkerFront = 
           // Before passing to users, replace the added and removed actor
           // ids with front in the mutation record.
           emittedMutation.added = addedFronts;
           emittedMutation.removed = removedFronts;
 
           // If this is coming from a DOM mutation, the actor's numChildren
           // was passed in. Otherwise, it is simulated from a frame load or
           // unload, so don't change the front's form.
-          if ('numChildren' in change) {
+          if ("numChildren" in change) {
             targetFront._form.numChildren = change.numChildren;
           }
         } else if (change.type === "frameLoad") {
           // Nothing we need to do here, except verify that we don't have any
           // document children, because we should have gotten a documentUnload
           // first.
           for (let child of targetFront.treeChildren()) {
             if (child.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) {
-              console.trace("Got an unexpected frameLoad in the inspector, please file a bug on bugzilla.mozilla.org!");
+              console.trace("Got an unexpected frameLoad in the inspector, " +
+                "please file a bug on bugzilla.mozilla.org!");
             }
           }
         } else if (change.type === "documentUnload") {
           if (targetFront === this.rootNode) {
             this._createRootNodePromise();
           }
 
           // We try to give fronts instead of actorIDs, but these fronts need
@@ -3652,150 +3684,155 @@ var WalkerFront = exports.WalkerFront = 
   }, {
     impl: "_getMutations"
   }),
 
   /**
    * Handle the `new-mutations` notification by fetching the
    * available mutation records.
    */
-  onMutations: protocol.preEvent("new-mutations", function() {
+  onMutations: protocol.preEvent("new-mutations", function () {
     // Fetch and process the mutations.
     this.getMutations({cleanup: this.autoCleanup}).catch(() => {});
   }),
 
-  isLocal: function() {
+  isLocal: function () {
     return !!this.conn._transport._serverConnection;
   },
 
   // XXX hack during transition to remote inspector: get a proper NodeFront
   // for a given local node.  Only works locally.
-  frontForRawNode: function(rawNode) {
+  frontForRawNode: function (rawNode) {
     if (!this.isLocal()) {
       console.warn("Tried to use frontForRawNode on a remote connection.");
       return null;
     }
-    let walkerActor = this.conn._transport._serverConnection.getActor(this.actorID);
+    let walkerActor = this.conn._transport._serverConnection
+      .getActor(this.actorID);
     if (!walkerActor) {
       throw Error("Could not find client side for actor " + this.actorID);
     }
     let nodeActor = walkerActor._ref(rawNode);
 
     // Pass the node through a read/write pair to create the client side actor.
     let nodeType = types.getType("domnode");
-    let returnNode = nodeType.read(nodeType.write(nodeActor, walkerActor), this);
+    let returnNode = nodeType.read(
+      nodeType.write(nodeActor, walkerActor), this);
     let top = returnNode;
     let extras = walkerActor.parents(nodeActor, {sameTypeRootTreeItem: true});
     for (let extraActor of extras) {
       top = nodeType.read(nodeType.write(extraActor, walkerActor), this);
     }
 
     if (top !== this.rootNode) {
       // Imported an already-orphaned node.
       this._orphaned.add(top);
-      walkerActor._orphaned.add(this.conn._transport._serverConnection.getActor(top.actorID));
+      walkerActor._orphaned
+        .add(this.conn._transport._serverConnection.getActor(top.actorID));
     }
     return returnNode;
   },
 
   removeNode: protocol.custom(Task.async(function* (node) {
     let previousSibling = yield this.previousSibling(node);
     let nextSibling = yield this._removeNode(node);
     return {
       previousSibling: previousSibling,
       nextSibling: nextSibling,
     };
   }), {
     impl: "_removeNode"
   }),
 });
 
+exports.WalkerFront = WalkerFront;
+
 /**
  * Convenience API for building a list of attribute modifications
  * for the `modifyAttributes` request.
  */
 var AttributeModificationList = Class({
-  initialize: function(node) {
+  initialize: function (node) {
     this.node = node;
     this.modifications = [];
   },
 
-  apply: function() {
+  apply: function () {
     let ret = this.node.modifyAttributes(this.modifications);
     return ret;
   },
 
-  destroy: function() {
+  destroy: function () {
     this.node = null;
     this.modification = null;
   },
 
-  setAttributeNS: function(ns, name, value) {
+  setAttributeNS: function (ns, name, value) {
     this.modifications.push({
       attributeNamespace: ns,
       attributeName: name,
       newValue: value
     });
   },
 
-  setAttribute: function(name, value) {
+  setAttribute: function (name, value) {
     this.setAttributeNS(undefined, name, value);
   },
 
-  removeAttributeNS: function(ns, name) {
+  removeAttributeNS: function (ns, name) {
     this.setAttributeNS(ns, name, undefined);
   },
 
-  removeAttribute: function(name) {
+  removeAttribute: function (name) {
     this.setAttributeNS(undefined, name, undefined);
   }
-})
+});
 
 /**
  * Server side of the inspector actor, which is used to create
  * inspector-related actors, including the walker.
  */
 var InspectorActor = exports.InspectorActor = protocol.ActorClass({
   typeName: "inspector",
 
-  initialize: function(conn, tabActor) {
+  initialize: function (conn, tabActor) {
     protocol.Actor.prototype.initialize.call(this, conn);
     this.tabActor = tabActor;
   },
 
   destroy: function () {
     protocol.Actor.prototype.destroy.call(this);
 
     this._highlighterPromise = null;
     this._pageStylePromise = null;
     this._walkerPromise = null;
     this.walker = null;
     this.tabActor = null;
   },
 
   // Forces destruction of the actor and all its children
   // like highlighter, walker and style actors.
-  disconnect: function() {
+  disconnect: function () {
     this.destroy();
   },
 
   get window() {
     return this.tabActor.window;
   },
 
-  getWalker: method(function(options={}) {
+  getWalker: method(function (options = {}) {
     if (this._walkerPromise) {
       return this._walkerPromise;
     }
 
     let deferred = promise.defer();
     this._walkerPromise = deferred.promise;
 
     let window = this.window;
-    var domReady = () => {
+    let domReady = () => {
       let tabActor = this.tabActor;
       window.removeEventListener("DOMContentLoaded", domReady, true);
       this.walker = WalkerActor(this.conn, tabActor, options);
       this.manage(this.walker);
       events.once(this.walker, "destroyed", () => {
         this._walkerPromise = null;
         this._pageStylePromise = null;
       });
@@ -3813,17 +3850,17 @@ var InspectorActor = exports.InspectorAc
     request: {
       options: Arg(0, "nullable:json")
     },
     response: {
       walker: RetVal("domwalker")
     }
   }),
 
-  getPageStyle: method(function() {
+  getPageStyle: method(function () {
     if (this._pageStylePromise) {
       return this._pageStylePromise;
     }
 
     this._pageStylePromise = this.getWalker().then(walker => {
       let pageStyle = PageStyleActor(this);
       this.manage(pageStyle);
       return pageStyle;
@@ -3878,19 +3915,18 @@ var InspectorActor = exports.InspectorAc
    *
    * @param {String} type The type of highlighter to create
    * @return {Highlighter} The highlighter actor instance or null if the
    * typeName passed doesn't match any available highlighter
    */
   getHighlighterByType: method(function (typeName) {
     if (isTypeRegistered(typeName)) {
       return CustomHighlighterActor(this, typeName);
-    } else {
-      return null;
     }
+    return null;
   }, {
     request: {
       typeName: Arg(0)
     },
     response: {
       highlighter: RetVal("nullable:customhighlighter")
     }
   }),
@@ -3925,117 +3961,123 @@ var InspectorActor = exports.InspectorAc
   /**
    * Resolve a URL to its absolute form, in the scope of a given content window.
    * @param {String} url.
    * @param {NodeActor} node If provided, the owner window of this node will be
    * used to resolve the URL. Otherwise, the top-level content window will be
    * used instead.
    * @return {String} url.
    */
-  resolveRelativeURL: method(function(url, node) {
+  resolveRelativeURL: method(function (url, node) {
     let document = isNodeDead(node)
                    ? this.window.document
                    : nodeDocument(node.rawNode);
 
     if (!document) {
       return url;
-    } else {
-      let baseURI = Services.io.newURI(document.location.href, null, null);
-      return Services.io.newURI(url, null, baseURI).spec;
     }
+
+    let baseURI = Services.io.newURI(document.location.href, null, null);
+    return Services.io.newURI(url, null, baseURI).spec;
   }, {
     request: {url: Arg(0, "string"), node: Arg(1, "nullable:domnode")},
     response: {value: RetVal("string")}
   })
 });
 
 /**
  * Client side of the inspector actor, which is used to create
  * inspector-related actors, including the walker.
  */
-var InspectorFront = exports.InspectorFront = protocol.FrontClass(InspectorActor, {
-  initialize: function(client, tabForm) {
+var InspectorFront = protocol.FrontClass(InspectorActor, {
+  initialize: function (client, tabForm) {
     protocol.Front.prototype.initialize.call(this, client);
     this.actorID = tabForm.inspectorActor;
 
     // XXX: This is the first actor type in its hierarchy to use the protocol
     // library, so we're going to self-own on the client side for now.
     this.manage(this);
   },
 
-  destroy: function() {
+  destroy: function () {
     delete this.walker;
     protocol.Front.prototype.destroy.call(this);
   },
 
-  getWalker: protocol.custom(function(options = {}) {
+  getWalker: protocol.custom(function (options = {}) {
     return this._getWalker(options).then(walker => {
       this.walker = walker;
       return walker;
     });
   }, {
     impl: "_getWalker"
   }),
 
-  getPageStyle: protocol.custom(function() {
+  getPageStyle: protocol.custom(function () {
     return this._getPageStyle().then(pageStyle => {
       // We need a walker to understand node references from the
       // node style.
       if (this.walker) {
         return pageStyle;
       }
       return this.getWalker().then(() => {
         return pageStyle;
       });
     });
   }, {
     impl: "_getPageStyle"
   })
 });
 
+exports.InspectorFront = InspectorFront;
+
 // Exported for test purposes.
 exports._documentWalker = DocumentWalker;
 
 function nodeDocument(node) {
   if (Cu.isDeadWrapper(node)) {
     return null;
   }
-  return node.ownerDocument || (node.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE ? node : null);
+  return node.ownerDocument ||
+         (node.nodeType == Ci.nsIDOMNode.DOCUMENT_NODE ? node : null);
 }
 
 function nodeDocshell(node) {
   let doc = node ? nodeDocument(node) : null;
   let win = doc ? doc.defaultView : null;
   if (win) {
-    return win.
-           QueryInterface(Ci.nsIInterfaceRequestor).
-           getInterface(Ci.nsIDocShell);
+    return win.QueryInterface(Ci.nsIInterfaceRequestor)
+              .getInterface(Ci.nsIDocShell);
   }
 }
 
 function isNodeDead(node) {
   return !node || !node.rawNode || Cu.isDeadWrapper(node.rawNode);
 }
 
 /**
  * Wrapper for inDeepTreeWalker.  Adds filtering to the traversal methods.
  * See inDeepTreeWalker for more information about the methods.
  *
  * @param {DOMNode} node
  * @param {Window} rootWin
- * @param {Int} whatToShow See Ci.nsIDOMNodeFilter / inIDeepTreeWalker for options.
+ * @param {Int} whatToShow See Ci.nsIDOMNodeFilter / inIDeepTreeWalker for
+ * options.
  * @param {Function} filter A custom filter function Taking in a DOMNode
  *        and returning an Int. See WalkerActor.nodeFilter for an example.
  */
-function DocumentWalker(node, rootWin, whatToShow=Ci.nsIDOMNodeFilter.SHOW_ALL, filter=standardTreeWalkerFilter) {
+function DocumentWalker(node, rootWin,
+    whatToShow = Ci.nsIDOMNodeFilter.SHOW_ALL,
+    filter = standardTreeWalkerFilter) {
   if (!rootWin.location) {
     throw new Error("Got an invalid root window in DocumentWalker");
   }
 
-  this.walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"].createInstance(Ci.inIDeepTreeWalker);
+  this.walker = Cc["@mozilla.org/inspector/deep-tree-walker;1"]
+    .createInstance(Ci.inIDeepTreeWalker);
   this.walker.showAnonymousContent = true;
   this.walker.showSubDocuments = true;
   this.walker.showDocumentsAsNodes = true;
   this.walker.init(rootWin.document, whatToShow);
   this.filter = filter;
 
   // Make sure that the walker knows about the initial node (which could
   // be skipped due to a filter).  Note that simply calling parentNode()
@@ -4052,75 +4094,78 @@ DocumentWalker.prototype = {
     return this.walker.node;
   },
   get whatToShow() {
     return this.walker.whatToShow;
   },
   get currentNode() {
     return this.walker.currentNode;
   },
-  set currentNode(aVal) {
-    this.walker.currentNode = aVal;
+  set currentNode(val) {
+    this.walker.currentNode = val;
   },
 
-  parentNode: function() {
+  parentNode: function () {
     return this.walker.parentNode();
   },
 
   nextNode: function() {
     let node = this.walker.currentNode;
     if (!node) {
       return null;
     }
 
     let nextNode = this.walker.nextNode();
-    while (nextNode && this.filter(nextNode) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+    while (nextNode &&
+           this.filter(nextNode) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
       nextNode = this.walker.nextNode();
     }
 
     return nextNode;
   },
 
-  firstChild: function() {
+  firstChild: function () {
     let node = this.walker.currentNode;
     if (!node) {
       return null;
     }
 
     let firstChild = this.walker.firstChild();
-    while (firstChild && this.filter(firstChild) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+    while (firstChild &&
+           this.filter(firstChild) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
       firstChild = this.walker.nextSibling();
     }
 
     return firstChild;
   },
 
-  lastChild: function() {
+  lastChild: function () {
     let node = this.walker.currentNode;
     if (!node) {
       return null;
     }
 
     let lastChild = this.walker.lastChild();
-    while (lastChild && this.filter(lastChild) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
+    while (lastChild &&
+           this.filter(lastChild) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
       lastChild = this.walker.previousSibling();
     }
 
     return lastChild;
   },
 
-  previousSibling: function() {
+  previousSibling: function () {
     let node = this.walker.previousSibling();
     while (node && this.filter(node) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
       node = this.walker.previousSibling();
     }
     return node;
   },
 
-  nextSibling: function() {
+  nextSibling: function () {
     let node = this.walker.nextSibling();
     while (node && this.filter(node) === Ci.nsIDOMNodeFilter.FILTER_SKIP) {
       node = this.walker.nextSibling();
     }
     return node;
   }
 };
 
@@ -4131,54 +4176,54 @@ function isInXULDocument(el) {
          doc.documentElement.namespaceURI === XUL_NS;
 }
 
 /**
  * This DeepTreeWalker filter skips whitespace text nodes and anonymous
  * content with the exception of ::before and ::after and anonymous content
  * in XUL document (needed to show all elements in the browser toolbox).
  */
-function standardTreeWalkerFilter(aNode) {
+function standardTreeWalkerFilter(node) {
   // ::before and ::after are native anonymous content, but we always
   // want to show them
-  if (aNode.nodeName === "_moz_generated_content_before" ||
-      aNode.nodeName === "_moz_generated_content_after") {
+  if (node.nodeName === "_moz_generated_content_before" ||
+      node.nodeName === "_moz_generated_content_after") {
     return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
   }
 
   // Ignore empty whitespace text nodes.
-  if (aNode.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
-      !/[^\s]/.exec(aNode.nodeValue)) {
+  if (node.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
+      !/[^\s]/.exec(node.nodeValue)) {
     return Ci.nsIDOMNodeFilter.FILTER_SKIP;
   }
 
   // Ignore all native and XBL anonymous content inside a non-XUL document
-  if (!isInXULDocument(aNode) && (isXBLAnonymous(aNode) ||
-                                  isNativeAnonymous(aNode))) {
+  if (!isInXULDocument(node) && (isXBLAnonymous(node) ||
+                                  isNativeAnonymous(node))) {
     // Note: this will skip inspecting the contents of feedSubscribeLine since
     // that's XUL content injected in an HTML document, but we need to because
     // this also skips many other elements that need to be skipped - like form
     // controls, scrollbars, video controls, etc (see bug 1187482).
     return Ci.nsIDOMNodeFilter.FILTER_SKIP;
   }
 
   return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
 }
 
 /**
  * This DeepTreeWalker filter is like standardTreeWalkerFilter except that
  * it also includes all anonymous content (like internal form controls).
  */
-function allAnonymousContentTreeWalkerFilter(aNode) {
+function allAnonymousContentTreeWalkerFilter(node) {
   // Ignore empty whitespace text nodes.
-  if (aNode.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
-      !/[^\s]/.exec(aNode.nodeValue)) {
+  if (node.nodeType == Ci.nsIDOMNode.TEXT_NODE &&
+      !/[^\s]/.exec(node.nodeValue)) {
     return Ci.nsIDOMNodeFilter.FILTER_SKIP;
   }
-  return Ci.nsIDOMNodeFilter.FILTER_ACCEPT
+  return Ci.nsIDOMNodeFilter.FILTER_ACCEPT;
 }
 
 /**
  * Returns a promise that is settled once the given HTMLImageElement has
  * finished loading.
  *
  * @param {HTMLImageElement} image - The image element.
  * @param {Number} timeout - Maximum amount of time the image is allowed to load
@@ -4244,17 +4289,17 @@ function ensureImageLoaded(image, timeou
  */
 var imageToImageData = Task.async(function* (node, maxDim) {
   let { HTMLCanvasElement, HTMLImageElement } = node.ownerDocument.defaultView;
 
   let isImg = node instanceof HTMLImageElement;
   let isCanvas = node instanceof HTMLCanvasElement;
 
   if (!isImg && !isCanvas) {
-    throw "node is not a <canvas> or <img> element.";
+    throw new Error("node is not a <canvas> or <img> element.");
   }
 
   if (isImg) {
     // Ensure that the image is ready.
     yield ensureImageLoaded(node, IMAGE_FETCHING_TIMEOUT);
   }
 
   // Get the image resize ratio if a maxDim was provided
@@ -4286,14 +4331,14 @@ var imageToImageData = Task.async(functi
 
   return {
     data: imageData,
     size: {
       naturalWidth: imgWidth,
       naturalHeight: imgHeight,
       resized: resizeRatio !== 1
     }
-  }
+  };
 });
 
 loader.lazyGetter(this, "DOMUtils", function () {
   return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
 });
--- a/devtools/server/actors/webbrowser.js
+++ b/devtools/server/actors/webbrowser.js
@@ -42,71 +42,74 @@ function getWindowID(window) {
                .getInterface(Ci.nsIDOMWindowUtils)
                .currentInnerWindowID;
 }
 
 function getDocShellChromeEventHandler(docShell) {
   let handler = docShell.chromeEventHandler;
   if (!handler) {
     try {
-      // toplevel xul window's docshell doesn't have chromeEventHandler attribute
-      // the chrome event handler is just the global window object
+      // Toplevel xul window's docshell doesn't have chromeEventHandler
+      // attribute. The chrome event handler is just the global window object.
       handler = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                         .getInterface(Ci.nsIDOMWindow);
-    } catch(e) {}
+    } catch (e) {
+      // ignore
+    }
   }
   return handler;
 }
-function getChildDocShells(docShell) {
-  let docShellsEnum = docShell.getDocShellEnumerator(
+
+function getChildDocShells(parentDocShell) {
+  let docShellsEnum = parentDocShell.getDocShellEnumerator(
     Ci.nsIDocShellTreeItem.typeAll,
     Ci.nsIDocShell.ENUMERATE_FORWARDS
   );
 
   let docShells = [];
   while (docShellsEnum.hasMoreElements()) {
     let docShell = docShellsEnum.getNext();
     docShell.QueryInterface(Ci.nsIInterfaceRequestor)
             .getInterface(Ci.nsIWebProgress);
     docShells.push(docShell);
   }
   return docShells;
 }
+
 exports.getChildDocShells = getChildDocShells;
 
 /**
  * Browser-specific actors.
  */
 
 function getInnerId(window) {
-  return window.QueryInterface(Ci.nsIInterfaceRequestor).
-                getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
-};
+  return window.QueryInterface(Ci.nsIInterfaceRequestor)
+               .getInterface(Ci.nsIDOMWindowUtils).currentInnerWindowID;
+}
 
 /**
- * Yield all windows of type |aWindowType|, from the oldest window to the
+ * Yield all windows of type |windowType|, from the oldest window to the
  * youngest, using nsIWindowMediator::getEnumerator. We're usually
  * interested in "navigator:browser" windows.
  */
-function* allAppShellDOMWindows(aWindowType)
-{
-  let e = Services.wm.getEnumerator(aWindowType);
+function* allAppShellDOMWindows(windowType) {
+  let e = Services.wm.getEnumerator(windowType);
   while (e.hasMoreElements()) {
     yield e.getNext();
   }
 }
 
 exports.allAppShellDOMWindows = allAppShellDOMWindows;
 
 /**
- * Retrieve the window type of the top-level window |aWindow|.
+ * Retrieve the window type of the top-level window |window|.
  */
-function appShellDOMWindowType(aWindow) {
+function appShellDOMWindowType(window) {
   /* This is what nsIWindowMediator's enumerator checks. */
-  return aWindow.document.documentElement.getAttribute('windowtype');
+  return window.document.documentElement.getAttribute("windowtype");
 }
 
 /**
  * Send Debugger:Shutdown events to all "navigator:browser" windows.
  */
 function sendShutdownEvent() {
   for (let win of allAppShellDOMWindows(DebuggerServer.chromeWindowType)) {
     let evt = win.document.createEvent("Event");
@@ -120,45 +123,43 @@ exports.sendShutdownEvent = sendShutdown
 /**
  * Construct a root actor appropriate for use in a server running in a
  * browser. The returned root actor:
  * - respects the factories registered with DebuggerServer.addGlobalActor,
  * - uses a BrowserTabList to supply tab actors,
  * - sends all navigator:browser window documents a Debugger:Shutdown event
  *   when it exits.
  *
- * * @param aConnection DebuggerServerConnection
- *        The conection to the client.
+ * * @param connection DebuggerServerConnection
+ *          The conection to the client.
  */
-function createRootActor(aConnection)
-{
-  return new RootActor(aConnection,
-                       {
-                         tabList: new BrowserTabList(aConnection),
-                         addonList: new BrowserAddonList(aConnection),
-                         workerList: new WorkerActorList(aConnection, {}),
-                         serviceWorkerRegistrationList:
-                           new ServiceWorkerRegistrationActorList(aConnection),
-                         processList: new ProcessActorList(),
-                         globalActorFactories: DebuggerServer.globalActorFactories,
-                         onShutdown: sendShutdownEvent
-                       });
+function createRootActor(connection) {
+  return new RootActor(connection, {
+    tabList: new BrowserTabList(connection),
+    addonList: new BrowserAddonList(connection),
+    workerList: new WorkerActorList(connection, {}),
+    serviceWorkerRegistrationList:
+      new ServiceWorkerRegistrationActorList(connection),
+    processList: new ProcessActorList(),
+    globalActorFactories: DebuggerServer.globalActorFactories,
+    onShutdown: sendShutdownEvent
+  });
 }
 
 /**
  * A live list of BrowserTabActors representing the current browser tabs,
  * to be provided to the root actor to answer 'listTabs' requests.
  *
  * This object also takes care of listening for TabClose events and
  * onCloseWindow notifications, and exiting the BrowserTabActors concerned.
  *
  * (See the documentation for RootActor for the definition of the "live
  * list" interface.)
  *
- * @param aConnection DebuggerServerConnection
+ * @param connection DebuggerServerConnection
  *     The connection in which this list's tab actors may participate.
  *
  * Some notes:
  *
  * This constructor is specific to the desktop browser environment; it
  * maintains the tab list by tracking XUL windows and their XUL documents'
  * "tabbrowser", "tab", and "browser" elements. What's entailed in maintaining
  * an accurate list of open tabs in this context?
@@ -208,19 +209,18 @@ function createRootActor(aConnection)
  *
  * However, while we could thus assume that each tab stays with the XUL window
  * it belonged to when it was created, I'm not sure this is behavior one should
  * rely upon. When a XUL window is closed, we take the less efficient, more
  * conservative approach of simply searching the entire table for actors that
  * belong to the closing XUL window, rather than trying to somehow track which
  * XUL window each tab belongs to.
  */
-function BrowserTabList(aConnection)
-{
-  this._connection = aConnection;
+function BrowserTabList(connection) {
+  this._connection = connection;
 
   /*
    * The XUL document of a tabbed browser window has "tab" elements, whose
    * 'linkedBrowser' JavaScript properties are "browser" elements; those
    * browsers' 'contentWindow' properties are wrappers on the tabs' content
    * window objects.
    *
    * This map's keys are "browser" XUL elements; it maps each browser element
@@ -255,59 +255,59 @@ function BrowserTabList(aConnection)
   this._mustNotify = false;
 
   /* True if we're testing, and should throw if consistency checks fail. */
   this._testing = false;
 }
 
 BrowserTabList.prototype.constructor = BrowserTabList;
 
-
 /**
  * Get the selected browser for the given navigator:browser window.
  * @private
- * @param aWindow nsIChromeWindow
+ * @param window nsIChromeWindow
  *        The navigator:browser window for which you want the selected browser.
  * @return nsIDOMElement|null
  *         The currently selected xul:browser element, if any. Note that the
  *         browser window might not be loaded yet - the function will return
  *         |null| in such cases.
  */
-BrowserTabList.prototype._getSelectedBrowser = function(aWindow) {
-  return aWindow.gBrowser ? aWindow.gBrowser.selectedBrowser : null;
+BrowserTabList.prototype._getSelectedBrowser = function (window) {
+  return window.gBrowser ? window.gBrowser.selectedBrowser : null;
 };
 
 /**
  * Produces an iterable (in this case a generator) to enumerate all available
  * browser tabs.
  */
-BrowserTabList.prototype._getBrowsers = function*() {
+BrowserTabList.prototype._getBrowsers = function* () {
   // Iterate over all navigator:browser XUL windows.
   for (let win of allAppShellDOMWindows(DebuggerServer.chromeWindowType)) {
     // For each tab in this XUL window, ensure that we have an actor for
     // it, reusing existing actors where possible. We actually iterate
     // over 'browser' XUL elements, and BrowserTabActor uses
     // browser.contentWindow as the debuggee global.
     for (let browser of this._getChildren(win)) {
       yield browser;
     }
   }
 };
 
-BrowserTabList.prototype._getChildren = function(aWindow) {
-  let children = aWindow.gBrowser ? aWindow.gBrowser.browsers : [];
+BrowserTabList.prototype._getChildren = function (window) {
+  let children = window.gBrowser ? window.gBrowser.browsers : [];
   return children ? children : [];
 };
 
-BrowserTabList.prototype._isRemoteBrowser = function(browser) {
+BrowserTabList.prototype._isRemoteBrowser = function (browser) {
   return browser.getAttribute("remote") == "true";
 };
 
-BrowserTabList.prototype.getList = function() {
-  let topXULWindow = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
+BrowserTabList.prototype.getList = function () {
+  let topXULWindow = Services.wm.getMostRecentWindow(
+    DebuggerServer.chromeWindowType);
   let selectedBrowser = null;
   if (topXULWindow) {
     selectedBrowser = this._getSelectedBrowser(topXULWindow);
   }
 
   // As a sanity check, make sure all the actors presently in our map get
   // picked up when we iterate over all windows' tabs.
   let initialMapSize = this._actorByBrowser.size;
@@ -327,133 +327,140 @@ BrowserTabList.prototype.getList = funct
           .then(actor => {
             // Set the 'selected' properties on all actors correctly.
             actor.selected = selected;
             return actor;
           })
     );
   }
 
-  if (this._testing && initialMapSize !== this._foundCount)
-    throw Error("_actorByBrowser map contained actors for dead tabs");
+  if (this._testing && initialMapSize !== this._foundCount) {
+    throw new Error("_actorByBrowser map contained actors for dead tabs");
+  }
 
   this._mustNotify = true;
   this._checkListening();
 
   return promise.all(actorPromises);
 };
 
-BrowserTabList.prototype._getActorForBrowser = function(browser) {
+BrowserTabList.prototype._getActorForBrowser = function (browser) {
   // Do we have an existing actor for this browser? If not, create one.
   let actor = this._actorByBrowser.get(browser);
   if (actor) {
     this._foundCount++;
     return actor.update();
   } else if (this._isRemoteBrowser(browser)) {
     actor = new RemoteBrowserTabActor(this._connection, browser);
     this._actorByBrowser.set(browser, actor);
     this._checkListening();
     return actor.connect();
-  } else {
-    actor = new BrowserTabActor(this._connection, browser);
-    this._actorByBrowser.set(browser, actor);
-    this._checkListening();
-    return promise.resolve(actor);
   }
+
+  actor = new BrowserTabActor(this._connection, browser);
+  this._actorByBrowser.set(browser, actor);
+  this._checkListening();
+  return promise.resolve(actor);
 };
 
-BrowserTabList.prototype.getTab = function({ outerWindowID, tabId }) {
-  if (typeof(outerWindowID) == "number") {
+BrowserTabList.prototype.getTab = function ({ outerWindowID, tabId }) {
+  if (typeof outerWindowID == "number") {
     for (let browser of this._getBrowsers()) {
       if (browser.outerWindowID == outerWindowID) {
         return this._getActorForBrowser(browser);
       }
     }
     return promise.reject({
       error: "noTab",
       message: "Unable to find tab with outerWindowID '" + outerWindowID + "'"
     });
-  } else if (typeof(tabId) == "number") {
+  } else if (typeof tabId == "number") {
     // Tabs OOP
     for (let browser of this._getBrowsers()) {
       if (browser.frameLoader.tabParent &&
           browser.frameLoader.tabParent.tabId === tabId) {
         return this._getActorForBrowser(browser);
       }
     }
     return promise.reject({
       error: "noTab",
       message: "Unable to find tab with tabId '" + tabId + "'"
     });
   }
 
-  let topXULWindow = Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType);
+  let topXULWindow = Services.wm.getMostRecentWindow(
+    DebuggerServer.chromeWindowType);
   if (topXULWindow) {
     let selectedBrowser = this._getSelectedBrowser(topXULWindow);
     return this._getActorForBrowser(selectedBrowser);
   }
   return promise.reject({
     error: "noTab",
     message: "Unable to find any selected browser"
   });
 };
 
-Object.defineProperty(BrowserTabList.prototype, 'onListChanged', {
-  enumerable: true, configurable:true,
-  get: function() { return this._onListChanged; },
-  set: function(v) {
-    if (v !== null && typeof v !== 'function') {
-      throw Error("onListChanged property may only be set to 'null' or a function");
+Object.defineProperty(BrowserTabList.prototype, "onListChanged", {
+  enumerable: true,
+  configurable: true,
+  get() {
+    return this._onListChanged;
+  },
+  set(v) {
+    if (v !== null && typeof v !== "function") {
+      throw new Error(
+        "onListChanged property may only be set to 'null' or a function");
     }
     this._onListChanged = v;
     this._checkListening();
   }
 });
 
 /**
  * The set of tabs has changed somehow. Call our onListChanged handler, if
  * one is set, and if we haven't already called it since the last iteration.
  */
-BrowserTabList.prototype._notifyListChanged = function() {
-  if (!this._onListChanged)
+BrowserTabList.prototype._notifyListChanged = function () {
+  if (!this._onListChanged) {
     return;
+  }
   if (this._mustNotify) {
     this._onListChanged();
     this._mustNotify = false;
   }
 };
 
 /**
- * Exit |aActor|, belonging to |aBrowser|, and notify the onListChanged
+ * Exit |actor|, belonging to |browser|, and notify the onListChanged
  * handle if needed.
  */
-BrowserTabList.prototype._handleActorClose = function(aActor, aBrowser) {
+BrowserTabList.prototype._handleActorClose = function (actor, browser) {
   if (this._testing) {
-    if (this._actorByBrowser.get(aBrowser) !== aActor) {
-      throw Error("BrowserTabActor not stored in map under given browser");
+    if (this._actorByBrowser.get(browser) !== actor) {
+      throw new Error("BrowserTabActor not stored in map under given browser");
     }
-    if (aActor.browser !== aBrowser) {
-      throw Error("actor's browser and map key don't match");
+    if (actor.browser !== browser) {
+      throw new Error("actor's browser and map key don't match");
     }
   }
 
-  this._actorByBrowser.delete(aBrowser);
-  aActor.exit();
+  this._actorByBrowser.delete(browser);
+  actor.exit();
 
   this._notifyListChanged();
   this._checkListening();
 };
 
 /**
  * Make sure we are listening or not listening for activity elsewhere in
  * the browser, as appropriate. Other than setting up newly created XUL
  * windows, all listener / observer connection and disconnection should
  * happen here.
  */
-BrowserTabList.prototype._checkListening = function() {
+BrowserTabList.prototype._checkListening = function () {
   /*
    * If we have an onListChanged handler that we haven't sent an announcement
    * to since the last iteration, we need to watch for tab creation.
    *
    * Oddly, we don't need to watch for 'close' events here. If our actor list
    * is empty, then either it was empty the last time we iterated, and no
    * close events are possible, or it was not empty the last time we
    * iterated, but all the actors have since been closed, and we must have
@@ -473,121 +480,128 @@ BrowserTabList.prototype._checkListening
    */
   this._listenToMediatorIf((this._onListChanged && this._mustNotify) ||
                            (this._actorByBrowser.size > 0));
 };
 
 /*
  * Add or remove event listeners for all XUL windows.
  *
- * @param aShouldListen boolean
+ * @param shouldListen boolean
  *    True if we should add event handlers; false if we should remove them.
- * @param aGuard string
+ * @param guard string
  *    The name of a guard property of 'this', indicating whether we're
  *    already listening for those events.
- * @param aEventNames array of strings
+ * @param eventNames array of strings
  *    An array of event names.
  */
-BrowserTabList.prototype._listenForEventsIf = function(aShouldListen, aGuard, aEventNames) {
-  if (!aShouldListen !== !this[aGuard]) {
-    let op = aShouldListen ? "addEventListener" : "removeEventListener";
-    for (let win of allAppShellDOMWindows(DebuggerServer.chromeWindowType)) {
-      for (let name of aEventNames) {
-        win[op](name, this, false);
+BrowserTabList.prototype._listenForEventsIf =
+  function (shouldListen, guard, eventNames) {
+    if (!shouldListen !== !this[guard]) {
+      let op = shouldListen ? "addEventListener" : "removeEventListener";
+      for (let win of allAppShellDOMWindows(DebuggerServer.chromeWindowType)) {
+        for (let name of eventNames) {
+          win[op](name, this, false);
+        }
       }
+      this[guard] = shouldListen;
     }
-    this[aGuard] = aShouldListen;
-  }
-};
+  };
 
 /**
  * Implement nsIDOMEventListener.
  */
-BrowserTabList.prototype.handleEvent = DevToolsUtils.makeInfallible(function(aEvent) {
-  switch (aEvent.type) {
-  case "TabOpen":
-  case "TabSelect":
-    /* Don't create a new actor; iterate will take care of that. Just notify. */
-    this._notifyListChanged();
-    this._checkListening();
-    break;
-  case "TabClose":
-    let browser = aEvent.target.linkedBrowser;
-    let actor = this._actorByBrowser.get(browser);
-    if (actor) {
-      this._handleActorClose(actor, browser);
-    }
-    break;
+BrowserTabList.prototype.handleEvent =
+DevToolsUtils.makeInfallible(function (event) {
+  switch (event.type) {
+    case "TabOpen":
+    case "TabSelect":
+      // Don't create a new actor; iterate will take care of that.
+      // Just notify.
+      this._notifyListChanged();
+      this._checkListening();
+      break;
+    case "TabClose":
+      let browser = event.target.linkedBrowser;
+      let actor = this._actorByBrowser.get(browser);
+      if (actor) {
+        this._handleActorClose(actor, browser);
+      }
+      break;
   }
 }, "BrowserTabList.prototype.handleEvent");
 
 /*
- * If |aShouldListen| is true, ensure we've registered a listener with the
+ * If |shouldListen| is true, ensure we've registered a listener with the
  * window mediator. Otherwise, ensure we haven't registered a listener.
  */
-BrowserTabList.prototype._listenToMediatorIf = function(aShouldListen) {
-  if (!aShouldListen !== !this._listeningToMediator) {
-    let op = aShouldListen ? "addListener" : "removeListener";
+BrowserTabList.prototype._listenToMediatorIf = function (shouldListen) {
+  if (!shouldListen !== !this._listeningToMediator) {
+    let op = shouldListen ? "addListener" : "removeListener";
     Services.wm[op](this);
-    this._listeningToMediator = aShouldListen;
+    this._listeningToMediator = shouldListen;
   }
 };
 
 /**
  * nsIWindowMediatorListener implementation.
  *
  * See _onTabClosed for explanation of why we needn't actually tweak any
  * actors or tables here.
  *
  * An nsIWindowMediatorListener's methods get passed all sorts of windows; we
  * only care about the tab containers. Those have 'getBrowser' methods.
  */
 BrowserTabList.prototype.onWindowTitleChange = () => { };
 
-BrowserTabList.prototype.onOpenWindow = DevToolsUtils.makeInfallible(function(aWindow) {
+BrowserTabList.prototype.onOpenWindow =
+DevToolsUtils.makeInfallible(function (window) {
   let handleLoad = DevToolsUtils.makeInfallible(() => {
     /* We don't want any further load events from this window. */
-    aWindow.removeEventListener("load", handleLoad, false);
+    window.removeEventListener("load", handleLoad, false);
 
-    if (appShellDOMWindowType(aWindow) !== DebuggerServer.chromeWindowType)
+    if (appShellDOMWindowType(window) !== DebuggerServer.chromeWindowType) {
       return;
+    }
 
     // Listen for future tab activity.
     if (this._listeningForTabOpen) {
-      aWindow.addEventListener("TabOpen", this, false);
-      aWindow.addEventListener("TabSelect", this, false);
+      window.addEventListener("TabOpen", this, false);
+      window.addEventListener("TabSelect", this, false);
     }
     if (this._listeningForTabClose) {
-      aWindow.addEventListener("TabClose", this, false);
+      window.addEventListener("TabClose", this, false);
     }
 
     // As explained above, we will not receive a TabOpen event for this
     // document's initial tab, so we must notify our client of the new tab
     // this will have.
     this._notifyListChanged();
   });
 
   /*
    * You can hardly do anything at all with a XUL window at this point; it
    * doesn't even have its document yet. Wait until its document has
    * loaded, and then see what we've got. This also avoids
    * nsIWindowMediator enumeration from within listeners (bug 873589).
    */
-  aWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                   .getInterface(Ci.nsIDOMWindow);
+  window = window.QueryInterface(Ci.nsIInterfaceRequestor)
+                 .getInterface(Ci.nsIDOMWindow);
 
-  aWindow.addEventListener("load", handleLoad, false);
+  window.addEventListener("load", handleLoad, false);
 }, "BrowserTabList.prototype.onOpenWindow");
 
-BrowserTabList.prototype.onCloseWindow = DevToolsUtils.makeInfallible(function(aWindow) {
-  aWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+BrowserTabList.prototype.onCloseWindow =
+DevToolsUtils.makeInfallible(function (window) {
+  window = window.QueryInterface(Ci.nsIInterfaceRequestor)
                    .getInterface(Ci.nsIDOMWindow);
 
-  if (appShellDOMWindowType(aWindow) !== DebuggerServer.chromeWindowType)
+  if (appShellDOMWindowType(window) !== DebuggerServer.chromeWindowType) {
     return;
+  }
 
   /*
    * nsIWindowMediator deadlocks if you call its GetEnumerator method from
    * a nsIWindowMediatorListener's onCloseWindow hook (bug 873589), so
    * handle the close in a different tick.
    */
   Services.tm.currentThread.dispatch(DevToolsUtils.makeInfallible(() => {
     /*
@@ -628,47 +642,48 @@ exports.BrowserTabList = BrowserTabList;
  *
  * ### RDP events:
  *
  *  - `tabNavigated`:
  *    Sent when the tab is about to navigate or has just navigated to
  *    a different document.
  *    This event contains the following attributes:
  *     * url (string) The new URI being loaded.
- *     * nativeConsoleAPI (boolean) `false` if the console API of the page has been
- *                                          overridden (e.g. by Firebug),
+ *     * nativeConsoleAPI (boolean) `false` if the console API of the page has
+ *                                          been overridden (e.g. by Firebug),
  *                                  `true`  if the Gecko implementation is used.
  *     * state (string) `start` if we just start requesting the new URL,
  *                      `stop`  if the new URL is done loading.
  *     * isFrameSwitching (boolean) Indicates the event is dispatched when
  *                                  switching the TabActor context to
  *                                  a different frame. When we switch to
  *                                  an iframe, there is no document load.
  *                                  The targeted document is most likely
  *                                  going to be already done loading.
  *     * title (string) The document title being loaded.
  *                      (sent only on state=stop)
  *
  *  - `frameUpdate`:
  *    Sent when there was a change in the child frames contained in the document
  *    or when the tab's context was switched to another frame.
- *    This event can have four different forms depending on the type of incident:
+ *    This event can have four different forms depending on the type of change:
  *    * One or many frames are updated:
  *      { frames: [{ id, url, title, parentID }, ...] }
  *    * One frame got destroyed:
  *      { frames: [{ id, destroy: true }]}
  *    * All frames got destroyed:
  *      { destroyAll: true }
  *    * We switched the context of the TabActor to a specific frame:
  *      { selected: #id }
  *
  * ### Internal, non-rdp events:
  * Various events are also dispatched on the TabActor itself that are not
  * related to RDP, so, not sent to the client. They all relate to the documents
- * tracked by the TabActor (its main targeted document, but also any of its iframes).
+ * tracked by the TabActor (its main targeted document, but also any of its
+ * iframes).
  *  - will-navigate
  *    This event fires once navigation starts.
  *    All pending user prompts are dealt with,
  *    but it is fired before the first request starts.
  *  - navigate
  *    This event is fired once the document's readyState is "complete".
  *  - window-ready
  *    This event is fired on three distinct scenarios:
@@ -690,49 +705,54 @@ exports.BrowserTabList = BrowserTabList;
  *       The equivalent of `pagehide`.
  *  - changed-toplevel-document
  *    This event fires when we switch the TabActor targeted document
  *    to one of its iframes, or back to its original top document.
  *    It is dispatched between window-destroyed and window-ready.
  *
  * Note that *all* these events are dispatched in the following order
  * when we switch the context of the TabActor to a given iframe:
- *   will-navigate, window-destroyed, changed-toplevel-document, window-ready, navigate
+ *  - will-navigate
+ *  - window-destroyed
+ *  - changed-toplevel-document
+ *  - window-ready
+ *  - navigate
  *
  * This class is subclassed by BrowserTabActor and
  * ContentActor. Subclasses are expected to implement a getter
  * for the docShell property.
  *
- * @param aConnection DebuggerServerConnection
+ * @param connection DebuggerServerConnection
  *        The conection to the client.
  */
-function TabActor(aConnection)
-{
-  this.conn = aConnection;
+function TabActor(connection) {
+  this.conn = connection;
   this._tabActorPool = null;
   // A map of actor names to actor instances provided by extensions.
   this._extraActors = {};
   this._exited = false;
   this._sources = null;
 
   // Map of DOM stylesheets to StyleSheetActors
   this._styleSheetActors = new Map();
 
-  this._shouldAddNewGlobalAsDebuggee = this._shouldAddNewGlobalAsDebuggee.bind(this);
+  this._shouldAddNewGlobalAsDebuggee =
+    this._shouldAddNewGlobalAsDebuggee.bind(this);
 
   this.makeDebugger = makeDebugger.bind(null, {
     findDebuggees: () => {
       return this.windows.concat(this.webextensionsContentScriptGlobals);
     },
     shouldAddNewGlobalAsDebuggee: this._shouldAddNewGlobalAsDebuggee
   });
 
   // Flag eventually overloaded by sub classes in order to watch new docshells
   // Used on b2g to catch activity frames and in chrome to list all frames
-  this.listenForNewDocShells = Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
+  this.listenForNewDocShells =
+    Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT;
 
   this.traits = {
     reconfigure: true,
     // Supports frame listing via `listFrames` request and `frameUpdate` events
     // as well as frame switching via `switchToFrame` request
     frames: true,
     // Do not require to send reconfigure request to reset the document state
     // to what it was before using the TabActor
@@ -745,24 +765,33 @@ function TabActor(aConnection)
 }
 
 // XXX (bug 710213): TabActor attach/detach/exit/disconnect is a
 // *complete* mess, needs to be rethought asap.
 
 TabActor.prototype = {
   traits: null,
 
-  get exited() { return this._exited; },
-  get attached() { return !!this._attached; },
+  get exited() {
+    return this._exited;
+  },
+
+  get attached() {
+    return !!this._attached;
+  },
 
   _tabPool: null,
-  get tabActorPool() { return this._tabPool; },
+  get tabActorPool() {
+    return this._tabPool;
+  },
 
   _contextPool: null,
-  get contextActorPool() { return this._contextPool; },
+  get contextActorPool() {
+    return this._contextPool;
+  },
 
   _pendingNavigation: null,
 
   // A constant prefix that will be used to form the actor ID by the server.
   actorPrefix: "tab",
 
   /**
    * An object on which listen for DOMWindowCreated and pageshow events.
@@ -779,17 +808,18 @@ TabActor.prototype = {
       .QueryInterface(Ci.nsIInterfaceRequestor)
       .getInterface(Ci.nsIContentFrameMessageManager);
   },
 
   /**
    * Getter for the tab's doc shell.
    */
   get docShell() {
-    throw "The docShell getter should be implemented by a subclass of TabActor";
+    throw new Error(
+      "The docShell getter should be implemented by a subclass of TabActor");
   },
 
   /**
    * Getter for the list of all docshell in this tabActor
    * @return {Array}
    */
   get docShells() {
     return getChildDocShells(this.docShell);
@@ -915,21 +945,21 @@ TabActor.prototype = {
     return this._sources;
   },
 
   /**
    * This is called by BrowserTabList.getList for existing tab actors prior to
    * calling |form| below.  It can be used to do any async work that may be
    * needed to assemble the form.
    */
-  update: function() {
+  update() {
     return promise.resolve(this);
   },
 
-  form: function BTA_form() {
+  form() {
     assert(!this.exited,
                "form() shouldn't be called on exited browser actor.");
     assert(this.actorID,
                "tab should have an actorID.");
 
     let response = {
       actor: this.actorID
     };
@@ -960,24 +990,24 @@ TabActor.prototype = {
 
     this._appendExtraActors(response);
     return response;
   },
 
   /**
    * Called when the actor is removed from the connection.
    */
-  disconnect: function BTA_disconnect() {
+  disconnect() {
     this.exit();
   },
 
   /**
    * Called by the root actor when the underlying tab is closed.
    */
-  exit: function BTA_exit() {
+  exit() {
     if (this.exited) {
       return;
     }
 
     // Tell the thread actor that the tab is closed, so that it may terminate
     // instead of resuming the debuggee script.
     if (this._attached) {
       this.threadActor._tabClosed = true;
@@ -997,17 +1027,17 @@ TabActor.prototype = {
 
     this._exited = true;
   },
 
   /**
    * Return true if the given global is associated with this tab and should be
    * added as a debuggee, false otherwise.
    */
-  _shouldAddNewGlobalAsDebuggee: function (wrappedGlobal) {
+  _shouldAddNewGlobalAsDebuggee(wrappedGlobal) {
     if (wrappedGlobal.hostAnnotations &&
         wrappedGlobal.hostAnnotations.type == "document" &&
         wrappedGlobal.hostAnnotations.element === this.window) {
       return true;
     }
 
     let global = unwrapDebuggerObjectGlobal(wrappedGlobal);
     if (!global) {
@@ -1015,35 +1045,36 @@ TabActor.prototype = {
     }
 
     // Check if the global is a sdk page-mod sandbox.
     let metadata = {};
     let id = "";
     try {
       id = getInnerId(this.window);
       metadata = Cu.getSandboxMetadata(global);
+    } catch (e) {
+      // ignore
     }
-    catch (e) {}
     if (metadata
         && metadata["inner-window-id"]
         && metadata["inner-window-id"] == id) {
       return true;
     }
 
     return false;
   },
 
   /* Support for DebuggerServer.addTabActor. */
   _createExtraActors: createExtraActors,
   _appendExtraActors: appendExtraActors,
 
   /**
    * Does the actual work of attaching to a tab.
    */
-  _attach: function BTA_attach() {
+  _attach() {
     if (this._attached) {
       return;
     }
 
     // Create a pool for tab-lifetime actors.
     assert(!this._tabPool, "Shouldn't have a tab pool if we weren't attached.");
     this._tabPool = new ActorPool(this.conn);
     this.conn.addActorPool(this._tabPool);
@@ -1061,55 +1092,58 @@ TabActor.prototype = {
       // Ensure replying to attach() request first
       // before notifying about new docshells.
       DevToolsUtils.executeSoon(() => this._watchDocshells());
     }
 
     this._attached = true;
   },
 
-  _watchDocshells: function BTA_watchDocshells() {
+  _watchDocshells() {
     // In child processes, we watch all docshells living in the process.
     if (this.listenForNewDocShells) {
       Services.obs.addObserver(this, "webnavigation-create", false);
     }
     Services.obs.addObserver(this, "webnavigation-destroy", false);
 
     // We watch for all child docshells under the current document,
     this._progressListener.watch(this.docShell);
 
     // And list all already existing ones.
     this._updateChildDocShells();
   },
 
-  onSwitchToFrame: function BTA_onSwitchToFrame(aRequest) {
-    let windowId = aRequest.windowId;
+  onSwitchToFrame(request) {
+    let windowId = request.windowId;
     let win;
+
     try {
       win = Services.wm.getOuterWindowWithId(windowId);
-    } catch(e) {}
+    } catch (e) {
+      // ignore
+    }
     if (!win) {
       return { error: "noWindow",
                message: "The related docshell is destroyed or not found" };
     } else if (win == this.window) {
       return {};
     }
 
     // Reply first before changing the document
     DevToolsUtils.executeSoon(() => this._changeTopLevelDocument(win));
 
     return {};
   },
 
-  onListFrames: function BTA_onListFrames(aRequest) {
+  onListFrames(request) {
     let windows = this._docShellsToWindows(this.docShells);
     return { frames: windows };
   },
 
-  onListWorkers: function BTA_onListWorkers(aRequest) {
+  onListWorkers(request) {
     if (!this.attached) {
       return { error: "wrongState" };
     }
 
     if (this._workerActorList === null) {
       this._workerActorList = new WorkerActorList(this.conn, {
         type: Ci.nsIWorkerDebugger.TYPE_DEDICATED,
         window: this.window
@@ -1130,77 +1164,78 @@ TabActor.prototype = {
 
       return {
         "from": this.actorID,
         "workers": actors.map((actor) => actor.form())
       };
     });
   },
 
-  _onWorkerActorListChanged: function () {
+  _onWorkerActorListChanged() {
     this._workerActorList.onListChanged = null;
     this.conn.sendActorEvent(this.actorID, "workerListChanged");
   },
 
-  observe: function (aSubject, aTopic, aData) {
+  observe(subject, topic, data) {
     // Ignore any event that comes before/after the tab actor is attached
     // That typically happens during firefox shutdown.
     if (!this.attached) {
       return;
     }
-    if (aTopic == "webnavigation-create") {
-      aSubject.QueryInterface(Ci.nsIDocShell);
-      this._onDocShellCreated(aSubject);
-    } else if (aTopic == "webnavigation-destroy") {
-      this._onDocShellDestroy(aSubject);
+    if (topic == "webnavigation-create") {
+      subject.QueryInterface(Ci.nsIDocShell);
+      this._onDocShellCreated(subject);
+    } else if (topic == "webnavigation-destroy") {
+      this._onDocShellDestroy(subject);
     }
   },
 
-  _onDocShellCreated: function (docShell) {
-    // (chrome-)webnavigation-create is fired very early during docshell construction.
-    // In new root docshells within child processes, involving TabChild,
-    // this event is from within this call:
+  _onDocShellCreated(docShell) {
+    // (chrome-)webnavigation-create is fired very early during docshell
+    // construction. In new root docshells within child processes, involving
+    // TabChild, this event is from within this call:
     //   http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l912
-    // whereas the chromeEventHandler (and most likely other stuff) is set later:
+    // whereas the chromeEventHandler (and most likely other stuff) is set
+    // later:
     //   http://hg.mozilla.org/mozilla-central/annotate/74d7fb43bb44/dom/ipc/TabChild.cpp#l944
     // So wait a tick before watching it:
     DevToolsUtils.executeSoon(() => {
-      // Bug 1142752: sometimes, the docshell appears to be immediately destroyed,
-      // bailout early to prevent random exceptions.
+      // Bug 1142752: sometimes, the docshell appears to be immediately
+      // destroyed, bailout early to prevent random exceptions.
       if (docShell.isBeingDestroyed()) {
         return;
       }
 
       // In child processes, we have new root docshells,
       // let's watch them and all their child docshells.
       if (this._isRootDocShell(docShell)) {
         this._progressListener.watch(docShell);
       }
       this._notifyDocShellsUpdate([docShell]);
     });
   },
 
-  _onDocShellDestroy: function (docShell) {
+  _onDocShellDestroy(docShell) {
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
     this._notifyDocShellDestroy(webProgress);
   },
 
-  _isRootDocShell: function (docShell) {
-    // Root docshells like top level xul windows don't have chromeEventHandler.
-    // Root docshells in child processes have one, it is TabChildGlobal,
-    // which isn't a DOM Element.
-    // Non-root docshell have a chromeEventHandler that is either
-    // xul:iframe, xul:browser or html:iframe.
-    return !docShell.chromeEventHandler ||
-           !(docShell.chromeEventHandler instanceof Ci.nsIDOMElement);
+  _isRootDocShell(docShell) {
+    // Should report as root docshell:
+    //  - New top level window's docshells, when using ChromeActor against a
+    // process. It allows tracking iframes of the newly opened windows
+    // like Browser console or new browser windows.
+    //  - MozActivities or window.open frames on B2G, where a new root docshell
+    // is spawn in the child process of the app.
+    return !docShell.parent;
   },
 
   // Convert docShell list to windows objects list being sent to the client
-  _docShellsToWindows: function (docshells) {
+  _docShellsToWindows(docshells) {
     return docshells.map(docShell => {
       let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                                 .getInterface(Ci.nsIWebProgress);
       let window = webProgress.DOMWindow;
       let id = window.QueryInterface(Ci.nsIInterfaceRequestor)
                      .getInterface(Ci.nsIDOMWindowUtils)
                      .outerWindowID;
       let parentID = undefined;
@@ -1216,48 +1251,46 @@ TabActor.prototype = {
         id: id,
         url: window.location.href,
         title: window.document.title,
         parentID: parentID
       };
     });
   },
 
-  _notifyDocShellsUpdate: function (docshells) {
+  _notifyDocShellsUpdate(docshells) {
     let windows = this._docShellsToWindows(docshells);
     this.conn.send({ from: this.actorID,
                      type: "frameUpdate",
                      frames: windows
                    });
   },
 
-  _updateChildDocShells: function () {
+  _updateChildDocShells() {
     this._notifyDocShellsUpdate(this.docShells);
   },
 
-  _notifyDocShellDestroy: function (webProgress) {
+  _notifyDocShellDestroy(webProgress) {
     webProgress = webProgress.QueryInterface(Ci.nsIWebProgress);
     let id = webProgress.DOMWindow
                         .QueryInterface(Ci.nsIInterfaceRequestor)
                         .getInterface(Ci.nsIDOMWindowUtils)
                         .outerWindowID;
     this.conn.send({ from: this.actorID,
                      type: "frameUpdate",
                      frames: [{
                        id: id,
                        destroy: true
                      }]
                    });
 
-    // Stop watching this docshell if it's a root one.
-    // (child processes spawn new root docshells)
+    // Stop watching this docshell (the unwatch() method will check if we
+    // started watching it before).
     webProgress.QueryInterface(Ci.nsIDocShell);
-    if (this._isRootDocShell(webProgress)) {
-      this._progressListener.unwatch(webProgress);
-    }
+    this._progressListener.unwatch(webProgress);
 
     if (webProgress.DOMWindow == this._originalWindow) {
       // If the original top level document we connected to is removed,
       // we try to switch to any other top level document
       let rootDocShells = this.docShells
                               .filter(d => {
                                 return d != this.docShell &&
                                        this._isRootDocShell(d);
@@ -1280,57 +1313,57 @@ TabActor.prototype = {
     // and we aren't on the top-level document,
     // we have to switch to the top-level one.
     if (webProgress.DOMWindow == this.window &&
         this.window != this._originalWindow) {
       this._changeTopLevelDocument(this._originalWindow);
     }
   },
 
-  _notifyDocShellDestroyAll: function () {
+  _notifyDocShellDestroyAll() {
     this.conn.send({ from: this.actorID,
                      type: "frameUpdate",
                      destroyAll: true
                    });
   },
 
   /**
    * Creates a thread actor and a pool for context-lifetime actors. It then sets
    * up the content window for debugging.
    */
-  _pushContext: function BTA_pushContext() {
+  _pushContext() {
     assert(!this._contextPool, "Can't push multiple contexts");
 
     this._contextPool = new ActorPool(this.conn);
     this.conn.addActorPool(this._contextPool);
 
     this.threadActor = new ThreadActor(this, this.window);
     this._contextPool.addActor(this.threadActor);
   },
 
   /**
    * Exits the current thread actor and removes the context-lifetime actor pool.
    * The content window is no longer being debugged after this call.
    */
-  _popContext: function BTA_popContext() {
+  _popContext() {
     assert(!!this._contextPool, "No context to pop.");
 
     this.conn.removeActorPool(this._contextPool);
     this._contextPool = null;
     this.threadActor.exit();
     this.threadActor = null;
     this._sources = null;
   },
 
   /**
    * Does the actual work of detaching from a tab.
    *
    * @returns false if the tab wasn't attached or true of detaching succeeds.
    */
-  _detach: function BTA_detach() {
+  _detach() {
     if (!this.attached) {
       return false;
     }
 
     // Check for docShell availability, as it can be already gone
     // during Firefox shutdown.
     if (this.docShell) {
       this._progressListener.unwatch(this.docShell);
@@ -1368,114 +1401,108 @@ TabActor.prototype = {
       this._workerActorList = null;
     }
 
     if (this._workerActorPool !== null) {
       this.conn.removeActorPool(this._workerActorPool);
       this._workerActorPool = null;
     }
 
-    // Make sure that no more serviceWorkerRegistrationChanged notifications are
-    // sent.
-    if (this._mustNotifyServiceWorkerRegistrationChanged) {
-      swm.removeListener(this);
-      this._mustNotifyServiceWorkerRegistrationChanged = false;
-    }
-
     this._attached = false;
 
     return true;
   },
 
   // Protocol Request Handlers
 
-  onAttach: function BTA_onAttach(aRequest) {
+  onAttach(request) {
     if (this.exited) {
       return { type: "exited" };
     }
 
     this._attach();
 
     return {
       type: "tabAttached",
       threadActor: this.threadActor.actorID,
       cacheDisabled: this._getCacheDisabled(),
       javascriptEnabled: this._getJavascriptEnabled(),
       traits: this.traits,
     };
   },
 
-  onDetach: function BTA_onDetach(aRequest) {
+  onDetach(request) {
     if (!this._detach()) {
       return { error: "wrongState" };
     }
 
     return { type: "detached" };
   },
 
   /**
    * Bring the tab's window to front.
    */
-  onFocus: function() {
+  onFocus() {
     if (this.window) {
       this.window.focus();
     }
     return {};
   },
 
   /**
    * Reload the page in this tab.
    */
-  onReload: function(aRequest) {
-    let force = aRequest && aRequest.options && aRequest.options.force;
+  onReload(request) {
+    let force = request && request.options && request.options.force;
     // Wait a tick so that the response packet can be dispatched before the
     // subsequent navigation event packet.
     Services.tm.currentThread.dispatch(DevToolsUtils.makeInfallible(() => {
       // This won't work while the browser is shutting down and we don't really
       // care.
       if (Services.startup.shuttingDown) {
         return;
       }
-      this.webNavigation.reload(force ? Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE
-                                      : Ci.nsIWebNavigation.LOAD_FLAGS_NONE);
+      this.webNavigation.reload(force ?
+        Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE :
+        Ci.nsIWebNavigation.LOAD_FLAGS_NONE);
     }, "TabActor.prototype.onReload's delayed body"), 0);
     return {};
   },
 
   /**
    * Navigate this tab to a new location
    */
-  onNavigateTo: function(aRequest) {
+  onNavigateTo(request) {
     // Wait a tick so that the response packet can be dispatched before the
     // subsequent navigation event packet.
     Services.tm.currentThread.dispatch(DevToolsUtils.makeInfallible(() => {
-      this.window.location = aRequest.url;
+      this.window.location = request.url;
     }, "TabActor.prototype.onNavigateTo's delayed body"), 0);
     return {};
   },
 
   /**
    * Reconfigure options.
    */
-  onReconfigure: function (aRequest) {
-    let options = aRequest.options || {};
+  onReconfigure(request) {
+    let options = request.options || {};
 
     if (!this.docShell) {
       // The tab is already closed.
       return {};
     }
     this._toggleDevToolsSettings(options);
 
     return {};
   },
 
   /**
    * Handle logic to enable/disable JS/cache/Service Worker testing.
    */
-  _toggleDevToolsSettings: function(options) {
+  _toggleDevToolsSettings(options) {
     // Wait a tick so that the response packet can be dispatched before the
     // subsequent navigation event packet.
     let reload = false;
 
     if (typeof options.javascriptEnabled !== "undefined" &&
         options.javascriptEnabled !== this._getJavascriptEnabled()) {
       this._setJavascriptEnabled(options.javascriptEnabled);
       reload = true;
@@ -1507,171 +1534,171 @@ TabActor.prototype = {
       this.onReload();
     }
   },
 
   /**
    * Opposite of the _toggleDevToolsSettings method, that reset document state
    * when closing the toolbox.
    */
-  _restoreDocumentSettings: function () {
+  _restoreDocumentSettings() {
     this._restoreJavascript();
     this._setCacheDisabled(false);
     this._setServiceWorkersTestingEnabled(false);
     this._restoreUserAgent();
   },
 
   /**
    * Disable or enable the cache via docShell.
    */
-  _setCacheDisabled: function(disabled) {
-    let enable =  Ci.nsIRequest.LOAD_NORMAL;
+  _setCacheDisabled(disabled) {
+    let enable = Ci.nsIRequest.LOAD_NORMAL;
     let disable = Ci.nsIRequest.LOAD_BYPASS_CACHE |
                   Ci.nsIRequest.INHIBIT_CACHING;
 
     this.docShell.defaultLoadFlags = disabled ? disable : enable;
   },
 
   /**
    * Disable or enable JS via docShell.
    */
   _wasJavascriptEnabled: null,
-  _setJavascriptEnabled: function(allow) {
+  _setJavascriptEnabled(allow) {
     if (this._wasJavascriptEnabled === null) {
       this._wasJavascriptEnabled = this.docShell.allowJavascript;
     }
     this.docShell.allowJavascript = allow;
   },
 
   /**
    * Restore JS state, before the actor modified it.
    */
-  _restoreJavascript: function () {
+  _restoreJavascript() {
     if (this._wasJavascriptEnabled !== null) {
       this._setJavascriptEnabled(this._wasJavascriptEnabled);
       this._wasJavascriptEnabled = null;
     }
   },
 
   /**
    * Return JS allowed status.
    */
-  _getJavascriptEnabled: function() {
+  _getJavascriptEnabled() {
     if (!this.docShell) {
       // The tab is already closed.
       return null;
     }
 
     return this.docShell.allowJavascript;
   },
 
   /**
    * Disable or enable the service workers testing features.
    */
-  _setServiceWorkersTestingEnabled: function(enabled) {
+  _setServiceWorkersTestingEnabled(enabled) {
     let windowUtils = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
                                  .getInterface(Ci.nsIDOMWindowUtils);
     windowUtils.serviceWorkersTestingEnabled = enabled;
   },
 
   /**
    * Return cache allowed status.
    */
-  _getCacheDisabled: function() {
+  _getCacheDisabled() {
     if (!this.docShell) {
       // The tab is already closed.
       return null;
     }
 
     let disable = Ci.nsIRequest.LOAD_BYPASS_CACHE |
                   Ci.nsIRequest.INHIBIT_CACHING;
     return this.docShell.defaultLoadFlags === disable;
   },
 
   /**
    * Return service workers testing allowed status.
    */
-  _getServiceWorkersTestingEnabled: function() {
+  _getServiceWorkersTestingEnabled() {
     if (!this.docShell) {
       // The tab is already closed.
       return null;
     }
 
     let windowUtils = this.window.QueryInterface(Ci.nsIInterfaceRequestor)
                                  .getInterface(Ci.nsIDOMWindowUtils);
     return windowUtils.serviceWorkersTestingEnabled;
   },
 
   _previousCustomUserAgent: null,
 
   /**
    * Return custom user agent.
    */
-  _getCustomUserAgent: function() {
+  _getCustomUserAgent() {
     if (!this.docShell) {
       // The tab is already closed.
       return null;
     }
     return this.docShell.customUserAgent;
   },
 
   /**
    * Sets custom user agent for the current tab
    */
-  _setCustomUserAgent: function(userAgent) {
+  _setCustomUserAgent(userAgent) {
     if (this._previousCustomUserAgent === null) {
       this._previousCustomUserAgent = this.docShell.customUserAgent;
     }
     this.docShell.customUserAgent = userAgent;
   },
 
   /**
    * Restore the user agent, before the actor modified it
    */
-  _restoreUserAgent: function() {
+  _restoreUserAgent() {
     if (this._previousCustomUserAgent !== null) {
       this.docShell.customUserAgent = this._previousCustomUserAgent;
     }
   },
 
   /**
    * Prepare to enter a nested event loop by disabling debuggee events.
    */
-  preNest: function BTA_preNest() {
+  preNest() {
     if (!this.window) {
       // The tab is already closed.
       return;
     }
     let windowUtils = this.window
                           .QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIDOMWindowUtils);
     windowUtils.suppressEventHandling(true);
     windowUtils.suspendTimeouts();
   },
 
   /**
    * Prepare to exit a nested event loop by enabling debuggee events.
    */
-  postNest: function BTA_postNest(aNestData) {
+  postNest(nestData) {
     if (!this.window) {
       // The tab is already closed.
       return;
     }
     let windowUtils = this.window
                           .QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIDOMWindowUtils);
     windowUtils.resumeTimeouts();
     windowUtils.suppressEventHandling(false);
     if (this._pendingNavigation) {
       this._pendingNavigation.resume();
       this._pendingNavigation = null;
     }
   },
 
-  _changeTopLevelDocument: function (window) {
+  _changeTopLevelDocument(window) {
     // Fake a will-navigate on the previous document
     // to let a chance to unregister it
     this._willNavigate(this.window, window.location.href, null, true);
 
     this._windowDestroyed(this.window, null, true);
 
     // Immediately change the window as this window, if in process of unload
     // may already be non working on the next cycle and start throwing
@@ -1681,17 +1708,17 @@ TabActor.prototype = {
       // Then fake window-ready and navigate on the given document
       this._windowReady(window, true);
       DevToolsUtils.executeSoon(() => {
         this._navigate(window, true);
       });
     });
   },
 
-  _setWindow: function (window) {
+  _setWindow(window) {
     let docShell = window.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIWebNavigation)
                          .QueryInterface(Ci.nsIDocShell);
     // Here is the very important call where we switch the currently
     // targeted context (it will indirectly update this.window and
     // many other attributes defined from docShell).
     Object.defineProperty(this, "docShell", {
       value: docShell,
@@ -1708,32 +1735,33 @@ TabActor.prototype = {
                    });
   },
 
   /**
    * Handle location changes, by clearing the previous debuggees and enabling
    * debugging, which may have been disabled temporarily by the
    * DebuggerProgressListener.
    */
-  _windowReady: function (window, isFrameSwitching = false) {
+  _windowReady(window, isFrameSwitching = false) {
     let isTopLevel = window == this.window;
 
     // We just reset iframe list on WillNavigate, so we now list all existing
     // frames when we load a new document in the original window
     if (window == this._originalWindow && !isFrameSwitching) {
       this._updateChildDocShells();
     }
 
     events.emit(this, "window-ready", {
       window: window,
       isTopLevel: isTopLevel,
       id: getWindowID(window)
     });
 
-    // TODO bug 997119: move that code to ThreadActor by listening to window-ready
+    // TODO bug 997119: move that code to ThreadActor by listening to
+    // window-ready
     let threadActor = this.threadActor;
     if (isTopLevel && threadActor.state != "detached") {
       this.sources.reset({ sourceMaps: true });
       threadActor.clearDebuggees();
       threadActor.dbg.enabled = true;
       threadActor.maybePauseOnExceptions();
       // Update the global no matter if the debugger is on or off,
       // otherwise the global will be wrong when enabled later.
@@ -1742,44 +1770,44 @@ TabActor.prototype = {
 
     // Refresh the debuggee list when a new window object appears (top window or
     // iframe).
     if (threadActor.attached) {
       threadActor.dbg.addDebuggees();
     }
   },
 
-  _windowDestroyed: function (window, id = null, isFrozen = false) {
+  _windowDestroyed(window, id = null, isFrozen = false) {
     events.emit(this, "window-destroyed", {
       window: window,
       isTopLevel: window == this.window,
       id: id || getWindowID(window),
       isFrozen: isFrozen
     });
   },
 
   /**
    * Start notifying server and client about a new document
    * being loaded in the currently targeted context.
    */
-  _willNavigate: function (window, newURI, request, isFrameSwitching = false) {
+  _willNavigate(window, newURI, request, isFrameSwitching = false) {
     let isTopLevel = window == this.window;
     let reset = false;
 
     if (window == this._originalWindow && !isFrameSwitching) {
       // Clear the iframe list if the original top-level document changes.
       this._notifyDocShellDestroyAll();
 
       // If the top level document changes and we are targeting
       // an iframe, we need to reset to the upcoming new top level document.
       // But for this will-navigate event, we will dispatch on the old window.
-      // (The inspector codebase expect to receive will-navigate for the currently
-      // displayed document in order to cleanup the markup view)
+      // (The inspector codebase expect to receive will-navigate for the
+      // currently displayed document in order to cleanup the markup view)
       if (this.window != this._originalWindow) {
-        reset=true;
+        reset = true;
         window = this.window;
         isTopLevel = true;
       }
     }
 
     // will-navigate event needs to be dispatched synchronously,
     // by calling the listeners in the order or registration.
     // This event fires once navigation starts,
@@ -1794,21 +1822,23 @@ TabActor.prototype = {
 
     // We don't do anything for inner frames in TabActor.
     // (we will only update thread actor on window-ready)
     if (!isTopLevel) {
       return;
     }
 
     // Proceed normally only if the debuggee is not paused.
-    // TODO bug 997119: move that code to ThreadActor by listening to will-navigate
+    // TODO bug 997119: move that code to ThreadActor by listening to
+    // will-navigate
     let threadActor = this.threadActor;
     if (request && threadActor.state == "paused") {
       request.suspend();
-      this.conn.send(threadActor.unsafeSynchronize(Promise.resolve(threadActor.onResume())));
+      this.conn.send(
+        threadActor.unsafeSynchronize(Promise.resolve(threadActor.onResume())));
       threadActor.dbg.enabled = false;
       this._pendingNavigation = request;
     }
     threadActor.disableAllBreakpoints();
 
     this.conn.send({
       from: this.actorID,
       type: "tabNavigated",
@@ -1822,17 +1852,17 @@ TabActor.prototype = {
       this._setWindow(this._originalWindow);
     }
   },
 
   /**
    * Notify server and client about a new document done loading in the current
    * targeted context.
    */
-  _navigate: function (window, isFrameSwitching = false) {
+  _navigate(window, isFrameSwitching = false) {
     let isTopLevel = window == this.window;
 
     // navigate event needs to be dispatched synchronously,
     // by calling the listeners in the order or registration.
     // This event is fired once the document is loaded,
     // after the load event, it's document ready-state is 'complete'.
     events.emit(this, "navigate", {
       window: window,
@@ -1861,100 +1891,115 @@ TabActor.prototype = {
       isFrameSwitching: isFrameSwitching
     });
   },
 
   /**
    * Tells if the window.console object is native or overwritten by script in
    * the page.
    *
-   * @param nsIDOMWindow aWindow
+   * @param nsIDOMWindow window
    *        The window object you want to check.
    * @return boolean
    *         True if the window.console object is native, or false otherwise.
    */
-  hasNativeConsoleAPI: function BTA_hasNativeConsoleAPI(aWindow) {
+  hasNativeConsoleAPI(window) {
     let isNative = false;
     try {
       // We are very explicitly examining the "console" property of
       // the non-Xrayed object here.
-      let console = aWindow.wrappedJSObject.console;
-      isNative = console instanceof aWindow.Console;
+      let console = window.wrappedJSObject.console;
+      isNative = console instanceof window.Console;
+    } catch (ex) {
+      // ignore
     }
-    catch (ex) { }
     return isNative;
   },
 
   /**
    * Create or return the StyleSheetActor for a style sheet. This method
    * is here because the Style Editor and Inspector share style sheet actors.
    *
    * @param DOMStyleSheet styleSheet
    *        The style sheet to create an actor for.
    * @return StyleSheetActor actor
    *         The actor for this style sheet.
    *
    */
-  createStyleSheetActor: function BTA_createStyleSheetActor(styleSheet) {
+  createStyleSheetActor(styleSheet) {
     if (this._styleSheetActors.has(styleSheet)) {
       return this._styleSheetActors.get(styleSheet);
     }
     let actor = new StyleSheetActor(styleSheet, this);
     this._styleSheetActors.set(styleSheet, actor);
 
     this._tabPool.addActor(actor);
 
     return actor;
   },
 
-  removeActorByName: function BTA_removeActor(aName) {
-    if (aName in this._extraActors) {
-      const actor = this._extraActors[aName];
+  removeActorByName(name) {
+    if (name in this._extraActors) {
+      const actor = this._extraActors[name];
       if (this._tabActorPool.has(actor)) {
         this._tabActorPool.removeActor(actor);
       }
-      delete this._extraActors[aName];
+      delete this._extraActors[name];
     }
   },
 
   /**
    * Takes a packet containing a url, line and column and returns
    * the updated url, line and column based on the current source mapping
    * (source mapped files, pretty prints).
    *
    * @param {String} request.url
    * @param {Number} request.line
    * @param {Number?} request.column
    * @return {Promise<Object>}
    */
-  onResolveLocation: function (request) {
+  onResolveLocation(request) {
     let { url, line } = request;
     let column = request.column || 0;
-    let actor;
+    let actor = this.sources.getSourceActorByURL(url);
 
-    if (actor = this.sources.getSourceActorByURL(url)) {
+    if (actor) {
       // Get the generated source actor if this is source mapped
       let generatedActor = actor.generatedSource ?
-                           this.sources.createNonSourceMappedActor(actor.generatedSource) :
-                           actor;
-      let generatedLocation = new GeneratedLocation(generatedActor, line, column);
+        this.sources.createNonSourceMappedActor(actor.generatedSource) :
+        actor;
+      let generatedLocation = new GeneratedLocation(
+        generatedActor, line, column);
 
       return this.sources.getOriginalLocation(generatedLocation).then(loc => {
         // If no map found, return this packet
         if (loc.originalLine == null) {
-          return { from: this.actorID, type: "resolveLocation", error: "MAP_NOT_FOUND" };
+          return {
+            from: this.actorID,
+            type: "resolveLocation",
+            error: "MAP_NOT_FOUND"
+          };
         }
 
         loc = loc.toJSON();
-        return { from: this.actorID, url: loc.source.url, column: loc.column, line: loc.line };
+        return {
+          from: this.actorID,
+          url: loc.source.url,
+          column: loc.column,
+          line: loc.line
+        };
       });
     }
 
     // Fall back to this packet when source is not found
-    return promise.resolve({ from: this.actorID, type: "resolveLocation", error: "SOURCE_NOT_FOUND" });
+    return promise.resolve({
+      from: this.actorID,
+      type: "resolveLocation",
+      error: "SOURCE_NOT_FOUND"
+    });
   },
 };
 
 /**
  * The request types this actor can handle.
  */
 TabActor.prototype.requestTypes = {
   "attach": TabActor.prototype.onAttach,
@@ -1971,41 +2016,40 @@ TabActor.prototype.requestTypes = {
 
 exports.TabActor = TabActor;
 
 /**
  * Creates a tab actor for handling requests to a single in-process
  * <xul:browser> tab, or <html:iframe>.
  * Most of the implementation comes from TabActor.
  *
- * @param aConnection DebuggerServerConnection
+ * @param connection DebuggerServerConnection
  *        The connection to the client.
- * @param aBrowser browser
+ * @param browser browser
  *        The frame instance that contains this tab.
  */
-function BrowserTabActor(aConnection, aBrowser)
-{
-  TabActor.call(this, aConnection, aBrowser);
-  this._browser = aBrowser;
-  if (typeof(aBrowser.getTabBrowser) == "function") {
-    this._tabbrowser = aBrowser.getTabBrowser();
+function BrowserTabActor(connection, browser) {
+  TabActor.call(this, connection, browser);
+  this._browser = browser;
+  if (typeof browser.getTabBrowser == "function") {
+    this._tabbrowser = browser.getTabBrowser();
   }
 
   Object.defineProperty(this, "docShell", {
     value: this._browser.docShell,
     configurable: true
   });
 }
 
 BrowserTabActor.prototype = Object.create(TabActor.prototype);
 
 BrowserTabActor.prototype.constructor = BrowserTabActor;
 
 Object.defineProperty(BrowserTabActor.prototype, "title", {
-  get: function() {
+  get() {
     // On Fennec, we can check the session store data for zombie tabs
     if (this._browser.__SS_restore) {
       let sessionStore = this._browser.__SS_data;
       // Get the last selected entry
       let entry = sessionStore.entries[sessionStore.index - 1];
       return entry.title;
     }
     let title = this.contentDocument.title || this._browser.contentTitle;
@@ -2020,17 +2064,17 @@ Object.defineProperty(BrowserTabActor.pr
     }
     return title;
   },
   enumerable: true,
   configurable: false
 });
 
 Object.defineProperty(BrowserTabActor.prototype, "url", {
-  get: function() {
+  get() {
     // On Fennec, we can check the session store data for zombie tabs
     if (this._browser.__SS_restore) {
       let sessionStore = this._browser.__SS_data;
       // Get the last selected entry
       let entry = sessionStore.entries[sessionStore.index - 1];
       return entry.url;
     }
     if (this.webNavigation.currentURI) {
@@ -2038,232 +2082,255 @@ Object.defineProperty(BrowserTabActor.pr
     }
     return null;
   },
   enumerable: true,
   configurable: true
 });
 
 Object.defineProperty(BrowserTabActor.prototype, "browser", {
-  get: function() {
+  get() {
     return this._browser;
   },
   enumerable: true,
   configurable: false
 });
 
-BrowserTabActor.prototype.disconnect = function() {
+BrowserTabActor.prototype.disconnect = function () {
   TabActor.prototype.disconnect.call(this);
   this._browser = null;
   this._tabbrowser = null;
 };
 
-BrowserTabActor.prototype.exit = function() {
+BrowserTabActor.prototype.exit = function () {
   TabActor.prototype.exit.call(this);
   this._browser = null;
   this._tabbrowser = null;
 };
 
 exports.BrowserTabActor = BrowserTabActor;
 
 /**
  * This actor is a shim that connects to a ContentActor in a remote
  * browser process. All RDP packets get forwarded using the message
  * manager.
  *
- * @param aConnection The main RDP connection.
- * @param aBrowser XUL <browser> element to connect to.
+ * @param connection The main RDP connection.
+ * @param browser XUL <browser> element to connect to.
  */
-function RemoteBrowserTabActor(aConnection, aBrowser)
-{
-  this._conn = aConnection;
-  this._browser = aBrowser;
+function RemoteBrowserTabActor(connection, browser) {
+  this._conn = connection;
+  this._browser = browser;
   this._form = null;
 }
 
 RemoteBrowserTabActor.prototype = {
-  connect: function() {
+  connect() {
     let onDestroy = () => {
       this._form = null;
     };
-    let connect = DebuggerServer.connectToChild(this._conn, this._browser, onDestroy);
+    let connect = DebuggerServer.connectToChild(
+      this._conn, this._browser, onDestroy);
     return connect.then(form => {
       this._form = form;
       return this;
     });
   },
 
   get _mm() {
     return this._browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader
            .messageManager;
   },
 
-  update: function() {
+  update() {
     // If the child happens to be crashed/close/detach, it won't have _form set,
-    // so only request form update if some code is still listening on the other side.
+    // so only request form update if some code is still listening on the other
+    // side.
     if (this._form) {
       let deferred = promise.defer();
       let onFormUpdate = msg => {
         // There may be more than just one childtab.js up and running
         if (this._form.actor != msg.json.actor) {
           return;
         }
         this._mm.removeMessageListener("debug:form", onFormUpdate);
         this._form = msg.json;
         deferred.resolve(this);
       };
       this._mm.addMessageListener("debug:form", onFormUpdate);
       this._mm.sendAsyncMessage("debug:form");
       return deferred.promise;
-    } else {
-      return this.connect();
     }
+
+    return this.connect();
   },
 
-  form: function() {
+  form() {
     return this._form;
   },
 
-  exit: function() {
+  exit() {
     this._browser = null;
   },
 };
 
 exports.RemoteBrowserTabActor = RemoteBrowserTabActor;
 
-function BrowserAddonList(aConnection)
-{
-  this._connection = aConnection;
+function BrowserAddonList(connection) {
+  this._connection = connection;
   this._actorByAddonId = new Map();
   this._onListChanged = null;
 }
 
-BrowserAddonList.prototype.getList = function() {
-  var deferred = promise.defer();
+BrowserAddonList.prototype.getList = function () {
+  let deferred = promise.defer();
   AddonManager.getAllAddons((addons) => {
     for (let addon of addons) {
       let actor = this._actorByAddonId.get(addon.id);
       if (!actor) {
         actor = new BrowserAddonActor(this._connection, addon);
         this._actorByAddonId.set(addon.id, actor);
       }
     }
     deferred.resolve([...this._actorByAddonId].map(([_, actor]) => actor));
   });
   return deferred.promise;
-}
+};
 
 Object.defineProperty(BrowserAddonList.prototype, "onListChanged", {
-  enumerable: true, configurable: true,
-  get: function() { return this._onListChanged; },
-  set: function(v) {
+  enumerable: true,
+  configurable: true,
+  get() {
+    return this._onListChanged;
+  },
+  set(v) {
     if (v !== null && typeof v != "function") {
-      throw Error("onListChanged property may only be set to 'null' or a function");
+      throw new Error(
+        "onListChanged property may only be set to 'null' or a function");
     }
     this._onListChanged = v;
     if (this._onListChanged) {
       AddonManager.addAddonListener(this);
     } else {
       AddonManager.removeAddonListener(this);
     }
   }
 });
 
-BrowserAddonList.prototype.onInstalled = function (aAddon) {
+BrowserAddonList.prototype.onInstalled = function (addon) {
   this._onListChanged();
 };
 
-BrowserAddonList.prototype.onUninstalled = function (aAddon) {
-  this._actorByAddonId.delete(aAddon.id);
+BrowserAddonList.prototype.onUninstalled = function (addon) {
+  this._actorByAddonId.delete(addon.id);
   this._onListChanged();
 };
 
 exports.BrowserAddonList = BrowserAddonList;
 
 /**
  * The DebuggerProgressListener object is an nsIWebProgressListener which
  * handles onStateChange events for the inspected browser. If the user tries to
  * navigate away from a paused page, the listener makes sure that the debuggee
  * is resumed before the navigation begins.
  *
  * @param TabActor aTabActor
  *        The tab actor associated with this listener.
  */
-function DebuggerProgressListener(aTabActor) {
-  this._tabActor = aTabActor;
+function DebuggerProgressListener(tabActor) {
+  this._tabActor = tabActor;
   this._onWindowCreated = this.onWindowCreated.bind(this);
   this._onWindowHidden = this.onWindowHidden.bind(this);
 
   // Watch for windows destroyed (global observer that will need filtering)
   Services.obs.addObserver(this, "inner-window-destroyed", false);
 
   // XXX: for now we maintain the list of windows we know about in this instance
   // so that we can discriminate windows we care about when observing
   // inner-window-destroyed events. Bug 1016952 would remove the need for this.
   this._knownWindowIDs = new Map();
+
+  this._watchedDocShells = new WeakSet();
 }
 
 DebuggerProgressListener.prototype = {
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsIWebProgressListener,
     Ci.nsISupportsWeakReference,
     Ci.nsISupports,
   ]),
 
-  destroy: function() {
+  destroy() {
     Services.obs.removeObserver(this, "inner-window-destroyed", false);
     this._knownWindowIDs.clear();
     this._knownWindowIDs = null;
   },
 
-  watch: function(docShell) {
+  watch(docShell) {
+    // Add the docshell to the watched set. We're actually adding the window,
+    // because docShell objects are not wrappercached and would be rejected
+    // by the WeakSet.
+    let docShellWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                                 .getInterface(Ci.nsIDOMWindow);
+    this._watchedDocShells.add(docShellWindow);
+
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
-    webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATUS |
-                                          Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
-                                          Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
+    webProgress.addProgressListener(this,
+                                    Ci.nsIWebProgress.NOTIFY_STATUS |
+                                    Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
+                                    Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
 
     let handler = getDocShellChromeEventHandler(docShell);
     handler.addEventListener("DOMWindowCreated", this._onWindowCreated, true);
     handler.addEventListener("pageshow", this._onWindowCreated, true);
     handler.addEventListener("pagehide", this._onWindowHidden, true);
 
     // Dispatch the _windowReady event on the tabActor for pre-existing windows
     for (let win of this._getWindowsInDocShell(docShell)) {
       this._tabActor._windowReady(win);
       this._knownWindowIDs.set(getWindowID(win), win);
     }
   },
 
-  unwatch: function(docShell) {
+  unwatch(docShell) {
+    let docShellWindow = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
+                                 .getInterface(Ci.nsIDOMWindow);
+    if (!this._watchedDocShells.has(docShellWindow)) {
+      return;
+    }
+
     let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                               .getInterface(Ci.nsIWebProgress);
     // During process shutdown, the docshell may already be cleaned up and throw
     try {
       webProgress.removeProgressListener(this);
-    } catch(e) {}
+    } catch (e) {
+      // ignore
+    }
 
     let handler = getDocShellChromeEventHandler(docShell);
-    handler.removeEventListener("DOMWindowCreated", this._onWindowCreated, true);
+    handler.removeEventListener("DOMWindowCreated",
+      this._onWindowCreated, true);
     handler.removeEventListener("pageshow", this._onWindowCreated, true);
     handler.removeEventListener("pagehide", this._onWindowHidden, true);
 
     for (let win of this._getWindowsInDocShell(docShell)) {
       this._knownWindowIDs.delete(getWindowID(win));
     }
   },
 
-  _getWindowsInDocShell: function(docShell) {
+  _getWindowsInDocShell(docShell) {
     return getChildDocShells(docShell).map(d => {
       return d.QueryInterface(Ci.nsIInterfaceRequestor)
               .getInterface(Ci.nsIDOMWindow);
     });
   },
 
-  onWindowCreated: DevToolsUtils.makeInfallible(function(evt) {
+  onWindowCreated: DevToolsUtils.makeInfallible(function (evt) {
     if (!this._tabActor.attached) {
       return;
     }
 
     // pageshow events for non-persisted pages have already been handled by a
     // prior DOMWindowCreated event. For persisted pages, act as if the window
     // had just been created since it's been unfrozen from bfcache.
     if (evt.type == "pageshow" && !evt.persisted) {
@@ -2273,81 +2340,81 @@ DebuggerProgressListener.prototype = {
     let window = evt.target.defaultView;
     this._tabActor._windowReady(window);
 
     if (evt.type !== "pageshow") {
       this._knownWindowIDs.set(getWindowID(window), window);
     }
   }, "DebuggerProgressListener.prototype.onWindowCreated"),
 
-  onWindowHidden: DevToolsUtils.makeInfallible(function(evt) {
+  onWindowHidden: DevToolsUtils.makeInfallible(function (evt) {
     if (!this._tabActor.attached) {
       return;
     }
 
     // Only act as if the window has been destroyed if the 'pagehide' event
     // was sent for a persisted window (persisted is set when the page is put
     // and frozen in the bfcache). If the page isn't persisted, the observer's
     // inner-window-destroyed event will handle it.
     if (!evt.persisted) {
       return;
     }
 
     let window = evt.target.defaultView;
     this._tabActor._windowDestroyed(window, null, true);
   }, "DebuggerProgressListener.prototype.onWindowHidden"),
 
-  observe: DevToolsUtils.makeInfallible(function(subject, topic) {
+  observe: DevToolsUtils.makeInfallible(function (subject, topic) {
     if (!this._tabActor.attached) {
       return;
     }
 
     // Because this observer will be called for all inner-window-destroyed in
     // the application, we need to filter out events for windows we are not
     // watching
     let innerID = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
     let window = this._knownWindowIDs.get(innerID);
     if (window) {
       this._knownWindowIDs.delete(innerID);
       this._tabActor._windowDestroyed(window, innerID);
     }
   }, "DebuggerProgressListener.prototype.observe"),
 
   onStateChange:
-  DevToolsUtils.makeInfallible(function(aProgress, aRequest, aFlag, aStatus) {
+  DevToolsUtils.makeInfallible(function (progress, request, flag, status) {
     if (!this._tabActor.attached) {
       return;
     }
 
-    let isStart = aFlag & Ci.nsIWebProgressListener.STATE_START;
-    let isStop = aFlag & Ci.nsIWebProgressListener.STATE_STOP;
-    let isDocument = aFlag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
-    let isWindow = aFlag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
+    let isStart = flag & Ci.nsIWebProgressListener.STATE_START;
+    let isStop = flag & Ci.nsIWebProgressListener.STATE_STOP;
+    let isDocument = flag & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT;
+    let isWindow = flag & Ci.nsIWebProgressListener.STATE_IS_WINDOW;
 
     // Catch any iframe location change
     if (isDocument && isStop) {
       // Watch document stop to ensure having the new iframe url.
-      aProgress.QueryInterface(Ci.nsIDocShell);
-      this._tabActor._notifyDocShellsUpdate([aProgress]);
+      progress.QueryInterface(Ci.nsIDocShell);
+      this._tabActor._notifyDocShellsUpdate([progress]);
     }
 
-    let window = aProgress.DOMWindow;
+    let window = progress.DOMWindow;
     if (isDocument && isStart) {
       // One of the earliest events that tells us a new URI
       // is being loaded in this window.
-      let newURI = aRequest instanceof Ci.nsIChannel ? aRequest.URI.spec : null;
-      this._tabActor._willNavigate(window, newURI, aRequest);
+      let newURI = request instanceof Ci.nsIChannel ? request.URI.spec : null;
+      this._tabActor._willNavigate(window, newURI, request);
     }
     if (isWindow && isStop) {
       // Somewhat equivalent of load event.
       // (window.document.readyState == complete)
       this._tabActor._navigate(window);
     }
   }, "DebuggerProgressListener.prototype.onStateChange")
 };
 
-exports.register = function(handle) {
+exports.register = function (handle) {
   handle.setRootActor(createRootActor);
 };
 
-exports.unregister = function(handle) {
+exports.unregister = function (handle) {
   handle.setRootActor(null);
 };
--- a/devtools/server/protocol.js
+++ b/devtools/server/protocol.js
@@ -938,73 +938,106 @@ exports.Actor = Actor;
 exports.method = function(fn, spec={}) {
   fn._methodSpec = Object.freeze(spec);
   if (spec.request) Object.freeze(spec.request);
   if (spec.response) Object.freeze(spec.response);
   return fn;
 }
 
 /**
- * Process an actor definition from its prototype and generate
- * request handlers.
+ * Generates an actor specification from an actor description.
  */
-var actorProto = function(actorProto) {
-  if (actorProto._actorSpec) {
-    throw new Error("actorProto called twice on the same actor prototype!");
-  }
-
-  let protoSpec = {
-    methods: [],
+var generateActorSpec = function(actorDesc) {
+  let actorSpec = {
+    typeName: actorDesc.typeName,
+    methods: []
   };
 
-  // Find method and form specifications attached to prototype properties.
-  for (let name of Object.getOwnPropertyNames(actorProto)) {
-    let desc = Object.getOwnPropertyDescriptor(actorProto, name);
+  // Find method and form specifications attached to properties.
+  for (let name of Object.getOwnPropertyNames(actorDesc)) {
+    let desc = Object.getOwnPropertyDescriptor(actorDesc, name);
     if (!desc.value) {
       continue;
     }
 
     if (name.startsWith("formType")) {
       if (typeof(desc.value) === "string") {
-        protoSpec[name] = types.getType(desc.value);
+        actorSpec[name] = types.getType(desc.value);
       } else if (desc.value.name && registeredTypes.has(desc.value.name)) {
-        protoSpec[name] = desc.value;
+        actorSpec[name] = desc.value;
       } else {
         // Shorthand for a newly-registered DictType.
-        protoSpec[name] = types.addDictType(actorProto.typeName + "__" + name, desc.value);
+        actorSpec[name] = types.addDictType(actorDesc.typeName + "__" + name, desc.value);
       }
     }
 
     if (desc.value._methodSpec) {
-      let frozenSpec = desc.value._methodSpec;
+      let methodSpec = desc.value._methodSpec;
       let spec = {};
-      spec.name = frozenSpec.name || name;
-      spec.request = Request(object.merge({type: spec.name}, frozenSpec.request || undefined));
-      spec.response = Response(frozenSpec.response || undefined);
-      spec.telemetry = frozenSpec.telemetry;
-      spec.release = frozenSpec.release;
-      spec.oneway = frozenSpec.oneway;
+      spec.name = methodSpec.name || name;
+      spec.request = Request(object.merge({type: spec.name}, methodSpec.request || undefined));
+      spec.response = Response(methodSpec.response || undefined);
+      spec.telemetry = methodSpec.telemetry;
+      spec.release = methodSpec.release;
+      spec.oneway = methodSpec.oneway;
+
+      actorSpec.methods.push(spec);
+    }
+  }
 
-      protoSpec.methods.push(spec);
+  // Find additional method specifications
+  if (actorDesc.methods) {
+    for (let name in actorDesc.methods) {
+      let methodSpec = actorDesc.methods[name];
+      let spec = {};
+
+      spec.name = methodSpec.name || name;
+      spec.request = Request(object.merge({type: spec.name}, methodSpec.request || undefined));
+      spec.response = Response(methodSpec.response || undefined);
+      spec.telemetry = methodSpec.telemetry;
+      spec.release = methodSpec.release;
+      spec.oneway = methodSpec.oneway;
+
+      actorSpec.methods.push(spec);
     }
   }
 
   // Find event specifications
-  if (actorProto.events) {
-    protoSpec.events = new Map();
-    for (let name in actorProto.events) {
-      let eventRequest = actorProto.events[name];
+  if (actorDesc.events) {
+    actorSpec.events = new Map();
+    for (let name in actorDesc.events) {
+      let eventRequest = actorDesc.events[name];
       Object.freeze(eventRequest);
-      protoSpec.events.set(name, Request(object.merge({type: name}, eventRequest)));
+      actorSpec.events.set(name, Request(object.merge({type: name}, eventRequest)));
     }
   }
 
+  if (!registeredTypes.has(actorSpec.typeName)) {
+    types.addActorType(actorSpec.typeName);
+  }
+  registeredTypes.get(actorSpec.typeName).actorSpec = actorSpec;
+
+  return actorSpec;
+};
+exports.generateActorSpec = generateActorSpec;
+
+/**
+ * Generates request handlers as described by the given actor specification on
+ * the given actor prototype. Returns the actor prototype.
+ */
+var generateRequestHandlers = function(actorSpec, actorProto) {
+  if (actorProto._actorSpec) {
+    throw new Error("actorProto called twice on the same actor prototype!");
+  }
+
+  actorProto.typeName = actorSpec.typeName;
+
   // Generate request handlers for each method definition
   actorProto.requestTypes = Object.create(null);
-  protoSpec.methods.forEach(spec => {
+  actorSpec.methods.forEach(spec => {
     let handler = function(packet, conn) {
       try {
         let args;
         try {
           args = spec.request.read(packet, this);
         } catch(ex) {
           console.error("Error reading request: " + packet.type);
           throw ex;
@@ -1050,40 +1083,52 @@ var actorProto = function(actorProto) {
           return p.then(() => this.writeError(e));
         });
       }
     };
 
     actorProto.requestTypes[spec.request.type] = handler;
   });
 
-  actorProto._actorSpec = protoSpec;
+  actorProto._actorSpec = actorSpec;
+
   return actorProto;
 }
 
 /**
  * Create an actor class for the given actor prototype.
  *
- * @param object proto
- *    The object prototype.  Must have a 'typeName' property,
+ * @param object actorProto
+ *    The actor prototype.  Must have a 'typeName' property,
  *    should have method definitions, can have event definitions.
  */
-exports.ActorClass = function(proto) {
-  if (!proto.typeName) {
-    throw Error("Actor prototype must have a typeName member.");
+exports.ActorClass = function (actorProto) {
+  return ActorClassWithSpec(generateActorSpec(actorProto), actorProto);
+};
+
+/**
+ * Create an actor class for the given actor specification and prototype.
+ *
+ * @param object actorSpec
+ *    The actor specification. Must have a 'typeName' property.
+ * @param object actorProto
+ *    The actor prototype. Should have method definitions, can have event
+ *    definitions.
+ */
+var ActorClassWithSpec = function(actorSpec, actorProto) {
+  if (!actorSpec.typeName) {
+    throw Error("Actor specification must have a typeName member.");
   }
-  proto.extends = Actor;
-  if (!registeredTypes.has(proto.typeName)) {
-    types.addActorType(proto.typeName);
-  }
-  let cls = Class(actorProto(proto));
 
-  registeredTypes.get(proto.typeName).actorSpec = proto._actorSpec;
+  actorProto.extends = Actor;
+  let cls = Class(generateRequestHandlers(actorSpec, actorProto));
+
   return cls;
 };
+exports.ActorClassWithSpec = ActorClassWithSpec;
 
 /**
  * Base class for client-side actor fronts.
  */
 var Front = Class({
   extends: Pool,
 
   actorID: null,
@@ -1265,47 +1310,46 @@ exports.custom = function(fn, options={}
   return fn;
 }
 
 function prototypeOf(obj) {
   return typeof(obj) === "function" ? obj.prototype : obj;
 }
 
 /**
- * Process a front definition from its prototype and generate
- * request methods.
+ * Generates request methods as described by the given actor specification on
+ * the given front prototype. Returns the front prototype.
  */
-var frontProto = function(proto) {
-  let actorType = prototypeOf(proto.actorType);
-  if (proto._actorSpec) {
+var generateRequestMethods = function(actorSpec, frontProto) {
+  if (frontProto._actorSpec) {
     throw new Error("frontProto called twice on the same front prototype!");
   }
-  proto._actorSpec = actorType._actorSpec;
-  proto.typeName = actorType.typeName;
+
+  frontProto.typeName = actorSpec.typeName;
 
   // Generate request methods.
-  let methods = proto._actorSpec.methods;
+  let methods = actorSpec.methods;
   methods.forEach(spec => {
     let name = spec.name;
 
     // If there's already a property by this name in the front, it must
     // be a custom front method.
-    if (name in proto) {
-      let custom = proto[spec.name]._customFront;
+    if (name in frontProto) {
+      let custom = frontProto[spec.name]._customFront;
       if (custom === undefined) {
         throw Error("Existing method for " + spec.name + " not marked customFront while processing " + actorType.typeName + ".");
       }
       // If the user doesn't need the impl don't generate it.
       if (!custom.impl) {
         return;
       }
       name = custom.impl;
     }
 
-    proto[name] = function(...args) {
+    frontProto[name] = function(...args) {
       let histogram, startTime;
       if (spec.telemetry) {
         if (spec.oneway) {
           // That just doesn't make sense.
           throw Error("Telemetry specified for a oneway request");
         }
         let transportType = this.conn.localTransport
           ? "LOCAL_"
@@ -1349,36 +1393,36 @@ var frontProto = function(proto) {
         }
 
         return ret;
       });
     }
 
     // Release methods should call the destroy function on return.
     if (spec.release) {
-      let fn = proto[name];
-      proto[name] = function(...args) {
+      let fn = frontProto[name];
+      frontProto[name] = function(...args) {
         return fn.apply(this, args).then(result => {
           this.destroy();
           return result;
         })
       }
     }
   });
 
 
   // Process event specifications
-  proto._clientSpec = {};
+  frontProto._clientSpec = {};
 
-  let events = proto._actorSpec.events;
+  let events = actorSpec.events;
   if (events) {
     // This actor has events, scan the prototype for preEvent handlers...
     let preHandlers = new Map();
-    for (let name of Object.getOwnPropertyNames(proto)) {
-      let desc = Object.getOwnPropertyDescriptor(proto, name);
+    for (let name of Object.getOwnPropertyNames(frontProto)) {
+      let desc = Object.getOwnPropertyDescriptor(frontProto, name);
       if (!desc.value) {
         continue;
       }
       if (desc.value._preEvent) {
         let preEvent = desc.value._preEvent;
         if (!events.has(preEvent)) {
           throw Error("preEvent for event that doesn't exist: " + preEvent);
         }
@@ -1386,46 +1430,66 @@ var frontProto = function(proto) {
         if (!handlers) {
           handlers = [];
           preHandlers.set(preEvent, handlers);
         }
         handlers.push(desc.value);
       }
     }
 
-    proto._clientSpec.events = new Map();
+    frontProto._clientSpec.events = new Map();
 
     for (let [name, request] of events) {
-      proto._clientSpec.events.set(request.type, {
+      frontProto._clientSpec.events.set(request.type, {
         name: name,
         request: request,
         pre: preHandlers.get(name)
       });
     }
   }
-  return proto;
+
+  frontProto._actorSpec = actorSpec;
+
+  return frontProto;
 }
 
 /**
- * Create a front class for the given actor class, with the given prototype.
+ * Create a front class for the given actor class and front prototype.
  *
  * @param ActorClass actorType
  *    The actor class you're creating a front for.
+ * @param object frontProto
+ *    The front prototype.  Must have a 'typeName' property,
+ *    should have method definitions, can have event definitions.
+ */
+exports.FrontClass = function(actorType, frontProto) {
+  return FrontClassWithSpec(prototypeOf(actorType)._actorSpec, frontProto);
+}
+
+/**
+ * Create a front class for the given actor specification and front prototype.
+ *
+ * @param object actorSpec
+ *    The actor specification you're creating a front for.
  * @param object proto
  *    The object prototype.  Must have a 'typeName' property,
  *    should have method definitions, can have event definitions.
  */
-exports.FrontClass = function(actorType, proto) {
-  proto.actorType = actorType;
-  proto.extends = Front;
-  let cls = Class(frontProto(proto));
-  registeredTypes.get(cls.prototype.typeName).frontClass = cls;
+var FrontClassWithSpec = function(actorSpec, frontProto) {
+  frontProto.extends = Front;
+  let cls = Class(generateRequestMethods(actorSpec, frontProto));
+
+  if (!registeredTypes.has(actorSpec.typeName)) {
+    types.addActorType(actorSpec.typeName);
+  }
+  registeredTypes.get(actorSpec.typeName).frontClass = cls;
+
   return cls;
 }
-
+exports.FrontClassWithSpec = FrontClassWithSpec;
 
 exports.dumpActorSpec = function(type) {
   let actorSpec = type.actorSpec;
   let ret = {
     category: "actor",
     typeName: type.name,
     methods: [],
     events: {}
--- a/devtools/shared/gcli/commands/screenshot.js
+++ b/devtools/shared/gcli/commands/screenshot.js
@@ -2,16 +2,17 @@
  * 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 { Cc, Ci, Cr } = require("chrome");
 const l10n = require("gcli/l10n");
 const Services = require("Services");
+const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
 const { getRect } = require("devtools/shared/layout/utils");
 const promise = require("promise");
 
 loader.lazyImporter(this, "Downloads", "resource://gre/modules/Downloads.jsm");
 loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm");
 loader.lazyImporter(this, "OS", "resource://gre/modules/osfile.jsm");
 loader.lazyImporter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm");
 loader.lazyImporter(this, "PrivateBrowsingUtils",
@@ -352,29 +353,28 @@ function getFilename(defaultName) {
 
 /**
  * Save the image data to the clipboard. This returns a promise, so it can
  * be treated exactly like imgur / file processing, but it's really sync
  * for now.
  */
 function saveToClipboard(context, reply) {
   try {
+    const channel = NetUtil.newChannel({
+      uri: reply.data,
+      loadUsingSystemPrincipal: true,
+      contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE
+    });
+    const input = channel.open2();
+
     const loadContext = context.environment.chromeWindow
                                .QueryInterface(Ci.nsIInterfaceRequestor)
                                .getInterface(Ci.nsIWebNavigation)
                                .QueryInterface(Ci.nsILoadContext);
-    const io = Cc["@mozilla.org/network/io-service;1"]
-                  .getService(Ci.nsIIOService);
-    const channel = io.newChannel2(reply.data, null, null,
-                                   null,      // aLoadingNode
-                                   Services.scriptSecurityManager.getSystemPrincipal(),
-                                   null,      // aTriggeringPrincipal
-                                   Ci.nsILoadInfo.SEC_NORMAL,
-                                   Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE);
-    const input = channel.open();
+
     const imgTools = Cc["@mozilla.org/image/tools;1"]
                         .getService(Ci.imgITools);
 
     const container = {};
     imgTools.decodeImageData(input, channel.contentType, container);
 
     const wrapped = Cc["@mozilla.org/supports-interface-pointer;1"]
                       .createInstance(Ci.nsISupportsInterfacePointer);
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,7 +1,7 @@
-#Mon Nov 02 13:44:39 GMT 2015
+#Tue Apr 12 09:52:06 CEST 2016
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-all.zip
-distributionSha256Sum=2ba0aaa11a3e96ec0af31d532d808e1f09cc6dcad0954e637902a1ab544b9e60
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
+distributionSha256Sum=496d60c331f8666f99b66d08ff67a880697a7e85a9d9b76ff08814cf97f61a4c
--- a/mobile/android/app/lint.xml
+++ b/mobile/android/app/lint.xml
@@ -19,27 +19,33 @@
          Right now, we set these to lint warnings so:
 
          DO NOT ADD TO THIS LIST.
 
          We did this so we can land lint in automation
          and not fail everything. -->
     <issue id="AppCompatResource" severity="warning" />
     <issue id="GoogleAppIndexingDeepLinkError" severity="warning" />
+    <issue id="GoogleAppIndexingUrlError" severity="warning" />
     <issue id="Instantiatable" severity="warning" />
     <issue id="LongLogTag" severity="warning" />
     <issue id="MissingPermission" severity="warning" />
     <issue id="NewApi" severity="warning" />
     <issue id="OnClick" severity="warning" />
     <issue id="ReferenceType" severity="warning" />
     <issue id="ResourceAsColor" severity="warning" />
     <issue id="ResourceType" severity="warning" />
     <issue id="ValidFragment" severity="warning" />
     <issue id="WrongConstant" severity="warning" />
 
+    <!-- We fixed all "Registered" lint errors. However the current gradle plugin has a bug where
+         it ignores @SuppressLint annotations for this check. See CrashReporter class and
+         https://code.google.com/p/android/issues/detail?id=204846 -->
+    <issue id="Registered" severity="warning" />
+
     <!-- WHEN YOU FIX A LINT WARNING, ADD IT TO THIS LIST.
 
          We want all lint warnings to be fatal errors.
          This is the list of checks that we've explicitly
          set as errors. Ideally, once we have no more warnings,
          we switch to the `warningsAsErrors` lint option
          (bug 1253737) rather than listing everything explicitly. -->
     <issue id="AaptCrash" severity="error" />
@@ -139,17 +145,16 @@
     <issue id="ParcelCreator" severity="error" />
     <issue id="Performance" severity="error" />
     <issue id="Proguard" severity="error" />
     <issue id="ProguardSplit" severity="error" />
     <issue id="PropertyEscape" severity="error" />
     <issue id="ProtectedPermissions" severity="error" />
     <issue id="PxUsage" severity="error" />
     <issue id="Range" severity="error" />
-    <issue id="Registered" severity="error" />
     <issue id="RelativeOverlap" severity="error" />
     <issue id="RequiredSize" severity="error" />
     <issue id="ResAuto" severity="error" />
     <issue id="ResourceCycle" severity="error" />
     <issue id="ResourceName" severity="error" />
     <issue id="ResourceType" severity="error" />
     <issue id="RtlCompat" severity="error" />
     <issue id="RtlEnabled" severity="error" />
--- a/mobile/android/base/java/org/mozilla/gecko/CrashReporter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/CrashReporter.java
@@ -18,32 +18,34 @@ import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.nio.channels.Channels;
 import java.nio.channels.FileChannel;
 import java.util.zip.GZIPOutputStream;
 
 import org.mozilla.gecko.AppConstants.Versions;
 
+import android.annotation.SuppressLint;
 import android.app.AlertDialog;
 import android.app.ProgressDialog;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.support.v7.app.AppCompatActivity;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.View;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
 import android.widget.EditText;
 
+@SuppressLint("Registered") // This activity is only registered in the manifest if MOZ_CRASHREPORTER is set
 public class CrashReporter extends AppCompatActivity
 {
     private static final String LOGTAG = "GeckoCrashReporter";
 
     private static final String PASSED_MINI_DUMP_KEY = "minidumpPath";
     private static final String MINI_DUMP_PATH_KEY = "upload_file_minidump";
     private static final String PAGE_URL_KEY = "URL";
     private static final String NOTES_KEY = "Notes";
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoActivity.java
@@ -3,17 +3,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import android.content.ComponentName;
 import android.content.Intent;
 import android.support.v7.app.AppCompatActivity;
 
-public class GeckoActivity extends AppCompatActivity implements GeckoActivityStatus {
+public abstract class GeckoActivity extends AppCompatActivity implements GeckoActivityStatus {
     // has this activity recently started another Gecko activity?
     private boolean mGeckoActivityOpened;
 
     /**
      * Display any resources that show strings or encompass locale-specific
      * representations.
      *
      * onLocaleReady must always be called on the UI thread.
--- a/mobile/android/base/java/org/mozilla/gecko/Locales.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Locales.java
@@ -43,33 +43,33 @@ public class Locales {
         StrictMode.allowThreadDiskWrites();
         try {
             localeManager.getAndApplyPersistedLocale(context);
         } finally {
             StrictMode.setThreadPolicy(savedPolicy);
         }
     }
 
-    public static class LocaleAwareAppCompatActivity extends AppCompatActivity {
+    public static abstract class LocaleAwareAppCompatActivity extends AppCompatActivity {
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             Locales.initializeLocale(getApplicationContext());
             super.onCreate(savedInstanceState);
         }
 
     }
-    public static class LocaleAwareFragmentActivity extends FragmentActivity {
+    public static abstract class LocaleAwareFragmentActivity extends FragmentActivity {
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             Locales.initializeLocale(getApplicationContext());
             super.onCreate(savedInstanceState);
         }
     }
 
-    public static class LocaleAwareActivity extends Activity {
+    public static abstract class LocaleAwareActivity extends Activity {
         @Override
         protected void onCreate(Bundle savedInstanceState) {
             Locales.initializeLocale(getApplicationContext());
             super.onCreate(savedInstanceState);
         }
     }
 
     /**
--- a/mobile/android/base/java/org/mozilla/gecko/util/UnusedResourcesUtil.java
+++ b/mobile/android/base/java/org/mozilla/gecko/util/UnusedResourcesUtil.java
@@ -83,9 +83,36 @@ final class UnusedResourcesUtil {
 
     public static final int[] USED_IN_PREFS = {
             R.xml.preferences_advanced,
             R.xml.preferences_accessibility,
             R.xml.preferences_home,
             R.xml.preferences_privacy,
             R.xml.preferences_privacy_clear_tablet,
     };
+
+    // We are migrating to Gradle 2.10 and the Android Gradle plugin 2.0. The new plugin does find
+    // more unused resources but we are not ready to remove them yet. Some of the resources are going
+    // to be reused soon. This is a temporary solution so that the gradle migration is not blocked.
+    // See bug 1263390 / bug 1268414.
+    public static final int[] TEMPORARY_UNUSED_WHILE_MIGRATING_GRADLE = {
+            R.color.remote_tabs_setup_button_background_hit,
+
+            R.drawable.remote_tabs_setup_button_background,
+
+            R.style.ActionBarThemeGeckoPreferences,
+            R.style.TabsPanelSectionBase,
+            R.style.TabsPanelSection,
+            R.style.TabsPanelItemBase,
+            R.style.TabsPanelItem,
+            R.style.TabsPanelItem_TextAppearance,
+            R.style.TabsPanelItem_TextAppearance_Header,
+            R.style.TabsPanelItem_TextAppearance_Linkified,
+            R.style.TabWidget,
+            R.style.GeckoDialogTitle,
+            R.style.GeckoDialogTitle_SubTitle,
+            R.style.RemoteTabsPanelItem,
+            R.style.RemoteTabsPanelItem_TextAppearance,
+            R.style.RemoteTabsPanelItem_TextAppearance_Header,
+            R.style.RemoteTabsPanelItem_TextAppearance_Linkified,
+            R.style.RemoteTabsPanelItem_Button,
+    };
 }
--- a/mobile/android/config/tooltool-manifests/android-frontend/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-frontend/releng.manifest
@@ -2,19 +2,19 @@
 {
 "versions": [
   "Android SDK 6.0 / API 23",
   "Android tools r24.4",
   "Android build tools 23.0.1",
   "Android Support Repository (Support Library 23.0.1)",
   "Google Support Repository (Google Play Services 8.1.0)"
 ],
-"size": 535625068,
+"size": 510579808,
 "visibility": "internal",
-"digest": "0627515046a23c1d109e2782865b1b3b546c1d552955e4156317f76cbb195eb630aa25feea3f4edd1c685f129da0c2a5169d4d6349c1c31d8a95158a4569a478",
+"digest": "a4ea080f1aa5cb1d05250d45a288446ae07a54362a166bc7faa67281b5d50ee55001c1770cf9a942535b583e2f4c99d420902f065b03842d94a7d9273dca756d",
 "algorithm": "sha512",
 "filename": "android-sdk-linux.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "visibility": "public",
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
@@ -30,26 +30,26 @@
 "filename": "java_home-1.7.0-openjdk-1.7.0.85.x86_64.tar.xz",
 "unpack": true
 },
 {
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "jcentral.tar.xz",
 "unpack": true,
-"digest": "3fd467642a9067a1adfde7e3461b1366912b306607677b213d9f19201c23aab5f7f6361ebea7652bed1565215ed4524b51f5ced83ea68bb51ba2abca09b66148",
-"size": 41591712
+"digest": "0a970a85165bad0247c5a015cf6e0eb22bc497ec3ab3fed3948031b066041462599586f30f275738c123715e78ca65684701ab3dba99944f36f8a21c1364a857",
+"size": 41914156
 },
 {
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "gradle.tar.xz",
 "unpack": true,
-"digest": "9011a0a322b55c6f55ca7aa83298886f3f57e2a91a33a079fcdae5af746f9cf1528f36942138cff5a00154757d9acba2f1a4332d0f92da18e454b3c0c1788d20",
-"size": 50805888
+"digest": "2dcedca230ac47157611991d29231ea997396a094e08eca7cff47509ea79046c3bcd33c01198f367c99e9ba78d77af41619c0d47e24956f4b403b368304f8099",
+"size": 52223524
 },
 {
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "dotgradle.tar.xz",
 "unpack": true,
 "digest": "9f082ccd71ad18991eb71fcad355c6990f50a72a09ab9b79696521485656083a72faf5a8d4714de9c4b901ee2319b6786a51964846bb7075061642a8505501c2",
 "size": 512
--- a/mobile/android/config/tooltool-manifests/android-gradle-dependencies/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-gradle-dependencies/releng.manifest
@@ -2,19 +2,19 @@
 {
 "versions": [
   "Android SDK 6.0 / API 23",
   "Android tools r24.4",
   "Android build tools 23.0.1",
   "Android Support Repository (Support Library 23.0.1)",
   "Google Support Repository (Google Play Services 8.1.0)"
 ],
-"size": 535625068,
+"size": 510579808,
 "visibility": "internal",
-"digest": "0627515046a23c1d109e2782865b1b3b546c1d552955e4156317f76cbb195eb630aa25feea3f4edd1c685f129da0c2a5169d4d6349c1c31d8a95158a4569a478",
+"digest": "a4ea080f1aa5cb1d05250d45a288446ae07a54362a166bc7faa67281b5d50ee55001c1770cf9a942535b583e2f4c99d420902f065b03842d94a7d9273dca756d",
 "algorithm": "sha512",
 "filename": "android-sdk-linux.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "visibility": "public",
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
--- a/mobile/android/config/tooltool-manifests/android-x86/releng.manifest
+++ b/mobile/android/config/tooltool-manifests/android-x86/releng.manifest
@@ -11,19 +11,19 @@
 {
 "versions": [
   "Android SDK 6.0 / API 23",
   "Android tools r24.4",
   "Android build tools 23.0.1",
   "Android Support Repository (Support Library 23.0.1)",
   "Google Support Repository (Google Play Services 8.1.0)"
 ],
-"size": 535625068,
+"size": 510579808,
 "visibility": "internal", 
-"digest": "0627515046a23c1d109e2782865b1b3b546c1d552955e4156317f76cbb195eb630aa25feea3f4edd1c685f129da0c2a5169d4d6349c1c31d8a95158a4569a478",
+"digest": "a4ea080f1aa5cb1d05250d45a288446ae07a54362a166bc7faa67281b5d50ee55001c1770cf9a942535b583e2f4c99d420902f065b03842d94a7d9273dca756d",
 "algorithm": "sha512",
 "filename": "android-sdk-linux.tar.xz",
 "unpack": true
 },
 {
 "size": 167175,
 "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
 "algorithm": "sha512",
@@ -45,20 +45,20 @@
 "filename": "gcc.tar.xz",
 "unpack": true
 },
 {
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "jcentral.tar.xz",
 "unpack": true,
-"digest": "3fd467642a9067a1adfde7e3461b1366912b306607677b213d9f19201c23aab5f7f6361ebea7652bed1565215ed4524b51f5ced83ea68bb51ba2abca09b66148",
-"size": 41591712
+"digest": "0a970a85165bad0247c5a015cf6e0eb22bc497ec3ab3fed3948031b066041462599586f30f275738c123715e78ca65684701ab3dba99944f36f8a21c1364a857",
+"size": 41914156
 },
 {
 "algorithm": "sha512",
 "visibility": "public",
 "filename": "gradle.tar.xz",
 "unpack": true,
-"digest": "9011a0a322b55c6f55ca7aa83298886f3f57e2a91a33a079fcdae5af746f9cf1528f36942138cff5a00154757d9acba2f1a4332d0f92da18e454b3c0c1788d20",
-"size": 50805888
+"digest": "2dcedca230ac47157611991d29231ea997396a094e08eca7cff47509ea79046c3bcd33c01198f367c99e9ba78d77af41619c0d47e24956f4b403b368304f8099",
+"size": 52223524
 }
 ]
--- a/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/activities/FxAccountWebFlowActivity.java
+++ b/mobile/android/services/src/main/java/org/mozilla/gecko/fxa/activities/FxAccountWebFlowActivity.java
@@ -9,17 +9,17 @@ import android.os.Bundle;
 import org.mozilla.gecko.Locales;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.sync.setup.activities.ActivityUtils;
 
 /**
  * Activity which shows the status activity or passes through to web flow.
  */
-public class FxAccountWebFlowActivity extends FxAccountAbstractActivity {
+public abstract class FxAccountWebFlowActivity extends FxAccountAbstractActivity {
     protected static final String LOG_TAG = FxAccountWebFlowActivity.class.getSimpleName();
 
     protected static final String ABOUT_ACCOUNTS = "about:accounts";
 
     public static final String EXTRA_ENDPOINT = "entrypoint";
 
     protected static final String[] EXTRAS_TO_PASSTHROUGH = new String[] {
             EXTRA_ENDPOINT,
--- a/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/TestRunner.java
+++ b/mobile/android/tests/background/junit4/src/org/mozilla/gecko/background/testhelpers/TestRunner.java
@@ -62,48 +62,35 @@ public class TestRunner extends Robolect
         }
 
         buildFolder = FileFsFile.from(getBuildDir(config)).join("intermediates");
 
         final String type = getType(config);
         final String flavor = getFlavor(config);
         final String packageName = getPackageName(config);
 
-        final FsFile res;
-        final FsFile assets;
-        final FsFile manifest;
+        final FsFile assets = buildFolder.join("assets", flavor, type);;
+        final FsFile manifest = buildFolder.join("manifests", "full", flavor, type, "AndroidManifest.xml");
 
-        if (areResourcesFromLibrary()) {
-            FsFile bundlesFolder = buildFolder.join("bundles", flavor, type);
-            res = bundlesFolder.join("res");
-            assets = bundlesFolder.join("assets");
-            manifest = bundlesFolder.join("AndroidManifest.xml");
+        final FsFile res;
+        if (buildFolder.join("res", "merged").exists()) {
+            res = buildFolder.join("res", "merged", flavor, type);
+        } else if(buildFolder.join("res").exists()) {
+            res = buildFolder.join("res", flavor, type);
         } else {
-            if (buildFolder.join("res", "merged").exists()) {
-                res = buildFolder.join("res", "merged", flavor, type);
-            } else if(buildFolder.join("res").exists()) {
-                res = buildFolder.join("res", flavor, type);
-            } else {
-                throw new IllegalStateException("No resource folder found");
-            }
-            assets = buildFolder.join("assets", flavor, type);
-            manifest = buildFolder.join("manifests", "full", flavor, type, "AndroidManifest.xml");
+            throw new IllegalStateException("No resource folder found");
         }
 
         Logger.debug("Robolectric assets directory: " + assets.getPath());
         Logger.debug("   Robolectric res directory: " + res.getPath());
         Logger.debug("   Robolectric manifest path: " + manifest.getPath());
         Logger.debug("    Robolectric package name: " + packageName);
         return new AndroidManifest(manifest, res, assets, packageName);
     }
 
-    private boolean areResourcesFromLibrary() {
-        return buildFolder.join("bundles").exists();
-    }
-
     private static String getType(Config config) {
         try {
             return ReflectionHelpers.getStaticField(config.constants(), "BUILD_TYPE");
         } catch (Throwable e) {
             return null;
         }
     }
 
--- a/testing/docker/android-gradle-build/bin/after.sh
+++ b/testing/docker/android-gradle-build/bin/after.sh
@@ -1,14 +1,14 @@
 #!/bin/bash -vex
 
 set -x -e
 
 : WORKSPACE ${WORKSPACE:=/workspace}
-: GRADLE_VERSION ${GRADLE_VERSION:=2.7}
+: GRADLE_VERSION ${GRADLE_VERSION:=2.10}
 
 set -v
 
 # Package everything up.
 pushd ${WORKSPACE}
 # Not yet.  See notes on tooltool below.
 # cp -R /root/.android-sdk android-sdk-linux
 # tar cJf android-sdk-linux.tar.xz android-sdk-linux
--- a/toolkit/components/places/tests/PlacesTestUtils.jsm
+++ b/toolkit/components/places/tests/PlacesTestUtils.jsm
@@ -132,11 +132,48 @@ this.PlacesTestUtils = Object.freeze({
         handleError: function () {},
         handleCompletion: function(aReason)
         {
           resolve();
         }
       });
       commit.finalize();
     });
-  }
+  },
+
+  /**
+   * Asynchronously checks if an address is found in the database.
+   * @param aURI
+   *        nsIURI or address to look for.
+   *
+   * @return {Promise}
+   * @resolves Returns true if the page is found.
+   * @rejects JavaScript exception.
+   */
+  isPageInDB: Task.async(function* (aURI) {
+    let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
+    let db = yield PlacesUtils.promiseDBConnection();
+    let rows = yield db.executeCached(
+      "SELECT id FROM moz_places WHERE url = :url",
+      { url });
+    return rows.length > 0;
+  }),
 
+  /**
+   * Asynchronously checks how many visits exist for a specified page.
+   * @param aURI
+   *        nsIURI or address to look for.
+   *
+   * @return {Promise}
+   * @resolves Returns the number of visits found.
+   * @rejects JavaScript exception.
+   */
+  visitsInDB: Task.async(function* (aURI) {
+    let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
+    let db = yield PlacesUtils.promiseDBConnection();
+    let rows = yield db.executeCached(
+      `SELECT count(*) FROM moz_historyvisits v
+       JOIN moz_places h ON h.id = v.place_id
+       WHERE url = :url`,
+      { url });
+    return rows[0].getResultByIndex(0);
+  })
 });
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_isPageInDB.js
@@ -0,0 +1,10 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+
+add_task(function* test_execute() {
+  var good_uri = uri("http://mozilla.com");
+  var bad_uri = uri("http://google.com");
+  yield PlacesTestUtils.addVisits({uri: good_uri});
+  do_check_true(yield PlacesTestUtils.isPageInDB(good_uri));
+  do_check_false(yield PlacesTestUtils.isPageInDB(bad_uri));
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/unit/test_visitsInDB.js
@@ -0,0 +1,12 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+
+add_task(function* test_execute() {
+  const TEST_URI = uri("http://mozilla.com");
+
+  do_check_eq(0, yield PlacesTestUtils.visitsInDB(TEST_URI));
+  yield PlacesTestUtils.addVisits({uri: TEST_URI});
+  do_check_eq(1, yield PlacesTestUtils.visitsInDB(TEST_URI));
+  yield PlacesTestUtils.addVisits({uri: TEST_URI});
+  do_check_eq(2, yield PlacesTestUtils.visitsInDB(TEST_URI));
+});
--- a/toolkit/components/places/tests/unit/xpcshell.ini
+++ b/toolkit/components/places/tests/unit/xpcshell.ini
@@ -98,16 +98,17 @@ skip-if = os == "android"
 [test_history_catobs.js]
 [test_history_clear.js]
 [test_history_notifications.js]
 [test_history_observer.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_history_sidebar.js]
 [test_hosts_triggers.js]
+[test_isPageInDB.js]
 [test_isURIVisited.js]
 [test_isvisited.js]
 [test_keywords.js]
 [test_lastModified.js]
 [test_markpageas.js]
 [test_mozIAsyncLivemarks.js]
 [test_multi_queries.js]
 # Bug 676989: test fails consistently on Android
@@ -144,8 +145,9 @@ skip-if = os == "android"
 [test_tagging.js]
 [test_telemetry.js]
 [test_update_frecency_after_delete.js]
 # Bug 676989: test hangs consistently on Android
 skip-if = os == "android"
 [test_utils_backups_create.js]
 [test_utils_getURLsForContainerNode.js]
 [test_utils_setAnnotationsFor.js]
+[test_visitsInDB.js]
--- a/toolkit/locales/en-US/chrome/mozapps/handling/handling.dtd
+++ b/toolkit/locales/en-US/chrome/mozapps/handling/handling.dtd
@@ -1,9 +1,10 @@
 <!-- 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/. -->
 
 <!ENTITY window.emWidth "26em">
 <!ENTITY window.emHeight "26em">
-<!ENTITY ChooseApp.description "Choose an Application">
+<!ENTITY ChooseOtherApp.description "Choose other Application">
 <!ENTITY ChooseApp.label "Choose…">
 <!ENTITY ChooseApp.accessKey "C">
+<!ENTITY accept "Open link">
--- a/toolkit/mozapps/handling/content/dialog.xul
+++ b/toolkit/mozapps/handling/content/dialog.xul
@@ -29,19 +29,24 @@
   </hbox>
 
   <vbox flex="1">
     <label id="item-action-text" control="items"/>
     <richlistbox id="items" flex="1"
                  ondblclick="dialog.onDblClick();"
                  onselect="dialog.updateOKButton();">
       <richlistitem id="item-choose" orient="horizontal" selected="true">
-        <label value="&ChooseApp.description;" flex="1"/>
+        <label value="&ChooseOtherApp.description;" flex="1"/>
         <button oncommand="dialog.chooseApplication();"
                 label="&ChooseApp.label;" accesskey="&ChooseApp.accessKey;"/>
       </richlistitem>
     </richlistbox>
   </vbox>
 
   <checkbox id="remember" aria-describedby="remember-text" oncommand="dialog.onCheck();"/>
   <description id="remember-text"/>
 
+  <hbox class="dialog-button-box" pack="end">
+    <button dlgtype="cancel" icon="cancel" class="dialog-button"/>
+    <button dlgtype="accept" label="&accept;" icon="open" class="dialog-button"/>
+  </hbox>
+
 </dialog>