Bug 1274333 - Fix indentation of Heritage.extend. r=tromey draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Thu, 19 May 2016 11:58:49 -0500
changeset 368919 8d64882a803e060f7bc91a33ef7f44ebc73c8a53
parent 368918 26baaed1380122098f0fc0cecffd1b85b213b89a
child 521390 e705c21fbb7e6ca469c92cbc61a0c6e431e5f741
push id18658
push userbmo:jryans@gmail.com
push dateThu, 19 May 2016 17:30:49 +0000
reviewerstromey
bugs1274333
milestone49.0a1
Bug 1274333 - Fix indentation of Heritage.extend. r=tromey ESLint's auto-fix got confused by cases that passed an object literal to Heritage.extend() but placed the opening brace on the next line. MozReview-Commit-ID: 60NIZHYpwv3
devtools/client/webconsole/console-output.js
devtools/client/webconsole/hudservice.js
--- a/devtools/client/webconsole/console-output.js
+++ b/devtools/client/webconsole/console-output.js
@@ -15,17 +15,17 @@ loader.lazyImporter(this, "escapeHTML", 
 loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm");
 loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
 
 loader.lazyRequireGetter(this, "promise");
 loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true);
 loader.lazyRequireGetter(this, "TableWidget", "devtools/client/shared/widgets/TableWidget", true);
 loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/main", true);
 
-const Heritage = require("sdk/core/heritage");
+const { extend } = require("sdk/core/heritage");
 const URI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 const STRINGS_URI = "chrome://devtools/locale/webconsole.properties";
 
 const WebConsoleUtils = require("devtools/shared/webconsole/utils").Utils;
 const { getSourceNames } = require("devtools/client/shared/source-utils");
 const l10n = new WebConsoleUtils.L10n(STRINGS_URI);
@@ -57,27 +57,33 @@ const COMPAT = {
     LOG: 3,
   },
 
   // The preference keys to use for each category/severity combination, indexed
   // first by category (rows) and then by severity (columns).
   //
   // Most of these rather idiosyncratic names are historical and predate the
   // division of message type into "category" and "severity".
+  /* eslint-disable no-multi-spaces */
+  /* eslint-disable max-len */
+  /* eslint-disable no-inline-comments */
   PREFERENCE_KEYS: [
-    // Error        Warning       Info    Log
-    [ "network", "netwarn", null, "networkinfo", ],  // Network
-    [ "csserror", "cssparser", null, null, ],  // CSS
-    [ "exception", "jswarn", null, "jslog", ],  // JS
-    [ "error", "warn", "info", "log", ],  // Web Developer
-    [ null, null, null, null, ],  // Input
-    [ null, null, null, null, ],  // Output
-    [ "secerror", "secwarn", null, null, ],  // Security
-    [ "servererror", "serverwarn", "serverinfo", "serverlog", ],  // Server Logging
+    // Error         Warning       Info          Log
+    [ "network",     "netwarn",    null,         "networkinfo", ],  // Network
+    [ "csserror",    "cssparser",  null,         null,          ],  // CSS
+    [ "exception",   "jswarn",     null,         "jslog",       ],  // JS
+    [ "error",       "warn",       "info",       "log",         ],  // Web Developer
+    [ null,          null,         null,         null,          ],  // Input
+    [ null,          null,         null,         null,          ],  // Output
+    [ "secerror",    "secwarn",    null,         null,          ],  // Security
+    [ "servererror", "serverwarn", "serverinfo", "serverlog",   ],  // Server Logging
   ],
+  /* eslint-enable no-inline-comments */
+  /* eslint-enable max-len */
+  /* eslint-enable no-multi-spaces */
 
   // The fragment of a CSS class name that identifies each category.
   CATEGORY_CLASS_FRAGMENTS: [ "network", "cssparser", "exception", "console",
                               "input", "output", "security", "server" ],
 
   // The fragment of a CSS class name that identifies each severity.
   SEVERITY_CLASS_FRAGMENTS: [ "error", "warn", "info", "log" ],
 
@@ -567,100 +573,95 @@ Messages.BaseMessage.prototype = {
   destroy: function ()
   {
     // Destroy all widgets that have registered themselves in this.widgets
     for (let widget of this.widgets) {
       widget.destroy();
     }
     this.widgets.clear();
   }
-}; // Messages.BaseMessage.prototype
-
+};
 
 /**
  * The NavigationMarker is used to show a page load event.
  *
  * @constructor
  * @extends Messages.BaseMessage
  * @param object response
  *        The response received from the back end.
  * @param number timestamp
  *        The message date and time, milliseconds elapsed since 1 January 1970
  *        00:00:00 UTC.
  */
