merge fx-team to mozilla-central a=merge
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Fri, 29 Jan 2016 11:47:23 +0100
changeset 282280 8a3c5c9b1486c3328bc4684d5ac5b3b849b09474
parent 282273 ac21d6f878e6fdd69ec4140d1b63a94601524abe (current diff)
parent 282279 103a122789a33d1f1b12a5a1d34425c5b730213e (diff)
child 282297 3ba18d54f7578ff2d212c2cf55f14927851e7706
child 282346 df5126ec78738d3f9e8a127d693724e01abe2ee0
push id29954
push usercbook@mozilla.com
push dateFri, 29 Jan 2016 10:47:31 +0000
treeherdermozilla-central@8a3c5c9b1486 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone47.0a1
first release with
nightly linux32
8a3c5c9b1486 / 47.0a1 / 20160129030206 / files
nightly linux64
8a3c5c9b1486 / 47.0a1 / 20160129030206 / files
nightly mac
8a3c5c9b1486 / 47.0a1 / 20160129030206 / files
nightly win32
8a3c5c9b1486 / 47.0a1 / 20160129030206 / files
nightly win64
8a3c5c9b1486 / 47.0a1 / 20160129030206 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
merge fx-team to mozilla-central a=merge
devtools/client/performance/views/optimizations-list.js
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -95,17 +95,16 @@ devtools.jar:
     content/performance/views/toolbar.js (performance/views/toolbar.js)
     content/performance/views/details.js (performance/views/details.js)
     content/performance/views/details-abstract-subview.js (performance/views/details-abstract-subview.js)
     content/performance/views/details-waterfall.js (performance/views/details-waterfall.js)
     content/performance/views/details-js-call-tree.js (performance/views/details-js-call-tree.js)
     content/performance/views/details-js-flamegraph.js (performance/views/details-js-flamegraph.js)
     content/performance/views/details-memory-call-tree.js (performance/views/details-memory-call-tree.js)
     content/performance/views/details-memory-flamegraph.js (performance/views/details-memory-flamegraph.js)
-    content/performance/views/optimizations-list.js (performance/views/optimizations-list.js)
     content/performance/views/recordings.js (performance/views/recordings.js)
     content/memory/memory.xhtml (memory/memory.xhtml)
     content/memory/initializer.js (memory/initializer.js)
     content/promisedebugger/promise-controller.js (promisedebugger/promise-controller.js)
     content/promisedebugger/promise-panel.js (promisedebugger/promise-panel.js)
     content/promisedebugger/promise-debugger.xhtml (promisedebugger/promise-debugger.xhtml)
     content/commandline/commandline.css (commandline/commandline.css)
     content/commandline/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml)
@@ -214,16 +213,18 @@ devtools.jar:
     skin/promisedebugger.css (themes/promisedebugger.css)
     skin/images/timeline-filter.svg (themes/images/timeline-filter.svg)
     skin/scratchpad.css (themes/scratchpad.css)
     skin/shadereditor.css (themes/shadereditor.css)
     skin/storage.css (themes/storage.css)
     skin/splitview.css (themes/splitview.css)
     skin/styleeditor.css (themes/styleeditor.css)
     skin/webaudioeditor.css (themes/webaudioeditor.css)
+    skin/components-frame.css (themes/components-frame.css)
+    skin/jit-optimizations.css (themes/jit-optimizations.css)
     skin/images/magnifying-glass.png (themes/images/magnifying-glass.png)
     skin/images/magnifying-glass@2x.png (themes/images/magnifying-glass@2x.png)
     skin/images/magnifying-glass-light.png (themes/images/magnifying-glass-light.png)
     skin/images/magnifying-glass-light@2x.png (themes/images/magnifying-glass-light@2x.png)
     skin/images/itemToggle.png (themes/images/itemToggle.png)
     skin/images/itemToggle@2x.png (themes/images/itemToggle@2x.png)
     skin/images/itemArrow-dark-rtl.svg (themes/images/itemArrow-dark-rtl.svg)
     skin/images/itemArrow-dark-ltr.svg (themes/images/itemArrow-dark-ltr.svg)
new file mode 100644
--- /dev/null
+++ b/devtools/client/locales/en-US/jit-optimizations.properties
@@ -0,0 +1,31 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# LOCALIZATION NOTE These strings are used within the JIT tools
+# in the Performance Tools which is available from the Web Developer
+# sub-menu -> 'Performance' The correct localization of this file might
+# be to keep it in English, or another language commonly spoken among
+# web developers. You want to make that choice consistent across the
+# developer tools. A good criteria is the language in which you'd find the best
+# documentation on web development on the web.
+
+# LOCALIZATION NOTE (jit.title):
+# This string is displayed in the header of the JIT Optimizations view.
+jit.title=JIT Optimizations
+
+# LOCALIZATION NOTE (jit.optimizationFailure):
+# This string is displayed in a tooltip when no JIT optimizations were detected.
+jit.optimizationFailure=Optimization failed
+
+# LOCALIZATION NOTE (jit.samples):
+# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
+# This string is displayed for the unit representing the number of times a
+# frame is sampled.
+# "#1" represents the number of samples
+# example: 30 samples
+jit.samples=#1 sample;#1 samples
+
+# LOCALIZATION NOTE (jit.empty):
+# This string is displayed when there are no JIT optimizations to display.
+jit.empty=No JIT optimizations recorded for this frame.
--- a/devtools/client/locales/en-US/performance.dtd
+++ b/devtools/client/locales/en-US/performance.dtd
@@ -135,20 +135,16 @@
 <!ENTITY performanceUI.enableFramerate.tooltiptext "Record framerate while profiling.">
 
 <!-- LOCALIZATION NOTE (performanceUI.enableJITOptimizations): This string
   -  is displayed next to a checkbox determining whether or not JIT optimization data
   -  should be recorded. -->
 <!ENTITY performanceUI.enableJITOptimizations             "Record JIT Optimizations">
 <!ENTITY performanceUI.enableJITOptimizations.tooltiptext "Record JIT optimization data sampled in each JavaScript frame.">
 
-<!-- LOCALIZATION NOTE (performanceUI.JITOptimizationsTitle): This string
-  -  is displayed as the title of the JIT Optimizations panel. -->
-<!ENTITY performanceUI.JITOptimizationsTitle "JIT Optimizations">
-
 <!-- LOCALIZATION NOTE (performanceUI.console.recordingNoticeStart/recordingNoticeEnd):
   -  This string is displayed when a recording is selected that started via console.profile.
   -  Wraps the command used to start, like "Currently recording via console.profile("label")" -->
 <!ENTITY performanceUI.console.recordingNoticeStart "Currently recording via">
 <!ENTITY performanceUI.console.recordingNoticeEnd   "">
 
 <!-- LOCALIZATION NOTE (performanceUI.console.stopCommandStart/stopCommandEnd):
   -  This string is displayed when a recording is selected that started via console.profile.
--- a/devtools/client/locales/en-US/performance.properties
+++ b/devtools/client/locales/en-US/performance.properties
@@ -136,32 +136,16 @@ recordingsList.saveDialogTitle=Save recording…
 # LOCALIZATION NOTE (recordingsList.saveDialogJSONFilter):
 # This string is displayed as a filter for saving a recording to disk.
 recordingsList.saveDialogJSONFilter=JSON Files
 
 # LOCALIZATION NOTE (recordingsList.saveDialogAllFilter):
 # This string is displayed as a filter for saving a recording to disk.
 recordingsList.saveDialogAllFilter=All Files
 
-# LOCALIZATION NOTE (jit.optimizationFailure):
-# This string is displayed in a tooltip when no JIT optimizations were detected.
-jit.optimizationFailure=Optimization failed
-
-# LOCALIZATION NOTE (jit.samples):
-# See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-# This string is displayed for the unit representing the number of times a
-# frame is sampled.
-# "#1" represents the number of samples
-# example: 30 samples
-jit.samples=#1 sample;#1 samples
-
-# LOCALIZATION NOTE (jit.empty):
-# This string is displayed when there are no JIT optimizations to display.
-jit.empty=No JIT optimizations recorded for this frame.
-
 # LOCALIZATION NOTE (timeline.tick):
 # This string is displayed in the timeline overview, for delimiting ticks
 # by time, in milliseconds.
 timeline.tick=%S ms
 
 # LOCALIZATION NOTE (timeline.records):
 # This string is displayed in the timeline waterfall, as a title for the menu.
 timeline.records=RECORDS
--- a/devtools/client/memory/memory.xhtml
+++ b/devtools/client/memory/memory.xhtml
@@ -9,16 +9,17 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <html xmlns="http://www.w3.org/1999/xhtml">
   <head>
     <link rel="stylesheet" href="chrome://devtools/skin/common.css" type="text/css"/>
     <link rel="stylesheet" href="chrome://devtools/skin/widgets.css" type="text/css"/>
     <link rel="stylesheet" href="chrome://devtools/skin/memory.css" type="text/css"/>