-Messages.NavigationMarker = function (response, timestamp)
-{
+Messages.NavigationMarker = function (response, timestamp) {
   Messages.BaseMessage.call(this);
 
   // Store the response packet received from the server. It might
   // be useful for extensions customizing the console output.
   this.response = response;
   this._url = response.url;
   this.textContent = "------ " + this._url;
   this.timestamp = timestamp;
 };
 
-Messages.NavigationMarker.prototype = Heritage.extend(Messages.BaseMessage.prototype,
-  {
+Messages.NavigationMarker.prototype = extend(Messages.BaseMessage.prototype, {
   /**
    * The address of the loading page.
    * @private
    * @type string
    */
-    _url: null,
+  _url: null,
 
   /**
    * Message timestamp.
    *
    * @type number
    *       Milliseconds elapsed since 1 January 1970 00:00:00 UTC.
    */
-    timestamp: 0,
-
-    _categoryCompat: COMPAT.CATEGORIES.NETWORK,
-    _severityCompat: COMPAT.SEVERITIES.LOG,
-    _categoryNameCompat: "network",
-    _severityNameCompat: "info",
-    _filterKeyCompat: "networkinfo",
+  timestamp: 0,
+
+  _categoryCompat: COMPAT.CATEGORIES.NETWORK,
+  _severityCompat: COMPAT.SEVERITIES.LOG,
+  _categoryNameCompat: "network",
+  _severityNameCompat: "info",
+  _filterKeyCompat: "networkinfo",
 
   /**
    * Prepare the DOM element for this message.
    * @return this
    */
-    render: function ()
-  {
-      if (this.element) {
-        return this;
-      }
-
-      let url = this._url;
-      let pos = url.indexOf("?");
-      if (pos > -1) {
-        url = url.substr(0, pos);
-      }
-
-      let doc = this.output.document;
-      let urlnode = doc.createElementNS(XHTML_NS, "a");
-      urlnode.className = "url";
-      urlnode.textContent = url;
-      urlnode.title = this._url;
-      urlnode.href = this._url;
-      urlnode.draggable = false;
-      this._addLinkCallback(urlnode);
-
-      let render = Messages.BaseMessage.prototype.render.bind(this);
-      render().element.appendChild(urlnode);
-      this.element.classList.add("navigation-marker");
-      this.element.url = this._url;
-      this.element.appendChild(doc.createTextNode("\n"));
-
+  render: function () {
+    if (this.element) {
       return this;
-    },
-  }); // Messages.NavigationMarker.prototype
-
+    }
+
+    let url = this._url;
+    let pos = url.indexOf("?");
+    if (pos > -1) {
+      url = url.substr(0, pos);
+    }
+
+    let doc = this.output.document;
+    let urlnode = doc.createElementNS(XHTML_NS, "a");
+    urlnode.className = "url";
+    urlnode.textContent = url;
+    urlnode.title = this._url;
+    urlnode.href = this._url;
+    urlnode.draggable = false;
+    this._addLinkCallback(urlnode);
+
+    let render = Messages.BaseMessage.prototype.render.bind(this);
+    render().element.appendChild(urlnode);
+    this.element.classList.add("navigation-marker");
+    this.element.url = this._url;
+    this.element.appendChild(doc.createTextNode("\n"));
+
+    return this;
+  },
+});
 
 /**
  * The Simple message is used to show any basic message in the Web Console.
  *
  * @constructor
  * @extends Messages.BaseMessage
  * @param string|Node|function message
  *        The message to display.
@@ -680,18 +681,17 @@ Messages.NavigationMarker.prototype = He
  *        and lineText.
  *        - stack: array that tells the message source stack.
  *        - className: (string) additional element class names for styling
  *        purposes.
  *        - private: (boolean) mark this as a private message.
  *        - filterDuplicates: (boolean) true if you do want this message to be
  *        filtered as a potential duplicate message, false otherwise.
  */
-Messages.Simple = function (message, options = {})
-{
+Messages.Simple = function (message, options = {}) {
   Messages.BaseMessage.call(this);
 
   this.category = options.category;
   this.severity = options.severity;
   this.location = options.location;
   this.stack = options.stack;
   this.timestamp = options.timestamp || Date.now();
   this.prefix = options.prefix;
@@ -701,374 +701,373 @@ Messages.Simple = function (message, opt
   this._className = options.className;
   this._link = options.link;
   this._linkCallback = options.linkCallback;
   this._filterDuplicates = options.filterDuplicates;
 
   this._onClickCollapsible = this._onClickCollapsible.bind(this);
 };
 
-Messages.Simple.prototype = Heritage.extend(Messages.BaseMessage.prototype,
-  {
+Messages.Simple.prototype = extend(Messages.BaseMessage.prototype, {
   /**
    * Message category.
    * @type string
    */
-    category: null,
+  category: null,
 
   /**
    * Message severity.
    * @type string
    */
-    severity: null,
+  severity: null,
 
   /**
    * Message source location. Properties: url, line, column, lineText.
    * @type object
    */
-    location: null,
+  location: null,
 
   /**
    * Holds the stackframes received from the server.
    *
    * @private
    * @type array
    */
-    stack: null,
+  stack: null,
 
   /**
    * Message prefix
    * @type string|null
    */
-    prefix: null,
+  prefix: null,
 
   /**
    * Tells if this message comes from a private browsing context.
    * @type boolean
    */
-    private: false,
+  private: false,
 
   /**
    * Custom class name for the DOM element of the message.
    * @private
    * @type string
    */
-    _className: null,
+  _className: null,
 
   /**
    * Message link - if this message is clicked then this URL opens in a new tab.
    * @private
    * @type string
    */
-    _link: null,
+  _link: null,
 
   /**
    * Message click event handler.
    * @private
    * @type function
    */
-    _linkCallback: null,
+  _linkCallback: null,
 
   /**
    * Tells if this message should be checked if it is a duplicate of another
    * message or not.
    */
-    _filterDuplicates: false,
+  _filterDuplicates: false,
 
   /**
    * The raw message displayed by this Message object. This can be a function,
    * DOM node or a string.
    *
    * @private
    * @type mixed
    */
-    _message: null,
-
-    _objectActors: null,
-    _groupDepthCompat: 0,
+  _message: null,
+
+  _objectActors: null,
+  _groupDepthCompat: 0,
 
   /**
    * Message timestamp.
    *
    * @type number
    *       Milliseconds elapsed since 1 January 1970 00:00:00 UTC.
    */
-    timestamp: 0,
-
-    get _categoryCompat() {
-      return this.category ?
+  timestamp: 0,
+
+  get _categoryCompat() {
+    return this.category ?
            COMPAT.CATEGORIES[this.category.toUpperCase()] : null;
-    },
-    get _severityCompat() {
-      return this.severity ?
+  },
+  get _severityCompat() {
+    return this.severity ?
            COMPAT.SEVERITIES[this.severity.toUpperCase()] : null;
-    },
-    get _categoryNameCompat() {
-      return this.category ?
+  },
+  get _categoryNameCompat() {
+    return this.category ?
            COMPAT.CATEGORY_CLASS_FRAGMENTS[this._categoryCompat] : null;
-    },
-    get _severityNameCompat() {
-      return this.severity ?
+  },
+  get _severityNameCompat() {
+    return this.severity ?
            COMPAT.SEVERITY_CLASS_FRAGMENTS[this._severityCompat] : null;
-    },
-
-    get _filterKeyCompat() {
-      return this._categoryCompat !== null && this._severityCompat !== null ?
+  },
+
+  get _filterKeyCompat() {
+    return this._categoryCompat !== null && this._severityCompat !== null ?
            COMPAT.PREFERENCE_KEYS[this._categoryCompat][this._severityCompat] :
            null;
-    },
-
-    init: function ()
+  },
+
+  init: function ()
   {
-      Messages.BaseMessage.prototype.init.apply(this, arguments);
-      this._groupDepthCompat = this.output.owner.groupDepth;
-      this._initRepeatID();
-      return this;
-    },
+    Messages.BaseMessage.prototype.init.apply(this, arguments);
+    this._groupDepthCompat = this.output.owner.groupDepth;
+    this._initRepeatID();
+    return this;
+  },
 
   /**
    * Tells if the message can be expanded/collapsed.
    * @type boolean
    */
-    collapsible: false,
+  collapsible: false,
 
   /**
    * Getter that tells if this message is collapsed - no details are shown.
    * @type boolean
    */
-    get collapsed() {
-      return this.collapsible && this.element && !this.element.hasAttribute("open");
-    },
-
-    _initRepeatID: function ()
+  get collapsed() {
+    return this.collapsible && this.element && !this.element.hasAttribute("open");
+  },
+
+  _initRepeatID: function ()
   {
-      if (!this._filterDuplicates) {
-        return;
-      }
+    if (!this._filterDuplicates) {
+      return;
+    }
 
     // Add the properties we care about for identifying duplicate messages.
-      let rid = this._repeatID;
-      delete rid.uid;
-
-      rid.category = this.category;
-      rid.severity = this.severity;
-      rid.prefix = this.prefix;
-      rid.private = this.private;
-      rid.location = this.location;
-      rid.link = this._link;
-      rid.linkCallback = this._linkCallback + "";
-      rid.className = this._className;
-      rid.groupDepth = this._groupDepthCompat;
-      rid.textContent = "";
-    },
-
-    getRepeatID: function ()
+    let rid = this._repeatID;
+    delete rid.uid;
+
+    rid.category = this.category;
+    rid.severity = this.severity;
+    rid.prefix = this.prefix;
+    rid.private = this.private;
+    rid.location = this.location;
+    rid.link = this._link;
+    rid.linkCallback = this._linkCallback + "";
+    rid.className = this._className;
+    rid.groupDepth = this._groupDepthCompat;
+    rid.textContent = "";
+  },
+
+  getRepeatID: function ()
   {
     // No point in returning a string that includes other properties when there
     // is a unique ID.
-      if (this._repeatID.uid) {
-        return JSON.stringify({ uid: this._repeatID.uid });
-      }
-
-      return JSON.stringify(this._repeatID);
-    },
-
-    render: function ()
+    if (this._repeatID.uid) {
+      return JSON.stringify({ uid: this._repeatID.uid });
+    }
+
+    return JSON.stringify(this._repeatID);
+  },
+
+  render: function ()
   {
-      if (this.element) {
-        return this;
-      }
-
-      let timestamp = new Widgets.MessageTimestamp(this, this.timestamp).render();
-
-      let icon = this.document.createElementNS(XHTML_NS, "span");
-      icon.className = "icon";
-      icon.title = l10n.getStr("severity." + this._severityNameCompat);
-      if (this.stack) {
-        icon.addEventListener("click", this._onClickCollapsible);
-      }
-
-      let prefixNode;
-      if (this.prefix) {
-        prefixNode = this.document.createElementNS(XHTML_NS, "span");
-        prefixNode.className = "prefix devtools-monospace";
-        prefixNode.textContent = this.prefix + ":";
-      }
+    if (this.element) {
+      return this;
+    }
+
+    let timestamp = new Widgets.MessageTimestamp(this, this.timestamp).render();
+
+    let icon = this.document.createElementNS(XHTML_NS, "span");
+    icon.className = "icon";
+    icon.title = l10n.getStr("severity." + this._severityNameCompat);
+    if (this.stack) {
+      icon.addEventListener("click", this._onClickCollapsible);
+    }
+
+    let prefixNode;
+    if (this.prefix) {
+      prefixNode = this.document.createElementNS(XHTML_NS, "span");
+      prefixNode.className = "prefix devtools-monospace";
+      prefixNode.textContent = this.prefix + ":";
+    }
 
     // Apply the current group by indenting appropriately.
     // TODO: remove this once bug 778766 is fixed.
-      let indent = this._groupDepthCompat * COMPAT.GROUP_INDENT;
-      let indentNode = this.document.createElementNS(XHTML_NS, "span");
-      indentNode.className = "indent";
-      indentNode.style.width = indent + "px";
-
-      let body = this._renderBody();
-      this._repeatID.textContent += "|" + body.textContent;
-
-      let repeatNode = this._renderRepeatNode();
-      let location = this._renderLocation();
-
-      Messages.BaseMessage.prototype.render.call(this);
-      if (this._className) {
-        this.element.className += " " + this._className;
-      }
-
-      this.element.appendChild(timestamp.element);
-      this.element.appendChild(indentNode);
-      this.element.appendChild(icon);
-      if (prefixNode) {
-        this.element.appendChild(prefixNode);
-      }
-
-      if (this.stack) {
-        let twisty = this.document.createElementNS(XHTML_NS, "a");
-        twisty.className = "theme-twisty";
-        twisty.href = "#";
-        twisty.title = l10n.getStr("messageToggleDetails");
-        twisty.addEventListener("click", this._onClickCollapsible);
-        this.element.appendChild(twisty);
-        this.collapsible = true;
-        this.element.setAttribute("collapsible", true);
-      }
-
-      this.element.appendChild(body);
-      if (repeatNode) {
-        this.element.appendChild(repeatNode);
-      }
-      if (location) {
-        this.element.appendChild(location);
-      }
-
-      this.element.appendChild(this.document.createTextNode("\n"));
-
-      this.element.clipboardText = this.element.textContent;
-
-      if (this.private) {
-        this.element.setAttribute("private", true);
-      }
+    let indent = this._groupDepthCompat * COMPAT.GROUP_INDENT;
+    let indentNode = this.document.createElementNS(XHTML_NS, "span");
+    indentNode.className = "indent";
+    indentNode.style.width = indent + "px";
+
+    let body = this._renderBody();
+    this._repeatID.textContent += "|" + body.textContent;
+
+    let repeatNode = this._renderRepeatNode();
+    let location = this._renderLocation();
+
+    Messages.BaseMessage.prototype.render.call(this);
+    if (this._className) {
+      this.element.className += " " + this._className;
+    }
+
+    this.element.appendChild(timestamp.element);
+    this.element.appendChild(indentNode);
+    this.element.appendChild(icon);
+    if (prefixNode) {
+      this.element.appendChild(prefixNode);
+    }
+
+    if (this.stack) {
+      let twisty = this.document.createElementNS(XHTML_NS, "a");
+      twisty.className = "theme-twisty";
+      twisty.href = "#";
+      twisty.title = l10n.getStr("messageToggleDetails");
+      twisty.addEventListener("click", this._onClickCollapsible);
+      this.element.appendChild(twisty);
+      this.collapsible = true;
+      this.element.setAttribute("collapsible", true);
+    }
+
+    this.element.appendChild(body);
+    if (repeatNode) {
+      this.element.appendChild(repeatNode);
+    }
+    if (location) {
+      this.element.appendChild(location);
+    }
+
+    this.element.appendChild(this.document.createTextNode("\n"));
+
+    this.element.clipboardText = this.element.textContent;
+
+    if (this.private) {
+      this.element.setAttribute("private", true);
+    }
 
     // TODO: handle object releasing in a more elegant way once all console
     // messages use the new API - bug 778766.
-      this.element._objectActors = this._objectActors;
-      this._objectActors = null;
-
-      return this;
-    },
+    this.element._objectActors = this._objectActors;
+    this._objectActors = null;
+
+    return this;
+  },
 
   /**
    * Render the message body DOM element.
    * @private
    * @return Element
    */
-    _renderBody: function ()
+  _renderBody: function ()
   {
-      let body = this.document.createElementNS(XHTML_NS, "span");
-      body.className = "message-body-wrapper message-body devtools-monospace";
-
-      let bodyInner = this.document.createElementNS(XHTML_NS, "span");
-      body.appendChild(bodyInner);
-
-      let anchor, container = bodyInner;
-      if (this._link || this._linkCallback) {
-        container = anchor = this.document.createElementNS(XHTML_NS, "a");
-        anchor.href = this._link || "#";
-        anchor.draggable = false;
-        this._addLinkCallback(anchor, this._linkCallback);
-        bodyInner.appendChild(anchor);
-      }
-
-      if (typeof this._message == "function") {
-        container.appendChild(this._message(this));
-      } else if (this._message instanceof Ci.nsIDOMNode) {
-        container.appendChild(this._message);
-      } else {
-        container.textContent = this._message;
-      }
-
-      if (this.stack) {
-        let stack = new Widgets.Stacktrace(this, this.stack).render().element;
-        body.appendChild(this.document.createTextNode("\n"));
-        body.appendChild(stack);
-      }
-
-      return body;
-    },
+    let body = this.document.createElementNS(XHTML_NS, "span");
+    body.className = "message-body-wrapper message-body devtools-monospace";
+
+    let bodyInner = this.document.createElementNS(XHTML_NS, "span");
+    body.appendChild(bodyInner);
+
+    let anchor, container = bodyInner;
+    if (this._link || this._linkCallback) {
+      container = anchor = this.document.createElementNS(XHTML_NS, "a");
+      anchor.href = this._link || "#";
+      anchor.draggable = false;
+      this._addLinkCallback(anchor, this._linkCallback);
+      bodyInner.appendChild(anchor);
+    }
+
+    if (typeof this._message == "function") {
+      container.appendChild(this._message(this));
+    } else if (this._message instanceof Ci.nsIDOMNode) {
+      container.appendChild(this._message);
+    } else {
+      container.textContent = this._message;
+    }
+
+    if (this.stack) {
+      let stack = new Widgets.Stacktrace(this, this.stack).render().element;
+      body.appendChild(this.document.createTextNode("\n"));
+      body.appendChild(stack);
+    }
+
+    return body;
+  },
 
   /**
    * Render the repeat bubble DOM element part of the message.
    * @private
    * @return Element
    */
-    _renderRepeatNode: function ()
+  _renderRepeatNode: function ()
   {
-      if (!this._filterDuplicates) {
-        return null;
-      }
-
-      let repeatNode = this.document.createElementNS(XHTML_NS, "span");
-      repeatNode.setAttribute("value", "1");
-      repeatNode.className = "message-repeats";
-      repeatNode.textContent = 1;
-      repeatNode._uid = this.getRepeatID();
-      return repeatNode;
-    },
+    if (!this._filterDuplicates) {
+      return null;
+    }
+
+    let repeatNode = this.document.createElementNS(XHTML_NS, "span");
+    repeatNode.setAttribute("value", "1");
+    repeatNode.className = "message-repeats";
+    repeatNode.textContent = 1;
+    repeatNode._uid = this.getRepeatID();
+    return repeatNode;
+  },
 
   /**
    * Render the message source location DOM element.
    * @private
    * @return Element
    */
-    _renderLocation: function ()
+  _renderLocation: function ()
   {
-      if (!this.location) {
-        return null;
-      }
-
-      let {url, line, column} = this.location;
-      if (IGNORED_SOURCE_URLS.indexOf(url) != -1) {
-        return null;
-      }
+    if (!this.location) {
+      return null;
+    }
+
+    let {url, line, column} = this.location;
+    if (IGNORED_SOURCE_URLS.indexOf(url) != -1) {
+      return null;
+    }
 
     // The ConsoleOutput owner is a WebConsoleFrame instance from webconsole.js.
     // TODO: move createLocationNode() into this file when bug 778766 is fixed.
-      return this.output.owner.createLocationNode({url: url,
+    return this.output.owner.createLocationNode({url: url,
                                                  line: line,
                                                  column: column});
-    },
+  },
 
   /**
    * The click event handler for the message expander arrow element. This method
    * toggles the display of message details.
    *
    * @private
    * @param nsIDOMEvent ev
    *        The DOM event object.
    * @see this.toggleDetails()
    */
-    _onClickCollapsible: function (ev)
+  _onClickCollapsible: function (ev)
   {
-      ev.preventDefault();
-      this.toggleDetails();
-    },
+    ev.preventDefault();
+    this.toggleDetails();
+  },
 
   /**
    * Expand/collapse message details.
    */
-    toggleDetails: function ()
+  toggleDetails: function ()
   {
-      let twisty = this.element.querySelector(".theme-twisty");
-      if (this.element.hasAttribute("open")) {
-        this.element.removeAttribute("open");
-        twisty.removeAttribute("open");
-      } else {
-        this.element.setAttribute("open", true);
-        twisty.setAttribute("open", true);
-      }
-    },
-  }); // Messages.Simple.prototype
+    let twisty = this.element.querySelector(".theme-twisty");
+    if (this.element.hasAttribute("open")) {
+      this.element.removeAttribute("open");
+      twisty.removeAttribute("open");
+    } else {
+      this.element.setAttribute("open", true);
+      twisty.setAttribute("open", true);
+    }
+  },
+}); // Messages.Simple.prototype
 
 
 /**
  * The Extended message.
  *
  * @constructor
  * @extends Messages.Simple
  * @param array messagePieces
@@ -1090,93 +1089,92 @@ Messages.Extended = function (messagePie
     this._quoteStrings = options.quoteStrings;
   }
 
   this._repeatID.quoteStrings = this._quoteStrings;
   this._repeatID.messagePieces = JSON.stringify(messagePieces);
   this._repeatID.actors = new Set(); // using a set to avoid duplicates
 };
 
-Messages.Extended.prototype = Heritage.extend(Messages.Simple.prototype,
-  {
+Messages.Extended.prototype = extend(Messages.Simple.prototype, {
   /**
    * The message pieces displayed by this message instance.
    * @private
    * @type array
    */
-    _messagePieces: null,
+  _messagePieces: null,
 
   /**
    * Boolean that tells if the strings displayed in this message are wrapped.
    * @private
    * @type boolean
    */
-    _quoteStrings: true,
-
-    getRepeatID: function ()
+  _quoteStrings: true,
+
+  getRepeatID: function ()
   {
-      if (this._repeatID.uid) {
-        return JSON.stringify({ uid: this._repeatID.uid });
-      }
+    if (this._repeatID.uid) {
+      return JSON.stringify({ uid: this._repeatID.uid });
+    }
 
     // Sets are not stringified correctly. Temporarily switching to an array.
-      let actors = this._repeatID.actors;
-      this._repeatID.actors = [...actors];
-      let result = JSON.stringify(this._repeatID);
-      this._repeatID.actors = actors;
-      return result;
-    },
-
-    render: function ()
+    let actors = this._repeatID.actors;
+    this._repeatID.actors = [...actors];
+    let result = JSON.stringify(this._repeatID);
+    this._repeatID.actors = actors;
+    return result;
+  },
+
+  render: function ()
   {
-      let result = this.document.createDocumentFragment();
-
-      for (let i = 0; i < this._messagePieces.length; i++) {
-        let separator = i > 0 ? this._renderBodyPieceSeparator() : null;
-        if (separator) {
-          result.appendChild(separator);
-        }
-
-        let piece = this._messagePieces[i];
-        result.appendChild(this._renderBodyPiece(piece));
+    let result = this.document.createDocumentFragment();
+
+    for (let i = 0; i < this._messagePieces.length; i++) {
+      let separator = i > 0 ? this._renderBodyPieceSeparator() : null;
+      if (separator) {
+        result.appendChild(separator);
       }
 
-      this._message = result;
-      this._messagePieces = null;
-      return Messages.Simple.prototype.render.call(this);
-    },
+      let piece = this._messagePieces[i];
+      result.appendChild(this._renderBodyPiece(piece));
+    }
+
+    this._message = result;
+    this._messagePieces = null;
+    return Messages.Simple.prototype.render.call(this);
+  },
 
   /**
    * Render the separator between the pieces of the message.
    *
    * @private
    * @return Element
    */
-    _renderBodyPieceSeparator: function () { return null; },
+  _renderBodyPieceSeparator: function () { return null; },
 
   /**
    * Render one piece/element of the message array.
    *
    * @private
    * @param mixed piece
    *        Message element to display - this can be a LongString, ObjectActor,
    *        DOM node or a function to invoke.
    * @return Element
    */
-    _renderBodyPiece: function (piece, options = {})
+  _renderBodyPiece: function (piece, options = {})
   {
-      if (piece instanceof Ci.nsIDOMNode) {
-        return piece;
-      }
-      if (typeof piece == "function") {
-        return piece(this);
-      }
-
-      return this._renderValueGrip(piece, options);
-    },
+    if (piece instanceof Ci.nsIDOMNode) {
+      return piece;
+    }
+    if (typeof piece == "function") {
+      return piece(this);
+    }
+
+    return this._renderValueGrip(piece, options);
+  },
 
   /**
    * Render a grip that represents a value received from the server. This method
    * picks the appropriate widget to render the value with.
    *
    * @private
    * @param object grip
    *        The value grip received from the server.
@@ -1188,153 +1186,153 @@ Messages.Extended.prototype = Heritage.e
    *        grip. This is typically set to true when the object needs to be
    *        displayed in an array preview, or as a property value in object
    *        previews, etc.
    *        - shorten - boolean that tells the renderer to display a truncated
    *        grip.
    * @return DOMElement
    *         The DOM element that displays the given grip.
    */
-    _renderValueGrip: function (grip, options = {})
+  _renderValueGrip: function (grip, options = {})
   {
-      let isPrimitive = VariablesView.isPrimitive({ value: grip });
-      let isActorGrip = WebConsoleUtils.isActorGrip(grip);
-      let noStringQuotes = !this._quoteStrings;
-      if ("noStringQuotes" in options) {
-        noStringQuotes = options.noStringQuotes;
+    let isPrimitive = VariablesView.isPrimitive({ value: grip });
+    let isActorGrip = WebConsoleUtils.isActorGrip(grip);
+    let noStringQuotes = !this._quoteStrings;
+    if ("noStringQuotes" in options) {
+      noStringQuotes = options.noStringQuotes;
+    }
+
+    if (isActorGrip) {
+      this._repeatID.actors.add(grip.actor);
+
+      if (!isPrimitive) {
+        return this._renderObjectActor(grip, options);
       }
-
-      if (isActorGrip) {
-        this._repeatID.actors.add(grip.actor);
-
-        if (!isPrimitive) {
-          return this._renderObjectActor(grip, options);
-        }
-        if (grip.type == "longString") {
-          let widget = new Widgets.LongString(this, grip, options).render();
-          return widget.element;
-        }
+      if (grip.type == "longString") {
+        let widget = new Widgets.LongString(this, grip, options).render();
+        return widget.element;
       }
-
-      let unshortenedGrip = grip;
-      if (options.shorten) {
-        grip = this.shortenValueGrip(grip);
+    }
+
+    let unshortenedGrip = grip;
+    if (options.shorten) {
+      grip = this.shortenValueGrip(grip);
+    }
+
+    let result = this.document.createElementNS(XHTML_NS, "span");
+    if (isPrimitive) {
+      if (Widgets.URLString.prototype.containsURL.call(Widgets.URLString.prototype, grip)) {
+        let widget = new Widgets.URLString(this, grip, unshortenedGrip).render();
+        return widget.element;
       }
 
-      let result = this.document.createElementNS(XHTML_NS, "span");
-      if (isPrimitive) {
-        if (Widgets.URLString.prototype.containsURL.call(Widgets.URLString.prototype, grip)) {
-          let widget = new Widgets.URLString(this, grip, unshortenedGrip).render();
-          return widget.element;
-        }
-
-        let className = this.getClassNameForValueGrip(grip);
-        if (className) {
-          result.className = className;
-        }
-
-        result.textContent = VariablesView.getString(grip, {
-          noStringQuotes: noStringQuotes,
-          concise: options.concise,
-        });
-      } else {
-        result.textContent = grip;
+      let className = this.getClassNameForValueGrip(grip);
+      if (className) {
+        result.className = className;
       }
 
-      return result;
-    },
+      result.textContent = VariablesView.getString(grip, {
+        noStringQuotes: noStringQuotes,
+        concise: options.concise,
+      });
+    } else {
+      result.textContent = grip;
+    }
+
+    return result;
+  },
 
   /**
    * Shorten grips of the type string, leaves other grips unmodified.
    *
    * @param object grip
    *        Value grip from the server.
    * @return object
    *        Possible values of object:
    *        - A shortened string, if original grip was of string type.
    *        - The unmodified input grip, if it wasn't of string type.
    */
-    shortenValueGrip: function (grip)
+  shortenValueGrip: function (grip)
   {
-      let shortVal = grip;
-      if (typeof (grip) == "string") {
-        shortVal = grip.replace(/(\r\n|\n|\r)/gm, " ");
-        if (shortVal.length > MAX_STRING_GRIP_LENGTH) {
-          shortVal = shortVal.substring(0, MAX_STRING_GRIP_LENGTH - 1) + ELLIPSIS;
-        }
+    let shortVal = grip;
+    if (typeof (grip) == "string") {
+      shortVal = grip.replace(/(\r\n|\n|\r)/gm, " ");
+      if (shortVal.length > MAX_STRING_GRIP_LENGTH) {
+        shortVal = shortVal.substring(0, MAX_STRING_GRIP_LENGTH - 1) + ELLIPSIS;
       }
-
-      return shortVal;
-    },
+    }
+
+    return shortVal;
+  },
 
   /**
    * Get a CodeMirror-compatible class name for a given value grip.
    *
    * @param object grip
    *        Value grip from the server.
    * @return string
    *         The class name for the grip.
    */
-    getClassNameForValueGrip: function (grip)
+  getClassNameForValueGrip: function (grip)
   {
-      let map = {
-        "number": "cm-number",
-        "longstring": "console-string",
-        "string": "console-string",
-        "regexp": "cm-string-2",
-        "boolean": "cm-atom",
-        "-infinity": "cm-atom",
-        "infinity": "cm-atom",
-        "null": "cm-atom",
-        "undefined": "cm-comment",
-        "symbol": "cm-atom"
-      };
-
-      let className = map[typeof grip];
-      if (!className && grip && grip.type) {
-        className = map[grip.type.toLowerCase()];
-      }
-      if (!className && grip && grip.class) {
-        className = map[grip.class.toLowerCase()];
-      }
-
-      return className;
-    },
+    let map = {
+      "number": "cm-number",
+      "longstring": "console-string",
+      "string": "console-string",
+      "regexp": "cm-string-2",
+      "boolean": "cm-atom",
+      "-infinity": "cm-atom",
+      "infinity": "cm-atom",
+      "null": "cm-atom",
+      "undefined": "cm-comment",
+      "symbol": "cm-atom"
+    };
+
+    let className = map[typeof grip];
+    if (!className && grip && grip.type) {
+      className = map[grip.type.toLowerCase()];
+    }
+    if (!className && grip && grip.class) {
+      className = map[grip.class.toLowerCase()];
+    }
+
+    return className;
+  },
 
   /**
    * Display an object actor with the appropriate renderer.
    *
    * @private
    * @param object objectActor
    *        The ObjectActor to display.
    * @param object options
    *        Options to use for displaying the ObjectActor.
    * @see this._renderValueGrip for the available options.
    * @return DOMElement
    *         The DOM element that displays the object actor.
    */
-    _renderObjectActor: function (objectActor, options = {})
+  _renderObjectActor: function (objectActor, options = {})
   {
-      let widget = Widgets.ObjectRenderers.byClass[objectActor.class];
-
-      let { preview } = objectActor;
-      if ((!widget || (widget.canRender && !widget.canRender(objectActor)))
+    let widget = Widgets.ObjectRenderers.byClass[objectActor.class];
+
+    let { preview } = objectActor;
+    if ((!widget || (widget.canRender && !widget.canRender(objectActor)))
         && preview
         && preview.kind) {
-        widget = Widgets.ObjectRenderers.byKind[preview.kind];
-      }
-
-      if (!widget || (widget.canRender && !widget.canRender(objectActor))) {
-        widget = Widgets.JSObject;
-      }
-
-      let instance = new widget(this, objectActor, options).render();
-      return instance.element;
-    },
-  }); // Messages.Extended.prototype
+      widget = Widgets.ObjectRenderers.byKind[preview.kind];
+    }
+
+    if (!widget || (widget.canRender && !widget.canRender(objectActor))) {
+      widget = Widgets.JSObject;
+    }
+
+    let instance = new widget(this, objectActor, options).render();
+    return instance.element;
+  },
+}); // Messages.Extended.prototype
 
 
 
 /**
  * The JavaScriptEvalOutput message.
  *
  * @constructor
  * @extends Messages.Extended
@@ -1419,165 +1417,164 @@ Messages.ConsoleGeneric = function (pack
   }
 
   this._repeatID.consoleApiLevel = packet.level;
   this._repeatID.styles = packet.styles;
   this.stack = this._repeatID.stacktrace = packet.stacktrace;
   this._styles = packet.styles || [];
 };
 
-Messages.ConsoleGeneric.prototype = Heritage.extend(Messages.Extended.prototype,
+Messages.ConsoleGeneric.prototype = extend(Messages.Extended.prototype, {
+  _styles: null,
+
+  _renderBodyPieceSeparator: function ()
   {
-    _styles: null,
-
-    _renderBodyPieceSeparator: function ()
-  {
-      return this.document.createTextNode(" ");
-    },
-
-    render: function ()
+    return this.document.createTextNode(" ");
+  },
+
+  render: function ()
   {
-      let msg = this.document.createElementNS(XHTML_NS, "span");
-      msg.className = "message-body devtools-monospace";
-
-      this._renderBodyPieces(msg);
-
-      let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
-      let location = Messages.Simple.prototype._renderLocation.call(this);
-      if (location) {
-        location.target = "jsdebugger";
-      }
-
-      let flex = this.document.createElementNS(XHTML_NS, "span");
-      flex.className = "message-flex-body";
-
-      flex.appendChild(msg);
-
-      if (repeatNode) {
-        flex.appendChild(repeatNode);
-      }
-      if (location) {
-        flex.appendChild(location);
-      }
-
-      let result = this.document.createDocumentFragment();
-      result.appendChild(flex);
-
-      this._message = result;
-      this._stacktrace = null;
-
-      Messages.Simple.prototype.render.call(this);
-
-      return this;
-    },
-
-    _renderBody: function ()
+    let msg = this.document.createElementNS(XHTML_NS, "span");
+    msg.className = "message-body devtools-monospace";
+
+    this._renderBodyPieces(msg);
+
+    let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
+    let location = Messages.Simple.prototype._renderLocation.call(this);
+    if (location) {
+      location.target = "jsdebugger";
+    }
+
+    let flex = this.document.createElementNS(XHTML_NS, "span");
+    flex.className = "message-flex-body";
+
+    flex.appendChild(msg);
+
+    if (repeatNode) {
+      flex.appendChild(repeatNode);
+    }
+    if (location) {
+      flex.appendChild(location);
+    }
+
+    let result = this.document.createDocumentFragment();
+    result.appendChild(flex);
+
+    this._message = result;
+    this._stacktrace = null;
+
+    Messages.Simple.prototype.render.call(this);
+
+    return this;
+  },
+
+  _renderBody: function ()
   {
-      let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
-      body.classList.remove("devtools-monospace", "message-body");
-      return body;
-    },
-
-    _renderBodyPieces: function (container)
+    let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
+    body.classList.remove("devtools-monospace", "message-body");
+    return body;
+  },
+
+  _renderBodyPieces: function (container)
   {
-      let lastStyle = null;
-      let stylePieces = this._styles.length > 0 ? this._styles.length : 1;
-
-      for (let i = 0; i < this._messagePieces.length; i++) {
+    let lastStyle = null;
+    let stylePieces = this._styles.length > 0 ? this._styles.length : 1;
+
+    for (let i = 0; i < this._messagePieces.length; i++) {
       // Pieces with an associated style definition come from "%c" formatting.
       // For body pieces beyond that, add a separator before each one.
-        if (i >= stylePieces) {
-          container.appendChild(this._renderBodyPieceSeparator());
-        }
-
-        let piece = this._messagePieces[i];
-        let style = this._styles[i];
+      if (i >= stylePieces) {
+        container.appendChild(this._renderBodyPieceSeparator());
+      }
+
+      let piece = this._messagePieces[i];
+      let style = this._styles[i];
 
       // No long string support.
-        lastStyle = (style && typeof style == "string") ?
+      lastStyle = (style && typeof style == "string") ?
                   this.cleanupStyle(style) : null;
 
-        container.appendChild(this._renderBodyPiece(piece, lastStyle));
-      }
-
-      this._messagePieces = null;
-      this._styles = null;
-    },
-
-    _renderBodyPiece: function (piece, style)
+      container.appendChild(this._renderBodyPiece(piece, lastStyle));
+    }
+
+    this._messagePieces = null;
+    this._styles = null;
+  },
+
+  _renderBodyPiece: function (piece, style)
   {
     // Skip quotes for top-level strings.
-      let options = { noStringQuotes: true };
-      let elem = Messages.Extended.prototype._renderBodyPiece.call(this, piece, options);
-      let result = elem;
-
-      if (style) {
-        if (elem.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
-          elem.style = style;
-        } else {
-          let span = this.document.createElementNS(XHTML_NS, "span");
-          span.style = style;
-          span.appendChild(elem);
-          result = span;
-        }
+    let options = { noStringQuotes: true };
+    let elem = Messages.Extended.prototype._renderBodyPiece.call(this, piece, options);
+    let result = elem;
+
+    if (style) {
+      if (elem.nodeType == Ci.nsIDOMNode.ELEMENT_NODE) {
+        elem.style = style;
+      } else {
+        let span = this.document.createElementNS(XHTML_NS, "span");
+        span.style = style;
+        span.appendChild(elem);
+        result = span;
       }
-
-      return result;
-    },
+    }
+
+    return result;
+  },
 
   // no-op for the message location and .repeats elements.
   // |this.render()| handles customized message output.
-    _renderLocation: function () { },
-    _renderRepeatNode: function () { },
+  _renderLocation: function () { },
+  _renderRepeatNode: function () { },
 
   /**
    * Given a style attribute value, return a cleaned up version of the string
    * such that:
    *
    * - no external URL is allowed to load. See RE_CLEANUP_STYLES.
    * - only some of the properties are allowed, based on a whitelist. See
    *   RE_ALLOWED_STYLES.
    *
    * @param string style
    *        The style string to cleanup.
    * @return string
    *         The style value after cleanup.
    */