+    <link rel="stylesheet" href="chrome://devtools/skin/components-frame.css" type="text/css"/>
 
     <script type="application/javascript;version=1.8"
             src="chrome://devtools/content/shared/theme-switching.js"/>
     <script type="application/javascript;version=1.8"
             src="initializer.js"></script>
   </head>
   <body class="theme-body">
     <div id="app">
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/components/moz.build
@@ -0,0 +1,9 @@
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DevToolsModules(
+    'optimizations-item.js',
+    'optimizations.js',
+)
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/components/optimizations-item.js
@@ -0,0 +1,145 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { Cu } = require("chrome");
+Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
+const STRINGS_URI = "chrome://devtools/locale/jit-optimizations.properties";
+const L10N = new ViewHelpers.L10N(STRINGS_URI);
+const { DOM: dom, PropTypes, createClass, createFactory } = require("devtools/client/shared/vendor/react");
+const Frame = createFactory(require("devtools/client/shared/components/frame"));
+const OPTIMIZATION_FAILURE = L10N.getStr("jit.optimizationFailure");
+const JIT_SAMPLES = L10N.getStr("jit.samples");
+const JIT_EMPTY_TEXT = L10N.getStr("jit.empty");
+const PROPNAME_MAX_LENGTH = 4;
+// If TREE_ROW_HEIGHT changes, be sure to change `var(--jit-tree-row-height)`
+// in `devtools/client/themes/jit-optimizations.css`
+const TREE_ROW_HEIGHT = 14;
+
+const OPTIMIZATION_ITEM_TYPES = ["site", "attempts", "types", "attempt", "type", "observedtype"];
+const OptimizationsItem = module.exports = createClass({
+  displayName: "OptimizationsItem",
+
+  propTypes: {
+    onViewSourceInDebugger: PropTypes.func.isRequired,
+    frameData: PropTypes.object.isRequired,
+    type: PropTypes.oneOf(OPTIMIZATION_ITEM_TYPES).isRequired,
+  },
+
+  render() {
+    let {
+      item,
+      depth,
+      arrow,
+      focused,
+      type,
+      frameData,
+      onViewSourceInDebugger,
+    } = this.props;
+
+    let content;
+    switch (type) {
+      case "site":         content = this._renderSite(this.props); break;
+      case "attempts":     content = this._renderAttempts(this.props); break;
+      case "types":        content = this._renderTypes(this.props); break;
+      case "attempt":      content = this._renderAttempt(this.props); break;
+      case "type":         content = this._renderType(this.props); break;
+      case "observedtype": content = this._renderObservedType(this.props); break;
+    };
+
+    return dom.div(
+      {
+        className: `optimization-tree-item optimization-tree-item-${type}`,
+        style: { marginLeft: depth * TREE_ROW_HEIGHT }
+      },
+      arrow,
+      content
+    );
+  },
+
+  _renderSite({ item: site, onViewSourceInDebugger, frameData }) {
+    let attempts = site.data.attempts;
+    let lastStrategy = attempts[attempts.length - 1].strategy;
+    let propString = "";
+    let propertyName = site.data.propertyName;
+
+    // Display property name if it exists
+    if (propertyName) {
+      if (propertyName.length > PROPNAME_MAX_LENGTH) {
+        propString = ` (.${propertyName.substr(0, PROPNAME_MAX_LENGTH)}…)`;
+      } else {
+        propString = ` (.${propertyName})`;
+      }
+    }
+
+    let sampleString = PluralForm.get(site.samples, JIT_SAMPLES).replace("#1", site.samples);
+    let text = `${lastStrategy}${propString} – (${sampleString})`;
+    let frame = Frame({
+      onClick: () => onViewSourceInDebugger(frameData.url, site.data.line),
+      frame: {
+        source: frameData.url,
+        line: site.data.line,
+        column: site.data.column,
+      }
+    })
+    let children = [text, frame];
+
+    if (!site.hasSuccessfulOutcome()) {
+      children.unshift(dom.span({ className: "opt-icon warning" }));
+    }
+
+    return dom.span({ className: "optimization-site" }, ...children);
+  },
+
+  _renderAttempts({ item: attempts }) {
+    return dom.span({ className: "optimization-attempts" },
+      `Attempts (${attempts.length})`
+    );
+  },
+
+  _renderTypes({ item: types }) {
+    return dom.span({ className: "optimization-types" },
+      `Types (${types.length})`
+    );
+  },
+
+  _renderAttempt({ item: attempt }) {
+    let success = JITOptimizations.isSuccessfulOutcome(attempt.outcome);
+    let { strategy, outcome } = attempt;
+    return dom.span({ className: "optimization-attempt" },
+      dom.span({ className: "optimization-strategy" }, strategy),
+      " → ",
+      dom.span({ className: `optimization-outcome ${success ? "success" : "failure"}` }, outcome)
+    );
+  },
+
+  _renderType({ item: type }) {
+    return dom.span({ className: "optimization-ion-type" }, `${type.site}:${type.mirType}`);
+  },
+
+  _renderObservedType({ onViewSourceInDebugger, item: type }) {
+    let children = [
+      `${type.keyedBy}${type.name ? ` → ${type.name}` : ""}`
+    ];
+
+    // If we have a line and location, make a link to the debugger
+    if (type.location && type.line) {
+      children.push(
+        Frame({
+          onClick: () => onViewSourceInDebugger(type.location, type.line),
+          frame: {
+            source: type.location,
+            line: type.line,
+            column: type.column,
+          }
+        })
+      );
+    }
+    // Otherwise if we just have a location, it's probably just a memory location.
+    else if (type.location) {
+      children.push(`@${type.location}`);
+    }
+
+    return dom.span({ className: "optimization-observed-type" }, ...children);
+  },
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/performance/components/optimizations.js
@@ -0,0 +1,183 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const { Cu } = require("chrome");
+Cu.import("resource://devtools/client/shared/widgets/ViewHelpers.jsm");
+const STRINGS_URI = "chrome://devtools/locale/jit-optimizations.properties";
+const L10N = new ViewHelpers.L10N(STRINGS_URI);
+const { assert } = require("devtools/shared/DevToolsUtils");
+const { DOM: dom, createClass, createFactory, PropTypes } = require("devtools/client/shared/vendor/react");
+const Tree = createFactory(require("../../shared/components/tree"));
+const OptimizationsItem = createFactory(require("./optimizations-item"));
+const FrameView = createFactory(require("../../shared/components/frame"));
+
+const onClickTooltipString = frame =>
+  L10N.getFormatStr("viewsourceindebugger",`${frame.source}:${frame.line}:${frame.column}`);
+const JIT_TITLE = L10N.getStr("jit.title");
+// If TREE_ROW_HEIGHT changes, be sure to change `var(--jit-tree-row-height)`
+// in `devtools/client/themes/jit-optimizations.css`
+const TREE_ROW_HEIGHT = 14;
+
+const Optimizations = module.exports = createClass({
+  displayName: "Optimizations",
+
+  propTypes: {
+    onViewSourceInDebugger: PropTypes.func.isRequired,
+    frameData: PropTypes.object.isRequired,
+    optimizationSites: PropTypes.array.isRequired,
+  },
+
+  getInitialState() {
+    return {
+      expanded: new Set()
+    };
+  },
+
+  getDefaultProps() {
+    return {};
+  },
+
+  render() {
+    let header = this._createHeader(this.props);
+    let tree = this._createTree(this.props);
+
+    return dom.div({}, header, tree);
+  },
+
+  /**
+   * Frame data generated from `frameNode.getInfo()`, or an empty
+   * object, as well as a handler for clicking on the frame component.
+   *
+   * @param {?Object} .frameData
+   * @param {Function} .onViewSourceInDebugger
+   * @return {ReactElement}
+   */
+  _createHeader: function ({ frameData, onViewSourceInDebugger }) {
+    let { isMetaCategory, url, line } = frameData;
+    let name = isMetaCategory ? frameData.categoryData.label :
+               frameData.functionName || "";
+
+    // Simulate `SavedFrame`s interface
+    let frame = { source: url, line: +line, functionDisplayName: name };
+
+    // Neither Meta Category nodes, or the lack of a selected frame node,
+    // renders out a frame source, like "file.js:123"; so just use
+    // an empty span.
+    let frameComponent;
+    if (isMetaCategory || !name) {
+      frameComponent = dom.span();
+    } else {
+      frameComponent = FrameView({
+        frame,
+        onClick: () => onViewSourceInDebugger(frame),
+      });
+    }
+
+    return dom.div({ className: "optimization-header" },
+      dom.span({ className: "header-title" }, JIT_TITLE),
+      dom.span({ className: "header-function-name" }, name),
+      frameComponent
+    );
+  },
+
+  _createTree(props) {
+    let { frameData, onViewSourceInDebugger, optimizationSites: sites } = this.props;
+
+    let getSite = id => sites.find(site => site.id === id);
+    let getIonTypeForObserved = type =>
+      getSite(type.id).data.types.find(iontype => (iontype.typeset || []).indexOf(type) !== -1);
+    let isSite = site => getSite(site.id) === site;
+    let isAttempts = attempts => getSite(attempts.id).data.attempts === attempts;
+    let isAttempt = attempt => getSite(attempt.id).data.attempts.indexOf(attempt) !== -1;
+    let isTypes = types => getSite(types.id).data.types === types;
+    let isType = type => getSite(type.id).data.types.indexOf(type) !== -1;
+    let isObservedType = type => getIonTypeForObserved(type);
+
+    let getRowType = node => {
+      return isSite(node) ? "site" :
+             isAttempts(node) ? "attempts" :
+             isTypes(node) ? "types" :
+             isAttempt(node) ? "attempt" :
+             isType(node) ? "type":
+             isObservedType(node) ? "observedtype": null;
+    };
+
+    // Creates a unique key for each node in the
+    // optimizations data
+    let getKey = node => {
+      let site = getSite(node.id);
+      if (isSite(node)) {
+        return node.id;
+      } else if (isAttempts(node)) {
+        return `${node.id}-A`;
+      } else if (isTypes(node)) {
+        return `${node.id}-T`;
+      } else if (isType(node)) {
+        return `${node.id}-T-${site.data.types.indexOf(node)}`;
+      } else if (isAttempt(node)) {
+        return `${node.id}-A-${site.data.attempts.indexOf(node)}`;
+      } else if (isObservedType(node)) {
+        let iontype = getIonTypeForObserved(node);
+        return `${getKey(iontype)}-O-${iontype.typeset.indexOf(node)}`;
+      }
+    };
+
+    return Tree({
+      autoExpandDepth: 0,
+      getParent: node => {
+        let site = getSite(node.id);
+        let parent;
+        if (isAttempts(node) || isTypes(node)) {
+          parent = site;
+        } else if (isType(node)) {
+          parent = site.data.types;
+        } else if (isAttempt(node)) {
+          parent = site.data.attempts;
+        } else if (isObservedType(node)) {
+          parent = getIonTypeForObserved(node);
+        }
+        assert(parent, "Could not find a parent for optimization data node");
+
+        return parent;
+      },
+      getChildren: node => {
+        if (isSite(node)) {
+          return [node.data.types, node.data.attempts];
+        } else if (isAttempts(node) || isTypes(node)) {
+          return node;
+        } else if (isType(node)) {
+          return node.typeset || [];
+        } else {
+          return [];
+        }
+      },
+      isExpanded: node => this.state.expanded.has(node),
+      onExpand: node => this.setState(state => {
+        let expanded = new Set(state.expanded);
+        expanded.add(node);
+        return { expanded };
+      }),
+      onCollapse: node => this.setState(state => {
+        let expanded = new Set(state.expanded);
+        expanded.delete(node);
+        return { expanded };
+      }),
+      onFocus: function () {},
+      getKey,
+      getRoots: () => sites || [],
+      itemHeight: TREE_ROW_HEIGHT,
+      renderItem: (item, depth, focused, arrow, expanded) =>
+        new OptimizationsItem({
+          onViewSourceInDebugger,
+          item,
+          depth,
+          focused,
+          arrow,
+          expanded,
+          type: getRowType(item),
+          frameData,
+        }),
+    });
+  }
+});
--- a/devtools/client/performance/modules/logic/frame-utils.js
+++ b/devtools/client/performance/modules/logic/frame-utils.js
@@ -1,30 +1,33 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const global = require("devtools/client/performance/modules/global");
 const demangle = require("devtools/client/shared/demangle");
+const { assert } = require("devtools/shared/DevToolsUtils");
 const { isChromeScheme, isContentScheme, parseURL } =
   require("devtools/client/shared/source-utils");
 
 // Character codes used in various parsing helper functions.
 const CHAR_CODE_R = "r".charCodeAt(0);
 const CHAR_CODE_0 = "0".charCodeAt(0);
 const CHAR_CODE_9 = "9".charCodeAt(0);
 const CHAR_CODE_CAP_Z = "Z".charCodeAt(0);
 
 const CHAR_CODE_LPAREN = "(".charCodeAt(0);
 const CHAR_CODE_RPAREN = ")".charCodeAt(0);
 const CHAR_CODE_COLON = ":".charCodeAt(0);
 const CHAR_CODE_SPACE = " ".charCodeAt(0);
 const CHAR_CODE_UNDERSCORE = "_".charCodeAt(0);
 
+const EVAL_TOKEN = "%20%3E%20eval";
+
 // The cache used to store inflated frames.
 const gInflatedFrameStore = new WeakMap();
 
 // The cache used to store frame data from `getInfo`.
 const gFrameData = new WeakMap();
 
 /**
  * Parses the raw location of this function call to retrieve the actual
@@ -144,16 +147,36 @@ function parseLocation(location, fallbac
   column = column || fallbackColumn;
 
   // If the URL digged out from the `location` is valid, this is a JS frame.
   if (parsedUrl) {
     functionName = location.substring(0, parenIndex - 1);
     fileName = parsedUrl.fileName;
     port = parsedUrl.port;
     host = parsedUrl.host;
+
+    // Check for the case of the filename containing eval
+    // e.g. "file.js%20line%2065%20%3E%20eval"
+    let evalIndex = fileName.indexOf(EVAL_TOKEN);
+    if (evalIndex !== -1 && evalIndex === (fileName.length - EVAL_TOKEN.length)) {
+      // Match the filename
+      let evalLine = line;
+      let [, _fileName, , _line] = fileName.match(/(.+)(%20line%20(\d+)%20%3E%20eval)/) || [];
+      fileName = `${_fileName} (eval:${evalLine})`;
+      line =  _line;
+      assert(_fileName !== undefined,
+             "Filename could not be found from an eval location site");
+      assert(_line !== undefined,
+             "Line could not be found from an eval location site");
+
+      // Match the url as well
+      [, url] = url.match(/(.+)( line (\d+) > eval)/) || [];
+      assert(url !== undefined,
+             "The URL could not be parsed correctly from an eval location site");
+    }
   } else {
     functionName = location;
     url = null;
   }
 
   return { functionName, fileName, host, port, url, line, column };
 };
 
--- a/devtools/client/performance/modules/logic/jit.js
+++ b/devtools/client/performance/modules/logic/jit.js
@@ -47,17 +47,17 @@ const SUCCESSFUL_OUTCOMES = [
  * Based off of the observed types for a value (like a variable that could be a
  * string or an instance of an object), it determines what kind of type it should be classified
  * as. Each IonType here contains an array of all ObservedTypes under `types`,
  * the Ion type that IonMonkey decided this value should be (Int32, Object, etc.) as `mirType`,
  * and the component of this optimization type that this value refers to -- like
  * a "getter" optimization, `a[b]`, has site `a` (the "Receiver") and `b` (the "Index").
  *
  * Generally the more ObservedTypes, the more deoptimized this OptimizationSite is.
- * There could be no ObservedTypes, in which case `types` is undefined.
+ * There could be no ObservedTypes, in which case `typeset` is undefined.
  *
  * @type {?Array<ObservedType>} typeset
  * @type {string} site
  * @type {string} mirType
  *
  *
  * @struct ObservedType
  * When IonMonkey attempts to determine what type a value is, it checks on each sample.
@@ -179,33 +179,43 @@ const JITOptimizations = function (rawSi
     }
   }
 
   // Inflate the optimization information.
   for (let site of sites) {
     let data = site.data;
     let STRATEGY_SLOT = data.attempts.schema.strategy;
     let OUTCOME_SLOT = data.attempts.schema.outcome;
+    let attempts = data.attempts.data.map((a) => {
+      return {
+        id: site.id,
+        strategy: stringTable[a[STRATEGY_SLOT]],
+        outcome: stringTable[a[OUTCOME_SLOT]]
+      }
+    });
+    let types = data.types.map((t) => {
+      let typeset = maybeTypeset(t.typeset, stringTable);
+      if (typeset) {
+        typeset.forEach(t => t.id = site.id);
+      }
+
+      return {
+        id: site.id,
+        typeset,
+        site: stringTable[t.site],
+        mirType: stringTable[t.mirType]
+      };
+    });
+    // Add IDs to to all children objects, so we can correllate sites when
+    // just looking at a specific type, attempt, etc..
+    attempts.id = types.id = site.id;
 
     site.data = {
-      attempts: data.attempts.data.map((a) => {
-        return {
-          strategy: stringTable[a[STRATEGY_SLOT]],
-          outcome: stringTable[a[OUTCOME_SLOT]]
-        }
-      }),
-
-      types: data.types.map((t) => {
-        return {
-          typeset: maybeTypeset(t.typeset, stringTable),
-          site: stringTable[t.site],
-          mirType: stringTable[t.mirType]
-        };
-      }),
-
+      attempts,
+      types,
       propertyName: maybeString(stringTable, data.propertyName),
       line: data.line,
       column: data.column
     };
   }
 
   this.optimizationSites = sites.sort((a, b) => b.samples - a.samples);
 };
--- a/devtools/client/performance/moz.build
+++ b/devtools/client/performance/moz.build
@@ -1,14 +1,15 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += [
+    'components',
     'legacy',
     'modules',
 ]
 
 DevToolsModules(
     'events.js',
     'panel.js'
 )
--- a/devtools/client/performance/performance-controller.js
+++ b/devtools/client/performance/performance-controller.js
@@ -13,16 +13,19 @@ var { Heritage, ViewHelpers, WidgetMetho
 // Events emitted by various objects in the panel.
 var EVENTS = require("devtools/client/performance/events");
 Object.defineProperty(this, "EVENTS", {
   value: EVENTS,
   enumerable: true,
   writable: false
 });
 
+var React = require("devtools/client/shared/vendor/react");
+var ReactDOM = require("devtools/client/shared/vendor/react-dom");
+var Optimizations = React.createFactory(require("devtools/client/performance/components/optimizations"));
 var Services = require("Services");
 var promise = require("promise");
 var EventEmitter = require("devtools/shared/event-emitter");
 var DevToolsUtils = require("devtools/shared/DevToolsUtils");
 var system = require("devtools/shared/system");
 
 // Logic modules
 
--- a/devtools/client/performance/performance.xul
+++ b/devtools/client/performance/performance.xul
@@ -2,16 +2,18 @@
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 <?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/content/shared/widgets/widgets.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/skin/common.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/skin/widgets.css" type="text/css"?>
 <?xml-stylesheet href="chrome://devtools/skin/performance.css" type="text/css"?>
+<?xml-stylesheet href="chrome://devtools/skin/jit-optimizations.css" type="text/css"?>
+<?xml-stylesheet href="chrome://devtools/skin/components-frame.css" type="text/css"?>
 <!DOCTYPE window [
   <!ENTITY % performanceDTD SYSTEM "chrome://devtools/locale/performance.dtd">
   %performanceDTD;
 ]>
 
 <window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
   <script src="chrome://devtools/content/shared/theme-switching.js"/>
   <script type="application/javascript" src="performance-controller.js"/>
@@ -21,17 +23,16 @@
   <script type="application/javascript" src="views/details-abstract-subview.js"/>
   <script type="application/javascript" src="views/details-waterfall.js"/>
   <script type="application/javascript" src="views/details-js-call-tree.js"/>
   <script type="application/javascript" src="views/details-js-flamegraph.js"/>
   <script type="application/javascript" src="views/details-memory-call-tree.js"/>
   <script type="application/javascript" src="views/details-memory-flamegraph.js"/>
   <script type="application/javascript" src="views/details.js"/>
   <script type="application/javascript" src="views/recordings.js"/>
-  <script type="application/javascript" src="views/optimizations-list.js"/>
 
   <popupset id="performance-options-popupset">
     <menupopup id="performance-filter-menupopup"/>
     <menupopup id="performance-options-menupopup" position="before_end">
       <menuitem id="option-show-platform-data"
                 type="checkbox"
                 data-pref="show-platform-data"
                 label="&performanceUI.showPlatformData;"
@@ -313,27 +314,17 @@
                            value="&performanceUI.table.function;"
                            tooltiptext="&performanceUI.table.function.tooltip;"/>
                   </hbox>
                   <vbox class="call-tree-cells-container" flex="1"/>
                 </vbox>
                 <splitter class="devtools-side-splitter"/>
                 <!-- Optimizations Panel -->
                 <vbox id="jit-optimizations-view"
-                      class="hidden">
-                  <toolbar id="jit-optimizations-toolbar" class="devtools-toolbar">
-                    <hbox id="jit-optimizations-header">
-                      <span class="jit-optimizations-title">&performanceUI.JITOptimizationsTitle;</span>
-                      <span class="header-function-name" />
-                      <span class="header-file opt-url debugger-link" />
-                      <span class="header-line opt-line" />
-                    </hbox>
-                  </toolbar>
-                  <hbox id="optimizations-graph"></hbox>
-                  <vbox id="jit-optimizations-raw-view"></vbox>
+                  class="hidden">
                 </vbox>
               </hbox>
 
               <!-- JS FlameChart -->
               <hbox id="js-flamegraph-view" flex="1">
               </hbox>
 
               <!-- Memory Tree -->
--- a/devtools/client/performance/test/browser.ini
+++ b/devtools/client/performance/test/browser.ini
@@ -38,17 +38,19 @@ skip-if = true # Bug 1161817
 [browser_perf-details-03.js]
 [browser_perf-details-04.js]
 [browser_perf-details-05.js]
 [browser_perf-details-06.js]
 [browser_perf-details-07.js]
 [browser_perf-events-calltree.js]
 [browser_perf-highlighted.js]
 [browser_perf-jit-view-01.js]
+skip-if = true # Bug 1176056
 [browser_perf-jit-view-02.js]
+skip-if = true # Bug 1176056
 [browser_perf-legacy-front-01.js]
 [browser_perf-legacy-front-02.js]
 [browser_perf-legacy-front-03.js]
 [browser_perf-legacy-front-04.js]
 [browser_perf-legacy-front-05.js]
 [browser_perf-legacy-front-06.js]
 [browser_perf-legacy-front-07.js]
 [browser_perf-legacy-front-08.js]
--- a/devtools/client/performance/test/browser_profiler_tree-view-11.js
+++ b/devtools/client/performance/test/browser_profiler_tree-view-11.js
@@ -6,17 +6,17 @@
  * icon is next to the frame with optimizations
  */
 
 var { CATEGORY_MASK } = require("devtools/client/performance/modules/global");
 
 function* spawnTest() {
   let { panel } = yield initPerformance(SIMPLE_URL);
   let { EVENTS, $, $$, window, PerformanceController } = panel.panelWin;
-  let { OverviewView, DetailsView, JITOptimizationsView, JsCallTreeView, RecordingsView } = panel.panelWin;
+  let { OverviewView, DetailsView, JsCallTreeView, RecordingsView } = panel.panelWin;
 
   let profilerData = { threads: [gThread] };
 
   Services.prefs.setBoolPref(JIT_PREF, true);
   Services.prefs.setBoolPref(PLATFORM_DATA_PREF, false);
   Services.prefs.setBoolPref(INVERT_PREF, false);
 
   // Make two recordings, so we have one to switch to later, as the
--- a/devtools/client/performance/test/unit/test_frame-utils-01.js
+++ b/devtools/client/performance/test/unit/test_frame-utils-01.js
@@ -15,16 +15,19 @@ const CONTENT_LOCATIONS = [
   "hello/<.world (http://foo/#bar:123:987)",
   "hello/<.world (http://foo/:123:987)",
   "hello/<.world (app://myfxosapp/file.js:100:1)",
 
   // Test scripts with port numbers (bug 1164131)
   "hello/<.world (http://localhost:8888/file.js:100:1)",
   "hello/<.world (http://localhost:8888/file.js:100)",
 
+  // Eval
+  "hello/<.world (http://localhost:8888/file.js line 65 > eval:1)",
+
   // Occurs when executing an inline script on a root html page with port
   // (I've never seen it with a column number but check anyway) bug 1164131
   "hello/<.world (http://localhost:8888/:1)",
   "hello/<.world (http://localhost:8888/:100:50)",
 
   // bug 1197636
   "Native[\"arraycopy(blah)\"] (http://localhost:8888/profiler.html:4)",
   "Native[\"arraycopy(blah)\"] (http://localhost:8888/profiler.html:4:5)",
@@ -67,16 +70,17 @@ add_task(function () {
     ["hello/<.world", "bar.js", "foo", "http://foo/bar.js", 123, null, "foo", null],
     ["hello/<.world", "bar.js", "foo", "http://foo/bar.js#baz", 123, 987, "foo", null],
     ["hello/<.world", "bar.js", "foo", "http://foo/bar.js?myquery=params&search=1", 123, 987, "foo", null],
     ["hello/<.world", "/", "foo", "http://foo/#bar", 123, 987, "foo", null],
     ["hello/<.world", "/", "foo", "http://foo/", 123, 987, "foo", null],
     ["hello/<.world", "file.js", "myfxosapp", "app://myfxosapp/file.js", 100, 1, "myfxosapp", null],
     ["hello/<.world", "file.js", "localhost:8888", "http://localhost:8888/file.js", 100, 1, "localhost:8888", 8888],
     ["hello/<.world", "file.js", "localhost:8888", "http://localhost:8888/file.js", 100, null, "localhost:8888", 8888],
+    ["hello/<.world", "file.js (eval:1)", "localhost:8888", "http://localhost:8888/file.js", 65, null, "localhost:8888", 8888],
     ["hello/<.world", "/", "localhost:8888", "http://localhost:8888/", 1, null, "localhost:8888", 8888],
     ["hello/<.world", "/", "localhost:8888", "http://localhost:8888/", 100, 50, "localhost:8888", 8888],
     ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost:8888", "http://localhost:8888/profiler.html", 4, null, "localhost:8888", 8888],
     ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost:8888", "http://localhost:8888/profiler.html", 4, 5, "localhost:8888", 8888],
   ];
 
   for (let i = 0; i < PARSED_CONTENT.length; i++) {
     let parsed = parseLocation.apply(null, CONTENT_LOCATIONS[i]);
--- a/devtools/client/performance/views/details-js-call-tree.js
+++ b/devtools/client/performance/views/details-js-call-tree.js
@@ -24,24 +24,25 @@ var JsCallTreeView = Heritage.extend(Det
   initialize: function () {
     DetailsSubview.initialize.call(this);
 
     this._onLink = this._onLink.bind(this);
     this._onFocus = this._onFocus.bind(this);
 
     this.container = $("#js-calltree-view .call-tree-cells-container");
 
-    OptimizationsListView.initialize();
+    this.optimizationsElement = $("#jit-optimizations-view");
   },
 
   /**
    * Unbinds events.
    */
   destroy: function () {
-    OptimizationsListView.destroy();
+    ReactDOM.unmountComponentAtNode(this.optimizationsElement);
+    this.optimizationsElement = null;
     this.container = null;
     this.threadNode = null;
     DetailsSubview.destroy.call(this);
   },
 
   /**
    * Method for handling all the set up for rendering a new call tree.
    *
@@ -62,35 +63,58 @@ var JsCallTreeView = Heritage.extend(Det
     let threadNode = this.threadNode = this._prepareCallTree(profile, interval, options);
     this._populateCallTree(threadNode, options);
 
     if (optimizations) {
       this.showOptimizations();
     } else {
       this.hideOptimizations();
     }
-    OptimizationsListView.reset();
 
     this.emit(EVENTS.JS_CALL_TREE_RENDERED);
   },
 
   showOptimizations: function () {
-    $("#jit-optimizations-view").classList.remove("hidden");
+    this.optimizationsElement.classList.remove("hidden");
   },
 
   hideOptimizations: function () {
-    $("#jit-optimizations-view").classList.add("hidden");
+    this.optimizationsElement.classList.add("hidden");
   },
 
   _onFocus: function (_, treeItem) {
-    if (PerformanceController.getCurrentRecording().getConfiguration().withJITOptimizations) {
-      OptimizationsListView.setCurrentFrame(this.threadNode, treeItem.frame);
-      OptimizationsListView.render();
+    let recording = PerformanceController.getCurrentRecording();
+    let frameNode = treeItem.frame;
+
+    if (!frameNode) {
+      console.warn("No frame found!");
+      return;
     }
 
+    let frameData = frameNode.getInfo();
+    let optimizationSites = frameNode.hasOptimizations()
+                            ? frameNode.getOptimizations().optimizationSites
+                            : [];
+
+    let optimizations = Optimizations({
+      frameData,
+      optimizationSites,
+      onViewSourceInDebugger: (url, line) => {
+        gToolbox.viewSourceInDebugger(url, line).then(success => {
+          if (success) {
+            this.emit(EVENTS.SOURCE_SHOWN_IN_JS_DEBUGGER);
+          } else {
+            this.emit(EVENTS.SOURCE_NOT_FOUND_IN_JS_DEBUGGER);
+          }
+        });
+      }
+    });
+
+    ReactDOM.render(optimizations, this.optimizationsElement);
+
     this.emit("focus", treeItem);
   },
 
   /**
    * Fired on the "link" event for the call tree in this container.
    */
   _onLink: function (_, treeItem) {
     let { url, line } = treeItem.frame.getInfo();
deleted file mode 100644
--- a/devtools/client/performance/views/optimizations-list.js
+++ /dev/null
@@ -1,396 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-/* import-globals-from ../performance-controller.js */
-/* import-globals-from ../performance-view.js */
-/* globals document */
-"use strict";
-
-const URL_LABEL_TOOLTIP = L10N.getStr("table.url.tooltiptext");
-const OPTIMIZATION_FAILURE = L10N.getStr("jit.optimizationFailure");
-const JIT_SAMPLES = L10N.getStr("jit.samples");
-const JIT_EMPTY_TEXT = L10N.getStr("jit.empty");
-const PROPNAME_MAX_LENGTH = 4;
-
-/**
- * View for rendering a list of all optmizations found in a frame.
- * The terminology and types used here can be referenced:
- * @see devtools/client/performance/modules/logic/jit.js
- */
-
-var OptimizationsListView = {
-
-  _currentFrame: null,
-
-  /**
-   * Initialization function called when the tool starts up.
-   */
-  initialize: function () {
-    this.reset = this.reset.bind(this);
-    this._onThemeChanged = this._onThemeChanged.bind(this);
-
-    this.el = $("#jit-optimizations-view");
-    this.$headerName = $("#jit-optimizations-header .header-function-name");
-    this.$headerFile = $("#jit-optimizations-header .header-file");
-    this.$headerLine = $("#jit-optimizations-header .header-line");
-
-    this.tree = new TreeWidget($("#jit-optimizations-raw-view"), {
-      sorted: false,
-      emptyText: JIT_EMPTY_TEXT
-    });
-    this.graph = new OptimizationsGraph($("#optimizations-graph"));
-    this.graph.setTheme(PerformanceController.getTheme());
-
-    // Start the tree by resetting.
-    this.reset();
-
-    PerformanceController.on(EVENTS.THEME_CHANGED, this._onThemeChanged);
-  },
-
-  /**
-   * Destruction function called when the tool cleans up.
-   */
-  destroy: function () {
-    PerformanceController.off(EVENTS.THEME_CHANGED, this._onThemeChanged);
-    this.tree = null;
-    this.$headerName = this.$headerFile = this.$headerLine = this.el = null;
-  },
-
-  /**
-   * Takes a FrameNode, with corresponding optimization data to be displayed
-   * in the view.
-   *
-   * @param {FrameNode} frameNode
-   */
-  setCurrentFrame: function (threadNode, frameNode) {
-    if (threadNode !== this.getCurrentThread()) {
-      this._currentThread = threadNode;
-    }
-    if (frameNode !== this.getCurrentFrame()) {
-      this._currentFrame = frameNode;
-    }
-  },
-
-  /**
-   * Returns the current frame node for this view.
-   *
-   * @return {?FrameNode}
-   */
-  getCurrentFrame: function () {
-    return this._currentFrame;
-  },
-
-  /**
-   * Returns the current thread node for this view.
-   *
-   * @return {?ThreadNode}
-   */
-  getCurrentThread: function () {
-    return this._currentThread;
-  },
-
-  /**
-   * Clears out data in the tree, sets to an empty state,
-   * and removes current frame.
-   */
-  reset: function () {
-    this.setCurrentFrame(null, null);
-    this.clear();
-    this.el.classList.add("empty");
-    this.emit(EVENTS.OPTIMIZATIONS_RESET);
-    this.emit(EVENTS.OPTIMIZATIONS_RENDERED, this.getCurrentFrame());
-  },
-
-  /**
-   * Clears out data in the tree.
-   */
-  clear: function () {
-    this.tree.clear();
-  },
-
-  /**
-   * Takes a JITOptimizations object and builds a view containing all attempted
-   * optimizations for this frame. This view is very verbose and meant for those
-   * who understand JIT compilers.
-   */
-  render: function () {
-    let frameNode = this.getCurrentFrame();
-
-    if (!frameNode) {
-      this.reset();
-      return;
-    }
-
-    let view = this.tree;
-
-    // Set header information, even if the frame node
-    // does not have any optimization data
-    let frameData = frameNode.getInfo();
-    this._setHeaders(frameData);
-    this.clear();
-
-    // If this frame node does not have optimizations, or if its a meta node in the
-    // case of only showing content, reset the view.
-    if (!frameNode.hasOptimizations() || frameNode.isMetaCategory) {
-      this.reset();
-      return;
-    }
-    this.el.classList.remove("empty");
-
-    // An array of sorted OptimizationSites.
-    let sites = frameNode.getOptimizations().optimizationSites;
-
-    for (let site of sites) {
-      this._renderSite(view, site, frameData);
-    }
-
-    this._renderTierGraph();
-
-    this.emit(EVENTS.OPTIMIZATIONS_RENDERED, this.getCurrentFrame());
-  },
-
-  /**
-   * Renders the optimization tier graph over time.
-   */
-  _renderTierGraph: function () {
-    this.graph.render(this.getCurrentThread(), this.getCurrentFrame());
-  },
-
-  /**
-   * Creates an entry in the tree widget for an optimization site.
-   */
-  _renderSite: function (view, site, frameData) {
-    let { id, samples, data } = site;
-    let { types, attempts } = data;
-    let siteNode = this._createSiteNode(frameData, site);
-
-    // Cast `id` to a string so TreeWidget doesn't think it does not exist
-    id = id + "";
-
-    view.add([{ id: id, node: siteNode }]);
-
-    // Add types -- Ion types are the parent, with
-    // the observed types as children.
-    view.add([id, { id: `${id}-types`, label: `Types (${types.length})` }]);
-    this._renderIonType(view, site);
-
-    // Add attempts
-    view.add([id, { id: `${id}-attempts`, label: `Attempts (${attempts.length})` }]);
-    for (let i = attempts.length - 1; i >= 0; i--) {
-      let node = this._createAttemptNode(attempts[i]);
-      view.add([id, `${id}-attempts`, { node }]);
-    }
-  },
-
-  /**
-   * Renders all Ion types from an optimization site, with its children
-   * ObservedTypes.
-   */
-  _renderIonType: function (view, site) {
-    let { id, data: { types }} = site;
-    // Cast `id` to a string so TreeWidget doesn't think it does not exist
-    id = id + "";
-    for (let i = 0; i < types.length; i++) {
-      let ionType = types[i];
-
-      let ionNode = this._createIonNode(ionType);
-      view.add([id, `${id}-types`, { id: `${id}-types-${i}`, node: ionNode }]);
-      for (let observedType of (ionType.typeset || [])) {
-        let node = this._createObservedTypeNode(observedType);
-        view.add([id, `${id}-types`, `${id}-types-${i}`, { node }]);
-      }
-    }
-  },
-
-  /**
-   * Creates an element for insertion in the raw view for an OptimizationSite.
-   */
-  _createSiteNode: function (frameData, site) {
-    let node = document.createElement("span");
-    let desc = document.createElement("span");
-    let line = document.createElement("span");
-    let column = document.createElement("span");
-    let urlNode = this._createDebuggerLinkNode(frameData.url, site.data.line);
-
-    let attempts = site.getAttempts();
-    let lastStrategy = attempts[attempts.length - 1].strategy;
-
-    let propString = "";
-    if (site.data.propertyName) {
-      if (site.data.propertyName.length > PROPNAME_MAX_LENGTH) {
-        propString = ` (.${site.data.propertyName.substr(0, PROPNAME_MAX_LENGTH)}…)`;
-        desc.setAttribute("tooltiptext", site.data.propertyName);
-      } else {
-        propString = ` (.${site.data.propertyName})`;
-      }
-    }
-
-    if (!site.hasSuccessfulOutcome()) {
-      let icon = document.createElement("span");
-      icon.setAttribute("tooltiptext", OPTIMIZATION_FAILURE);
-      icon.setAttribute("severity", "warning");
-      icon.className = "opt-icon";
-      node.appendChild(icon);
-    }
-
-    let sampleString = PluralForm.get(site.samples, JIT_SAMPLES).replace("#1", site.samples);
-    desc.textContent = `${lastStrategy}${propString} – (${sampleString})`;
-    line.textContent = site.data.line;
-    line.className = "opt-line";
-    column.textContent = site.data.column;
-    column.className = "opt-line";
-    node.appendChild(desc);
-    node.appendChild(urlNode);
-    node.appendChild(line);
-    node.appendChild(column);
-
-    return node;
-  },
-
-  /**
-   * Creates an element for insertion in the raw view for an IonType.
-   *
-   * @see devtools/client/performance/modules/logic/jit.js
-   * @param {IonType} ionType
-   * @return {Element}
-   */
-  _createIonNode: function (ionType) {
-    let node = document.createElement("span");
-    node.textContent = `${ionType.site} : ${ionType.mirType}`;
-    node.className = "opt-ion-type";
-    return node;
-  },
-
-  /**
-   * Creates an element for insertion in the raw view for an ObservedType.
-   *
-   * @see devtools/client/performance/modules/logic/jit.js
-   * @param {ObservedType} type
-   * @return {Element}
-   */
-  _createObservedTypeNode: function (type) {
-    let node = document.createElement("span");
-    let typeNode = document.createElement("span");
-
-    typeNode.textContent = `${type.keyedBy}` + (type.name ? ` → ${type.name}` : "");
-    typeNode.className = "opt-type";
-    node.appendChild(typeNode);
-
-    // If we have a type and a location, try to make a
-    // link to the debugger
-    if (type.location && type.line) {
-      let urlNode = this._createDebuggerLinkNode(type.location, type.line);
-      node.appendChild(urlNode);
-    }
-    // Otherwise if we just have a location, it could just
-    // be a memory location
-    else if (type.location) {
-      let locNode = document.createElement("span");
-      locNode.textContent = `@${type.location}`;
-      locNode.className = "opt-url";
-      node.appendChild(locNode);
-    }
-
-    if (type.line) {
-      let line = document.createElement("span");
-      line.textContent = type.line;
-      line.className = "opt-line";
-      node.appendChild(line);
-    }
-    return node;
-  },
-
-  /**
-   * Creates an element for insertion in the raw view for an OptimizationAttempt.
-   *
-   * @see devtools/client/performance/modules/logic/jit.js
-   * @param {OptimizationAttempt} attempt
-   * @return {Element}
-   */
-  _createAttemptNode: function (attempt) {
-    let node = document.createElement("span");
-    let strategyNode = document.createElement("span");
-    let outcomeNode = document.createElement("span");
-
-    strategyNode.textContent = attempt.strategy;
-    strategyNode.className = "opt-strategy";
-    outcomeNode.textContent = attempt.outcome;
-    outcomeNode.className = "opt-outcome";
-    outcomeNode.setAttribute("outcome",
-      JITOptimizations.isSuccessfulOutcome(attempt.outcome) ? "success" : "failure");
-
-    node.appendChild(strategyNode);
-    node.appendChild(outcomeNode);
-    node.className = "opt-attempt";
-    return node;
-  },
-
-  /**
-   * Creates a new element, linking it up to the debugger upon clicking.
-   * Can also optionally pass in an element to modify it rather than
-   * creating a new one.
-   *
-   * @param {String} url
-   * @param {Number} line
-   * @param {?Element} el
-   * @return {Element}
-   */
-  _createDebuggerLinkNode: function (url, line, el) {
-    let node = el || document.createElement("span");
-    node.className = "opt-url";
-    let fileName;
-
-    if (this._isLinkableURL(url)) {
-      fileName = url.slice(url.lastIndexOf("/") + 1);
-      node.classList.add("debugger-link");
-      node.setAttribute("tooltiptext", URL_LABEL_TOOLTIP + " → " + url);
-      node.addEventListener("click", () => gToolbox.viewSourceInDebugger(url, line));
-    }
-    fileName = fileName || url || "";
-    node.textContent = fileName ? `@${fileName}` : "";
-    return node;
-  },
-
-  /**
-   * Updates the headers with the current frame's data.
-   */
-  _setHeaders: function (frameData) {
-    let isMeta = frameData.isMetaCategory;
-    let name = isMeta ? frameData.categoryData.label : frameData.functionName;
-    let url = isMeta ? "" : frameData.url;
-    let line = isMeta ? "" : frameData.line;
-
-    this.$headerName.textContent = name;
-    this.$headerLine.textContent = line;
-    this._createDebuggerLinkNode(url, line, this.$headerFile);
-
-    this.$headerLine.hidden = isMeta;
-    this.$headerFile.hidden = isMeta;
-  },
-
-  /**
-   * Takes a string and returns a boolean indicating whether or not
-   * this is a valid url for linking to the debugger.
-   *
-   * @param {String} url
-   * @return {Boolean}
-   */
-  _isLinkableURL: function (url) {
-    return url && url.indexOf &&
-       (url.indexOf("http") === 0 ||
-        url.indexOf("resource://") === 0 ||
-        url.indexOf("file://") === 0);
-  },
-
-  /**
-   * Called when `devtools.theme` changes.
-   */
-  _onThemeChanged: function (_, theme) {
-    this.graph.setTheme(theme);
-    this.graph.refresh({ force: true });
-  },
-
-  toString: () => "[object OptimizationsListView]"
-};
-
-EventEmitter.decorate(OptimizationsListView);
--- a/devtools/client/shared/components/frame.js
+++ b/devtools/client/shared/components/frame.js
@@ -21,17 +21,17 @@ const Frame = module.exports = createCla
   },
 
   propTypes: {
     // SavedFrame, or an object containing all the required properties.
     frame: PropTypes.shape({
       functionDisplayName: PropTypes.string,
       source: PropTypes.string.isRequired,
       line: PropTypes.number.isRequired,
-      column: PropTypes.number.isRequired,
+      column: PropTypes.number,
     }).isRequired,
     // Clicking on the frame link -- probably should link to the debugger.
     onClick: PropTypes.func.isRequired,
     // Option to display a function name before the source link.
     showFunctionName: PropTypes.bool,
     // Option to display a host name after the source link.
     showHost: PropTypes.bool,
   },
@@ -41,17 +41,17 @@ const Frame = module.exports = createCla
 
     const { short, long, host } = getSourceNames(frame.source, UNKNOWN_SOURCE_STRING);
 
     let tooltip = `${long}:${frame.line}`;
     if (frame.column) {
       tooltip += `:${frame.column}`;
     }
 
-    let sourceString = `${frame.source}:${frame.line}`;
+    let sourceString = `${long}:${frame.line}`;
     if (frame.column) {
       sourceString += `:${frame.column}`;
     }
 
     let onClickTooltipString = L10N.getFormatStr("frame.viewsourceindebugger", sourceString);
 
     let fields = [
       dom.a({
--- a/devtools/client/shared/components/test/mochitest/chrome.ini
+++ b/devtools/client/shared/components/test/mochitest/chrome.ini
@@ -1,12 +1,14 @@
 [DEFAULT]
 support-files =
   head.js
 
+[test_frame_01.html]
+[test_frame_02.html]
 [test_tree_01.html]
 [test_tree_02.html]
 [test_tree_03.html]
 [test_tree_04.html]
 [test_tree_05.html]
 [test_tree_06.html]
 [test_tree_07.html]
 [test_tree_08.html]
--- a/devtools/client/shared/components/test/mochitest/head.js
+++ b/devtools/client/shared/components/test/mochitest/head.js
@@ -18,16 +18,69 @@ var DevToolsUtils = require("devtools/sh
 var { TargetFactory } = require("devtools/client/framework/target");
 var { Toolbox } = require("devtools/client/framework/toolbox");
 
 DevToolsUtils.testing = true;
 var { require: browserRequire } = BrowserLoader("resource://devtools/client/shared/", this);
 
 var EXAMPLE_URL = "http://example.com/browser/browser/devtools/shared/test/";
 
+function forceRender(comp) {
+  return setState(comp, {})
+    .then(() => setState(comp, {}));
+}
+
+// All tests are asynchronous.
+SimpleTest.waitForExplicitFinish();
+
+function onNextAnimationFrame(fn) {
+  return () =>
+    requestAnimationFrame(() =>
+      requestAnimationFrame(fn));
+}
+
+function setState(component, newState) {
+  var deferred = promise.defer();
+  component.setState(newState, onNextAnimationFrame(deferred.resolve));
+  return deferred.promise;
+}
+
+function setProps(component, newState) {
+  var deferred = promise.defer();
+  component.setProps(newState, onNextAnimationFrame(deferred.resolve));
+  return deferred.promise;
+}
+
+function dumpn(msg) {
+  dump(`SHARED-COMPONENTS-TEST: ${msg}\n`);
+}
+
+/**
+ * Tree
+ */
+
+var TEST_TREE_INTERFACE = {
+  getParent: x => TEST_TREE.parent[x],
+  getChildren: x => TEST_TREE.children[x],
+  renderItem: (x, depth, focused, arrow) => "-".repeat(depth) + x + ":" + focused + "\n",
+  getRoots: () => ["A", "M"],
+  getKey: x => "key-" + x,
+  itemHeight: 1,
+  onExpand: x => TEST_TREE.expanded.add(x),
+  onCollapse: x => TEST_TREE.expanded.delete(x),
+  isExpanded: x => TEST_TREE.expanded.has(x),
+};
+
+function isRenderedTree(actual, expectedDescription, msg) {
+  const expected = expectedDescription.map(x => x + "\n").join("");
+  dumpn(`Expected tree:\n${expected}`);
+  dumpn(`Actual tree:\n${actual}`);
+  is(actual, expected, msg);
+}
+
 // Encoding of the following tree/forest:
 //
 // A
 // |-- B
 // |   |-- E
 // |   |   |-- K
 // |   |   `-- L
 // |   |-- F
@@ -73,56 +126,31 @@ var TEST_TREE = {
     L: "E",
     M: null,
     N: "M",
     O: "N"
   },
   expanded: new Set(),
 };
 
-var TEST_TREE_INTERFACE = {
-  getParent: x => TEST_TREE.parent[x],
-  getChildren: x => TEST_TREE.children[x],
-  renderItem: (x, depth, focused, arrow) => "-".repeat(depth) + x + ":" + focused + "\n",
-  getRoots: () => ["A", "M"],
-  getKey: x => "key-" + x,
-  itemHeight: 1,
-  onExpand: x => TEST_TREE.expanded.add(x),
-  onCollapse: x => TEST_TREE.expanded.delete(x),
-  isExpanded: x => TEST_TREE.expanded.has(x),
-};
-
-function forceRender(tree) {
-  return setState(tree, {})
-    .then(() => setState(tree, {}));
+/**
+ * Frame
+ */
+function checkFrameString (component, file, line, column) {
+  let el = component.getDOMNode();
+  is(el.querySelector(".frame-link-filename").textContent, file);
+  is(+el.querySelector(".frame-link-line").textContent, +line);
+  if (column != null) {
+    is(+el.querySelector(".frame-link-column").textContent, +column);
+    is(el.querySelectorAll(".frame-link-colon").length, 2);
+  } else {
+    is(el.querySelector(".frame-link-column"), null,
+      "Should not render column when none specified");
+    is(el.querySelectorAll(".frame-link-colon").length, 1,
+      "Should only render one colon when no column specified");
+  }
 }
 
-// All tests are asynchronous.
-SimpleTest.waitForExplicitFinish();
-
-function onNextAnimationFrame(fn) {
-  return () =>
-    requestAnimationFrame(() =>
-      requestAnimationFrame(fn));
-}
-
-function setState(component, newState) {
-  var deferred = promise.defer();
-  component.setState(newState, onNextAnimationFrame(deferred.resolve));
-  return deferred.promise;
+function checkFrameTooltips (component, mainTooltip, linkTooltip) {
+  let el = component.getDOMNode();
+  is(el.getAttribute("title"), mainTooltip);
+  is(el.querySelector("a.frame-link-filename").getAttribute("title"), linkTooltip);
 }
-
-function setProps(component, newState) {
-  var deferred = promise.defer();
-  component.setProps(newState, onNextAnimationFrame(deferred.resolve));
-  return deferred.promise;
-}
-
-function dumpn(msg) {
-  dump(`MEMORY-TEST: ${msg}\n`);
-}
-
-function isRenderedTree(actual, expectedDescription, msg) {
-  const expected = expectedDescription.map(x => x + "\n").join("");
-  dumpn(`Expected tree:\n${expected}`);
-  dumpn(`Actual tree:\n${actual}`);
-  is(actual, expected, msg);
-}
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_frame_01.html
@@ -0,0 +1,89 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test the formatting of the file name, line and columns are correct in frame components,
+with optional columns, unknown and non-URL sources.
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Frame component test</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+  try {
+    let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+    let React = browserRequire("devtools/client/shared/vendor/react");
+    let Frame = React.createFactory(browserRequire("devtools/client/shared/components/frame"));
+    ok(Frame, "Should get Frame");
+    let frame;
+
+    // Check when there's a column
+    frame = ReactDOM.render(Frame({
+      frame: {
+        source: "http://myfile.com/mahscripts.js",
+        line: 55,
+        column: 10,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameString(frame, "mahscripts.js", 55, 10);
+
+    // Check when there's no column
+    frame = ReactDOM.render(Frame({
+      frame: {
+        source: "http://myfile.com/mahscripts.js",
+        line: 55,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameString(frame, "mahscripts.js", 55);
+
+    // Check when column === 0
+    frame = ReactDOM.render(Frame({
+      frame: {
+        source: "http://myfile.com/mahscripts.js",
+        line: 55,
+        column: 0,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameString(frame, "mahscripts.js", 55, 0);
+
+    // Check when there's no parseable URL source
+    frame = ReactDOM.render(Frame({
+      frame: {
+        source: "self-hosted",
+        line: 1,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameString(frame, "self-hosted",1);
+
+    // Check when there's no source
+    frame = ReactDOM.render(Frame({
+      frame: {
+        line: 1,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameString(frame, "(unknown)",1);
+  } catch(e) {
+    ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+  } finally {
+    SimpleTest.finish();
+  }
+});
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/test/mochitest/test_frame_02.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Test the formatting of the tooltips in the frame component.
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Frame component test</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+</head>
+<body>
+<pre id="test">
+<script src="head.js" type="application/javascript;version=1.8"></script>
+<script type="application/javascript;version=1.8">
+window.onload = Task.async(function* () {
+  try {
+    let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
+    let React = browserRequire("devtools/client/shared/vendor/react");
+    let Frame = React.createFactory(browserRequire("devtools/client/shared/components/frame"));
+    ok(Frame, "Should get Frame");
+    let frame;
+
+    // Check when there's a column
+    frame = ReactDOM.render(Frame({
+      frame: {
+        source: "http://myfile.com/mahscripts.js",
+        line: 55,
+        column: 10,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameTooltips(frame,
+      "http://myfile.com/mahscripts.js:55:10",
+      "View source in Debugger → http://myfile.com/mahscripts.js:55:10");
+
+    // Check when there's no column
+    frame = ReactDOM.render(Frame({
+      frame: {
+        source: "http://myfile.com/mahscripts.js",
+        line: 55,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameTooltips(frame,
+      "http://myfile.com/mahscripts.js:55",
+      "View source in Debugger → http://myfile.com/mahscripts.js:55");
+
+    // Check when there's no parseable URL source
+    frame = ReactDOM.render(Frame({
+      frame: {
+        source: "self-hosted",
+        line: 1,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameTooltips(frame,
+      "self-hosted:1",
+      "View source in Debugger → self-hosted:1");
+
+    // Check when there's no source
+    frame = ReactDOM.render(Frame({
+      frame: {
+        line: 1,
+      },
+      onClick: ()=>{},
+    }), window.document.body);
+    yield forceRender(frame);
+    checkFrameTooltips(frame,
+      "(unknown):1",
+      "View source in Debugger → (unknown):1");
+
+  } catch(e) {
+    ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
+  } finally {
+    SimpleTest.finish();
+  }
+});
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/components-frame.css
@@ -0,0 +1,46 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * Frame Component
+ * Styles for React component at `devtools/client/shared/components/frame.js`
+ */
+
+.frame-link {
+  margin-left: 7px;
+}
+
+.focused .frame-link-filename,
+.focused .frame-link-column,
+.focused .frame-link-line,
+.focused .frame-link-host,
+.focused .frame-link-colon {
+  color: var(--theme-selection-color);
+}
+
+.frame-link .frame-link-filename {
+  color: var(--theme-highlight-blue);
+  cursor: pointer;
+}
+
+.frame-link .frame-link-filename:hover {
+  text-decoration: underline;
+}
+
+.frame-link .frame-link-host {
+  margin-inline-start: 5px;
+  font-size: 90%;
+  color: var(--theme-content-color2);
+}
+
+.frame-link .frame-link-function-display-name {
+  margin-inline-end: 5px;
+}
+
+.frame-link .frame-link-column,
+.frame-link .frame-link-line,
+.frame-link .frame-link-colon {
+  color: var(--theme-highlight-orange);
+}
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/jit-optimizations.css
@@ -0,0 +1,143 @@
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/**
+ * JIT View
+ */
+
+#jit-optimizations-view {
+  width: 350px;
+  overflow-x: auto;
+  min-width: 200px;
+  white-space: nowrap;
+  --jit-tree-row-height: 14;
+  --jit-tree-header-height: 16;
+}
+
+#jit-optimizations-view > div {
+  flex: 1;
+}
+
+#jit-optimizations-view div {
+  display: block;
+}
+
+.tree {
+  /**
+   * Flexing to fill out remaining vertical space.
+   */
+  flex: 1;
+  overflow-y: auto;
+  height: 100%;
+  background-color: var(--theme-body-background);
+}
+
+.optimization-header {
+  height: var(--jit-tree-header-height);
+  padding: 2px 5px;
+  background-color: var(--theme-tab-toolbar-background);
+}
+
+#jit-optimizations-view .header-title {
+  font-weight: bold;
+  padding-right: 7px;
+}
+
+.tree-node {
+  height: var(--jit-tree-row-height);
+  clear: both;
+}
+
+.tree-node button {
+  display: none;
+}
+
+#jit-optimizations-view .optimization-tree-item {
+  display: flex;
+}
+
+#jit-optimizations-view .arrow,
+#jit-optimizations-view .optimization-site,
+#jit-optimizations-view .optimization-attempts,
+#jit-optimizations-view .optimization-attempt,
+#jit-optimizations-view .optimization-types,
+#jit-optimizations-view .optimization-ion-type,
+#jit-optimizations-view .optimization-observed-type {
+  float: left;
+}
+
+#jit-optimizations-view .optimization-outcome.success {
+  color: var(--theme-highlight-green);
+}
+#jit-optimizations-view .optimization-outcome.failure {
+  color: var(--theme-highlight-red);
+}
+
+.opt-icon::before {
+  content: "";
+  background-image: url(chrome://devtools/skin/images/webconsole.svg);
+  background-repeat: no-repeat;
+  background-size: 72px 60px;
+  /* show grey "i" bubble by default */
+  background-position: -36px -36px;
+  width: 10px;
+  height: 10px;
+  display: inline-block;
+
+  max-height: 12px;
+}
+
+#jit-optimizations-view .opt-icon {
+  float: left;
+}
+
+#jit-optimizations-view .opt-icon::before {
+  margin: 1px 6px 0 0;
+}
+
+.theme-light .opt-icon::before {
+  background-image: url(chrome://devtools/skin/images/webconsole.svg#light-icons);
+}
+.opt-icon.warning::before {
+  background-position: -24px -24px;
+}
+
+/* Frame Component */
+.focused .frame-link-filename,
+.focused .frame-link-column,
+.focused .frame-link-line,
+.focused .frame-link-host,
+.focused .frame-link-colon {
+  color: var(--theme-selection-color);
+}
+
+.frame-link {
+  margin-left: 7px;
+}
+
+.frame-link-filename {
+  color: var(--theme-highlight-blue);
+  cursor: pointer;
+}
+
+.frame-link-filename:hover {
+  text-decoration: underline;
+}
+
+.frame-link-column,
+.frame-link-line,
+.frame-link-colon {
+  color: var(--theme-highlight-orange);
+}
+
+.frame-link-host {
+  margin-inline-start: 5px;
+  font-size: 90%;
+  color: var(--theme-content-color2);
+}
+
+.frame-link-function-display-name {
+  margin-inline-end: 5px;
+}
--- a/devtools/client/themes/memory.css
+++ b/devtools/client/themes/memory.css
@@ -460,48 +460,15 @@ html, body, #app, #memory-tool {
 .separator,
 .not-available,
 .heap-tree-item-address {
   opacity: .5;
   margin-left: .5em;
   margin-right: .5em;
 }
 
-.focused .frame-link-filename,
-.focused .frame-link-column,
-.focused .frame-link-line,
-.focused .frame-link-host,
-.focused .frame-link-colon {
-  color: var(--theme-selection-color);
-}
-
-.frame-link-filename {
-  color: var(--theme-highlight-blue);
-  cursor: pointer;
-}
-
-.frame-link-filename:hover {
-  text-decoration: underline;
-}
-
-.frame-link-column,
-.frame-link-line,
-.frame-link-colon {
-  color: var(--theme-highlight-orange);
-}
-
-.frame-link-host {
-  margin-inline-start: 5px;
-  font-size: 90%;
-  color: var(--theme-content-color2);
-}
-
-.frame-link-function-display-name {
-  margin-inline-end: 5px;
-}
-
 .no-allocation-stacks {
   border-color: var(--theme-splitter-color);
   border-style: solid;
   border-width: 0px 0px 1px 0px;
   text-align: center;
   padding: 5px;
 }
--- a/devtools/client/themes/performance.css
+++ b/devtools/client/themes/performance.css
@@ -267,16 +267,18 @@
 
 .call-tree-header {
   background-color: var(--theme-tab-toolbar-background);
 }
 
 .call-tree-item .call-tree-cell,
 .call-tree-item .call-tree-cell[type=function] description {
   -moz-user-select: text;
+  /* so that optimizations view doesn't break the lines in call tree */
+  white-space: nowrap;
 }
 
 .call-tree-item .call-tree-cell::-moz-selection,
 .call-tree-item .call-tree-cell[type=function] description::-moz-selection {
   background-color: var(--theme-highlight-orange);
 }
 
 .call-tree-item:last-child {
@@ -605,163 +607,16 @@ menuitem.marker-color-graphs-red:before,
 }
 menuitem.marker-color-graphs-grey:before,
 .marker-color-graphs-grey{
   background-color: var(--theme-graphs-grey);
   border-color: var(--theme-graphs-grey);
 }
 
 /**
- * JIT View
- */
-
-#jit-optimizations-view {
-  width: 350px;
-  overflow-x: hidden;
-  overflow-y: auto;
-  min-width: 200px;
-}
-
-#optimizations-graph {
-  height: 30px;
-}
-
-#jit-optimizations-view.empty #optimizations-graph {
-  display: none !important;
-}
-
-/* override default styles for tree widget */
-#jit-optimizations-view .tree-widget-empty-text {
-  font-size: inherit;
-  padding: 0px;
-  margin: 8px;
-}
-
-#jit-optimizations-view:not(.empty) .tree-widget-empty-text {
-  display: none;
-}
-
-#jit-optimizations-toolbar {
-  height: 18px;
-  min-height: 0px; /* override .devtools-toolbar min-height */
-}
-
-.jit-optimizations-title {
-  margin: 0px 4px;
-  font-weight: 600;
-}
-
-#jit-optimizations-raw-view {
-  font-size: 90%;
-}
-
-/* override default .tree-widget-item line-height */
-#jit-optimizations-raw-view .tree-widget-item {
-  line-height: 20px !important;
-  display: block;
-  overflow: hidden;
-}
-
-#jit-optimizations-raw-view .tree-widget-item[level="1"] {
-  font-weight: 600;
-}
-
-#jit-optimizations-view .opt-outcome::before {
-  content: "→";
-  margin: 4px 0px;
-  color: var(--theme-body-color);
-}
-#jit-optimizations-view .theme-selected .opt-outcome::before {
-  color: var(--theme-selection-color);
-}
-
-#jit-optimizations-view .tree-widget-item:not(.theme-selected) .opt-outcome[outcome=success] {
-  color: var(--theme-highlight-green);
-}
-#jit-optimizations-view .tree-widget-item:not(.theme-selected) .opt-outcome[outcome=failure] {
-  color: var(--theme-highlight-red);
-}
-#jit-optimizations-view .tree-widget-container {
-  -moz-margin-end: 0px;
-}
-#jit-optimizations-view .tree-widget-container > li,
-#jit-optimizations-view .tree-widget-children > li {
-  overflow: hidden;
-}
-
-.opt-line::before {
-  content: ":";
-  color: var(--theme-highlight-orange);
-}
-.theme-selected .opt-line::before {
-  color: var(--theme-selection-color);
-}
-.opt-line.header-line::before {
-  color: var(--theme-body-color);
-}
-#jit-optimizations-view.empty .opt-line.header-line::before {
-  display: none;
-}
-
-.opt-url {
-  -moz-margin-start: 4px !important;
-}
-.opt-url:hover {
-  text-decoration: underline;
-}
-.opt-url.debugger-link {
-  cursor: pointer;
-}
-
-.opt-icon::before {
-  content: "";
-  background-image: url(chrome://devtools/skin/images/webconsole.svg);
-  background-repeat: no-repeat;
-  background-size: 72px 60px;
-  /* show grey "i" bubble by default */
-  background-position: -36px -36px;
-  width: 12px;
-  height: 12px;
-  display: inline-block;
-
-  max-height: 12px;
-}
-
-#jit-optimizations-view .opt-icon::before {
-  margin: 5px 6px 0 0;
-}
-description.opt-icon {
-  margin: 0px 0px 0px 0px;
-}
-description.opt-icon::before {
-  margin: 1px 4px 0px 0px;
-}
-.theme-light .opt-icon::before {
-  background-image: url(chrome://devtools/skin/images/webconsole.svg#light-icons);
-}
-.opt-icon[severity=warning]::before {
-  background-position: -24px -24px;
-}
-
-ul.frames-list {
-  list-style-type: none;
-  padding: 0px;
-  margin: 0px;
-}
-
-ul.frames-list li {
-  cursor: pointer;
-}
-
-ul.frames-list li.selected {
-  background-color: var(--theme-selection-background);
-  color: var(--theme-selection-color);
-}
-
-/**
  * Configurable Options
  *
  * Elements can be tagged with a class and visibility is controlled via a
  * preference being applied or removed.
  */
 
 /**
  * devtools.performance.ui.experimental
@@ -782,8 +637,37 @@ menuitem.experimental-option::before {
 .theme-light menuitem.experimental-option::before {
   background-image: url(chrome://devtools/skin/images/webconsole.svg#light-icons);
 }
 
 #performance-options-menupopup:not(.experimental-enabled) .experimental-option,
 #performance-options-menupopup:not(.experimental-enabled) .experimental-option::before {
   display: none;
 }
+
+.opt-icon::before {
+  content: "";
+  background-image: url(chrome://devtools/skin/images/webconsole.svg);
+  background-repeat: no-repeat;
+  background-size: 72px 60px;
+  /* show grey "i" bubble by default */
+  background-position: -36px -36px;
+  width: 10px;
+  height: 10px;
+  display: inline-block;
+
+  max-height: 12px;
+}
+
+.theme-light .opt-icon::before {
+  background-image: url(chrome://devtools/skin/images/webconsole.svg#light-icons);
+}
+.opt-icon.warning::before {
+  background-position: -24px -24px;
+}
+
+/* for call tree */
+description.opt-icon {
+  margin: 0px 0px 0px 0px;
+}
+description.opt-icon::before {
+  margin: 1px 4px 0px 0px;
+}
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -192,18 +192,17 @@ const PREF_INPUT_HISTORY_COUNT = "devtoo
  *
  * The WebConsoleFrame is responsible for the actual Web Console UI
  * implementation.
  *
  * @constructor
  * @param object webConsoleOwner
  *        The WebConsole owner object.
  */
-function WebConsoleFrame(webConsoleOwner)
-{
+function WebConsoleFrame(webConsoleOwner) {
   this.owner = webConsoleOwner;
   this.hudId = this.owner.hudId;
   this.window = this.owner.iframeWindow;
 
   this._repeatNodes = {};
   this._outputQueue = [];
   this._itemDestroyQueue = [];
   this._pruneCategoriesQueue = {};
@@ -394,18 +393,17 @@ WebConsoleFrame.prototype = {
       "NetworkMonitor.saveRequestAndResponseBodies": newValue,
     };
 
     // Make sure the web console client connection is established first.
     this.webConsoleClient.setPreferences(toSet, response => {
       if (!response.error) {
         this._saveRequestAndResponseBodies = newValue;
         deferred.resolve(response);
-      }
-      else {
+      } else {
         deferred.reject(response.error);
       }
     });
 
     return deferred.promise;
   },
 
   /**
@@ -420,18 +418,17 @@ WebConsoleFrame.prototype = {
     return this.owner._browserConsole || Services.prefs.getBoolPref(PREF_PERSISTLOG);
   },
 
   /**
    * Initialize the WebConsoleFrame instance.
    * @return object
    *         A promise object that resolves once the frame is ready to use.
    */
-  init: function()
-  {
+  init: function() {
     this._initUI();
     let connectionInited = this._initConnection();
 
     // Don't reject if the history fails to load for some reason.
     // This would be fine, the panel will just start with empty history.
     let allReady = this.jsterm.historyLoaded.catch(() => {}).then(() => {
       return connectionInited;
     });
@@ -451,18 +448,17 @@ WebConsoleFrame.prototype = {
   /**
    * Connect to the server using the remote debugging protocol.
    *
    * @private
    * @return object
    *         A promise object that is resolved/reject based on the connection
    *         result.
    */
-  _initConnection: function WCF__initConnection()
-  {
+  _initConnection: function WCF__initConnection() {
     if (this._initDefer) {
       return this._initDefer.promise;
     }
 
     this._initDefer = promise.defer();
     this.proxy = new WebConsoleConnectionProxy(this, this.owner.target);
 
     this.proxy.connect().then(() => { // on success
@@ -476,18 +472,17 @@ WebConsoleFrame.prototype = {
 
     return this._initDefer.promise;
   },
 
   /**
    * Find the Web Console UI elements and setup event listeners as needed.
    * @private
    */
-  _initUI: function WCF__initUI()
-  {
+  _initUI: function WCF__initUI() {
     this.document = this.window.document;
     this.rootElement = this.document.documentElement;
 
     this._initDefaultFilterPrefs();
 
     // Register the controller to handle "select all" properly.
     this._commandController = new CommandController(this);
     this.window.controllers.insertControllerAt(0, this._commandController);
@@ -585,27 +580,25 @@ WebConsoleFrame.prototype = {
     this.outputNode.style.width = this.outputWrapper.clientWidth + "px";
   },
 
   /**
    * Sets the focus to JavaScript input field when the web console tab is
    * selected or when there is a split console present.
    * @private
    */
-  _onPanelSelected: function WCF__onPanelSelected(evt, id)
-  {
+  _onPanelSelected: function WCF__onPanelSelected(evt, id) {
     this.jsterm.inputNode.focus();
   },
 
   /**
    * Initialize the default filter preferences.
    * @private
    */
-  _initDefaultFilterPrefs: function WCF__initDefaultFilterPrefs()
-  {
+  _initDefaultFilterPrefs: function WCF__initDefaultFilterPrefs() {
     let prefs = ["network", "networkinfo", "csserror", "cssparser", "csslog",
                  "exception", "jswarn", "jslog", "error", "info", "warn", "log",
                  "secerror", "secwarn", "netwarn", "netxhr", "sharedworkers",
                  "serviceworkers", "windowlessworkers", "servererror",
                  "serverwarn", "serverinfo", "serverlog"];
 
     for (let pref of prefs) {
       this.filterPrefs[pref] = Services.prefs.getBoolPref(
@@ -617,18 +610,17 @@ WebConsoleFrame.prototype = {
    * Attach / detach reflow listeners depending on the checked status
    * of the `CSS > Log` menuitem.
    *
    * @param function [callback=null]
    *        Optional function to invoke when the listener has been
    *        added/removed.
    */
   _updateReflowActivityListener:
-    function WCF__updateReflowActivityListener(callback)
-  {
+    function WCF__updateReflowActivityListener(callback) {
     if (this.webConsoleClient) {
       let pref = this._filterPrefsPrefix + "csslog";
       if (Services.prefs.getBoolPref(pref)) {
         this.webConsoleClient.startListeners(["ReflowActivity"], callback);
       } else {
         this.webConsoleClient.stopListeners(["ReflowActivity"], callback);
       }
     }
@@ -639,18 +631,17 @@ WebConsoleFrame.prototype = {
    * preferences. If the user isn't interested in the server logs at
    * all the listener is not registered.
    *
    * @param function [callback=null]
    *        Optional function to invoke when the listener has been
    *        added/removed.
    */
   _updateServerLoggingListener:
-    function WCF__updateServerLoggingListener(callback)
-  {
+    function WCF__updateServerLoggingListener(callback) {
     if (!this.webConsoleClient) {
       return;
     }
 
     let startListener = false;
     let prefs = ["servererror", "serverwarn", "serverinfo", "serverlog"];
     for (let i = 0; i < prefs.length; i++) {
       if (this.filterPrefs[prefs[i]]) {
@@ -665,18 +656,17 @@ WebConsoleFrame.prototype = {
       this.webConsoleClient.stopListeners(["ServerLogging"], callback);
     }
   },
 
   /**
    * Sets the events for the filter input field.
    * @private
    */
-  _setFilterTextBoxEvents: function WCF__setFilterTextBoxEvents()
-  {
+  _setFilterTextBoxEvents: function WCF__setFilterTextBoxEvents() {
     let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     let timerEvent = this.adjustVisibilityOnSearchStringChange.bind(this);
 
     let onChange = function _onChange() {
       // To improve responsiveness, we let the user finish typing before we
       // perform the search.
       timer.cancel();
       timer.initWithCallback(timerEvent, SEARCH_DELAY,
@@ -693,18 +683,17 @@ WebConsoleFrame.prototype = {
    * @private
    * @param nsIDOMNode aParent
    *        The node to which the filter button should be appended.
    * @param object aDescriptor
    *        A descriptor that contains info about the button. Contains "name",
    *        "category", and "prefKey" properties, and optionally a "severities"
    *        property.
    */
-  _initFilterButtons: function WCF__initFilterButtons()
-  {
+  _initFilterButtons: function WCF__initFilterButtons() {
     let categories = this.document
                      .querySelectorAll(".webconsole-filter-button[category]");
     Array.forEach(categories, function(button) {
       button.addEventListener("contextmenu", (event) => {
         button.open = true;
       }, false);
       button.addEventListener("click", this._toggleFilter, false);
 
@@ -746,64 +735,60 @@ WebConsoleFrame.prototype = {
 
   /**
    * Increase, decrease or reset the font size.
    *
    * @param string size
    *        The size of the font change. Accepted values are "+" and "-".
    *        An unmatched size assumes a font reset.
    */
-  changeFontSize: function WCF_changeFontSize(size)
-  {
+  changeFontSize: function WCF_changeFontSize(size) {
     let fontSize = this.window
                    .getComputedStyle(this.outputNode, null)
                    .getPropertyValue("font-size").replace("px", "");
 
     if (this.outputNode.style.fontSize) {
       fontSize = this.outputNode.style.fontSize.replace("px", "");
     }
 
     if (size == "+" || size == "-") {
       fontSize = parseInt(fontSize, 10);
 
       if (size == "+") {
         fontSize += 1;
-      }
-      else {
+      } else {
         fontSize -= 1;
       }
 
       if (fontSize < MIN_FONT_SIZE) {
         fontSize = MIN_FONT_SIZE;
       }
 
       Services.prefs.setIntPref("devtools.webconsole.fontSize", fontSize);
       fontSize = fontSize + "px";
 
       this.completeNode.style.fontSize = fontSize;
       this.inputNode.style.fontSize = fontSize;
       this.outputNode.style.fontSize = fontSize;
-    }
-    else {
+    } else {
       this.completeNode.style.fontSize = "";
       this.inputNode.style.fontSize = "";
       this.outputNode.style.fontSize = "";
       Services.prefs.clearUserPref("devtools.webconsole.fontSize");
     }
     this._updateCharSize();
   },
 
   /**
    * Calculates the width and height of a single character of the input box.
    * This will be used in opening the popup at the correct offset.
    *
    * @private
    */
-  _updateCharSize: function WCF__updateCharSize()
-  {
+  _updateCharSize: function WCF__updateCharSize() {
     let doc = this.document;
     let tempLabel = doc.createElementNS(XHTML_NS, "span");
     let style = tempLabel.style;
     style.position = "fixed";
     style.padding = "0";
     style.margin = "0";
     style.width = "auto";
     style.color = "transparent";
@@ -821,18 +806,17 @@ WebConsoleFrame.prototype = {
   /**
    * The event handler that is called whenever a user switches a filter on or
    * off.
    *
    * @private
    * @param nsIDOMEvent event
    *        The event that triggered the filter change.
    */
-  _toggleFilter: function WCF__toggleFilter(event)
-  {
+  _toggleFilter: function WCF__toggleFilter(event) {
     let target = event.target;
     let tagName = target.tagName;
     // Prevent toggle if generated from a contextmenu event (right click)
     let isRightClick = (event.button === 2); // right click is button 2;
     if (tagName != event.currentTarget.tagName || isRightClick) {
       return;
     }
 
@@ -923,35 +907,33 @@ WebConsoleFrame.prototype = {
    * Set the menu attributes for a specific toggle button.
    *
    * @private
    * @param XULElement target
    *        Button with drop down items to be toggled.
    * @param boolean state
    *        True if the menu item is being toggled on, and false otherwise.
    */
-  _setMenuState: function WCF__setMenuState(target, state)
-  {
+  _setMenuState: function WCF__setMenuState(target, state) {
     let menuItems = target.querySelectorAll("menuitem");
     Array.forEach(menuItems, (item) => {
       item.setAttribute("checked", state);
       let prefKey = item.getAttribute("prefKey");
       this.setFilterState(prefKey, state);
     });
   },
 
   /**
    * Set the filter state for a specific toggle button.
    *
    * @param string toggleType
    * @param boolean state
    * @returns void
    */
-  setFilterState: function WCF_setFilterState(toggleType, state)
-  {
+  setFilterState: function WCF_setFilterState(toggleType, state) {
     this.filterPrefs[toggleType] = state;
     this.adjustVisibilityForMessageType(toggleType, state);
 
     Services.prefs.setBoolPref(this._filterPrefsPrefix + toggleType, state);
 
     if (this._updateListenersTimeout) {
       Timers.clearTimeout(this._updateListenersTimeout);
     }
@@ -961,18 +943,17 @@ WebConsoleFrame.prototype = {
   },
 
   /**
    * Get the filter state for a specific toggle button.
    *
    * @param string toggleType
    * @returns boolean
    */
-  getFilterState: function WCF_getFilterState(toggleType)
-  {
+  getFilterState: function WCF_getFilterState(toggleType) {
     return this.filterPrefs[toggleType];
   },
 
   /**
    * Called when a logging filter changes. Allows to stop/start
    * listeners according to the current filter state.
    */
   _onUpdateListeners: function() {
@@ -984,18 +965,17 @@ WebConsoleFrame.prototype = {
    * Check that the passed string matches the filter arguments.
    *
    * @param String str
    *        to search for filter words in.
    * @param String filter
    *        is a string containing all of the words to filter on.
    * @returns boolean
    */
-  stringMatchesFilters: function WCF_stringMatchesFilters(str, filter)
-  {
+  stringMatchesFilters: function WCF_stringMatchesFilters(str, filter) {
     if (!filter || !str) {
       return true;
     }
 
     let searchStr = str.toLowerCase();
     let filterStrings = filter.toLowerCase().split(/\s+/);
     return !filterStrings.some(function (f) {
       return searchStr.indexOf(f) == -1;
@@ -1010,18 +990,17 @@ WebConsoleFrame.prototype = {
    *        The preference key for the message type being filtered: one of the
    *        values in the MESSAGE_PREFERENCE_KEYS table.
    * @param boolean state
    *        True if the filter named by @messageType is being turned on; false
    *        otherwise.
    * @returns void
    */
   adjustVisibilityForMessageType:
-  function WCF_adjustVisibilityForMessageType(prefKey, state)
-  {
+  function WCF_adjustVisibilityForMessageType(prefKey, state) {
     let outputNode = this.outputNode;
     let doc = this.document;
 
     // Look for message nodes (".message") with the given preference key
     // (filter="error", filter="cssparser", etc.) and add or remove the
     // "filtered-by-type" class, which turns on or off the display.
 
     let attribute = WORKERTYPES_PREFKEYS.indexOf(prefKey) == -1
@@ -1030,60 +1009,56 @@ WebConsoleFrame.prototype = {
     let xpath = ".//*[contains(@class, 'message') and " +
       "@" + attribute + "='" + prefKey + "']";
     let result = doc.evaluate(xpath, outputNode, null,
       Ci.nsIDOMXPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
     for (let i = 0; i < result.snapshotLength; i++) {
       let node = result.snapshotItem(i);
       if (state) {
         node.classList.remove("filtered-by-type");
-      }
-      else {
+      } else {
         node.classList.add("filtered-by-type");
       }
     }
   },
 
   /**
    * Turns the display of log nodes on and off appropriately to reflect the
    * adjustment of the search string.
    */
   adjustVisibilityOnSearchStringChange:
-  function WCF_adjustVisibilityOnSearchStringChange()
-  {
+  function WCF_adjustVisibilityOnSearchStringChange() {
     let nodes = this.outputNode.getElementsByClassName("message");
     let searchString = this.filterBox.value;
 
     for (let i = 0, n = nodes.length; i < n; ++i) {
       let node = nodes[i];
 
       // hide nodes that match the strings
       let text = node.textContent;
 
       // if the text matches the words in aSearchString...
       if (this.stringMatchesFilters(text, searchString)) {
         node.classList.remove("filtered-by-string");
-      }
-      else {
+      } else {
         node.classList.add("filtered-by-string");
       }
     }
   },
 
   /**
    * Applies the user's filters to a newly-created message node via CSS
    * classes.
    *
    * @param nsIDOMNode node
    *        The newly-created message node.
    * @return boolean
    *         True if the message was filtered or false otherwise.
    */
-  filterMessageNode: function WCF_filterMessageNode(node)
-  {
+  filterMessageNode: function WCF_filterMessageNode(node) {
     let isFiltered = false;
 
     // Filter by the message type.
     let prefKey = MESSAGE_PREFERENCE_KEYS[node.category][node.severity];
     if (prefKey && !this.getFilterState(prefKey)) {
       // The node is filtered by type.
       node.classList.add("filtered-by-type");
       isFiltered = true;
@@ -1117,18 +1092,17 @@ WebConsoleFrame.prototype = {
    * Increment the number of repeats of original.
    *
    * @param nsIDOMNode original
    *        The Original Node. The one being merged into.
    * @param nsIDOMNode filtered
    *        The node being filtered out because it is repeated.
    */
   mergeFilteredMessageNode:
-  function WCF_mergeFilteredMessageNode(original, filtered)
-  {
+  function WCF_mergeFilteredMessageNode(original, filtered) {
     let repeatNode = original.getElementsByClassName("message-repeats")[0];
     if (!repeatNode) {
       return; // no repeat node, return early.
     }
 
     let occurrences = parseInt(repeatNode.getAttribute("value")) + 1;
     repeatNode.setAttribute("value", occurrences);
     repeatNode.textContent = occurrences;
@@ -1142,37 +1116,35 @@ WebConsoleFrame.prototype = {
    *
    * @private
    * @param nsIDOMNode node
    *        The message node to be filtered or not.
    * @returns nsIDOMNode|null
    *          Returns the duplicate node if the message was filtered, null
    *          otherwise.
    */
-  _filterRepeatedMessage: function WCF__filterRepeatedMessage(node)
-  {
+  _filterRepeatedMessage: function WCF__filterRepeatedMessage(node) {
     let repeatNode = node.getElementsByClassName("message-repeats")[0];
     if (!repeatNode) {
       return null;
     }
 
     let uid = repeatNode._uid;
     let dupeNode = null;
 
     if (node.category == CATEGORY_CSS ||
         node.category == CATEGORY_SECURITY) {
       dupeNode = this._repeatNodes[uid];
       if (!dupeNode) {
         this._repeatNodes[uid] = node;
       }
-    }
-    else if ((node.category == CATEGORY_WEBDEV ||
-              node.category == CATEGORY_JS) &&
-             node.category != CATEGORY_NETWORK &&
-             !node.classList.contains("inlined-variables-view")) {
+    } else if ((node.category == CATEGORY_WEBDEV ||
+                node.category == CATEGORY_JS) &&
+               node.category != CATEGORY_NETWORK &&
+               !node.classList.contains("inlined-variables-view")) {
       let lastMessage = this.outputNode.lastChild;
       if (!lastMessage) {
         return null;
       }
 
       let lastRepeatNode = lastMessage.getElementsByClassName("message-repeats")[0];
       if (lastRepeatNode && lastRepeatNode._uid == uid) {
         dupeNode = lastMessage;
@@ -1190,18 +1162,17 @@ WebConsoleFrame.prototype = {
   /**
    * Display cached messages that may have been collected before the UI is
    * displayed.
    *
    * @param array remoteMessages
    *        Array of cached messages coming from the remote Web Console
    *        content instance.
    */
-  displayCachedMessages: function WCF_displayCachedMessages(remoteMessages)
-  {
+  displayCachedMessages: function WCF_displayCachedMessages(remoteMessages) {
     if (!remoteMessages.length) {
       return;
     }
 
     remoteMessages.forEach(function(message) {
       switch (message._type) {
         case "PageError": {
           let category = Utils.categoryForScriptError(message);
@@ -1227,18 +1198,17 @@ WebConsoleFrame.prototype = {
    * Logs a message to the Web Console that originates from the Web Console
    * server.
    *
    * @param object message
    *        The message received from the server.
    * @return nsIDOMElement|null
    *         The message element to display in the Web Console output.
    */
-  logConsoleAPIMessage: function WCF_logConsoleAPIMessage(message)
-  {
+  logConsoleAPIMessage: function WCF_logConsoleAPIMessage(message) {
     let body = null;
     let clipboardText = null;
     let sourceURL = message.filename;
     let sourceLine = message.lineNumber;
     let level = message.level;
     let args = message.arguments;
     let objectActors = new Set();
     let node = null;
@@ -1395,31 +1365,29 @@ WebConsoleFrame.prototype = {
 
   /**
    * Handle ConsoleAPICall objects received from the server. This method outputs
    * the window.console API call.
    *
    * @param object message
    *        The console API message received from the server.
    */
-  handleConsoleAPICall: function WCF_handleConsoleAPICall(message)
-  {
+  handleConsoleAPICall: function WCF_handleConsoleAPICall(message) {
     this.outputMessage(CATEGORY_WEBDEV, this.logConsoleAPIMessage, [message]);
   },
 
   /**
    * Reports an error in the page source, either JavaScript or CSS.
    *
    * @param nsIScriptError scriptError
    *        The error message to report.
    * @return nsIDOMElement|undefined
    *         The message element to display in the Web Console output.
    */
-  reportPageError: function WCF_reportPageError(category, scriptError)
-  {
+  reportPageError: function WCF_reportPageError(category, scriptError) {
     // Warnings and legacy strict errors become warnings; other types become
     // errors.
     let severity = 'error';
     if (scriptError.warning || scriptError.strict) {
       severity = 'warning';
     } else if (scriptError.info) {
       severity = 'log';
     }
@@ -1492,47 +1460,44 @@ WebConsoleFrame.prototype = {
 
   /**
    * Handle PageError objects received from the server. This method outputs the
    * given error.
    *
    * @param nsIScriptError pageError
    *        The error received from the server.
    */
-  handlePageError: function WCF_handlePageError(pageError)
-  {
+  handlePageError: function WCF_handlePageError(pageError) {
     let category = Utils.categoryForScriptError(pageError);
     this.outputMessage(category, this.reportPageError, [category, pageError]);
   },
 
   /**
    * Handle log messages received from the server. This method outputs the given
    * message.
    *
    * @param object packet
    *        The message packet received from the server.
    */
-  handleLogMessage: function WCF_handleLogMessage(packet)
-  {
+  handleLogMessage: function WCF_handleLogMessage(packet) {
     if (packet.message) {
       this.outputMessage(CATEGORY_JS, this._reportLogMessage, [packet]);
     }
   },
 
   /**
    * Display log messages received from the server.
    *
    * @private
    * @param object packet
    *        The message packet received from the server.
    * @return nsIDOMElement
    *         The message element to render for the given log message.
    */
-  _reportLogMessage: function WCF__reportLogMessage(packet)
-  {
+  _reportLogMessage: function WCF__reportLogMessage(packet) {
     let msg = packet.message;
     if (msg.type && msg.type == "longString") {
       msg = msg.initial;
     }
     let node = this.createMessageNode(CATEGORY_JS, SEVERITY_LOG, msg, null,
                                       null, null, null, packet.timeStamp);
     if (WebConsoleUtils.isActorGrip(packet.message)) {
       node._objectActors = new Set([packet.message.actor]);
@@ -1543,18 +1508,17 @@ WebConsoleFrame.prototype = {
   /**
    * Log network event.
    *
    * @param object networkInfo
    *        The network request information to log.
    * @return nsIDOMElement|null
    *         The message element to display in the Web Console output.
    */
-  logNetEvent: function(networkInfo)
-  {
+  logNetEvent: function(networkInfo) {
     let actorId = networkInfo.actor;
     let request = networkInfo.request;
     let clipboardText = request.method + " " + request.url;
     let severity = SEVERITY_LOG;
     if (networkInfo.isXHR) {
       clipboardText = request.method + " XHR " + request.url;
       severity = SEVERITY_INFO;
     }
@@ -1626,18 +1590,17 @@ WebConsoleFrame.prototype = {
   },
 
   /**
    * Create a mixed content warning Node.
    *
    * @param linkNode
    *        Parent to the requested urlNode.
    */
-  makeMixedContentNode: function WCF_makeMixedContentNode(linkNode)
-  {
+  makeMixedContentNode: function WCF_makeMixedContentNode(linkNode) {
     let mixedContentWarning = "[" + l10n.getStr("webConsoleMixedContentWarning") + "]";
 
     // Mixed content warning message links to a Learn More page
     let mixedContentWarningNode = this.document.createElementNS(XHTML_NS, "a");
     mixedContentWarningNode.title = MIXED_CONTENT_LEARN_MORE;
     mixedContentWarningNode.href = MIXED_CONTENT_LEARN_MORE;
     mixedContentWarningNode.className = "learn-more-link";
     mixedContentWarningNode.textContent = mixedContentWarning;
@@ -1655,18 +1618,17 @@ WebConsoleFrame.prototype = {
    * Adds a more info link node to messages based on the nsIScriptError object
    * that we need to report to the console
    *
    * @param node
    *        The node to which we will be adding the more info link node
    * @param scriptError
    *        The script error object that we are reporting to the console
    */
-  addMoreInfoLink: function WCF_addMoreInfoLink(node, scriptError)
-  {
+  addMoreInfoLink: function WCF_addMoreInfoLink(node, scriptError) {
     let url;
     switch (scriptError.category) {
       case "Insecure Password Field":
         url = INSECURE_PASSWORDS_LEARN_MORE;
         break;
       case "Mixed Content Message":
       case "Mixed Content Blocker":
         url = MIXED_CONTENT_LEARN_MORE;
@@ -1699,18 +1661,17 @@ WebConsoleFrame.prototype = {
    * @param node
    *        The node to which we will be adding a clickable warning node.
    * @param url
    *        The url which points to the page where the user can learn more
    *        about security issues associated with the specific message that's
    *        being logged.
    */
   addLearnMoreWarningNode:
-  function WCF_addLearnMoreWarningNode(node, url)
-  {
+  function WCF_addLearnMoreWarningNode(node, url) {
     let moreInfoLabel = "[" + l10n.getStr("webConsoleMoreInfoLabel") + "]";
 
     let warningNode = this.document.createElementNS(XHTML_NS, "a");
     warningNode.title = url;
     warningNode.href = url;
     warningNode.draggable = false;
     warningNode.textContent = moreInfoLabel;
     warningNode.className = "learn-more-link";
@@ -1726,18 +1687,17 @@ WebConsoleFrame.prototype = {
   /**
    * Log file activity.
    *
    * @param string fileURI
    *        The file URI that was loaded.
    * @return nsIDOMElement|undefined
    *         The message element to display in the Web Console output.
    */
-  logFileActivity: function WCF_logFileActivity(fileURI)
-  {
+  logFileActivity: function WCF_logFileActivity(fileURI) {
     let urlNode = this.document.createElementNS(XHTML_NS, "a");
     urlNode.setAttribute("title", fileURI);
     urlNode.className = "url";
     urlNode.textContent = fileURI;
     urlNode.draggable = false;
     urlNode.href = fileURI;
 
     let outputNode = this.createMessageNode(CATEGORY_NETWORK, SEVERITY_LOG,
@@ -1751,29 +1711,27 @@ WebConsoleFrame.prototype = {
   },
 
   /**
    * Handle the file activity messages coming from the remote Web Console.
    *
    * @param string fileURI
    *        The file URI that was requested.
    */
-  handleFileActivity: function WCF_handleFileActivity(fileURI)
-  {
+  handleFileActivity: function WCF_handleFileActivity(fileURI) {
     this.outputMessage(CATEGORY_NETWORK, this.logFileActivity, [fileURI]);
   },
 
   /**
    * Handle the reflow activity messages coming from the remote Web Console.
    *
    * @param object msg
    *        An object holding information about a reflow batch.
    */
-  logReflowActivity: function WCF_logReflowActivity(message)
-  {
+  logReflowActivity: function WCF_logReflowActivity(message) {
     let {start, end, sourceURL, sourceLine} = message;
     let duration = Math.round((end - start) * 100) / 100;
     let node = this.document.createElementNS(XHTML_NS, "span");
     if (sourceURL) {
       node.textContent = l10n.getFormatStr("reflow.messageWithLink", [duration]);
       let a = this.document.createElementNS(XHTML_NS, "a");
       a.href = "#";
       a.draggable = "false";
@@ -1787,53 +1745,49 @@ WebConsoleFrame.prototype = {
       node.appendChild(a);
     } else {
       node.textContent = l10n.getFormatStr("reflow.messageWithNoLink", [duration]);
     }
     return this.createMessageNode(CATEGORY_CSS, SEVERITY_LOG, node);
   },
 
 
-  handleReflowActivity: function WCF_handleReflowActivity(message)
-  {
+  handleReflowActivity: function WCF_handleReflowActivity(message) {
     this.outputMessage(CATEGORY_CSS, this.logReflowActivity, [message]);
   },
 
   /**
    * Inform user that the window.console API has been replaced by a script
    * in a content page.
    */
-  logWarningAboutReplacedAPI: function WCF_logWarningAboutReplacedAPI()
-  {
+  logWarningAboutReplacedAPI: function WCF_logWarningAboutReplacedAPI() {
     let node = this.createMessageNode(CATEGORY_JS, SEVERITY_WARNING,
                                       l10n.getStr("ConsoleAPIDisabled"));
     this.outputMessage(CATEGORY_JS, node);
   },
 
   /**
    * Handle the network events coming from the remote Web Console.
    *
    * @param object networkInfo
    *        The network request information.
    */
-  handleNetworkEvent: function(networkInfo)
-  {
+  handleNetworkEvent: function(networkInfo) {
     this.outputMessage(CATEGORY_NETWORK, this.logNetEvent, [networkInfo]);
   },
 
   /**
    * Handle network event updates coming from the server.
    *
    * @param object networkInfo
    *        The network request information.
    * @param object packet
    *        Update details.
    */
-  handleNetworkEventUpdate: function(networkInfo, packet)
-  {
+  handleNetworkEventUpdate: function(networkInfo, packet) {
     if (networkInfo.node && this._updateNetMessage(packet.from)) {
       this.emit("new-messages", new Set([{
         update: true,
         node: networkInfo.node,
         response: packet,
       }]));
     }
 
@@ -1851,18 +1805,17 @@ WebConsoleFrame.prototype = {
    * given a network event actor ID.
    *
    * @private
    * @param string actorId
    *        The network event actor ID for which you want to update the message.
    * @return boolean
    *         |true| if the message node was updated, or |false| otherwise.
    */
-  _updateNetMessage: function WCF__updateNetMessage(actorId)
-  {
+  _updateNetMessage: function WCF__updateNetMessage(actorId) {
     let networkInfo = this.webConsoleClient.getNetworkRequest(actorId);
     if (!networkInfo || !networkInfo.node) {
       return;
     }
 
     let messageNode = networkInfo.node;
     let updates = networkInfo.updates;
     let hasEventTimings = updates.indexOf("eventTimings") > -1;
@@ -1905,18 +1858,17 @@ WebConsoleFrame.prototype = {
   },
 
   /**
    * Opens the network monitor and highlights the specified request.
    *
    * @param string requestId
    *        The actor ID of the network request.
    */
-  openNetworkPanel: function WCF_openNetworkPanel(requestId)
-  {
+  openNetworkPanel: function WCF_openNetworkPanel(requestId) {
     let toolbox = gDevTools.getToolbox(this.owner.target);
     // The browser console doesn't have a toolbox.
     if (!toolbox) {
       return;
     }
     return toolbox.selectTool("netmonitor").then(panel => {
       return panel.panelWin.NetMonitorController.inspectRequest(requestId);
     });
@@ -1925,40 +1877,37 @@ WebConsoleFrame.prototype = {
   /**
    * Handler for page location changes.
    *
    * @param string uri
    *        New page location.
    * @param string title
    *        New page title.
    */
-  onLocationChange: function WCF_onLocationChange(uri, title)
-  {
+  onLocationChange: function WCF_onLocationChange(uri, title) {
     this.contentLocation = uri;
     if (this.owner.onLocationChange) {
       this.owner.onLocationChange(uri, title);
     }
   },
 
   /**
    * Handler for the tabNavigated notification.
    *
    * @param string event
    *        Event name.
    * @param object packet
    *        Notification packet received from the server.
    */
-  handleTabNavigated: function WCF_handleTabNavigated(event, packet)
-  {
+  handleTabNavigated: function WCF_handleTabNavigated(event, packet) {
     if (event == "will-navigate") {
       if (this.persistLog) {
         let marker = new Messages.NavigationMarker(packet, Date.now());
         this.output.addMessage(marker);
-      }
-      else {
+      } else {
         this.jsterm.clearOutput();
       }
     }
 
     if (packet.url) {
       this.onLocationChange(packet.url, packet.title);
     }
 
@@ -1982,18 +1931,17 @@ WebConsoleFrame.prototype = {
    *        the actual element. If a method is given it will be bound to the HUD
    *        object and the arguments will be |args|.
    * @param array [args]
    *        If a method is given to output the message element then the method
    *        will be invoked with the list of arguments given here. The last
    *        object in this array should be the packet received from the
    *        back end.
    */
-  outputMessage: function WCF_outputMessage(category, methodOrNode, args)
-  {
+  outputMessage: function WCF_outputMessage(category, methodOrNode, args) {
     if (!this._outputQueue.length) {
       // If the queue is empty we consider that now was the last output flush.
       // This avoid an immediate output flush when the timer executes.
       this._lastOutputFlush = Date.now();
     }
 
     this._outputQueue.push([category, methodOrNode, args]);
 
@@ -2002,18 +1950,17 @@ WebConsoleFrame.prototype = {
 
   /**
    * Try to flush the output message queue. This takes the messages in the
    * output queue and displays them. Outputting stops at MESSAGES_IN_INTERVAL.
    * Further output is queued to happen later - see OUTPUT_INTERVAL.
    *
    * @private
    */
-  _flushMessageQueue: function WCF__flushMessageQueue()
-  {
+  _flushMessageQueue: function WCF__flushMessageQueue() {
     this._outputTimerInitialized = false;
     if (!this._outputTimer) {
       return;
     }
 
     let startTime = Date.now();
     let timeSinceFlush = startTime - this._lastOutputFlush;
     let shouldThrottle = this._outputQueue.length > MESSAGES_IN_INTERVAL &&
@@ -2096,19 +2043,18 @@ WebConsoleFrame.prototype = {
                         (lastVisibleNode.category == CATEGORY_INPUT ||
                          lastVisibleNode.category == CATEGORY_OUTPUT);
 
     // Scroll to the new node if it is not filtered, and if the output node is
     // scrolled at the bottom or if the new node is a jsterm input/output
     // message.
     if (lastVisibleNode && (scrolledToBottom || isInputOutput)) {
       Utils.scrollToVisible(lastVisibleNode);
-    }
-    else if (!scrolledToBottom && removedNodes > 0 &&
-             oldScrollHeight != scrollNode.scrollHeight) {
+    } else if (!scrolledToBottom && removedNodes > 0 &&
+               oldScrollHeight != scrollNode.scrollHeight) {
       // If there were pruned messages and if scroll is not at the bottom, then
       // we need to adjust the scroll location.
       scrollNode.scrollTop -= oldScrollHeight - scrollNode.scrollHeight;
     }
 
     if (messages.size) {
       this.emit("new-messages", messages);
     }
@@ -2124,18 +2070,17 @@ WebConsoleFrame.prototype = {
 
     this._lastOutputFlush = Date.now();
   },
 
   /**
    * Initialize the output timer.
    * @private
    */
-  _initOutputTimer: function WCF__initOutputTimer()
-  {
+  _initOutputTimer: function WCF__initOutputTimer() {
     let panelIsDestroyed = !this._outputTimer;
     let alreadyScheduled = this._outputTimerInitialized;
     let nothingToDo = !this._itemDestroyQueue.length &&
                       !this._outputQueue.length;
 
     // Don't schedule a callback in the following cases:
     if (panelIsDestroyed || alreadyScheduled || nothingToDo) {
       return;
@@ -2158,18 +2103,17 @@ WebConsoleFrame.prototype = {
    * @return object
    *         An object that holds the following properties:
    *         - node: the DOM element of the message.
    *         - isRepeated: the DOM element of the original message, if this is
    *         a repeated message, otherwise null.
    *         - visible: boolean that tells if the message is visible.
    */
   _outputMessageFromQueue:
-  function WCF__outputMessageFromQueue(hudIdSupportsString, item)
-  {
+  function WCF__outputMessageFromQueue(hudIdSupportsString, item) {
     let [category, methodOrNode, args] = item;
 
     // The last object in the args array should be message
     // object or response packet received from the server.
     let message = (args && args.length) ? args[args.length-1] : null;
 
     let node = typeof methodOrNode == "function" ?
                methodOrNode.apply(this, args || []) :
@@ -2206,18 +2150,17 @@ WebConsoleFrame.prototype = {
     };
   },
 
   /**
    * Prune the queue of messages to display. This avoids displaying messages
    * that will be removed at the end of the queue anyway.
    * @private
    */
-  _pruneOutputQueue: function WCF__pruneOutputQueue()
-  {
+  _pruneOutputQueue: function WCF__pruneOutputQueue() {
     let nodes = {};
 
     // Group the messages per category.
     this._outputQueue.forEach(function(item, index) {
       let [category] = item;
       if (!(category in nodes)) {
         nodes[category] = [];
       }
@@ -2247,18 +2190,17 @@ WebConsoleFrame.prototype = {
    * Destroy an item that was once in the outputQueue but isn't needed
    * after all.
    *
    * @private
    * @param array item
    *        The item you want to destroy.  Does not remove it from the output
    *        queue.
    */
-  _destroyItem: function WCF__destroyItem(item)
-  {
+  _destroyItem: function WCF__destroyItem(item) {
     // TODO: handle object releasing in a more elegant way once all console
     // messages use the new API - bug 778766.
     let [category, methodOrNode, args] = item;
     if (typeof methodOrNode != "function" && methodOrNode._objectActors) {
       for (let actor of methodOrNode._objectActors) {
         this._releaseObject(actor);
       }
       methodOrNode._objectActors.clear();
@@ -2276,78 +2218,72 @@ WebConsoleFrame.prototype = {
         arg._objectActors.clear();
       }
     }
 
     if (category == CATEGORY_NETWORK) {
       let connectionId = null;
       if (methodOrNode == this.logNetEvent) {
         connectionId = args[0].actor;
-      }
-      else if (typeof methodOrNode != "function") {
+      } else if (typeof methodOrNode != "function") {
         connectionId = methodOrNode._connectionId;
       }
       if (connectionId && this.webConsoleClient.hasNetworkRequest(connectionId)) {
         this.webConsoleClient.removeNetworkRequest(connectionId);
         this._releaseObject(connectionId);
       }
-    }
-    else if (category == CATEGORY_WEBDEV &&
-             methodOrNode == this.logConsoleAPIMessage) {
+    } else if (category == CATEGORY_WEBDEV &&
+               methodOrNode == this.logConsoleAPIMessage) {
       args[0].arguments.forEach((value) => {
         if (WebConsoleUtils.isActorGrip(value)) {
           this._releaseObject(value.actor);
         }
       });
-    }
-    else if (category == CATEGORY_JS &&
-             methodOrNode == this.reportPageError) {
+    } else if (category == CATEGORY_JS &&
+               methodOrNode == this.reportPageError) {
       let pageError = args[1];
       for (let prop of ["errorMessage", "lineText"]) {
         let grip = pageError[prop];
         if (WebConsoleUtils.isActorGrip(grip)) {
           this._releaseObject(grip.actor);
         }
       }
-    }
-    else if (category == CATEGORY_JS &&
-             methodOrNode == this._reportLogMessage) {
+    } else if (category == CATEGORY_JS &&
+               methodOrNode == this._reportLogMessage) {
       if (WebConsoleUtils.isActorGrip(args[0].message)) {
         this._releaseObject(args[0].message.actor);
       }
     }
   },
 
   /**
    * Ensures that the number of message nodes of type category don't exceed that
    * category's line limit by removing old messages as needed.
    *
    * @param integer category
    *        The category of message nodes to prune if needed.
    * @return number
    *         The number of removed nodes.
    */
-  pruneOutputIfNecessary: function WCF_pruneOutputIfNecessary(category)
-  {
+  pruneOutputIfNecessary: function WCF_pruneOutputIfNecessary(category) {
     let logLimit = Utils.logLimitForCategory(category);
     let messageNodes = this.outputNode.querySelectorAll(".message[category=" +
                        CATEGORY_CLASS_FRAGMENTS[category] + "]");
     let n = Math.max(0, messageNodes.length - logLimit);
     [...messageNodes].slice(0, n).forEach(this.removeOutputMessage, this);
     return n;
   },
 
   /**
    * Remove a given message from the output.
    *
    * @param nsIDOMNode node
    *        The message node you want to remove.
    */
-  removeOutputMessage: function WCF_removeOutputMessage(node)
-  {
+  removeOutputMessage: function WCF_removeOutputMessage(node) {
     if (node._messageObject) {
       node._messageObject.destroy();
     }
 
     if (node._objectActors) {
       for (let actor of node._objectActors) {
         this._releaseObject(actor);
       }
@@ -2355,23 +2291,21 @@ WebConsoleFrame.prototype = {
     }
 
     if (node.category == CATEGORY_CSS ||
         node.category == CATEGORY_SECURITY) {
       let repeatNode = node.getElementsByClassName("message-repeats")[0];
       if (repeatNode && repeatNode._uid) {
         delete this._repeatNodes[repeatNode._uid];
       }
-    }
-    else if (node._connectionId &&
-             node.category == CATEGORY_NETWORK) {
+    } else if (node._connectionId &&
+               node.category == CATEGORY_NETWORK) {
       this.webConsoleClient.removeNetworkRequest(node._connectionId);
       this._releaseObject(node._connectionId);
-    }
-    else if (node.classList.contains("inlined-variables-view")) {
+    } else if (node.classList.contains("inlined-variables-view")) {
       let view = node._variablesView;
       if (view) {
         view.controller.releaseActors();
       }
       node._variablesView = null;
     }
 
     node.remove();
@@ -2402,18 +2336,17 @@ WebConsoleFrame.prototype = {
    *        The timestamp to use for this message node. If omitted, the current
    *        date and time is used.
    * @return nsIDOMNode
    *         The message node: a DIV ready to be inserted into the Web Console
    *         output node.
    */
   createMessageNode:
   function WCF_createMessageNode(category, severity, body, sourceURL,
-                                 sourceLine, clipboardText, level, timestamp)
-  {
+                                 sourceLine, clipboardText, level, timestamp) {
     if (typeof body != "string" && clipboardText == null && body.innerText) {
       clipboardText = body.innerText;
     }
 
     let indentNode = this.document.createElementNS(XHTML_NS, "span");
     indentNode.className = "indent";
 
     // Apply the current group by indenting appropriately.
@@ -2445,23 +2378,21 @@ WebConsoleFrame.prototype = {
     node.id = "console-msg-" + gSequenceId();
     node.className = "message";
     node.clipboardText = clipboardText;
     node.timestamp = timestamp;
     this.setMessageType(node, category, severity);
 
     if (body instanceof Ci.nsIDOMNode) {
       bodyNode.appendChild(body);
-    }
-    else {
+    } else {
       let str = undefined;
       if (level == "dir") {
         str = VariablesView.getString(body.arguments[0]);
-      }
-      else {
+      } else {
         str = body;
       }
 
       if (str !== undefined) {
         body = this.document.createTextNode(str);
         bodyNode.appendChild(body);
       }
     }
@@ -2536,36 +2467,34 @@ WebConsoleFrame.prototype = {
    *        An object containing url, line and column number of the message source (destructured).
    * @param string target [optional]
    *        Tells which tool to open the link with, on click. Supported tools:
    *        jsdebugger, styleeditor, scratchpad.
    * @return nsIDOMNode
    *         The new anchor element, ready to be added to the message node.
    */
   createLocationNode:
-  function WCF_createLocationNode({url, line, column}, target)
-  {
+  function WCF_createLocationNode({url, line, column}, target) {
     if (!url) {
       url = "";
     }
     let locationNode = this.document.createElementNS(XHTML_NS, "a");
     let filenameNode = this.document.createElementNS(XHTML_NS, "span");
 
     // Create the text, which consists of an abbreviated version of the URL
     // Scratchpad URLs should not be abbreviated.
     let filename;
     let fullURL;
     let isScratchpad = false;
 
     if (/^Scratchpad\/\d+$/.test(url)) {
       filename = url;
       fullURL = url;
       isScratchpad = true;
-    }
-    else {
+    } else {
       fullURL = url.split(" -> ").pop();
       filename = WebConsoleUtils.abbreviateSourceURL(fullURL);
     }
 
     filenameNode.className = "filename";
     filenameNode.textContent = " " + (filename || l10n.getStr("unknownLocation"));
     locationNode.appendChild(filenameNode);
 
@@ -2583,22 +2512,20 @@ WebConsoleFrame.prototype = {
       if (target == "scratchpad" || isScratchpad) {
         this.owner.viewSourceInScratchpad(url, line);
         return;
       }
 
       let category = locationNode.parentNode.category;
       if (target == "styleeditor" || category == CATEGORY_CSS) {
         this.owner.viewSourceInStyleEditor(fullURL, line);
-      }
-      else if (target == "jsdebugger" ||
-               category == CATEGORY_JS || category == CATEGORY_WEBDEV) {
+      } else if (target == "jsdebugger" ||
+                 category == CATEGORY_JS || category == CATEGORY_WEBDEV) {
         this.owner.viewSourceInDebugger(fullURL, line);
-      }
-      else {
+      } else {
         this.owner.viewSource(fullURL, line);
       }
     };
 
     if (fullURL) {
       this._addMessageLinkCallback(locationNode, onClick);
     }
 
@@ -2620,36 +2547,34 @@ WebConsoleFrame.prototype = {
    *        The message node to alter.
    * @param number category
    *        The category for the message; one of the CATEGORY_ constants.
    * @param number severity
    *        The severity for the message; one of the SEVERITY_ constants.
    * @return void
    */
   setMessageType:
-  function WCF_setMessageType(messageNode, category, severity)
-  {
+  function WCF_setMessageType(messageNode, category, severity) {
     messageNode.category = category;
     messageNode.severity = severity;
     messageNode.setAttribute("category", CATEGORY_CLASS_FRAGMENTS[category]);
     messageNode.setAttribute("severity", SEVERITY_CLASS_FRAGMENTS[severity]);
     messageNode.setAttribute("filter", MESSAGE_PREFERENCE_KEYS[category][severity]);
   },
 
   /**
    * Add the mouse event handlers needed to make a link.
    *
    * @private
    * @param nsIDOMNode node
    *        The node for which you want to add the event handlers.
    * @param function callback
    *        The function you want to invoke on click.
    */
-  _addMessageLinkCallback: function WCF__addMessageLinkCallback(node, callback)
-  {
+  _addMessageLinkCallback: function WCF__addMessageLinkCallback(node, callback) {
     node.addEventListener("mousedown", (event) => {
       this._mousedown = true;
       this._startX = event.clientX;
       this._startY = event.clientY;
     }, false);
 
     node.addEventListener("click", (event) => {
       let mousedown = this._mousedown;
@@ -2661,30 +2586,28 @@ WebConsoleFrame.prototype = {
       if (event.detail != 1 || event.button != 0) {
         return;
       }
 
       // If this event started with a mousedown event and it ends at a different
       // location, we consider this text selection.
       if (mousedown &&
           (this._startX != event.clientX) &&
-          (this._startY != event.clientY))
-      {
+          (this._startY != event.clientY)) {
         this._startX = this._startY = undefined;
         return;
       }
 
       this._startX = this._startY = undefined;
 
       callback.call(this, event);
     }, false);
   },
 
-  _addFocusCallback: function WCF__addFocusCallback(node, callback)
-  {
+  _addFocusCallback: function WCF__addFocusCallback(node, callback) {
     node.addEventListener("mousedown", (event) => {
       this._mousedown = true;
       this._startX = event.clientX;
       this._startY = event.clientY;
     }, false);
 
     node.addEventListener("click", (event) => {
       let mousedown = this._mousedown;
@@ -2696,18 +2619,17 @@ WebConsoleFrame.prototype = {
       }
 
       // If this event started with a mousedown event and it ends at a different
       // location, we consider this text selection.
       // Add a fuzz modifier of two pixels in any direction to account for sloppy
       // clicking.
       if (mousedown &&
           (Math.abs(event.clientX - this._startX) >= 2) &&
-          (Math.abs(event.clientY - this._startY) >= 1))
-      {
+          (Math.abs(event.clientY - this._startY) >= 1)) {
         this._startX = this._startY = undefined;
         return;
       }
 
       this._startX = this._startY = undefined;
 
       callback.call(this, event);
     }, false);
@@ -2719,41 +2641,38 @@ WebConsoleFrame.prototype = {
    *
    * @private
    * @param object event
    *        This parameter is a string that holds the event name
    *        pref-changed in this case.
    * @param object data
    *        This is the pref-changed data object.
   */
-  _onToolboxPrefChanged: function WCF__onToolboxPrefChanged(event, data)
-  {
+  _onToolboxPrefChanged: function WCF__onToolboxPrefChanged(event, data) {
     if (data.pref == PREF_MESSAGE_TIMESTAMP) {
       if (data.newValue) {
         this.outputNode.classList.remove("hideTimestamps");
-      }
-      else {
+      } else {
         this.outputNode.classList.add("hideTimestamps");
       }
     }
   },
 
   /**
    * Copies the selected items to the system clipboard.
    *
    * @param object options
    *        - linkOnly:
    *        An optional flag to copy only URL without timestamp and
    *        other meta-information. Default is false.
    *        - contextmenu:
    *        An optional flag to copy the last clicked item which brought
    *        up the context menu if nothing is selected. Default is false.
    */
-  copySelectedItems: function WCF_copySelectedItems(options)
-  {
+  copySelectedItems: function WCF_copySelectedItems(options) {
     options = options || { linkOnly: false, contextmenu: false };
 
     // Gather up the selected items and concatenate their clipboard text.
     let strings = [];
 
     let children = this.output.getSelectedMessages();
     if (!children.length && options.contextmenu) {
       children = [this._contextMenuHandler.lastClickedMessage];
@@ -2761,18 +2680,17 @@ WebConsoleFrame.prototype = {
 
     for (let item of children) {
       // Ensure the selected item hasn't been filtered by type or string.
       if (!item.classList.contains("filtered-by-type") &&
           !item.classList.contains("filtered-by-string")) {
         let timestampString = l10n.timestampString(item.timestamp);
         if (options.linkOnly) {
           strings.push(item.url);
-        }
-        else {
+        } else {
           strings.push(item.clipboardText);
         }
       }
     }
 
     clipboardHelper.copyString(strings.join("\n"));
   },
 
@@ -2781,18 +2699,17 @@ WebConsoleFrame.prototype = {
    * remote object you want.
    *
    * @param string actor
    *        The object actor ID from which you want the properties.
    * @param function callback
    *        Function you want invoked once the properties are received.
    */
   objectPropertiesProvider:
-  function WCF_objectPropertiesProvider(actor, callback)
-  {
+  function WCF_objectPropertiesProvider(actor, callback) {
     this.webConsoleClient.inspectObjectProperties(actor,
       function(response) {
         if (response.error) {
           Cu.reportError("Failed to retrieve the object properties from the " +
                          "server. Error: " + response.error);
           return;
         }
         callback(response.properties);
@@ -2801,28 +2718,26 @@ WebConsoleFrame.prototype = {
 
   /**
    * Release an actor.
    *
    * @private
    * @param string actor
    *        The actor ID you want to release.
    */
-  _releaseObject: function WCF__releaseObject(actor)
-  {
+  _releaseObject: function WCF__releaseObject(actor) {
     if (this.proxy) {
       this.proxy.releaseActor(actor);
     }
   },
 
   /**
    * Open the selected item's URL in a new tab.
    */
-  openSelectedItemInTab: function WCF_openSelectedItemInTab()
-  {
+  openSelectedItemInTab: function WCF_openSelectedItemInTab() {
     let item = this.output.getSelectedMessages(1)[0] ||
                this._contextMenuHandler.lastClickedMessage;
 
     if (!item || !item.url) {
       return;
     }
 
     this.owner.openLink(item.url);
@@ -2831,18 +2746,17 @@ WebConsoleFrame.prototype = {
   /**
    * Destroy the WebConsoleFrame object. Call this method to avoid memory leaks
    * when the Web Console is closed.
    *
    * @return object
    *         A promise that is resolved when the WebConsoleFrame instance is
    *         destroyed.
    */
-  destroy: function WCF_destroy()
-  {
+  destroy: function WCF_destroy() {
     if (this._destroyer) {
       return this._destroyer.promise;
     }
 
     this._destroyer = promise.defer();
 
     let toolbox = gDevTools.getToolbox(this.owner.target);
     if (toolbox) {
@@ -2883,65 +2797,60 @@ WebConsoleFrame.prototype = {
 
     let onDestroy = () => {
       this._destroyer.resolve(null);
     };
 
     if (this.proxy) {
       this.proxy.disconnect().then(onDestroy);
       this.proxy = null;
-    }
-    else {
+    } else {
       onDestroy();
     }
 
     return this._destroyer.promise;
   },
 };
 
 
 /**
  * @see VariablesView.simpleValueEvalMacro
  */
-function simpleValueEvalMacro(item, currentString)
-{
+function simpleValueEvalMacro(item, currentString) {
   return VariablesView.simpleValueEvalMacro(item, currentString, "_self");
 };
 
 
 /**
  * @see VariablesView.overrideValueEvalMacro
  */
-function overrideValueEvalMacro(item, currentString)
-{
+function overrideValueEvalMacro(item, currentString) {
   return VariablesView.overrideValueEvalMacro(item, currentString, "_self");
 };
 
 
 /**
  * @see VariablesView.getterOrSetterEvalMacro
  */
-function getterOrSetterEvalMacro(item, currentString)
-{
+function getterOrSetterEvalMacro(item, currentString) {
   return VariablesView.getterOrSetterEvalMacro(item, currentString, "_self");
 }
 
 
 
 /**
  * Create a JSTerminal (a JavaScript command line). This is attached to an
  * existing HeadsUpDisplay (a Web Console instance). This code is responsible
  * with handling command line input, code evaluation and result output.
  *
  * @constructor
  * @param object webConsoleFrame
  *        The WebConsoleFrame object that owns this JSTerm instance.
  */
-function JSTerm(webConsoleFrame)
-{
+function JSTerm(webConsoleFrame) {
   this.hud = webConsoleFrame;
   this.hudId = this.hud.hudId;
   this.inputHistoryCount = Services.prefs.getIntPref(PREF_INPUT_HISTORY_COUNT);
 
   this.lastCompletion = { value: null };
   this._loadHistory();
 
   this._objectActorsInVariablesViews = new Map();
@@ -3097,41 +3006,38 @@ JSTerm.prototype = {
   autocompletePopup: null,
   inputNode: null,
   completeNode: null,
 
   /**
    * Getter for the element that holds the messages we display.
    * @type nsIDOMElement
    */
-  get outputNode()
-  {
+  get outputNode() {
     return this.hud.outputNode;
   },
 
   /**
    * Getter for the debugger WebConsoleClient.
    * @type object
    */
-  get webConsoleClient()
-  {
+  get webConsoleClient() {
     return this.hud.webConsoleClient;
   },
 
   COMPLETE_FORWARD: 0,
   COMPLETE_BACKWARD: 1,
   COMPLETE_HINT_ONLY: 2,
   COMPLETE_PAGEUP: 3,
   COMPLETE_PAGEDOWN: 4,
 
   /**
    * Initialize the JSTerminal UI.
    */
-  init: function JST_init()
-  {
+  init: function JST_init() {
     let autocompleteOptions = {
       onSelect: this.onAutocompleteSelect.bind(this),
       onClick: this.acceptProposedCompletion.bind(this),
       panelId: "webConsole_autocompletePopup",
       listBoxId: "webConsole_autocompletePopupListBox",
       position: "before_start",
       theme: "auto",
       direction: "ltr",
@@ -3143,18 +3049,17 @@ JSTerm.prototype = {
     let doc = this.hud.document;
     let inputContainer = doc.querySelector(".jsterm-input-container");
     this.completeNode = doc.querySelector(".jsterm-complete-node");
     this.inputNode = doc.querySelector(".jsterm-input-node");
 
     if (this.hud.owner._browserConsole &&
         !Services.prefs.getBoolPref("devtools.chrome.enabled")) {
       inputContainer.style.display = "none";
-    }
-    else {
+    } else {
       let okstring = l10n.getStr("selfxss.okstring");
       let msg = l10n.getFormatStr("selfxss.msg", [okstring]);
       this._onPaste = WebConsoleUtils.pasteHandlerGen(this.inputNode,
                                                       doc.getElementById("webconsole-notificationbox"),
                                                       msg, okstring);
       this.inputNode.addEventListener("keypress", this._keyPress, false);
       this.inputNode.addEventListener("paste", this._onPaste);
       this.inputNode.addEventListener("drop", this._onPaste);
@@ -3180,18 +3085,17 @@ JSTerm.prototype = {
    * @private
    * @param function [callback]
    *        Optional function to invoke when the evaluation result is added to
    *        the output.
    * @param object response
    *        The message received from the server.
    */
   _executeResultCallback:
-  function JST__executeResultCallback(callback, response)
-  {
+  function JST__executeResultCallback(callback, response) {
     if (!this.hud) {
       return;
     }
     if (response.error) {
       Cu.reportError("Evaluation error " + response.error + ": " +
                      response.message);
       return;
     }
@@ -3212,18 +3116,17 @@ JSTerm.prototype = {
           this.openVariablesView({
             label: VariablesView.getString(helperResult.object, { concise: true }),
             objectActor: helperResult.object,
           });
           break;
         case "error":
           try {
             errorMessage = l10n.getStr(helperResult.message);
-          }
-          catch (ex) {
+          } catch (ex) {
             errorMessage = helperResult.message;
           }
           break;
         case "help":
           this.hud.owner.openLink(HELP_URL);
           break;
         case "copyValueToClipboard":
           clipboardHelper.copyString(helperResult.value);
@@ -3274,18 +3177,17 @@ JSTerm.prototype = {
    *        The string you want to execute. If this is not provided, the current
    *        user input is used - taken from |this.getInputValue()|.
    * @param function [callback]
    *        Optional function to invoke when the result is displayed.
    *        This is deprecated - please use the promise return value instead.
    * @returns Promise
    *          Resolves with the message once the result is displayed.
    */
-  execute: function JST_execute(executeString, callback)
-  {
+  execute: function JST_execute(executeString, callback) {
     let deferred = promise.defer();
     let resultCallback = function(msg) {
       deferred.resolve(msg);
       if (callback) {
         callback(msg);
       }
     }
 
@@ -3351,25 +3253,23 @@ JSTerm.prototype = {
    *        global content window.
    *        - selectedNodeActor: tells the NodeActor ID of the current selection in
    *        the Inspector, if such a selection exists. This is used by helper
    *        functions that can evaluate on the current selection.
    * @return object
    *         A promise object that is resolved when the server response is
    *         received.
    */
-  requestEvaluation: function JST_requestEvaluation(str, options = {})
-  {
+  requestEvaluation: function JST_requestEvaluation(str, options = {}) {
     let deferred = promise.defer();
 
     function onResult(response) {
       if (!response.error) {
         deferred.resolve(response);
-      }
-      else {
+      } else {
         deferred.reject(response);
       }
     }
 
     let frameActor = null;
     if ("frame" in options) {
       frameActor = this.getFrameActor(options.frame);
     }
@@ -3388,28 +3288,26 @@ JSTerm.prototype = {
   /**
    * Retrieve the FrameActor ID given a frame depth.
    *
    * @param number frame
    *        Frame depth.
    * @return string|null
    *         The FrameActor ID for the given frame depth.
    */
-  getFrameActor: function JST_getFrameActor(frame)
-  {
+  getFrameActor: function JST_getFrameActor(frame) {
     let state = this.hud.owner.getDebuggerFrames();
     if (!state) {
       return null;
     }
 
     let grip;
     if (frame == this.SELECTED_FRAME) {
       grip = state.frames[state.selected];
-    }
-    else {
+    } else {
       grip = state.frames[frame];
     }
 
     return grip ? grip.actor : null;
   },
 
   /**
    * Opens a new variables view that allows the inspection of the given object.
@@ -3427,18 +3325,17 @@ JSTerm.prototype = {
    *        to. An iframe element is used as a container for the view. If this
    *        option is not used, then the variables view opens in the sidebar.
    *        - autofocus: optional boolean, |true| if you want to give focus to
    *        the variables view window after open, |false| otherwise.
    * @return object
    *         A promise object that is resolved when the variables view has
    *         opened. The new variables view instance is given to the callbacks.
    */
-  openVariablesView: function JST_openVariablesView(options)
-  {
+  openVariablesView: function JST_openVariablesView(options) {
     let onContainerReady = (window) => {
       let container = window.document.querySelector("#variables");
       let view = this._variablesView;
       if (!view || options.targetElement) {
         let viewOptions = {
           container: container,
           hideFilterInput: options.hideFilterInput,
         };
@@ -3471,85 +3368,79 @@ JSTerm.prototype = {
         iframe.style.visibility = "visible";
         deferred.resolve(iframe.contentWindow);
       }, true);
 
       iframe.flex = 1;
       iframe.style.visibility = "hidden";
       iframe.setAttribute("src", VARIABLES_VIEW_URL);
       options.targetElement.appendChild(iframe);
-    }
-    else {
+    } else {
       if (!this.sidebar) {
         this._createSidebar();
       }
       openPromise = this._addVariablesViewSidebarTab();
     }
 
     return openPromise.then(onContainerReady);
   },
 
   /**
    * Create the Web Console sidebar.
    *
    * @see devtools/framework/sidebar.js
    * @private
    */
-  _createSidebar: function JST__createSidebar()
-  {
+  _createSidebar: function JST__createSidebar() {
     let tabbox = this.hud.document.querySelector("#webconsole-sidebar");
     this.sidebar = new ToolSidebar(tabbox, this, "webconsole");
     this.sidebar.show();
     this.emit("sidebar-opened");
   },
 
   /**
    * Add the variables view tab to the sidebar.
    *
    * @private
    * @return object
    *         A promise object for the adding of the new tab.
    */
-  _addVariablesViewSidebarTab: function JST__addVariablesViewSidebarTab()
-  {
+  _addVariablesViewSidebarTab: function JST__addVariablesViewSidebarTab() {
     let deferred = promise.defer();
 
     let onTabReady = () => {
       let window = this.sidebar.getWindowForTab("variablesview");
       deferred.resolve(window);
     };
 
     let tabPanel = this.sidebar.getTabPanel("variablesview");
     if (tabPanel) {
       if (this.sidebar.getCurrentTabID() == "variablesview") {
         onTabReady();
-      }
-      else {
+      } else {
         this.sidebar.once("variablesview-selected", onTabReady);
         this.sidebar.select("variablesview");
       }
-    }
-    else {
+    } else {
       this.sidebar.once("variablesview-ready", onTabReady);
       this.sidebar.addTab("variablesview", VARIABLES_VIEW_URL, true);
     }
 
     return deferred.promise;
   },
 
   /**
    * The keypress event handler for the Variables View sidebar. Currently this
    * is used for removing the sidebar when Escape is pressed.
    *
    * @private
    * @param nsIDOMEvent event
    *        The keypress DOM event object.
    */
-  _onKeypressInVariablesView: function JST__onKeypressInVariablesView(event)
-  {
+  _onKeypressInVariablesView: function JST__onKeypressInVariablesView(event) {
     let tag = event.target.nodeName;
     if (event.keyCode != Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE || event.shiftKey ||
         event.altKey || event.ctrlKey || event.metaKey ||
         ["input", "textarea", "select", "textbox"].indexOf(tag) > -1) {
         return;
     }
 
     this._sidebarDestroy();
@@ -3564,18 +3455,17 @@ JSTerm.prototype = {
    * @param object options
    *        Options for the new Variables View instance:
    *        - container: the DOM element where the variables view is inserted.
    *        - hideFilterInput: boolean, if true the variables filter input is
    *        hidden.
    * @return object
    *         The new Variables View instance.
    */
-  _createVariablesView: function JST__createVariablesView(options)
-  {
+  _createVariablesView: function JST__createVariablesView(options) {
     let view = new VariablesView(options.container);
     view.toolbox = gDevTools.getToolbox(this.hud.owner.target);
     view.searchPlaceholder = l10n.getStr("propertiesFilterPlaceholder");
     view.emptyText = l10n.getStr("emptyPropertiesList");
     view.searchEnabled = !options.hideFilterInput;
     view.lazyEmpty = this._lazyVariablesView;
 
     VariablesViewController.attach(view, {
@@ -3611,51 +3501,47 @@ JSTerm.prototype = {
    * @param object options
    *        Options for updating the variables view:
    *        - view: the view you want to update.
    *        - objectActor: the grip of the new ObjectActor you want to show in
    *        the view.
    *        - rawObject: the new raw object you want to show.
    *        - label: the new label for the inspected object.
    */
-  _updateVariablesView: function JST__updateVariablesView(options)
-  {
+  _updateVariablesView: function JST__updateVariablesView(options) {
     let view = options.view;
     view.empty();
 
     // We need to avoid pruning the object inspection starting point.
     // That one is pruned when the console message is removed.
     view.controller.releaseActors(actor => {
       return view._consoleLastObjectActor != actor;
     });
 
     if (options.objectActor &&
         (!this.hud.owner._browserConsole ||
          Services.prefs.getBoolPref("devtools.chrome.enabled"))) {
       // Make sure eval works in the correct context.
       view.eval = this._variablesViewEvaluate.bind(this, options);
       view.switch = this._variablesViewSwitch.bind(this, options);
       view.delete = this._variablesViewDelete.bind(this, options);
-    }
-    else {
+    } else {
       view.eval = null;
       view.switch = null;
       view.delete = null;
     }
 
     let { variable, expanded } = view.controller.setSingleVariable(options);
     variable.evaluationMacro = simpleValueEvalMacro;
 
     if (options.objectActor) {
       view._consoleLastObjectActor = options.objectActor.actor;
-    }
-    else if (options.rawObject) {
+    } else if (options.rawObject) {
       view._consoleLastObjectActor = null;
-    }
-    else {
+    } else {
       throw new Error("Variables View cannot open without giving it an object " +
                       "display.");
     }
 
     expanded.then(() => {
       this.emit("variablesview-updated", view, options);
     });
   },
@@ -3668,18 +3554,17 @@ JSTerm.prototype = {
    * @param object options
    *        The options used for |this._updateVariablesView()|.
    * @param object variableObject
    *        The Variable object instance for the edited property.
    * @param string value
    *        The value the edited property was changed to.
    */
   _variablesViewEvaluate:
-  function JST__variablesViewEvaluate(options, variableObject, value)
-  {
+  function JST__variablesViewEvaluate(options, variableObject, value) {
     let updater = this._updateVariablesView.bind(this, options);
     let onEval = this._silentEvalCallback.bind(this, updater);
     let string = variableObject.evaluationMacro(variableObject, value);
 
     let evalOptions = {
       frame: this.SELECTED_FRAME,
       bindObjectActor: options.objectActor.actor,
     };
@@ -3692,18 +3577,17 @@ JSTerm.prototype = {
    * is deleted.
    *
    * @private
    * @param object options
    *        The options used for |this._updateVariablesView()|.
    * @param object variableObject
    *        The Variable object instance for the deleted property.
    */
-  _variablesViewDelete: function JST__variablesViewDelete(options, variableObject)
-  {
+  _variablesViewDelete: function JST__variablesViewDelete(options, variableObject) {
     let onEval = this._silentEvalCallback.bind(this, null);
 
     let evalOptions = {
       frame: this.SELECTED_FRAME,
       bindObjectActor: options.objectActor.actor,
     };
 
     this.requestEvaluation("delete _self" + variableObject.symbolicName, evalOptions)
@@ -3718,18 +3602,17 @@ JSTerm.prototype = {
    * @param object options
    *        The options used for |this._updateVariablesView()|.
    * @param object variableObject
    *        The Variable object instance for the renamed property.
    * @param string newName
    *        The new name for the property.
    */
   _variablesViewSwitch:
-  function JST__variablesViewSwitch(options, variableObject, newName)
-  {
+  function JST__variablesViewSwitch(options, variableObject, newName) {
     let updater = this._updateVariablesView.bind(this, options);
     let onEval = this._silentEvalCallback.bind(this, updater);
 
     let evalOptions = {
       frame: this.SELECTED_FRAME,
       bindObjectActor: options.objectActor.actor,
     };
 
@@ -3753,18 +3636,17 @@ JSTerm.prototype = {
    * Exceptions are displayed in the output.
    *
    * @private
    * @param function callback
    *        Function to invoke once the response is received.
    * @param object response
    *        The response packet received from the server.
    */
-  _silentEvalCallback: function JST__silentEvalCallback(callback, response)
-  {
+  _silentEvalCallback: function JST__silentEvalCallback(callback, response) {
     if (response.error) {
       Cu.reportError("Web Console evaluation failed. " + response.error + ":" +
                      response.message);
 
       callback && callback(response);
       return;
     }
 
@@ -3802,18 +3684,17 @@ JSTerm.prototype = {
    * Clear the Web Console output.
    *
    * This method emits the "messages-cleared" notification.
    *
    * @param boolean clearStorage
    *        True if you want to clear the console messages storage associated to
    *        this Web Console.
    */
-  clearOutput: function JST_clearOutput(clearStorage)
-  {
+  clearOutput: function JST_clearOutput(clearStorage) {
     let hud = this.hud;
     let outputNode = hud.outputNode;
     let node;
     while ((node = outputNode.firstChild)) {
       hud.removeOutputMessage(node);
     }
 
     hud.groupDepth = 0;
@@ -3831,32 +3712,30 @@ JSTerm.prototype = {
     this.emit("messages-cleared");
   },
 
   /**
    * Remove all of the private messages from the Web Console output.
    *
    * This method emits the "private-messages-cleared" notification.
    */
-  clearPrivateMessages: function JST_clearPrivateMessages()
-  {
+  clearPrivateMessages: function JST_clearPrivateMessages() {
     let nodes = this.hud.outputNode.querySelectorAll(".message[private]");
     for (let node of nodes) {
       this.hud.removeOutputMessage(node);
     }
     this.emit("private-messages-cleared");
   },
 
   /**
    * Updates the size of the input field (command line) to fit its contents.
    *
    * @returns void
    */
-  resizeInput: function JST_resizeInput()
-  {
+  resizeInput: function JST_resizeInput() {
     let inputNode = this.inputNode;
 
     // Reset the height so that scrollHeight will reflect the natural height of
     // the contents of the input field.
     inputNode.style.height = "auto";
 
     // Now resize the input field to fit its contents.
     let scrollHeight = inputNode.inputField.scrollHeight;
@@ -3869,68 +3748,63 @@ JSTerm.prototype = {
    * Sets the value of the input field (command line), and resizes the field to
    * fit its contents. This method is preferred over setting "inputNode.value"
    * directly, because it correctly resizes the field.
    *
    * @param string newValue
    *        The new value to set.
    * @returns void
    */
-  setInputValue: function JST_setInputValue(newValue)
-  {
+  setInputValue: function JST_setInputValue(newValue) {
     this.inputNode.value = newValue;
     this.lastInputValue = newValue;
     this.completeNode.value = "";
     this.resizeInput();
     this._inputChanged = true;
     this.emit("set-input-value");
   },
 
   /**
    * Gets the value from the input field
    * @returns string
    */
-  getInputValue: function()
-  {
+  getInputValue: function() {
     return this.inputNode.value || "";
   },
 
   /**
    * The inputNode "input" and "keyup" event handler.
    * @private
    */
-  _inputEventHandler: function JST__inputEventHandler()
-  {
+  _inputEventHandler: function JST__inputEventHandler() {
     if (this.lastInputValue != this.getInputValue()) {
       this.resizeInput();
       this.complete(this.COMPLETE_HINT_ONLY);
       this.lastInputValue = this.getInputValue();
       this._inputChanged = true;
     }
   },
 
   /**
    * The window "blur" event handler.
    * @private
    */
-  _blurEventHandler: function JST__blurEventHandler()
-  {
+  _blurEventHandler: function JST__blurEventHandler() {
     if (this.autocompletePopup) {
       this.clearCompletion();
     }
   },
 
   /**
    * The inputNode "keypress" event handler.
    *
    * @private
    * @param nsIDOMEvent event
    */
-  _keyPress: function JST__keyPress(event)
-  {
+  _keyPress: function JST__keyPress(event) {
     let inputNode = this.inputNode;
     let inputValue = this.getInputValue();
     let inputUpdated = false;
 
     if (event.ctrlKey) {
       switch (event.charCode) {
         case 101:
           // control-e
@@ -3983,106 +3857,99 @@ JSTerm.prototype = {
             inputNode.focus();
           }
           this.clearCompletion();
           break;
         default:
           break;
       }
       return;
-    }
-    else if (event.shiftKey &&
+    } else if (event.shiftKey &&
         event.keyCode == Ci.nsIDOMKeyEvent.DOM_VK_RETURN) {
       // shift return
       // TODO: expand the inputNode height by one line
       return;
     }
 
     switch (event.keyCode) {
       case Ci.nsIDOMKeyEvent.DOM_VK_ESCAPE:
         if (this.autocompletePopup.isOpen) {
           this.clearCompletion();
           event.preventDefault();
           event.stopPropagation();
-        }
-        else if (this.sidebar) {
+        } else if (this.sidebar) {
           this._sidebarDestroy();
           event.preventDefault();
           event.stopPropagation();
         }
         break;
 
       case Ci.nsIDOMKeyEvent.DOM_VK_RETURN:
         if (this._autocompletePopupNavigated &&
             this.autocompletePopup.isOpen &&
             this.autocompletePopup.selectedIndex > -1) {
           this.acceptProposedCompletion();
-        }
-        else {
+        } else {
           this.execute();
           this._inputChanged = false;
         }
         event.preventDefault();
         break;
 
       case Ci.nsIDOMKeyEvent.DOM_VK_UP:
         if (this.autocompletePopup.isOpen) {
           inputUpdated = this.complete(this.COMPLETE_BACKWARD);
           if (inputUpdated) {
             this._autocompletePopupNavigated = true;
           }
-        }
-        else if (this.canCaretGoPrevious()) {
+        } else if (this.canCaretGoPrevious()) {
           inputUpdated = this.historyPeruse(HISTORY_BACK);
         }
         if (inputUpdated) {
           event.preventDefault();
         }
         break;
 
       case Ci.nsIDOMKeyEvent.DOM_VK_DOWN:
         if (this.autocompletePopup.isOpen) {
           inputUpdated = this.complete(this.COMPLETE_FORWARD);
           if (inputUpdated) {
             this._autocompletePopupNavigated = true;
           }
-        }
-        else if (this.canCaretGoNext()) {
+        } else if (this.canCaretGoNext()) {
           inputUpdated = this.historyPeruse(HISTORY_FORWARD);
         }
         if (inputUpdated) {
           event.preventDefault();
         }
         break;
 
       case Ci.nsIDOMKeyEvent.DOM_VK_PAGE_UP:
         if (this.autocompletePopup.isOpen) {
           inputUpdated = this.complete(this.COMPLETE_PAGEUP);
           if (inputUpdated) {
             this._autocompletePopupNavigated = true;
           }
-        }
-        else {
+        } else {
           this.hud.outputWrapper.scrollTop =
             Math.max(0,
               this.hud.outputWrapper.scrollTop -
               this.hud.outputWrapper.clientHeight
             );
         }
         event.preventDefault();
         break;
 
       case Ci.nsIDOMKeyEvent.DOM_VK_PAGE_DOWN:
         if (this.autocompletePopup.isOpen) {
           inputUpdated = this.complete(this.COMPLETE_PAGEDOWN);
           if (inputUpdated) {
             this._autocompletePopupNavigated = true;
           }
-        }
-        else {
+        } else {
           this.hud.outputWrapper.scrollTop =
             Math.min(this.hud.outputWrapper.scrollHeight,
               this.hud.outputWrapper.scrollTop +
               this.hud.outputWrapper.clientHeight
             );
         }
         event.preventDefault();
         break;
@@ -4133,47 +4000,44 @@ JSTerm.prototype = {
         break;
       }
       case Ci.nsIDOMKeyEvent.DOM_VK_TAB:
         // Generate a completion and accept the first proposed value.
         if (this.complete(this.COMPLETE_HINT_ONLY) &&
             this.lastCompletion &&
             this.acceptProposedCompletion()) {
           event.preventDefault();
-        }
-        else if (this._inputChanged) {
+        } else if (this._inputChanged) {
           this.updateCompleteNode(l10n.getStr("Autocomplete.blank"));
           event.preventDefault();
         }
         break;
       default:
         break;
     }
   },
 
   /**
    * The inputNode "focus" event handler.
    * @private
    */
-  _focusEventHandler: function JST__focusEventHandler()
-  {
+  _focusEventHandler: function JST__focusEventHandler() {
     this._inputChanged = false;
   },
 
   /**
    * Go up/down the history stack of input values.
    *
    * @param number direction
    *        History navigation direction: HISTORY_BACK or HISTORY_FORWARD.
    *
    * @returns boolean
    *          True if the input value changed, false otherwise.
    */
-  historyPeruse: function JST_historyPeruse(direction)
-  {
+  historyPeruse: function JST_historyPeruse(direction) {
     if (!this.history.length) {
       return false;
     }
 
     // Up Arrow key
     if (direction == HISTORY_BACK) {
       if (this.historyPlaceHolder <= 0) {
         return false;
@@ -4184,55 +4048,51 @@ JSTerm.prototype = {
       // the user is already at the last entry.
       // Note: this code does not store changes to items that are already in
       // history.
       if (this.historyPlaceHolder+1 == this.historyIndex) {
         this.history[this.historyIndex] = this.getInputValue() || "";
       }
 
       this.setInputValue(inputVal);
-    }
-    // Down Arrow key
-    else if (direction == HISTORY_FORWARD) {
+    } else if (direction == HISTORY_FORWARD) {
+      // Down Arrow key
       if (this.historyPlaceHolder >= (this.history.length-1)) {
         return false;
       }
 
       let inputVal = this.history[++this.historyPlaceHolder];
       this.setInputValue(inputVal);
-    }
-    else {
+    } else {
       throw new Error("Invalid argument 0");
     }
 
     return true;
   },
 
   /**
    * Test for multiline input.
    *
    * @return boolean
    *         True if CR or LF found in node value; else false.
    */
-  hasMultilineInput: function JST_hasMultilineInput()
-  {
+  hasMultilineInput: function JST_hasMultilineInput() {
     return /[\r\n]/.test(this.getInputValue());
   },
 
   /**
    * Check if the caret is at a location that allows selecting the previous item
    * in history when the user presses the Up arrow key.
    *
    * @return boolean
    *         True if the caret is at a location that allows selecting the
    *         previous item in history when the user presses the Up arrow key,
    *         otherwise false.
    */
-  canCaretGoPrevious: function JST_canCaretGoPrevious()
-  {
+  canCaretGoPrevious: function JST_canCaretGoPrevious() {
     let node = this.inputNode;
     if (node.selectionStart != node.selectionEnd) {
       return false;
     }
 
     let multiline = /[\r\n]/.test(node.value);
     return node.selectionStart == 0 ? true :
            node.selectionStart == node.value.length && !multiline;
@@ -4242,18 +4102,17 @@ JSTerm.prototype = {
    * Check if the caret is at a location that allows selecting the next item in
    * history when the user presses the Down arrow key.
    *
    * @return boolean
    *         True if the caret is at a location that allows selecting the next
    *         item in history when the user presses the Down arrow key, otherwise
    *         false.
    */
-  canCaretGoNext: function JST_canCaretGoNext()
-  {
+  canCaretGoNext: function JST_canCaretGoNext() {
     let node = this.inputNode;
     if (node.selectionStart != node.selectionEnd) {
       return false;
     }
 
     let multiline = /[\r\n]/.test(node.value);
     return node.selectionStart == node.value.length ? true :
            node.selectionStart == 0 && !multiline;
@@ -4287,18 +4146,17 @@ JSTerm.prototype = {
    *          the this.getInputValue() is set to this value and the selection is set
    *          from the current cursor position to the end of the completed text.
    * @param function callback
    *        Optional function invoked when the autocomplete properties are
    *        updated.
    * @returns boolean true if there existed a completion for the current input,
    *          or false otherwise.
    */
-  complete: function JSTF_complete(type, callback)
-  {
+  complete: function JSTF_complete(type, callback) {
     let inputNode = this.inputNode;
     let inputValue = this.getInputValue();
     let frameActor = this.getFrameActor(this.SELECTED_FRAME);
 
     // If the inputNode has no value, then don't try to complete on it.
     if (!inputValue) {
       this.clearCompletion();
       callback && callback(this);
@@ -4321,27 +4179,23 @@ JSTerm.prototype = {
     }
 
     let popup = this.autocompletePopup;
     let accepted = false;
 
     if (type != this.COMPLETE_HINT_ONLY && popup.itemCount == 1) {
       this.acceptProposedCompletion();
       accepted = true;
-    }
-    else if (type == this.COMPLETE_BACKWARD) {
+    } else if (type == this.COMPLETE_BACKWARD) {
       popup.selectPreviousItem();
-    }
-    else if (type == this.COMPLETE_FORWARD) {
+    } else if (type == this.COMPLETE_FORWARD) {
       popup.selectNextItem();
-    }
-    else if (type == this.COMPLETE_PAGEUP) {
+    } else if (type == this.COMPLETE_PAGEUP) {
       popup.selectPreviousPageItem();
-    }
-    else if (type == this.COMPLETE_PAGEDOWN) {
+    } else if (type == this.COMPLETE_PAGEDOWN) {
       popup.selectNextPageItem();
     }
 
     callback && callback(this);
     this.emit("autocomplete-updated");
     return accepted || popup.itemCount > 0;
   },
 
@@ -4351,18 +4205,17 @@ JSTerm.prototype = {
    *
    * @private
    * @param int type
    *        Completion type. See this.complete() for details.
    * @param function [callback]
    *        Optional, function to invoke when completion results are received.
    */
   _updateCompletionResult:
-  function JST__updateCompletionResult(type, callback)
-  {
+  function JST__updateCompletionResult(type, callback) {
     let frameActor = this.getFrameActor(this.SELECTED_FRAME);
     if (this.lastCompletion.value == this.getInputValue() &&
         frameActor == this._lastFrameActorId) {
       return;
     }
 
     let requestId = gSequenceId();
     let cursor = this.inputNode.selectionStart;
@@ -4428,18 +4281,17 @@ JSTerm.prototype = {
    *        Request ID.
    * @param function [callback=null]
    *        Optional, function to invoke when the completion result is received.
    * @param object message
    *        The JSON message which holds the completion results received from
    *        the content process.
    */
   _receiveAutocompleteProperties:
-  function JST__receiveAutocompleteProperties(requestId, callback, message)
-  {
+  function JST__receiveAutocompleteProperties(requestId, callback, message) {
     let inputNode = this.inputNode;
     let inputValue = this.getInputValue();
     if (this.lastCompletion.value == inputValue ||
         requestId != this.lastCompletion.requestId) {
       return;
     }
     // Cache whatever came from the server if the last char is alphanumeric or '.'
     let cursor = inputNode.selectionStart;
@@ -4473,84 +4325,77 @@ JSTerm.prototype = {
     };
 
     if (items.length > 1 && !popup.isOpen) {
       let str = this.getInputValue().substr(0, this.inputNode.selectionStart);
       let offset = str.length - (str.lastIndexOf("\n") + 1) - lastPart.length;
       let x = offset * this.hud._inputCharWidth;
       popup.openPopup(inputNode, x + this.hud._chevronWidth);
       this._autocompletePopupNavigated = false;
-    }
-    else if (items.length < 2 && popup.isOpen) {
+    } else if (items.length < 2 && popup.isOpen) {
       popup.hidePopup();
       this._autocompletePopupNavigated = false;
     }
 
     if (items.length == 1) {
       popup.selectedIndex = 0;
     }
 
     this.onAutocompleteSelect();
 
     if (completionType != this.COMPLETE_HINT_ONLY && popup.itemCount == 1) {
       this.acceptProposedCompletion();
-    }
-    else if (completionType == this.COMPLETE_BACKWARD) {
+    } else if (completionType == this.COMPLETE_BACKWARD) {
       popup.selectPreviousItem();
-    }
-    else if (completionType == this.COMPLETE_FORWARD) {
+    } else if (completionType == this.COMPLETE_FORWARD) {
       popup.selectNextItem();
     }
 
     callback && callback(this);
     this.emit("autocomplete-updated");
   },
 
-  onAutocompleteSelect: function JSTF_onAutocompleteSelect()
-  {
+  onAutocompleteSelect: function JSTF_onAutocompleteSelect() {
     // Render the suggestion only if the cursor is at the end of the input.
     if (this.inputNode.selectionStart != this.getInputValue().length) {
       return;
     }
 
     let currentItem = this.autocompletePopup.selectedItem;
     if (currentItem && this.lastCompletion.value) {
       let suffix = currentItem.label.substring(this.lastCompletion.
                                                matchProp.length);
       this.updateCompleteNode(suffix);
-    }
-    else {
+    } else {
       this.updateCompleteNode("");
     }
   },
 
   /**
    * Clear the current completion information and close the autocomplete popup,
    * if needed.
    */
-  clearCompletion: function JSTF_clearCompletion()
-  {
+  clearCompletion: function JSTF_clearCompletion() {
     this.autocompletePopup.clearItems();
     this.lastCompletion = { value: null };
     this.updateCompleteNode("");
     if (this.autocompletePopup.isOpen) {
       this.autocompletePopup.hidePopup();
       this._autocompletePopupNavigated = false;
     }
   },
 
   /**
    * Accept the proposed input completion.
    *
    * @return boolean
    *         True if there was a selected completion item and the input value
    *         was updated, false otherwise.
    */
-  acceptProposedCompletion: function JSTF_acceptProposedCompletion()
-  {
+  acceptProposedCompletion: function JSTF_acceptProposedCompletion() {
     let updated = false;
 
     let currentItem = this.autocompletePopup.selectedItem;
     if (currentItem && this.lastCompletion.value) {
       let suffix = currentItem.label.substring(this.lastCompletion.
                                                matchProp.length);
       let cursor = this.inputNode.selectionStart;
       let value = this.getInputValue();
@@ -4566,30 +4411,28 @@ JSTerm.prototype = {
   },
 
   /**
    * Update the node that displays the currently selected autocomplete proposal.
    *
    * @param string suffix
    *        The proposed suffix for the inputNode value.
    */
-  updateCompleteNode: function JSTF_updateCompleteNode(suffix)
-  {
+  updateCompleteNode: function JSTF_updateCompleteNode(suffix) {
     // completion prefix = input, with non-control chars replaced by spaces
     let prefix = suffix ? this.getInputValue().replace(/[\S]/g, " ") : "";
     this.completeNode.value = prefix + suffix;
   },
 
 
   /**
    * Destroy the sidebar.
    * @private
    */
-  _sidebarDestroy: function JST__sidebarDestroy()
-  {
+  _sidebarDestroy: function JST__sidebarDestroy() {
     if (this._variablesView) {
       this._variablesView.controller.releaseActors();
       this._variablesView = null;
     }
 
     if (this.sidebar) {
       this.sidebar.hide();
       this.sidebar.destroy();
@@ -4597,18 +4440,17 @@ JSTerm.prototype = {
     }
 
     this.emit("sidebar-closed");
   },
 
   /**
    * Destroy the JSTerm object. Call this method to avoid memory leaks.
    */
-  destroy: function JST_destroy()
-  {
+  destroy: function JST_destroy() {
     this._sidebarDestroy();
 
     this.clearCompletion();
     this.clearOutput();
 
     this.autocompletePopup.destroy();
     this.autocompletePopup = null;
 
@@ -4640,49 +4482,46 @@ JSTerm.prototype = {
 var Utils = {
   /**
    * Scrolls a node so that it's visible in its containing element.
    *
    * @param nsIDOMNode node
    *        The node to make visible.
    * @returns void
    */
-  scrollToVisible: function Utils_scrollToVisible(node)
-  {
+  scrollToVisible: function Utils_scrollToVisible(node) {
     node.scrollIntoView(false);
   },
 
   /**
    * Check if the given output node is scrolled to the bottom.
    *
    * @param nsIDOMNode outputNode
    * @param nsIDOMNode scrollNode
    * @return boolean
    *         True if the output node is scrolled to the bottom, or false
    *         otherwise.
    */
-  isOutputScrolledToBottom: function (outputNode, scrollNode)
-  {
+  isOutputScrolledToBottom: function (outputNode, scrollNode) {
     let lastNodeHeight = outputNode.lastChild ?
                          outputNode.lastChild.clientHeight : 0;
     return scrollNode.scrollTop + scrollNode.clientHeight >=
            scrollNode.scrollHeight - lastNodeHeight / 2;
   },
 
   /**
    * Determine the category of a given nsIScriptError.
    *
    * @param nsIScriptError scriptError
    *        The script error you want to determine the category for.
    * @return CATEGORY_JS|CATEGORY_CSS|CATEGORY_SECURITY
    *         Depending on the script error CATEGORY_JS, CATEGORY_CSS, or
    *         CATEGORY_SECURITY can be returned.
    */
-  categoryForScriptError: function Utils_categoryForScriptError(scriptError)
-  {
+  categoryForScriptError: function Utils_categoryForScriptError(scriptError) {
     let category = scriptError.category;
 
     if (/^(?:CSS|Layout)\b/.test(category)) {
       return CATEGORY_CSS;
     }
 
     switch (category) {
       case "Mixed Content Blocker":
@@ -4708,84 +4547,75 @@ var Utils = {
    * Retrieve the limit of messages for a specific category.
    *
    * @param number category
    *        The category of messages you want to retrieve the limit for. See the
    *        CATEGORY_* constants.
    * @return number
    *         The number of messages allowed for the specific category.
    */
-  logLimitForCategory: function Utils_logLimitForCategory(category)
-  {
+  logLimitForCategory: function Utils_logLimitForCategory(category) {
     let logLimit = DEFAULT_LOG_LIMIT;
 
     try {
       let prefName = CATEGORY_CLASS_FRAGMENTS[category];
       logLimit = Services.prefs.getIntPref("devtools.hud.loglimit." + prefName);
       logLimit = Math.max(logLimit, 1);
-    }
-    catch (e) { }
+    } catch (e) { }
 
     return logLimit;
   },
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 // CommandController
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
  * A controller (an instance of nsIController) that makes editing actions
  * behave appropriately in the context of the Web Console.
  */
-function CommandController(webConsole)
-{
+function CommandController(webConsole) {
   this.owner = webConsole;
 }
 
 CommandController.prototype = {
   /**
    * Selects all the text in the HUD output.
    */
-  selectAll: function CommandController_selectAll()
-  {
+  selectAll: function CommandController_selectAll() {
     this.owner.output.selectAllMessages();
   },
 
   /**
    * Open the URL of the selected message in a new tab.
    */
-  openURL: function CommandController_openURL()
-  {
+  openURL: function CommandController_openURL() {
     this.owner.openSelectedItemInTab();
   },
 
-  copyURL: function CommandController_copyURL()
-  {
+  copyURL: function CommandController_copyURL() {
     this.owner.copySelectedItems({ linkOnly: true, contextmenu: true });
   },
 
   /**
    * Copies the last clicked message.
    */
-  copyLastClicked: function CommandController_copy()
-  {
+  copyLastClicked: function CommandController_copy() {
     this.owner.copySelectedItems({ linkOnly: false, contextmenu: true });
   },
 
-  supportsCommand: function CommandController_supportsCommand(command)
-  {
+  supportsCommand: function CommandController_supportsCommand(command) {
     if (!this.owner || !this.owner.output) {
       return false;
     }
     return this.isCommandEnabled(command);
   },
 
-  isCommandEnabled: function CommandController_isCommandEnabled(command)
-  {
+  isCommandEnabled: function CommandController_isCommandEnabled(command) {
     switch (command) {
       case "consoleCmd_openURL":
       case "consoleCmd_copyURL": {
         // Only enable URL-related actions if node is Net Activity.
         let selectedItem = this.owner.output.getSelectedMessages(1)[0] ||
                            this.owner._contextMenuHandler.lastClickedMessage;
         return selectedItem && "url" in selectedItem;
       }
@@ -4803,18 +4633,17 @@ CommandController.prototype = {
       case "cmd_fontSizeReduce":
       case "cmd_fontSizeReset":
       case "cmd_close":
         return this.owner.owner._browserConsole;
     }
     return false;
   },
 
-  doCommand: function CommandController_doCommand(command)
-  {
+  doCommand: function CommandController_doCommand(command) {
     switch (command) {
       case "consoleCmd_openURL":
         this.openURL();
         break;
       case "consoleCmd_copyURL":
         this.copyURL();
         break;
       case "consoleCmd_clearOutput":
@@ -4854,18 +4683,17 @@ CommandController.prototype = {
  * and the application we connect to through the remote debug protocol.
  *
  * @constructor
  * @param object webConsoleFrame
  *        The WebConsoleFrame object that owns this connection proxy.
  * @param RemoteTarget target
  *        The target that the console will connect to.
  */
-function WebConsoleConnectionProxy(webConsoleFrame, target)
-{
+function WebConsoleConnectionProxy(webConsoleFrame, target) {
   this.webConsoleFrame = webConsoleFrame;
   this.target = target;
 
   this._onPageError = this._onPageError.bind(this);
   this._onLogMessage = this._onLogMessage.bind(this);
   this._onConsoleAPICall = this._onConsoleAPICall.bind(this);
   this._onNetworkEvent = this._onNetworkEvent.bind(this);
   this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
@@ -4944,18 +4772,17 @@ WebConsoleConnectionProxy.prototype = {
 
   /**
    * Initialize a debugger client and connect it to the debugger server.
    *
    * @return object
    *         A promise object that is resolved/rejected based on the success of
    *         the connection initialization.
    */
-  connect: function WCCP_connect()
-  {
+  connect: function WCCP_connect() {
     if (this._connectDefer) {
       return this._connectDefer.promise;
     }
 
     this._connectDefer = promise.defer();
 
     let timeout = Services.prefs.getIntPref(PREF_CONNECTION_TIMEOUT);
     this._connectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
@@ -4995,50 +4822,47 @@ WebConsoleConnectionProxy.prototype = {
 
     return connPromise;
   },
 
   /**
    * Connection timeout handler.
    * @private
    */
-  _connectionTimeout: function WCCP__connectionTimeout()
-  {
+  _connectionTimeout: function WCCP__connectionTimeout() {
     let error = {
       error: "timeout",
       message: l10n.getStr("connectionTimeout"),
     };
 
     this._connectDefer.reject(error);
   },
 
   /**
    * Attach to the Web Console actor.
    * @private
    */
-  _attachConsole: function WCCP__attachConsole()
-  {
+  _attachConsole: function WCCP__attachConsole() {
     let listeners = ["PageError", "ConsoleAPI", "NetworkActivity",
                      "FileActivity"];
     this.client.attachConsole(this._consoleActor, listeners,
                               this._onAttachConsole);
   },
 
   /**
    * The "attachConsole" response handler.
    *
    * @private
    * @param object response
    *        The JSON response object received from the server.
    * @param object webConsoleClient
    *        The WebConsoleClient instance for the attached console, for the
    *        specific tab we work with.
    */
-  _onAttachConsole: function WCCP__onAttachConsole(response, webConsoleClient)
-  {
+  _onAttachConsole: function WCCP__onAttachConsole(response, webConsoleClient) {
     if (response.error) {
       Cu.reportError("attachConsole failed: " + response.error + " " +
                      response.message);
       this._connectDefer.reject(response);
       return;
     }
 
     this.webConsoleClient = webConsoleClient;
@@ -5060,18 +4884,17 @@ WebConsoleConnectionProxy.prototype = {
 
   /**
    * The "cachedMessages" response handler.
    *
    * @private
    * @param object response
    *        The JSON response object received from the server.
    */
-  _onCachedMessages: function WCCP__onCachedMessages(response)
-  {
+  _onCachedMessages: function WCCP__onCachedMessages(response) {
     if (response.error) {
       Cu.reportError("Web Console getCachedMessages error: " + response.error +
                      " " + response.message);
       this._connectDefer.reject(response);
       return;
     }
 
     if (!this._connectTimer) {
@@ -5098,69 +4921,65 @@ WebConsoleConnectionProxy.prototype = {
    * for displaying.
    *
    * @private
    * @param string type
    *        Message type.
    * @param object packet
    *        The message received from the server.
    */
-  _onPageError: function WCCP__onPageError(type, packet)
-  {
+  _onPageError: function WCCP__onPageError(type, packet) {
     if (this.webConsoleFrame && packet.from == this._consoleActor) {
       this.webConsoleFrame.handlePageError(packet.pageError);
     }
   },
 
   /**
    * The "logMessage" message type handler. We redirect any message to the UI
    * for displaying.
    *
    * @private
    * @param string type
    *        Message type.
    * @param object packet
    *        The message received from the server.
    */
-  _onLogMessage: function WCCP__onLogMessage(type, packet)
-  {
+  _onLogMessage: function WCCP__onLogMessage(type, packet) {
     if (this.webConsoleFrame && packet.from == this._consoleActor) {
       this.webConsoleFrame.handleLogMessage(packet);
     }
   },
 
   /**
    * The "consoleAPICall" message type handler. We redirect any message to
    * the UI for displaying.
    *
    * @private
    * @param string type
    *        Message type.
    * @param object packet
    *        The message received from the server.
    */
-  _onConsoleAPICall: function WCCP__onConsoleAPICall(type, packet)
-  {
+  _onConsoleAPICall: function WCCP__onConsoleAPICall(type, packet) {
     if (this.webConsoleFrame && packet.from == this._consoleActor) {
       this.webConsoleFrame.handleConsoleAPICall(packet.message);
     }
   },
 
   /**
    * The "networkEvent" message type handler. We redirect any message to
    * the UI for displaying.
    *
    * @private
    * @param string type
    *        Message type.
    * @param object networkInfo
    *        The network request information.
    */
-  _onNetworkEvent: function(type, networkInfo)
-  {
+  _onNetworkEvent: function(type, networkInfo) {
     if (this.webConsoleFrame) {
       this.webConsoleFrame.handleNetworkEvent(networkInfo);
     }
   },
 
   /**
    * The "networkEventUpdate" message type handler. We redirect any message to
    * the UI for displaying.
@@ -5168,122 +4987,114 @@ WebConsoleConnectionProxy.prototype = {
    * @private
    * @param string type
    *        Message type.
    * @param object packet
    *        The message received from the server.
    * @param object networkInfo
    *        The network request information.
    */
-  _onNetworkEventUpdate: function(type, { packet, networkInfo })
-  {
+  _onNetworkEventUpdate: function(type, { packet, networkInfo }) {
     if (this.webConsoleFrame) {
       this.webConsoleFrame.handleNetworkEventUpdate(networkInfo, packet);
     }
   },
 
   /**
    * The "fileActivity" message type handler. We redirect any message to
    * the UI for displaying.
    *
    * @private
    * @param string type
    *        Message type.
    * @param object packet
    *        The message received from the server.
    */
-  _onFileActivity: function WCCP__onFileActivity(type, packet)
-  {
+  _onFileActivity: function WCCP__onFileActivity(type, packet) {
     if (this.webConsoleFrame && packet.from == this._consoleActor) {
       this.webConsoleFrame.handleFileActivity(packet.uri);
     }
   },
 
-  _onReflowActivity: function WCCP__onReflowActivity(type, packet)
-  {
+  _onReflowActivity: function WCCP__onReflowActivity(type, packet) {
     if (this.webConsoleFrame && packet.from == this._consoleActor) {
       this.webConsoleFrame.handleReflowActivity(packet);
     }
   },
 
   /**
    * The "serverLogCall" message type handler. We redirect any message to
    * the UI for displaying.
    *
    * @private
    * @param string type
    *        Message type.
    * @param object packet
    *        The message received from the server.
    */
-  _onServerLogCall: function WCCP__onServerLogCall(type, packet)
-  {
+  _onServerLogCall: function WCCP__onServerLogCall(type, packet) {
     if (this.webConsoleFrame && packet.from == this._consoleActor) {
       this.webConsoleFrame.handleConsoleAPICall(packet.message);
     }
   },
 
   /**
    * The "lastPrivateContextExited" message type handler. When this message is
    * received the Web Console UI is cleared.
    *
    * @private
    * @param string type
    *        Message type.
    * @param object packet
    *        The message received from the server.
    */
   _onLastPrivateContextExited:
-  function WCCP__onLastPrivateContextExited(type, packet)
-  {
+  function WCCP__onLastPrivateContextExited(type, packet) {
     if (this.webConsoleFrame && packet.from == this._consoleActor) {
       this.webConsoleFrame.jsterm.clearPrivateMessages();
     }
   },
 
   /**
    * The "will-navigate" and "navigate" event handlers. We redirect any message
    * to the UI for displaying.
    *
    * @private
    * @param string event
    *        Event type.
    * @param object packet
    *        The message received from the server.
    */
-  _onTabNavigated: function WCCP__onTabNavigated(event, packet)
-  {
+  _onTabNavigated: function WCCP__onTabNavigated(event, packet) {
     if (!this.webConsoleFrame) {
       return;
     }
 
     this.webConsoleFrame.handleTabNavigated(event, packet);
   },
 
   /**
    * Release an object actor.
    *
    * @param string actor
    *        The actor ID to send the request to.
    */
-  releaseActor: function WCCP_releaseActor(actor)
-  {
+  releaseActor: function WCCP_releaseActor(actor) {
     if (this.client) {
       this.client.release(actor);
     }
   },
 
   /**
    * Disconnect the Web Console from the remote server.
    *
    * @return object
    *         A promise object that is resolved when disconnect completes.
    */
-  disconnect: function WCCP_disconnect()
-  {
+  disconnect: function WCCP_disconnect() {
     if (this._disconnecter) {
       return this._disconnecter.promise;
     }
 
     this._disconnecter = promise.defer();
 
     if (!this.client) {
       this._disconnecter.resolve(null);
@@ -5308,65 +5119,61 @@ WebConsoleConnectionProxy.prototype = {
     this.connected = false;
     this.webConsoleFrame = null;
     this._disconnecter.resolve(null);
 
     return this._disconnecter.promise;
   },
 };
 
-function gSequenceId()
-{
+function gSequenceId() {
   return gSequenceId.n++;
 }
 gSequenceId.n = 0;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Context Menu
 ///////////////////////////////////////////////////////////////////////////////
 
 /*
  * ConsoleContextMenu this used to handle the visibility of context menu items.
  *
  * @constructor
  * @param object owner
  *        The WebConsoleFrame instance that owns this object.
  */
-function ConsoleContextMenu(owner)
-{
+function ConsoleContextMenu(owner) {
   this.owner = owner;
   this.popup = this.owner.document.getElementById("output-contextmenu");
   this.build = this.build.bind(this);
   this.popup.addEventListener("popupshowing", this.build);
 }
 
 ConsoleContextMenu.prototype = {
   lastClickedMessage: null,
 
   /*
    * Handle to show/hide context menu item.
    */
-  build: function CCM_build(event)
-  {
+  build: function CCM_build(event) {
     let metadata = this.getSelectionMetadata(event.rangeParent);
     for (let element of this.popup.children) {
       element.hidden = this.shouldHideMenuItem(element, metadata);
     }
   },
 
   /*
    * Get selection information from the view.
    *
    * @param nsIDOMElement clickElement
    *        The DOM element the user clicked on.
    * @return object
    *         Selection metadata.
    */
-  getSelectionMetadata: function CCM_getSelectionMetadata(clickElement)
-  {
+  getSelectionMetadata: function CCM_getSelectionMetadata(clickElement) {
     let metadata = {
       selectionType: "",
       selection: new Set(),
     };
     let selectedItems = this.owner.output.getSelectedMessages();
     if (!selectedItems.length) {
       let clickedItem = this.owner.output.getMessageForElement(clickElement);
       if (clickedItem) {
@@ -5404,18 +5211,17 @@ ConsoleContextMenu.prototype = {
   /*
    * Determine if an item should be hidden.
    *
    * @param nsIDOMElement menuItem
    * @param object metadata
    * @return boolean
    *         Whether the given item should be hidden or not.
    */
-  shouldHideMenuItem: function CCM_shouldHideMenuItem(menuItem, metadata)
-  {
+  shouldHideMenuItem: function CCM_shouldHideMenuItem(menuItem, metadata) {
     let selectionType = menuItem.getAttribute("selectiontype");
     if (selectionType && !metadata.selectionType == selectionType) {
       return true;
     }
 
     let selection = menuItem.getAttribute("selection");
     if (!selection) {
       return false;
@@ -5432,16 +5238,15 @@ ConsoleContextMenu.prototype = {
     }
 
     return shouldHide;
   },
 
   /**
    * Destroy the ConsoleContextMenu object instance.
    */
-  destroy: function CCM_destroy()
-  {
+  destroy: function CCM_destroy() {
     this.popup.removeEventListener("popupshowing", this.build);
     this.popup = null;
     this.owner = null;
     this.lastClickedMessage = null;
   },
 };
--- a/mobile/android/search/java/org/mozilla/search/PostSearchFragment.java
+++ b/mobile/android/search/java/org/mozilla/search/PostSearchFragment.java
@@ -129,17 +129,17 @@ public class PostSearchFragment extends 
 
             try {
                 // If the url URI does not have an intent scheme, the intent data will be the entire
                 // URI and its action will be ACTION_VIEW.
                 final Intent i = Intent.parseUri(url, Intent.URI_INTENT_SCHEME);
 
                 // If the intent URI didn't specify a package, open this in Fennec.
                 if (i.getPackage() == null) {
-                    i.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
+                    i.setClassName(view.getContext().getPackageName(), AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
                     Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL,
                             TelemetryContract.Method.CONTENT, "search-result");
                 } else {
                     Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH,
                             TelemetryContract.Method.INTENT, "search-result");
                 }
 
                 i.addCategory(Intent.CATEGORY_BROWSABLE);
--- a/mobile/android/search/java/org/mozilla/search/SearchWidget.java
+++ b/mobile/android/search/java/org/mozilla/search/SearchWidget.java
@@ -62,33 +62,33 @@ public class SearchWidget extends AppWid
 
     @Override
     public void onReceive(final Context context, final Intent intent) {
         // This will hold the intent to redispatch.
         final Intent redirect;
         switch (intent.getAction()) {
             case ACTION_LAUNCH_BROWSER:
                 redirect = buildRedirectIntent(Intent.ACTION_MAIN,
-                                               AppConstants.ANDROID_PACKAGE_NAME,
+                                               context.getPackageName(),
                                                AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS,
                                                intent);
                 Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH,
                                       TelemetryContract.Method.WIDGET, "browser");
                 break;
             case ACTION_LAUNCH_NEW_TAB:
                 redirect = buildRedirectIntent(Intent.ACTION_VIEW,
-                                               AppConstants.ANDROID_PACKAGE_NAME,
+                                               context.getPackageName(),
                                                AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS,
                                                intent);
                 Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH,
                                       TelemetryContract.Method.WIDGET, "new-tab");
                 break;
             case ACTION_LAUNCH_SEARCH:
                 redirect = buildRedirectIntent(Intent.ACTION_VIEW,
-                                               AppConstants.ANDROID_PACKAGE_NAME,
+                                               context.getPackageName(),
                                                AppConstants.MOZ_ANDROID_SEARCH_INTENT_CLASS,
                                                intent);
                 Telemetry.sendUIEvent(TelemetryContract.Event.LAUNCH,
                                       TelemetryContract.Method.WIDGET, "search");
                 break;
             default:
                 redirect = null;
         }
--- a/toolkit/mozapps/extensions/content/extensions.xul
+++ b/toolkit/mozapps/extensions/content/extensions.xul
@@ -180,16 +180,17 @@
                  value="&updates.installed.label;"/>
           <label id="updates-downloaded" hidden="true"
                  value="&updates.downloaded.label;"/>
           <button id="updates-restart-btn" class="button-link" hidden="true"
                   label="&updates.restart.label;"
                   command="cmd_restartApp"/>
         </hbox>
         <button id="show-disabled-unsigned-extensions" hidden="true"
+                class="warning"
                 label="&showUnsignedExtensions.button.label;"
                 command="cmd_showUnsignedExtensions"/>
         <toolbarbutton id="header-utils-btn" class="header-button" type="menu"
                 tooltiptext="&toolsMenu.tooltip;">
           <menupopup id="utils-menu">
             <menuitem id="utils-updateNow"
                       label="&updates.checkForUpdates.label;"
                       accesskey="&updates.checkForUpdates.accesskey;"
--- a/toolkit/themes/shared/extensions/extensions.inc.css
+++ b/toolkit/themes/shared/extensions/extensions.inc.css
@@ -129,16 +129,21 @@
 }
 
 .loading {
   list-style-image: url("chrome://global/skin/icons/loading_16.png");
   padding-left: 20px;
   padding-right: 20px;
 }
 
+button.warning {
+  list-style-image: url("chrome://mozapps/skin/extensions/alerticon-warning.svg");
+  list-stye-position: inside;
+}
+
 
 /*** category selector ***/
 
 #categories {
   padding-top: 0;
 }
 
 .category[selected="true"]:hover {