-    cleanupStyle: function (style)
+  cleanupStyle: function (style)
   {
-      for (let r of RE_CLEANUP_STYLES) {
-        style = style.replace(r, "notallowed");
-      }
-
-      let dummy = this.output._dummyElement;
-      if (!dummy) {
-        dummy = this.output._dummyElement =
+    for (let r of RE_CLEANUP_STYLES) {
+      style = style.replace(r, "notallowed");
+    }
+
+    let dummy = this.output._dummyElement;
+    if (!dummy) {
+      dummy = this.output._dummyElement =
         this.document.createElementNS(XHTML_NS, "div");
+    }
+    dummy.style = style;
+
+    let toRemove = [];
+    for (let i = 0; i < dummy.style.length; i++) {
+      let prop = dummy.style[i];
+      if (!RE_ALLOWED_STYLES.test(prop)) {
+        toRemove.push(prop);
       }
-      dummy.style = style;
-
-      let toRemove = [];
-      for (let i = 0; i < dummy.style.length; i++) {
-        let prop = dummy.style[i];
-        if (!RE_ALLOWED_STYLES.test(prop)) {
-          toRemove.push(prop);
-        }
-      }
-
-      for (let prop of toRemove) {
-        dummy.style.removeProperty(prop);
-      }
-
-      style = dummy.style.cssText;
-
-      dummy.style = "";
-
-      return style;
-    },
-  }); // Messages.ConsoleGeneric.prototype
+    }
+
+    for (let prop of toRemove) {
+      dummy.style.removeProperty(prop);
+    }
+
+    style = dummy.style.cssText;
+
+    dummy.style = "";
+
+    return style;
+  },
+}); // Messages.ConsoleGeneric.prototype
 
 /**
  * The ConsoleTrace message is used for console.trace() calls.
  *
  * @constructor
  * @extends Messages.Simple
  * @param object packet
  *        The Console API call packet received from the server.
@@ -1600,121 +1597,120 @@ Messages.ConsoleTrace = function (packet
   this._renderStack = this._renderStack.bind(this);
   Messages.Simple.call(this, this._renderStack, options);
 
   this._repeatID.consoleApiLevel = packet.level;
   this._stacktrace = this._repeatID.stacktrace = packet.stacktrace;
   this._arguments = packet.arguments;
 };
 
-Messages.ConsoleTrace.prototype = Heritage.extend(Messages.Simple.prototype,
-  {
+Messages.ConsoleTrace.prototype = extend(Messages.Simple.prototype, {
   /**
    * Holds the stackframes received from the server.
    *
    * @private
    * @type array
    */
-    _stacktrace: null,
+  _stacktrace: null,
 
   /**
    * Holds the arguments the content script passed to the console.trace()
    * method. This array is cleared when the message is initialized, and
    * associated actors are released.
    *
    * @private
    * @type array
    */
-    _arguments: null,
-
-    init: function ()
+  _arguments: null,
+
+  init: function ()
   {
-      let result = Messages.Simple.prototype.init.apply(this, arguments);
+    let result = Messages.Simple.prototype.init.apply(this, arguments);
 
     // We ignore console.trace() arguments. Release object actors.
-      if (Array.isArray(this._arguments)) {
-        for (let arg of this._arguments) {
-          if (WebConsoleUtils.isActorGrip(arg)) {
-            this.output._releaseObject(arg.actor);
-          }
+    if (Array.isArray(this._arguments)) {
+      for (let arg of this._arguments) {
+        if (WebConsoleUtils.isActorGrip(arg)) {
+          this.output._releaseObject(arg.actor);
         }
       }
-      this._arguments = null;
-
-      return result;
-    },
-
-    render: function ()
+    }
+    this._arguments = null;
+
+    return result;
+  },
+
+  render: function ()
   {
-      Messages.Simple.prototype.render.apply(this, arguments);
-      this.element.setAttribute("open", true);
-      return this;
-    },
+    Messages.Simple.prototype.render.apply(this, arguments);
+    this.element.setAttribute("open", true);
+    return this;
+  },
 
   /**
    * Render the stack frames.
    *
    * @private
    * @return DOMElement
    */
-    _renderStack: function ()
+  _renderStack: function ()
   {
-      let cmvar = this.document.createElementNS(XHTML_NS, "span");
-      cmvar.className = "cm-variable";
-      cmvar.textContent = "console";
-
-      let cmprop = this.document.createElementNS(XHTML_NS, "span");
-      cmprop.className = "cm-property";
-      cmprop.textContent = "trace";
-
-      let title = this.document.createElementNS(XHTML_NS, "span");
-      title.className = "message-body devtools-monospace";
-      title.appendChild(cmvar);
-      title.appendChild(this.document.createTextNode("."));
-      title.appendChild(cmprop);
-      title.appendChild(this.document.createTextNode("():"));
-
-      let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
-      let location = Messages.Simple.prototype._renderLocation.call(this);
-      if (location) {
-        location.target = "jsdebugger";
-      }
-
-      let widget = new Widgets.Stacktrace(this, this._stacktrace).render();
-
-      let body = this.document.createElementNS(XHTML_NS, "span");
-      body.className = "message-flex-body";
-      body.appendChild(title);
-      if (repeatNode) {
-        body.appendChild(repeatNode);
-      }
-      if (location) {
-        body.appendChild(location);
-      }
-      body.appendChild(this.document.createTextNode("\n"));
-
-      let frag = this.document.createDocumentFragment();
-      frag.appendChild(body);
-      frag.appendChild(widget.element);
-
-      return frag;
-    },
-
-    _renderBody: function ()
+    let cmvar = this.document.createElementNS(XHTML_NS, "span");
+    cmvar.className = "cm-variable";
+    cmvar.textContent = "console";
+
+    let cmprop = this.document.createElementNS(XHTML_NS, "span");
+    cmprop.className = "cm-property";
+    cmprop.textContent = "trace";
+
+    let title = this.document.createElementNS(XHTML_NS, "span");
+    title.className = "message-body devtools-monospace";
+    title.appendChild(cmvar);
+    title.appendChild(this.document.createTextNode("."));
+    title.appendChild(cmprop);
+    title.appendChild(this.document.createTextNode("():"));
+
+    let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
+    let location = Messages.Simple.prototype._renderLocation.call(this);
+    if (location) {
+      location.target = "jsdebugger";
+    }
+
+    let widget = new Widgets.Stacktrace(this, this._stacktrace).render();
+
+    let body = this.document.createElementNS(XHTML_NS, "span");
+    body.className = "message-flex-body";
+    body.appendChild(title);
+    if (repeatNode) {
+      body.appendChild(repeatNode);
+    }
+    if (location) {
+      body.appendChild(location);
+    }
+    body.appendChild(this.document.createTextNode("\n"));
+
+    let frag = this.document.createDocumentFragment();
+    frag.appendChild(body);
+    frag.appendChild(widget.element);
+
+    return frag;
+  },
+
+  _renderBody: function ()
   {
-      let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
-      body.classList.remove("devtools-monospace", "message-body");
-      return body;
-    },
+    let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
+    body.classList.remove("devtools-monospace", "message-body");
+    return body;
+  },
 
   // no-op for the message location and .repeats elements.
   // |this._renderStack| handles customized message output.
-    _renderLocation: function () { },
-    _renderRepeatNode: function () { },
-  }); // Messages.ConsoleTrace.prototype
+  _renderLocation: function () { },
+  _renderRepeatNode: function () { },
+}); // Messages.ConsoleTrace.prototype
 
 /**
  * The ConsoleTable message is used for console.table() calls.
  *
  * @constructor
  * @extends Messages.Extended
  * @param object packet
  *        The Console API call packet received from the server.
@@ -1737,327 +1733,326 @@ Messages.ConsoleTable = function (packet
   this._populateTableData = this._populateTableData.bind(this);
   this._renderTable = this._renderTable.bind(this);
   Messages.Extended.call(this, [this._renderTable], options);
 
   this._repeatID.consoleApiLevel = packet.level;
   this._arguments = packet.arguments;
 };
 
-Messages.ConsoleTable.prototype = Heritage.extend(Messages.Extended.prototype,
-  {
+Messages.ConsoleTable.prototype = extend(Messages.Extended.prototype, {
   /**
    * Holds the arguments the content script passed to the console.table()
    * method.
    *
    * @private
    * @type array
    */
-    _arguments: null,
+  _arguments: null,
 
   /**
    * Array of objects that holds the data to log in the table.
    *
    * @private
    * @type array
    */
-    _data: null,
+  _data: null,
 
   /**
    * Key value pair of the id and display name for the columns in the table.
    * Refer to the TableWidget API.
    *
    * @private
    * @type object
    */
-    _columns: null,
+  _columns: null,
 
   /**
    * A promise that resolves when the table data is ready or null if invalid
    * arguments are provided.
    *
    * @private
    * @type promise|null
    */
-    _populatePromise: null,
-
-    init: function ()
+  _populatePromise: null,
+
+  init: function ()
   {
-      let result = Messages.Extended.prototype.init.apply(this, arguments);
-      this._data = [];
-      this._columns = {};
-
-      this._populatePromise = this._populateTableData();
-
-      return result;
-    },
+    let result = Messages.Extended.prototype.init.apply(this, arguments);
+    this._data = [];
+    this._columns = {};
+
+    this._populatePromise = this._populateTableData();
+
+    return result;
+  },
 
   /**
    * Sets the key value pair of the id and display name for the columns in the
    * table.
    *
    * @private
    * @param array|string columns
    *        Either a string or array containing the names for the columns in
    *        the output table.
    */
-    _setColumns: function (columns)
+  _setColumns: function (columns)
   {
-      if (columns.class == "Array") {
-        let items = columns.preview.items;
-
-        for (let item of items) {
-          if (typeof item == "string") {
-            this._columns[item] = item;
-          }
+    if (columns.class == "Array") {
+      let items = columns.preview.items;
+
+      for (let item of items) {
+        if (typeof item == "string") {
+          this._columns[item] = item;
         }
-      } else if (typeof columns == "string" && columns) {
-        this._columns[columns] = columns;
       }
-    },
+    } else if (typeof columns == "string" && columns) {
+      this._columns[columns] = columns;
+    }
+  },
 
   /**
    * Retrieves the table data and columns from the arguments received from the
    * server.
    *
    * @return Promise|null
    *         Returns a promise that resolves when the table data is ready or
    *         null if the arguments are invalid.
    */
-    _populateTableData: function ()
+  _populateTableData: function ()
   {
-      let deferred = promise.defer();
-
-      if (this._arguments.length <= 0) {
-        return;
-      }
-
-      let data = this._arguments[0];
-      if (data.class != "Array" && data.class != "Object" &&
+    let deferred = promise.defer();
+
+    if (this._arguments.length <= 0) {
+      return;
+    }
+
+    let data = this._arguments[0];
+    if (data.class != "Array" && data.class != "Object" &&
         data.class != "Map" && data.class != "Set" &&
         data.class != "WeakMap" && data.class != "WeakSet") {
-        return;
+      return;
+    }
+
+    let hasColumnsArg = false;
+    if (this._arguments.length > 1) {
+      if (data.class == "Object" || data.class == "Array") {
+        this._columns["_index"] = l10n.getStr("table.index");
+      } else {
+        this._columns["_index"] = l10n.getStr("table.iterationIndex");
       }
 
-      let hasColumnsArg = false;
-      if (this._arguments.length > 1) {
-        if (data.class == "Object" || data.class == "Array") {
-          this._columns["_index"] = l10n.getStr("table.index");
-        } else {
-          this._columns["_index"] = l10n.getStr("table.iterationIndex");
-        }
-
-        this._setColumns(this._arguments[1]);
-        hasColumnsArg = true;
-      }
-
-      if (data.class == "Object" || data.class == "Array") {
+      this._setColumns(this._arguments[1]);
+      hasColumnsArg = true;
+    }
+
+    if (data.class == "Object" || data.class == "Array") {
       // Get the object properties, and parse the key and value properties into
       // the table data and columns.
-        this.client = new ObjectClient(this.output.owner.jsterm.hud.proxy.client,
+      this.client = new ObjectClient(this.output.owner.jsterm.hud.proxy.client,
           data);
-        this.client.getPrototypeAndProperties(aResponse => {
-          let {ownProperties} = aResponse;
-          let rowCount = 0;
-          let columnCount = 0;
-
-          for (let index of Object.keys(ownProperties || {})) {
+      this.client.getPrototypeAndProperties(aResponse => {
+        let {ownProperties} = aResponse;
+        let rowCount = 0;
+        let columnCount = 0;
+
+        for (let index of Object.keys(ownProperties || {})) {
           // Avoid outputting the length property if the data argument provided
           // is an array
-            if (data.class == "Array" && index == "length") {
-              continue;
+          if (data.class == "Array" && index == "length") {
+            continue;
+          }
+
+          if (!hasColumnsArg) {
+            this._columns["_index"] = l10n.getStr("table.index");
+          }
+
+          if (data.class == "Array") {
+            if (index == parseInt(index)) {
+              index = parseInt(index);
             }
-
-            if (!hasColumnsArg) {
-              this._columns["_index"] = l10n.getStr("table.index");
-            }
-
-            if (data.class == "Array") {
-              if (index == parseInt(index)) {
-                index = parseInt(index);
+          }
+
+          let property = ownProperties[index].value;
+          let item = { _index: index };
+
+          if (property.class == "Object" || property.class == "Array") {
+            let {preview} = property;
+            let entries = property.class == "Object" ?
+                preview.ownProperties : preview.items;
+
+            for (let key of Object.keys(entries)) {
+              let value = property.class == "Object" ?
+                  preview.ownProperties[key].value : preview.items[key];
+
+              item[key] = this._renderValueGrip(value, { concise: true });
+
+              if (!hasColumnsArg && !(key in this._columns) &&
+                  (++columnCount <= TABLE_COLUMN_MAX_ITEMS)) {
+                this._columns[key] = key;
               }
             }
-
-            let property = ownProperties[index].value;
-            let item = { _index: index };
-
-            if (property.class == "Object" || property.class == "Array") {
-              let {preview} = property;
-              let entries = property.class == "Object" ?
-                preview.ownProperties : preview.items;
-
-              for (let key of Object.keys(entries)) {
-                let value = property.class == "Object" ?
-                  preview.ownProperties[key].value : preview.items[key];
-
-                item[key] = this._renderValueGrip(value, { concise: true });
-
-                if (!hasColumnsArg && !(key in this._columns) &&
-                  (++columnCount <= TABLE_COLUMN_MAX_ITEMS)) {
-                  this._columns[key] = key;
-                }
-              }
-            } else {
+          } else {
             // Display the value for any non-object data input.
-              item["_value"] = this._renderValueGrip(property, { concise: true });
-
-              if (!hasColumnsArg && !("_value" in this._columns)) {
-                this._columns["_value"] = l10n.getStr("table.value");
-              }
-            }
-
-            this._data.push(item);
-
-            if (++rowCount == TABLE_ROW_MAX_ITEMS) {
-              break;
+            item["_value"] = this._renderValueGrip(property, { concise: true });
+
+            if (!hasColumnsArg && !("_value" in this._columns)) {
+              this._columns["_value"] = l10n.getStr("table.value");
             }
           }
 
-          deferred.resolve();
-        });
-      } else if (data.class == "Map" || data.class == "WeakMap") {
-        let entries = data.preview.entries;
-
-        if (!hasColumnsArg) {
-          this._columns["_index"] = l10n.getStr("table.iterationIndex");
-          this._columns["_key"] = l10n.getStr("table.key");
-          this._columns["_value"] = l10n.getStr("table.value");
-        }
-
-        let rowCount = 0;
-        for (let [key, value] of entries) {
-          let item = {
-            _index: rowCount,
-            _key: this._renderValueGrip(key, { concise: true }),
-            _value: this._renderValueGrip(value, { concise: true })
-          };
-
           this._data.push(item);
 
           if (++rowCount == TABLE_ROW_MAX_ITEMS) {
             break;
           }
         }
 
         deferred.resolve();
-      } else if (data.class == "Set" || data.class == "WeakSet") {
-        let entries = data.preview.items;
-
-        if (!hasColumnsArg) {
-          this._columns["_index"] = l10n.getStr("table.iterationIndex");
-          this._columns["_value"] = l10n.getStr("table.value");
+      });
+    } else if (data.class == "Map" || data.class == "WeakMap") {
+      let entries = data.preview.entries;
+
+      if (!hasColumnsArg) {
+        this._columns["_index"] = l10n.getStr("table.iterationIndex");
+        this._columns["_key"] = l10n.getStr("table.key");
+        this._columns["_value"] = l10n.getStr("table.value");
+      }
+
+      let rowCount = 0;
+      for (let [key, value] of entries) {
+        let item = {
+          _index: rowCount,
+          _key: this._renderValueGrip(key, { concise: true }),
+          _value: this._renderValueGrip(value, { concise: true })
+        };
+
+        this._data.push(item);
+
+        if (++rowCount == TABLE_ROW_MAX_ITEMS) {
+          break;
         }
-
-        let rowCount = 0;
-        for (let entry of entries) {
-          let item = {
-            _index : rowCount,
-            _value: this._renderValueGrip(entry, { concise: true })
-          };
-
-          this._data.push(item);
-
-          if (++rowCount == TABLE_ROW_MAX_ITEMS) {
-            break;
-          }
+      }
+
+      deferred.resolve();
+    } else if (data.class == "Set" || data.class == "WeakSet") {
+      let entries = data.preview.items;
+
+      if (!hasColumnsArg) {
+        this._columns["_index"] = l10n.getStr("table.iterationIndex");
+        this._columns["_value"] = l10n.getStr("table.value");
+      }
+
+      let rowCount = 0;
+      for (let entry of entries) {
+        let item = {
+          _index : rowCount,
+          _value: this._renderValueGrip(entry, { concise: true })
+        };
+
+        this._data.push(item);
+
+        if (++rowCount == TABLE_ROW_MAX_ITEMS) {
+          break;
         }
-
-        deferred.resolve();
       }
 
-      return deferred.promise;
-    },
-
-    render: function ()
+      deferred.resolve();
+    }
+
+    return deferred.promise;
+  },
+
+  render: function ()
   {
-      Messages.Extended.prototype.render.apply(this, arguments);
-      this.element.setAttribute("open", true);
-      return this;
-    },
+    Messages.Extended.prototype.render.apply(this, arguments);
+    this.element.setAttribute("open", true);
+    return this;
+  },
 
   /**
    * Render the table.
    *
    * @private
    * @return DOMElement
    */
-    _renderTable: function ()
+  _renderTable: function ()
   {
-      let cmvar = this.document.createElementNS(XHTML_NS, "span");
-      cmvar.className = "cm-variable";
-      cmvar.textContent = "console";
-
-      let cmprop = this.document.createElementNS(XHTML_NS, "span");
-      cmprop.className = "cm-property";
-      cmprop.textContent = "table";
-
-      let title = this.document.createElementNS(XHTML_NS, "span");
-      title.className = "message-body devtools-monospace";
-      title.appendChild(cmvar);
-      title.appendChild(this.document.createTextNode("."));
-      title.appendChild(cmprop);
-      title.appendChild(this.document.createTextNode("():"));
-
-      let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
-      let location = Messages.Simple.prototype._renderLocation.call(this);
-      if (location) {
-        location.target = "jsdebugger";
-      }
-
-      let body = this.document.createElementNS(XHTML_NS, "span");
-      body.className = "message-flex-body";
-      body.appendChild(title);
-      if (repeatNode) {
-        body.appendChild(repeatNode);
-      }
-      if (location) {
-        body.appendChild(location);
-      }
-      body.appendChild(this.document.createTextNode("\n"));
-
-      let result = this.document.createElementNS(XHTML_NS, "div");
-      result.appendChild(body);
-
-      if (this._populatePromise) {
-        this._populatePromise.then(() => {
-          if (this._data.length > 0) {
-            let widget = new Widgets.Table(this, this._data, this._columns).render();
-            result.appendChild(widget.element);
-          }
-
-          result.scrollIntoView();
-          this.output.owner.emit("messages-table-rendered");
+    let cmvar = this.document.createElementNS(XHTML_NS, "span");
+    cmvar.className = "cm-variable";
+    cmvar.textContent = "console";
+
+    let cmprop = this.document.createElementNS(XHTML_NS, "span");
+    cmprop.className = "cm-property";
+    cmprop.textContent = "table";
+
+    let title = this.document.createElementNS(XHTML_NS, "span");
+    title.className = "message-body devtools-monospace";
+    title.appendChild(cmvar);
+    title.appendChild(this.document.createTextNode("."));
+    title.appendChild(cmprop);
+    title.appendChild(this.document.createTextNode("():"));
+
+    let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
+    let location = Messages.Simple.prototype._renderLocation.call(this);
+    if (location) {
+      location.target = "jsdebugger";
+    }
+
+    let body = this.document.createElementNS(XHTML_NS, "span");
+    body.className = "message-flex-body";
+    body.appendChild(title);
+    if (repeatNode) {
+      body.appendChild(repeatNode);
+    }
+    if (location) {
+      body.appendChild(location);
+    }
+    body.appendChild(this.document.createTextNode("\n"));
+
+    let result = this.document.createElementNS(XHTML_NS, "div");
+    result.appendChild(body);
+
+    if (this._populatePromise) {
+      this._populatePromise.then(() => {
+        if (this._data.length > 0) {
+          let widget = new Widgets.Table(this, this._data, this._columns).render();
+          result.appendChild(widget.element);
+        }
+
+        result.scrollIntoView();
+        this.output.owner.emit("messages-table-rendered");
 
         // Release object actors
-          if (Array.isArray(this._arguments)) {
-            for (let arg of this._arguments) {
-              if (WebConsoleUtils.isActorGrip(arg)) {
-                this.output._releaseObject(arg.actor);
-              }
+        if (Array.isArray(this._arguments)) {
+          for (let arg of this._arguments) {
+            if (WebConsoleUtils.isActorGrip(arg)) {
+              this.output._releaseObject(arg.actor);
             }
           }
-          this._arguments = null;
-        });
-      }
-
-      return result;
-    },
-
-    _renderBody: function ()
+        }
+        this._arguments = null;
+      });
+    }
+
+    return result;
+  },
+
+  _renderBody: function ()
   {
-      let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
-      body.classList.remove("devtools-monospace", "message-body");
-      return body;
-    },
+    let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
+    body.classList.remove("devtools-monospace", "message-body");
+    return body;
+  },
 
   // no-op for the message location and .repeats elements.
   // |this._renderTable| handles customized message output.
-    _renderLocation: function () { },
-    _renderRepeatNode: function () { },
-  }); // Messages.ConsoleTable.prototype
+  _renderLocation: function () { },
+  _renderRepeatNode: function () { },
+}); // Messages.ConsoleTable.prototype
 
 var Widgets = {};
 
 /**
  * The base widget class.
  *
  * @constructor
  * @param object message
@@ -2180,37 +2175,36 @@ Widgets.BaseWidget.prototype = {
  *        The UNIX timestamp to display.
  */
 Widgets.MessageTimestamp = function (message, timestamp)
 {
   Widgets.BaseWidget.call(this, message);
   this.timestamp = timestamp;
 };
 
-Widgets.MessageTimestamp.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
-  {
+Widgets.MessageTimestamp.prototype = extend(Widgets.BaseWidget.prototype, {
   /**
    * The UNIX timestamp.
    * @type number
    */
-    timestamp: 0,
-
-    render: function ()
+  timestamp: 0,
+
+  render: function ()
   {
-      if (this.element) {
-        return this;
-      }
-
-      this.element = this.document.createElementNS(XHTML_NS, "span");
-      this.element.className = "timestamp devtools-monospace";
-      this.element.textContent = l10n.timestampString(this.timestamp) + " ";
-
+    if (this.element) {
       return this;
-    },
-  }); // Widgets.MessageTimestamp.prototype
+    }
+
+    this.element = this.document.createElementNS(XHTML_NS, "span");
+    this.element.className = "timestamp devtools-monospace";
+    this.element.textContent = l10n.timestampString(this.timestamp) + " ";
+
+    return this;
+  },
+}); // Widgets.MessageTimestamp.prototype
 
 
 /**
  * The URLString widget, for rendering strings where at least one token is a
  * URL.
  *
  * @constructor
  * @param object message
@@ -2222,128 +2216,127 @@ Widgets.MessageTimestamp.prototype = Her
  */
 Widgets.URLString = function (message, str, unshortenedStr)
 {
   Widgets.BaseWidget.call(this, message);
   this.str = str;
   this.unshortenedStr = unshortenedStr;
 };
 
-Widgets.URLString.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
-  {
+Widgets.URLString.prototype = extend(Widgets.BaseWidget.prototype, {
   /**
    * The string to format, which contains at least one valid URL.
    * @type string
    */
-    str: "",
-
-    render: function ()
+  str: "",
+
+  render: function ()
   {
-      if (this.element) {
-        return this;
-      }
+    if (this.element) {
+      return this;
+    }
 
     // The rendered URLString will be a <span> containing a number of text
     // <spans> for non-URL tokens and <a>'s for URL tokens.
-      this.element = this.el("span", {
-        class: "console-string"
-      });
-      this.element.appendChild(this._renderText("\""));
+    this.element = this.el("span", {
+      class: "console-string"
+    });
+    this.element.appendChild(this._renderText("\""));
 
     // As we walk through the tokens of the source string, we make sure to preserve
     // the original whitespace that separated the tokens.
-      let tokens = this.str.split(/\s+/);
-      let textStart = 0;
-      let tokenStart;
-      for (let i = 0; i < tokens.length; i++) {
-        let token = tokens[i];
-        let unshortenedToken;
-        tokenStart = this.str.indexOf(token, textStart);
-        if (this._isURL(token)) {
+    let tokens = this.str.split(/\s+/);
+    let textStart = 0;
+    let tokenStart;
+    for (let i = 0; i < tokens.length; i++) {
+      let token = tokens[i];
+      let unshortenedToken;
+      tokenStart = this.str.indexOf(token, textStart);
+      if (this._isURL(token)) {
         // The last URL in the string might be shortened.  If so, get the
         // real URL so the rendered link can point to it.
-          if (i === tokens.length - 1 && this.unshortenedStr) {
-            unshortenedToken = this.unshortenedStr.slice(tokenStart).split(/\s+/, 1)[0];
-          }
-          this.element.appendChild(this._renderText(this.str.slice(textStart, tokenStart)));
-          textStart = tokenStart + token.length;
-          this.element.appendChild(this._renderURL(token, unshortenedToken));
+        if (i === tokens.length - 1 && this.unshortenedStr) {
+          unshortenedToken = this.unshortenedStr.slice(tokenStart).split(/\s+/, 1)[0];
         }
+        this.element.appendChild(this._renderText(this.str.slice(textStart, tokenStart)));
+        textStart = tokenStart + token.length;
+        this.element.appendChild(this._renderURL(token, unshortenedToken));
       }
+    }
 
     // Clean up any non-URL text at the end of the source string.
-      this.element.appendChild(this._renderText(this.str.slice(textStart, this.str.length)));
-      this.element.appendChild(this._renderText("\""));
-
-      return this;
-    },
+    this.element.appendChild(this._renderText(this.str.slice(textStart, this.str.length)));
+    this.element.appendChild(this._renderText("\""));
+
+    return this;
+  },
 
   /**
    * Determines whether a grip is a string containing a URL.
    *
    * @param string grip
    *        The grip, which may contain a URL.
    * @return boolean
    *         Whether the grip is a string containing a URL.
    */
-    containsURL: function (grip)
+  containsURL: function (grip)
   {
-      if (typeof grip != "string") {
-        return false;
-      }
-
-      let tokens = grip.split(/\s+/);
-      return tokens.some(this._isURL);
-    },
+    if (typeof grip != "string") {
+      return false;
+    }
+
+    let tokens = grip.split(/\s+/);
+    return tokens.some(this._isURL);
+  },
 
   /**
    * Determines whether a string token is a valid URL.
    *
    * @param string token
    *        The token.
    * @return boolean
    *         Whenther the token is a URL.
    */
-    _isURL: function (token) {
-      try {
-        let uri = URI.newURI(token, null, null);
-        let url = uri.QueryInterface(Ci.nsIURL);
-        return true;
-      } catch (e) {
-        return false;
-      }
-    },
+  _isURL: function (token) {
+    try {
+      let uri = URI.newURI(token, null, null);
+      let url = uri.QueryInterface(Ci.nsIURL);
+      return true;
+    } catch (e) {
+      return false;
+    }
+  },
 
   /**
    * Renders a string as a URL.
    *
    * @param string url
    *        The string to be rendered as a url.
    * @param string fullUrl
    *        The unshortened form of the URL, if it was shortened.
    * @return DOMElement
    *         An element containing the rendered string.
    */
-    _renderURL: function (url, fullUrl)
+  _renderURL: function (url, fullUrl)
   {
-      let unshortened = fullUrl || url;
-      let result = this.el("a", {
-        class: "url",
-        title: unshortened,
-        href: unshortened,
-        draggable: false
-      }, url);
-      this.message._addLinkCallback(result);
-      return result;
-    },
-
-    _renderText: function (text) {
-      return this.el("span", text);
-    },
-  }); // Widgets.URLString.prototype
+    let unshortened = fullUrl || url;
+    let result = this.el("a", {
+      class: "url",
+      title: unshortened,
+      href: unshortened,
+      draggable: false
+    }, url);
+    this.message._addLinkCallback(result);
+    return result;
+  },
+
+  _renderText: function (text) {
+    return this.el("span", text);
+  },
+}); // Widgets.URLString.prototype
 
 /**
  * Widget used for displaying ObjectActors that have no specialised renderers.
  *
  * @constructor
  * @param object message
  *        The owning message.
  * @param object objectActor
@@ -2356,71 +2349,70 @@ Widgets.URLString.prototype = Heritage.e
 Widgets.JSObject = function (message, objectActor, options = {})
 {
   Widgets.BaseWidget.call(this, message);
   this.objectActor = objectActor;
   this.options = options;
   this._onClick = this._onClick.bind(this);
 };
 
-Widgets.JSObject.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
-  {
+Widgets.JSObject.prototype = extend(Widgets.BaseWidget.prototype, {
   /**
    * The ObjectActor displayed by the widget.
    * @type object
    */
-    objectActor: null,
-
-    render: function ()
+  objectActor: null,
+
+  render: function ()
   {
-      if (!this.element) {
-        this._render();
-      }
-
-      return this;
-    },
-
-    _render: function ()
+    if (!this.element) {
+      this._render();
+    }
+
+    return this;
+  },
+
+  _render: function ()
   {
-      let str = VariablesView.getString(this.objectActor, this.options);
-      let className = this.message.getClassNameForValueGrip(this.objectActor);
-      if (!className && this.objectActor.class == "Object") {
-        className = "cm-variable";
-      }
-
-      this.element = this._anchor(str, { className: className });
-    },
+    let str = VariablesView.getString(this.objectActor, this.options);
+    let className = this.message.getClassNameForValueGrip(this.objectActor);
+    if (!className && this.objectActor.class == "Object") {
+      className = "cm-variable";
+    }
+
+    this.element = this._anchor(str, { className: className });
+  },
 
   /**
    * Render a concise representation of an object.
    */
-    _renderConciseObject: function ()
+  _renderConciseObject: function ()
   {
-      this.element = this._anchor(this.objectActor.class,
+    this.element = this._anchor(this.objectActor.class,
                                 { className: "cm-variable" });
-    },
+  },
 
   /**
    * Render the `<class> { ` prefix of an object.
    */
-    _renderObjectPrefix: function ()
+  _renderObjectPrefix: function ()
   {
-      let { kind } = this.objectActor.preview;
-      this.element = this.el("span.kind-" + kind);
-      this._anchor(this.objectActor.class, { className: "cm-variable" });
-      this._text(" { ");
-    },
+    let { kind } = this.objectActor.preview;
+    this.element = this.el("span.kind-" + kind);
+    this._anchor(this.objectActor.class, { className: "cm-variable" });
+    this._text(" { ");
+  },
 
   /**
    * Render the ` }` suffix of an object.
    */
-    _renderObjectSuffix: function ()
+  _renderObjectSuffix: function ()
   {
-      this._text(" }");
-    },
+    this._text(" }");
+  },
 
   /**
    * Render an object property.
    *
    * @param String key
    *        The property name.
    * @param Object value
    *        The property value, as an RDP grip.
@@ -2428,83 +2420,83 @@ Widgets.JSObject.prototype = Heritage.ex
    *        The container node to render to.
    * @param Boolean needsComma
    *        True if there was another property before this one and we need to
    *        separate them with a comma.
    * @param Boolean valueIsText
    *        Add the value as is, don't treat it as a grip and pass it to
    *        `_renderValueGrip`.
    */
-    _renderObjectProperty: function (key, value, container, needsComma, valueIsText = false)
+  _renderObjectProperty: function (key, value, container, needsComma, valueIsText = false)
   {
-      if (needsComma) {
-        this._text(", ");
-      }
-
-      container.appendChild(this.el("span.cm-property", key));
-      this._text(": ");
-
-      if (valueIsText) {
-        this._text(value);
-      } else {
-        let valueElem = this.message._renderValueGrip(value, { concise: true, shorten: true });
-        container.appendChild(valueElem);
-      }
-    },
+    if (needsComma) {
+      this._text(", ");
+    }
+
+    container.appendChild(this.el("span.cm-property", key));
+    this._text(": ");
+
+    if (valueIsText) {
+      this._text(value);
+    } else {
+      let valueElem = this.message._renderValueGrip(value, { concise: true, shorten: true });
+      container.appendChild(valueElem);
+    }
+  },
 
   /**
    * Render this object's properties.
    *
    * @param nsIDOMNode container
    *        The container node to render to.
    * @param Boolean needsComma
    *        True if there was another property before this one and we need to
    *        separate them with a comma.
    */
-    _renderObjectProperties: function (container, needsComma)
+  _renderObjectProperties: function (container, needsComma)
   {
-      let { preview } = this.objectActor;
-      let { ownProperties, safeGetterValues } = preview;
-
-      let shown = 0;
-
-      let getValue = desc => {
-        if (desc.get) {
-          return "Getter";
-        } else if (desc.set) {
-          return "Setter";
-        } else {
-          return desc.value;
-        }
-      };
-
-      for (let key of Object.keys(ownProperties || {})) {
-        this._renderObjectProperty(key, getValue(ownProperties[key]), container,
+    let { preview } = this.objectActor;
+    let { ownProperties, safeGetterValues } = preview;
+
+    let shown = 0;
+
+    let getValue = desc => {
+      if (desc.get) {
+        return "Getter";
+      } else if (desc.set) {
+        return "Setter";
+      } else {
+        return desc.value;
+      }
+    };
+
+    for (let key of Object.keys(ownProperties || {})) {
+      this._renderObjectProperty(key, getValue(ownProperties[key]), container,
                                  shown > 0 || needsComma,
                                  ownProperties[key].get || ownProperties[key].set);
-        shown++;
-      }
-
-      let ownPropertiesShown = shown;
-
-      for (let key of Object.keys(safeGetterValues || {})) {
-        this._renderObjectProperty(key, safeGetterValues[key].getterValue,
+      shown++;
+    }
+
+    let ownPropertiesShown = shown;
+
+    for (let key of Object.keys(safeGetterValues || {})) {
+      this._renderObjectProperty(key, safeGetterValues[key].getterValue,
                                  container, shown > 0 || needsComma);
-        shown++;
-      }
-
-      if (typeof preview.ownPropertiesLength == "number" &&
+      shown++;
+    }
+
+    if (typeof preview.ownPropertiesLength == "number" &&
         ownPropertiesShown < preview.ownPropertiesLength) {
-        this._text(", ");
-
-        let n = preview.ownPropertiesLength - ownPropertiesShown;
-        let str = VariablesView.stringifiers._getNMoreString(n);
-        this._anchor(str);
-      }
-    },
+      this._text(", ");
+
+      let n = preview.ownPropertiesLength - ownPropertiesShown;
+      let str = VariablesView.stringifiers._getNMoreString(n);
+      this._anchor(str);
+    }
+  },
 
   /**
    * Render an anchor with a given text content and link.
    *
    * @private
    * @param string text
    *        Text to show in the anchor.
    * @param object [options]
@@ -2516,131 +2508,131 @@ Widgets.JSObject.prototype = Heritage.ex
    *        on the anchor open the link in a new tab.
    *        - appendTo (DOMElement): append the element to the given DOM
    *        element. If not provided, the anchor is appended to |this.element|
    *        if it is available. If |appendTo| is provided and if it is a falsy
    *        value, the anchor is not appended to any element.
    * @return DOMElement
    *         The DOM element of the new anchor.
    */
-    _anchor: function (text, options = {})
+  _anchor: function (text, options = {})
   {
-      if (!options.onClick) {
+    if (!options.onClick) {
       // If the anchor has an URL, open it in a new tab. If not, show the
       // current object actor.
-        options.onClick = options.href ? this._onClickAnchor : this._onClick;
-      }
-
-      options.onContextMenu = options.onContextMenu || this._onContextMenu;
-
-      let anchor = this.el("a", {
-        class: options.className,
-        draggable: false,
-        href: options.href || "#",
-      }, text);
-
-      this.message._addLinkCallback(anchor, options.onClick);
-
-      anchor.addEventListener("contextmenu", options.onContextMenu.bind(this));
-
-      if (options.appendTo) {
-        options.appendTo.appendChild(anchor);
-      } else if (!("appendTo" in options) && this.element) {
-        this.element.appendChild(anchor);
-      }
-
-      return anchor;
-    },
-
-    openObjectInVariablesView: function ()
+      options.onClick = options.href ? this._onClickAnchor : this._onClick;
+    }
+
+    options.onContextMenu = options.onContextMenu || this._onContextMenu;
+
+    let anchor = this.el("a", {
+      class: options.className,
+      draggable: false,
+      href: options.href || "#",
+    }, text);
+
+    this.message._addLinkCallback(anchor, options.onClick);
+
+    anchor.addEventListener("contextmenu", options.onContextMenu.bind(this));
+
+    if (options.appendTo) {
+      options.appendTo.appendChild(anchor);
+    } else if (!("appendTo" in options) && this.element) {
+      this.element.appendChild(anchor);
+    }
+
+    return anchor;
+  },
+
+  openObjectInVariablesView: function ()
   {
-      this.output.openVariablesView({
-        label: VariablesView.getString(this.objectActor, { concise: true }),
-        objectActor: this.objectActor,
-        autofocus: true,
-      });
-    },
-
-    storeObjectInWindow: function ()
+    this.output.openVariablesView({
+      label: VariablesView.getString(this.objectActor, { concise: true }),
+      objectActor: this.objectActor,
+      autofocus: true,
+    });
+  },
+
+  storeObjectInWindow: function ()
   {
-      let evalString = `{ let i = 0;
+    let evalString = `{ let i = 0;
       while (this.hasOwnProperty("temp" + i) && i < 1000) {
         i++;
       }
       this["temp" + i] = _self;
       "temp" + i;
     }`;
-      let options = {
-        selectedObjectActor: this.objectActor.actor,
-      };
-
-      this.output.owner.jsterm.requestEvaluation(evalString, options).then((res) => {
-        this.output.owner.jsterm.focus();
-        this.output.owner.jsterm.setInputValue(res.result);
-      });
-    },
+    let options = {
+      selectedObjectActor: this.objectActor.actor,
+    };
+
+    this.output.owner.jsterm.requestEvaluation(evalString, options).then((res) => {
+      this.output.owner.jsterm.focus();
+      this.output.owner.jsterm.setInputValue(res.result);
+    });
+  },
 
   /**
    * The click event handler for objects shown inline.
    * @private
    */
-    _onClick: function ()
+  _onClick: function ()
   {
-      this.openObjectInVariablesView();
-    },
-
-    _onContextMenu: function (ev) {
+    this.openObjectInVariablesView();
+  },
+
+  _onContextMenu: function (ev) {
     // TODO offer a nice API for the context menu.
     // Probably worth to take a look at Firebug's way
     // https://github.com/firebug/firebug/blob/master/extension/content/firebug/chrome/menu.js
-      let doc = ev.target.ownerDocument;
-      let cmPopup = doc.getElementById("output-contextmenu");
-
-      let openInVarViewCmd = doc.getElementById("menu_openInVarView");
-      let openVarView = this.openObjectInVariablesView.bind(this);
-      openInVarViewCmd.addEventListener("command", openVarView);
-      openInVarViewCmd.removeAttribute("disabled");
-      cmPopup.addEventListener("popuphiding", function onPopupHiding() {
-        cmPopup.removeEventListener("popuphiding", onPopupHiding);
-        openInVarViewCmd.removeEventListener("command", openVarView);
-        openInVarViewCmd.setAttribute("disabled", "true");
-      });
+    let doc = ev.target.ownerDocument;
+    let cmPopup = doc.getElementById("output-contextmenu");
+
+    let openInVarViewCmd = doc.getElementById("menu_openInVarView");
+    let openVarView = this.openObjectInVariablesView.bind(this);
+    openInVarViewCmd.addEventListener("command", openVarView);
+    openInVarViewCmd.removeAttribute("disabled");
+    cmPopup.addEventListener("popuphiding", function onPopupHiding() {
+      cmPopup.removeEventListener("popuphiding", onPopupHiding);
+      openInVarViewCmd.removeEventListener("command", openVarView);
+      openInVarViewCmd.setAttribute("disabled", "true");
+    });
 
     // 'Store as global variable' command isn't supported on pre-44 servers,
     // so remove it from the menu in that case.
-      let storeInGlobalCmd = doc.getElementById("menu_storeAsGlobal");
-      if (!this.output.webConsoleClient.traits.selectedObjectActor) {
-        storeInGlobalCmd.remove();
-      } else if (storeInGlobalCmd) {
-        let storeObjectInWindow = this.storeObjectInWindow.bind(this);
-        storeInGlobalCmd.addEventListener("command", storeObjectInWindow);
-        storeInGlobalCmd.removeAttribute("disabled");
-        cmPopup.addEventListener("popuphiding", function onPopupHiding() {
-          cmPopup.removeEventListener("popuphiding", onPopupHiding);
-          storeInGlobalCmd.removeEventListener("command", storeObjectInWindow);
-          storeInGlobalCmd.setAttribute("disabled", "true");
-        });
-      }
-    },
+    let storeInGlobalCmd = doc.getElementById("menu_storeAsGlobal");
+    if (!this.output.webConsoleClient.traits.selectedObjectActor) {
+      storeInGlobalCmd.remove();
+    } else if (storeInGlobalCmd) {
+      let storeObjectInWindow = this.storeObjectInWindow.bind(this);
+      storeInGlobalCmd.addEventListener("command", storeObjectInWindow);
+      storeInGlobalCmd.removeAttribute("disabled");
+      cmPopup.addEventListener("popuphiding", function onPopupHiding() {
+        cmPopup.removeEventListener("popuphiding", onPopupHiding);
+        storeInGlobalCmd.removeEventListener("command", storeObjectInWindow);
+        storeInGlobalCmd.setAttribute("disabled", "true");
+      });
+    }
+  },
 
   /**
    * Add a string to the message.
    *
    * @private
    * @param string str
    *        String to add.
    * @param DOMElement [target = this.element]
    *        Optional DOM element to append the string to. The default is
    *        this.element.
    */
-    _text: function (str, target = this.element)
+  _text: function (str, target = this.element)
   {
-      target.appendChild(this.document.createTextNode(str));
-    },
-  }); // Widgets.JSObject.prototype
+    target.appendChild(this.document.createTextNode(str));
+  },
+}); // Widgets.JSObject.prototype
 
 Widgets.ObjectRenderers = {};
 Widgets.ObjectRenderers.byKind = {};
 Widgets.ObjectRenderers.byClass = {};
 
 /**
  * Add an object renderer.
  *
@@ -2687,17 +2679,17 @@ Widgets.ObjectRenderers.add = function (
     return true;
   });
 
   if (extendObj === Widgets.JSObject) {
     proto._render = obj.render;
   }
 
   constructor.canRender = obj.canRender;
-  constructor.prototype = Heritage.extend(extendObj.prototype, proto);
+  constructor.prototype = extend(extendObj.prototype, proto);
 
   if (obj.byClass) {
     Widgets.ObjectRenderers.byClass[obj.byClass] = constructor;
   } else if (obj.byKind) {
     Widgets.ObjectRenderers.byKind[obj.byKind] = constructor;
   } else {
     throw new Error("You are adding an object renderer without any byClass or " +
                     "byKind property.");
@@ -3489,127 +3481,126 @@ Widgets.LongString = function (message, 
   this.longStringActor = longStringActor;
   this.noStringQuotes = (options && "noStringQuotes" in options) ?
     options.noStringQuotes : !this.message._quoteStrings;
 
   this._onClick = this._onClick.bind(this);
   this._onSubstring = this._onSubstring.bind(this);
 };
 
-Widgets.LongString.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
-  {
+Widgets.LongString.prototype = extend(Widgets.BaseWidget.prototype, {
   /**
    * The LongStringActor displayed by the widget.
    * @type object
    */
-    longStringActor: null,
-
-    render: function ()
+  longStringActor: null,
+
+  render: function ()
   {
-      if (this.element) {
-        return this;
-      }
-
-      let result = this.element = this.document.createElementNS(XHTML_NS, "span");
-      result.className = "longString console-string";
-      this._renderString(this.longStringActor.initial);
-      result.appendChild(this._renderEllipsis());
-
+    if (this.element) {
       return this;
-    },
+    }
+
+    let result = this.element = this.document.createElementNS(XHTML_NS, "span");
+    result.className = "longString console-string";
+    this._renderString(this.longStringActor.initial);
+    result.appendChild(this._renderEllipsis());
+
+    return this;
+  },
 
   /**
    * Render the long string in the widget element.
    * @private
    * @param string str
    *        The string to display.
    */
-    _renderString: function (str)
+  _renderString: function (str)
   {
-      this.element.textContent = VariablesView.getString(str, {
-        noStringQuotes: this.noStringQuotes,
-        noEllipsis: true,
-      });
-    },
+    this.element.textContent = VariablesView.getString(str, {
+      noStringQuotes: this.noStringQuotes,
+      noEllipsis: true,
+    });
+  },
 
   /**
    * Render the anchor ellipsis that allows the user to expand the long string.
    *
    * @private
    * @return Element
    */
-    _renderEllipsis: function ()
+  _renderEllipsis: function ()
   {
-      let ellipsis = this.document.createElementNS(XHTML_NS, "a");
-      ellipsis.className = "longStringEllipsis";
-      ellipsis.textContent = l10n.getStr("longStringEllipsis");
-      ellipsis.href = "#";
-      ellipsis.draggable = false;
-      this.message._addLinkCallback(ellipsis, this._onClick);
-
-      return ellipsis;
-    },
+    let ellipsis = this.document.createElementNS(XHTML_NS, "a");
+    ellipsis.className = "longStringEllipsis";
+    ellipsis.textContent = l10n.getStr("longStringEllipsis");
+    ellipsis.href = "#";
+    ellipsis.draggable = false;
+    this.message._addLinkCallback(ellipsis, this._onClick);
+
+    return ellipsis;
+  },
 
   /**
    * The click event handler for the ellipsis shown after the short string. This
    * function expands the element to show the full string.
    * @private
    */
-    _onClick: function ()
+  _onClick: function ()
   {
-      let longString = this.output.webConsoleClient.longString(this.longStringActor);
-      let toIndex = Math.min(longString.length, MAX_LONG_STRING_LENGTH);
-
-      longString.substring(longString.initial.length, toIndex, this._onSubstring);
-    },
+    let longString = this.output.webConsoleClient.longString(this.longStringActor);
+    let toIndex = Math.min(longString.length, MAX_LONG_STRING_LENGTH);
+
+    longString.substring(longString.initial.length, toIndex, this._onSubstring);
+  },
 
   /**
    * The longString substring response callback.
    *
    * @private
    * @param object response
    *        Response packet.
    */
-    _onSubstring: function (response)
+  _onSubstring: function (response)
   {
-      if (response.error) {
-        console.error("LongString substring failure: " + response.error);
-        return;
-      }
-
-      this.element.lastChild.remove();
-      this.element.classList.remove("longString");
-
-      this._renderString(this.longStringActor.initial + response.substring);
-
-      this.output.owner.emit("new-messages", new Set([{
-        update: true,
-        node: this.message.element,
-        response: response,
-      }]));
-
-      let toIndex = Math.min(this.longStringActor.length, MAX_LONG_STRING_LENGTH);
-      if (toIndex != this.longStringActor.length) {
-        this._logWarningAboutStringTooLong();
-      }
-    },
+    if (response.error) {
+      console.error("LongString substring failure: " + response.error);
+      return;
+    }
+
+    this.element.lastChild.remove();
+    this.element.classList.remove("longString");
+
+    this._renderString(this.longStringActor.initial + response.substring);
+
+    this.output.owner.emit("new-messages", new Set([{
+      update: true,
+      node: this.message.element,
+      response: response,
+    }]));
+
+    let toIndex = Math.min(this.longStringActor.length, MAX_LONG_STRING_LENGTH);
+    if (toIndex != this.longStringActor.length) {
+      this._logWarningAboutStringTooLong();
+    }
+  },
 
   /**
    * Inform user that the string he tries to view is too long.
    * @private
    */
-    _logWarningAboutStringTooLong: function ()
+  _logWarningAboutStringTooLong: function ()
   {
-      let msg = new Messages.Simple(l10n.getStr("longStringTooLong"), {
-        category: "output",
-        severity: "warning",
-      });
-      this.output.addMessage(msg);
-    },
-  }); // Widgets.LongString.prototype
+    let msg = new Messages.Simple(l10n.getStr("longStringTooLong"), {
+      category: "output",
+      severity: "warning",
+    });
+    this.output.addMessage(msg);
+  },
+}); // Widgets.LongString.prototype
 
 
 /**
  * The stacktrace widget.
  *
  * @constructor
  * @extends Widgets.BaseWidget
  * @param object message
@@ -3619,89 +3610,88 @@ Widgets.LongString.prototype = Heritage.
  *        over the remote protocol.
  */
 Widgets.Stacktrace = function (message, stacktrace)
 {
   Widgets.BaseWidget.call(this, message);
   this.stacktrace = stacktrace;
 };
 
-Widgets.Stacktrace.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
-  {
+Widgets.Stacktrace.prototype = extend(Widgets.BaseWidget.prototype, {
   /**
    * The stackframes received from the server.
    * @type array
    */
-    stacktrace: null,
-
-    render: function ()
+  stacktrace: null,
+
+  render: function ()
   {
-      if (this.element) {
-        return this;
+    if (this.element) {
+      return this;
+    }
+
+    let result = this.element = this.document.createElementNS(XHTML_NS, "ul");
+    result.className = "stacktrace devtools-monospace";
+
+    if (this.stacktrace) {
+      for (let frame of this.stacktrace) {
+        result.appendChild(this._renderFrame(frame));
       }
-
-      let result = this.element = this.document.createElementNS(XHTML_NS, "ul");
-      result.className = "stacktrace devtools-monospace";
-
-      if (this.stacktrace) {
-        for (let frame of this.stacktrace) {
-          result.appendChild(this._renderFrame(frame));
-        }
-      }
-
-      return this;
-    },
+    }
+
+    return this;
+  },
 
   /**
    * Render a frame object received from the server.
    *
    * @param object frame
    *        The stack frame to display. This object should have the following
    *        properties: functionName, filename and lineNumber.
    * @return DOMElement
    *         The DOM element to display for the given frame.
    */
-    _renderFrame: function (frame)
+  _renderFrame: function (frame)
   {
-      let fn = this.document.createElementNS(XHTML_NS, "span");
-      fn.className = "function";
-
-      let asyncCause = "";
-      if (frame.asyncCause) {
-        asyncCause =
+    let fn = this.document.createElementNS(XHTML_NS, "span");
+    fn.className = "function";
+
+    let asyncCause = "";
+    if (frame.asyncCause) {
+      asyncCause =
         l10n.getFormatStr("stacktrace.asyncStack", [frame.asyncCause]) + " ";
-      }
-
-      if (frame.functionName) {
-        let span = this.document.createElementNS(XHTML_NS, "span");
-        span.className = "cm-variable";
-        span.textContent = asyncCause + frame.functionName;
-        fn.appendChild(span);
-        fn.appendChild(this.document.createTextNode("()"));
-      } else {
-        fn.classList.add("cm-comment");
-        fn.textContent = asyncCause + l10n.getStr("stacktrace.anonymousFunction");
-      }
-
-      let location = this.output.owner.createLocationNode({url: frame.filename,
+    }
+
+    if (frame.functionName) {
+      let span = this.document.createElementNS(XHTML_NS, "span");
+      span.className = "cm-variable";
+      span.textContent = asyncCause + frame.functionName;
+      fn.appendChild(span);
+      fn.appendChild(this.document.createTextNode("()"));
+    } else {
+      fn.classList.add("cm-comment");
+      fn.textContent = asyncCause + l10n.getStr("stacktrace.anonymousFunction");
+    }
+
+    let location = this.output.owner.createLocationNode({url: frame.filename,
                                                         line: frame.lineNumber});
 
     // .devtools-monospace sets font-size to 80%, however .body already has
     // .devtools-monospace. If we keep it here, the location would be rendered
     // smaller.
-      location.classList.remove("devtools-monospace");
-
-      let elem = this.document.createElementNS(XHTML_NS, "li");
-      elem.appendChild(fn);
-      elem.appendChild(location);
-      elem.appendChild(this.document.createTextNode("\n"));
-
-      return elem;
-    },
-  }); // Widgets.Stacktrace.prototype
+    location.classList.remove("devtools-monospace");
+
+    let elem = this.document.createElementNS(XHTML_NS, "li");
+    elem.appendChild(fn);
+    elem.appendChild(location);
+    elem.appendChild(this.document.createTextNode("\n"));
+
+    return elem;
+  },
+}); // Widgets.Stacktrace.prototype
 
 
 /**
  * The table widget.
  *
  * @constructor
  * @extends Widgets.BaseWidget
  * @param object message
@@ -3714,52 +3704,51 @@ Widgets.Stacktrace.prototype = Heritage.
  */
 Widgets.Table = function (message, data, columns)
 {
   Widgets.BaseWidget.call(this, message);
   this.data = data;
   this.columns = columns;
 };
 
-Widgets.Table.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
-  {
+Widgets.Table.prototype = extend(Widgets.BaseWidget.prototype, {
   /**
    * Array of objects that holds the data to output in the table.
    * @type array
    */
-    data: null,
+  data: null,
 
   /**
    * Object containing the key value pair of the id and display name for
    * the columns in the table.
    * @type object
    */
-    columns: null,
-
-    render: function () {
-      if (this.element) {
-        return this;
-      }
-
-      let result = this.element = this.document.createElementNS(XHTML_NS, "div");
-      result.className = "consoletable devtools-monospace";
-
-      this.table = new TableWidget(result, {
-        initialColumns: this.columns,
-        uniqueId: "_index",
-        firstColumn: "_index"
-      });
-
-      for (let row of this.data) {
-        this.table.push(row);
-      }
-
+  columns: null,
+
+  render: function () {
+    if (this.element) {
       return this;
     }
-  }); // Widgets.Table.prototype
+
+    let result = this.element = this.document.createElementNS(XHTML_NS, "div");
+    result.className = "consoletable devtools-monospace";
+
+    this.table = new TableWidget(result, {
+      initialColumns: this.columns,
+      uniqueId: "_index",
+      firstColumn: "_index"
+    });
+
+    for (let row of this.data) {
+      this.table.push(row);
+    }
+
+    return this;
+  }
+}); // Widgets.Table.prototype
 
 function gSequenceId()
 {
   return gSequenceId.n++;
 }
 gSequenceId.n = 0;
 
 exports.ConsoleOutput = ConsoleOutput;
--- a/devtools/client/webconsole/hudservice.js
+++ b/devtools/client/webconsole/hudservice.js
@@ -4,17 +4,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, Cu} = require("chrome");
 
 var WebConsoleUtils = require("devtools/shared/webconsole/utils").Utils;
-var Heritage = require("sdk/core/heritage");
+var { extend } = require("sdk/core/heritage");
 var {TargetFactory} = require("devtools/client/framework/target");
 var {Tools} = require("devtools/client/definitions");
 const { Task } = require("resource://gre/modules/Task.jsm");
 var promise = require("promise");
 var Services = require("Services");
 
 loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
 loader.lazyRequireGetter(this, "WebConsoleFrame", "devtools/client/webconsole/webconsole", true);
@@ -29,18 +29,17 @@ var l10n = new WebConsoleUtils.L10n(STRI
 
 const BROWSER_CONSOLE_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
 
 // The preference prefix for all of the Browser Console filters.
 const BROWSER_CONSOLE_FILTER_PREFS_PREFIX = "devtools.browserconsole.filter.";
 
 var gHudId = 0;
 
-// /////////////////////////////////////////////////////////////////////////
-// // The HUD service
+// The HUD service
 
 function HUD_SERVICE()
 {
   this.consoles = new Map();
   this.lastFinishedRequest = { callback: null };
 }
 
 HUD_SERVICE.prototype =
@@ -633,93 +632,92 @@ WebConsole.prototype = {
  *        The window of the browser console owner.
  */
 function BrowserConsole()
 {
   WebConsole.apply(this, arguments);
   this._telemetry = new Telemetry();
 }
 
-BrowserConsole.prototype = Heritage.extend(WebConsole.prototype,
-  {
-    _browserConsole: true,
-    _bc_init: null,
-    _bc_destroyer: null,
+BrowserConsole.prototype = extend(WebConsole.prototype, {
+  _browserConsole: true,
+  _bc_init: null,
+  _bc_destroyer: null,
 
-    $init: WebConsole.prototype.init,
+  $init: WebConsole.prototype.init,
 
   /**
    * Initialize the Browser Console instance.
    *
    * @return object
    *         A promise for the initialization.
    */
-    init: function BC_init()
+  init: function BC_init()
   {
-      if (this._bc_init) {
-        return this._bc_init;
-      }
+    if (this._bc_init) {
+      return this._bc_init;
+    }
 
-      this.ui._filterPrefsPrefix = BROWSER_CONSOLE_FILTER_PREFS_PREFIX;
+    this.ui._filterPrefsPrefix = BROWSER_CONSOLE_FILTER_PREFS_PREFIX;
 
-      let window = this.iframeWindow;
+    let window = this.iframeWindow;
 
     // Make sure that the closing of the Browser Console window destroys this
     // instance.
-      let onClose = () => {
-        window.removeEventListener("unload", onClose);
-        window.removeEventListener("focus", onFocus);
-        this.destroy();
-      };
-      window.addEventListener("unload", onClose);
+    let onClose = () => {
+      window.removeEventListener("unload", onClose);
+      window.removeEventListener("focus", onFocus);
+      this.destroy();
+    };
+    window.addEventListener("unload", onClose);
 
     // Make sure Ctrl-W closes the Browser Console window.
-      window.document.getElementById("cmd_close").removeAttribute("disabled");
+    window.document.getElementById("cmd_close").removeAttribute("disabled");
 
-      this._telemetry.toolOpened("browserconsole");
+    this._telemetry.toolOpened("browserconsole");
 
     // Create an onFocus handler just to display the dev edition promo.
     // This is to prevent race conditions in some environments.
     // Hook to display promotional Developer Edition doorhanger. Only displayed once.
-      let onFocus = () => showDoorhanger({ window, type: "deveditionpromo" });
-      window.addEventListener("focus", onFocus);
+    let onFocus = () => showDoorhanger({ window, type: "deveditionpromo" });
+    window.addEventListener("focus", onFocus);
 
-      this._bc_init = this.$init();
-      return this._bc_init;
-    },
+    this._bc_init = this.$init();
+    return this._bc_init;
+  },
 
-    $destroy: WebConsole.prototype.destroy,
+  $destroy: WebConsole.prototype.destroy,
 
   /**
    * Destroy the object.
    *
    * @return object
    *         A promise object that is resolved once the Browser Console is closed.
    */
-    destroy: function BC_destroy()
+  destroy: function BC_destroy()
   {
-      if (this._bc_destroyer) {
-        return this._bc_destroyer.promise;
-      }
+    if (this._bc_destroyer) {
+      return this._bc_destroyer.promise;
+    }
 
-      this._telemetry.toolClosed("browserconsole");
+    this._telemetry.toolClosed("browserconsole");
 
-      this._bc_destroyer = promise.defer();
+    this._bc_destroyer = promise.defer();
 
-      let chromeWindow = this.chromeWindow;
-      this.$destroy().then(() =>
+    let chromeWindow = this.chromeWindow;
+    this.$destroy().then(() =>
       this.target.client.close(() => {
         HUDService._browserConsoleID = null;
         chromeWindow.close();
         this._bc_destroyer.resolve(null);
       }));
 
-      return this._bc_destroyer.promise;
-    },
-  });
+    return this._bc_destroyer.promise;
+  },
+});
 
 const HUDService = new HUD_SERVICE();
 
 (() => {
   let methods = ["openWebConsole", "openBrowserConsole",
                  "toggleBrowserConsole", "getOpenWebConsole",
                  "getBrowserConsole", "getHudByWindow",
                  "openBrowserConsoleOrFocus", "getHudReferenceById"];