Merge m-c to fx-team
authorPanos Astithas <past@mozilla.com>
Sat, 05 Jan 2013 11:41:23 +0200
changeset 117754 d8ca3e1c469e5bc0f935ff74ef333f0a9a2b2888
parent 117736 3077141dd57fe885707a430b1f1e3a071ad4b71d (current diff)
parent 117753 2593683be851db2453867f382bdbd11cc9b895d8 (diff)
child 117755 cbe35d7e9a1ca62990a93f7a552a7a211665f89f
child 117902 90adcb5c0a81d1048d7563ffa4e720033ba10784
push id20674
push usereakhgari@mozilla.com
push dateSat, 05 Jan 2013 21:00:50 +0000
treeherdermozilla-inbound@9512633daa20 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone20.0a1
first release with
nightly linux32
d8ca3e1c469e / 20.0a1 / 20130105030839 / files
nightly linux64
d8ca3e1c469e / 20.0a1 / 20130105030839 / files
nightly mac
d8ca3e1c469e / 20.0a1 / 20130105030839 / files
nightly win32
d8ca3e1c469e / 20.0a1 / 20130105030839 / files
nightly win64
d8ca3e1c469e / 20.0a1 / 20130105030839 / 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 m-c to fx-team
browser/base/content/browser.js
browser/base/content/browser.xul
browser/devtools/commandline/CmdAddon.jsm
browser/devtools/commandline/CmdBreak.jsm
browser/devtools/commandline/CmdCalllog.jsm
browser/devtools/commandline/CmdCalllogChrome.jsm
browser/devtools/commandline/CmdCmd.jsm
browser/devtools/commandline/CmdConsole.jsm
browser/devtools/commandline/CmdCookie.jsm
browser/devtools/commandline/CmdDbg.jsm
browser/devtools/commandline/CmdEcho.jsm
browser/devtools/commandline/CmdExport.jsm
browser/devtools/commandline/CmdJsb.jsm
browser/devtools/commandline/CmdPagemod.jsm
browser/devtools/commandline/CmdRestart.jsm
browser/devtools/commandline/CmdScreenshot.jsm
browser/devtools/profiler/cleopatra/images/filter.png
browser/devtools/profiler/cleopatra/images/showall.png
browser/locales/en-US/chrome/browser/browser.dtd
browser/themes/gnomestripe/browser.css
browser/themes/pinstripe/browser.css
browser/themes/winstripe/browser.css
js/src/jscompartment.h
js/src/vm/Debugger.cpp
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -560,17 +560,17 @@
 #endif
               <menuseparator id="devToolsSeparator"/>
               <menu id="webDeveloperMenu"
                     label="&webDeveloperMenu.label;"
                     accesskey="&webDeveloperMenu.accesskey;">
                 <menupopup id="menuWebDeveloperPopup">
                   <menuitem id="menu_devToolbox"
                             observes="devtoolsMenuBroadcaster_DevToolbox"
-                            accesskey="&devToolbox.accesskey;"/>
+                            accesskey="&devToolboxMenuItem.accesskey;"/>
                   <menuseparator id="menu_devtools_separator"/>
                   <menuitem id="menu_devToolbar"
                             observes="devtoolsMenuBroadcaster_DevToolbar"
                             accesskey="&devToolbarMenu.accesskey;"/>
                   <menuitem id="menu_chromeDebugger"
                             observes="devtoolsMenuBroadcaster_ChromeDebugger"/>
                   <menuitem id="menu_responsiveUI"
                             observes="devtoolsMenuBroadcaster_ResponsiveUI"
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -169,17 +169,17 @@
     <broadcaster id="sync-syncnow-state"/>
 #endif
     <broadcaster id="workOfflineMenuitemState"/>
     <broadcaster id="socialSidebarBroadcaster" hidden="true"/>
     <broadcaster id="socialActiveBroadcaster" hidden="true"/>
 
     <!-- DevTools broadcasters -->
     <broadcaster id="devtoolsMenuBroadcaster_DevToolbox"
-                 label="&devToolbarToolsButton.label;"
+                 label="&devToolboxMenuItem.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:DevToolbox"/>
     <broadcaster id="devtoolsMenuBroadcaster_DevToolbar"
                  label="&devToolbarMenu.label;"
                  type="checkbox" autocheck="false"
                  command="Tools:DevToolbar"
                  key="key_devToolbar"/>
     <broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger"
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1511,16 +1511,21 @@ var gBrowserInit = {
     // In certain scenarios it's possible for unload to be fired before onload,
     // (e.g. if the window is being closed after browser.js loads but before the
     // load completes). In that case, there's nothing to do here.
     if (!this._loadHandled)
       return;
 
     gDevToolsBrowser.forgetBrowserWindow(window);
 
+    let desc = Object.getOwnPropertyDescriptor(window, "DeveloperToolbar");
+    if (desc && !desc.get) {
+      DeveloperToolbar.destroy();
+    }
+
     // First clean up services initialized in gBrowserInit.onLoad (or those whose
     // uninit methods don't depend on the services having been initialized).
     allTabs.uninit();
 
     CombinedStopReload.uninit();
 
     gGestureSupport.init(false);
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1147,17 +1147,18 @@
             <hbox class="gclitoolbar-prompt">
               <label class="gclitoolbar-prompt-label">&#187;</label>
             </hbox>
             <hbox class="gclitoolbar-complete-node"/>
             <textbox class="gclitoolbar-input-node" rows="1"/>
           </stack>
           <toolbarbutton id="developer-toolbar-toolbox-button"
                          class="developer-toolbar-button"
-                         observes="devtoolsMenuBroadcaster_DevToolbox"/>
+                         observes="devtoolsMenuBroadcaster_DevToolbox"
+                         tooltiptext="&devToolbarToolsButton.tooltip;"/>
 #ifndef XP_MACOSX
           <toolbarbutton id="developer-toolbar-closebutton"
                          class="devtools-closebutton"
                          oncommand="DeveloperToolbar.hide();"
                          tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
 #endif
    </toolbar>
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/commandline/BuiltinCommands.jsm
@@ -0,0 +1,1994 @@
+/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+this.EXPORTED_SYMBOLS = [ "CmdAddonFlags" ];
+
+Cu.import("resource:///modules/devtools/gcli.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
+                                  "resource:///modules/devtools/gDevTools.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+                                  "resource:///modules/devtools/Target.jsm");
+
+/* CmdAddon ---------------------------------------------------------------- */
+
+(function(module) {
+  XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+                                    "resource://gre/modules/AddonManager.jsm");
+
+  // We need to use an object in which to store any flags because a primitive
+  // would remain undefined.
+  module.CmdAddonFlags = {
+    addonsLoaded: false
+  };
+
+  /**
+  * 'addon' command.
+  */
+  gcli.addCommand({
+    name: "addon",
+    description: gcli.lookup("addonDesc")
+  });
+
+  /**
+  * 'addon list' command.
+  */
+  gcli.addCommand({
+    name: "addon list",
+    description: gcli.lookup("addonListDesc"),
+    params: [{
+      name: 'type',
+      type: {
+        name: 'selection',
+        data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
+      },
+      defaultValue: 'all',
+      description: gcli.lookup("addonListTypeDesc"),
+    }],
+    exec: function(aArgs, context) {
+      function representEnabledAddon(aAddon) {
+        return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
+        getAddonStatus(aAddon) + "]]></li>";
+      }
+
+      function representDisabledAddon(aAddon) {
+        return "<li class=\"gcli-addon-disabled\">" +
+          "<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
+          "]]></li>";
+      }
+
+      function getAddonStatus(aAddon) {
+        let operations = [];
+
+        if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
+          operations.push("PENDING_ENABLE");
+        }
+
+        if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
+          operations.push("PENDING_DISABLE");
+        }
+
+        if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
+          operations.push("PENDING_UNINSTALL");
+        }
+
+        if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
+          operations.push("PENDING_INSTALL");
+        }
+
+        if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
+          operations.push("PENDING_UPGRADE");
+        }
+
+        if (operations.length) {
+          return " (" + operations.join(", ") + ")";
+        }
+        return "";
+      }
+
+      /**
+      * Compares two addons by their name. Used in sorting.
+      */
+      function compareAddonNames(aNameA, aNameB) {
+        return String.localeCompare(aNameA.name, aNameB.name);
+      }
+
+      /**
+      * Resolves the promise which is the scope (this) of this function, filling
+      * it with an HTML representation of the passed add-ons.
+      */
+      function list(aType, aAddons) {
+        if (!aAddons.length) {
+          this.resolve(gcli.lookup("addonNoneOfType"));
+        }
+
+        // Separate the enabled add-ons from the disabled ones.
+        let enabledAddons = [];
+        let disabledAddons = [];
+
+        aAddons.forEach(function(aAddon) {
+          if (aAddon.isActive) {
+            enabledAddons.push(aAddon);
+          } else {
+            disabledAddons.push(aAddon);
+          }
+        });
+
+        let header;
+        switch(aType) {
+          case "dictionary":
+            header = gcli.lookup("addonListDictionaryHeading");
+            break;
+          case "extension":
+            header = gcli.lookup("addonListExtensionHeading");
+            break;
+          case "locale":
+            header = gcli.lookup("addonListLocaleHeading");
+            break;
+          case "plugin":
+            header = gcli.lookup("addonListPluginHeading");
+            break;
+          case "theme":
+            header = gcli.lookup("addonListThemeHeading");
+          case "all":
+            header = gcli.lookup("addonListAllHeading");
+            break;
+          default:
+            header = gcli.lookup("addonListUnknownHeading");
+        }
+
+        // Map and sort the add-ons, and create an HTML list.
+        let message = header +
+                      "<ol>" +
+                      enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
+                      disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
+                      "</ol>";
+
+        this.resolve(context.createView({ html: message }));
+      }
+
+      // Create the promise that will be resolved when the add-on listing has
+      // been finished.
+      let promise = context.createPromise();
+      let types = aArgs.type == "all" ? null : [aArgs.type];
+      AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
+      return promise;
+    }
+  });
+
+  // We need a list of addon names for the enable and disable commands. Because
+  // getting the name list is async we do not add the commands until we have the
+  // list.
+  AddonManager.getAllAddons(function addonAsync(aAddons) {
+    // We listen for installs to keep our addon list up to date. There is no need
+    // to listen for uninstalls because uninstalled addons are simply disabled
+    // until restart (to enable undo functionality).
+    AddonManager.addAddonListener({
+      onInstalled: function(aAddon) {
+        addonNameCache.push({
+          name: representAddon(aAddon).replace(/\s/g, "_"),
+          value: aAddon.name
+        });
+      },
+      onUninstalled: function(aAddon) {
+        let name = representAddon(aAddon).replace(/\s/g, "_");
+
+        for (let i = 0; i < addonNameCache.length; i++) {
+          if(addonNameCache[i].name == name) {
+            addonNameCache.splice(i, 1);
+            break;
+          }
+        }
+      },
+    });
+
+    /**
+    * Returns a string that represents the passed add-on.
+    */
+    function representAddon(aAddon) {
+      let name = aAddon.name + " " + aAddon.version;
+      return name.trim();
+    }
+
+    let addonNameCache = [];
+
+    // The name parameter, used in "addon enable" and "addon disable."
+    let nameParameter = {
+      name: "name",
+      type: {
+        name: "selection",
+        lookup: addonNameCache
+      },
+      description: gcli.lookup("addonNameDesc")
+    };
+
+    for (let addon of aAddons) {
+      addonNameCache.push({
+        name: representAddon(addon).replace(/\s/g, "_"),
+        value: addon.name
+      });
+    }
+
+    /**
+    * 'addon enable' command.
+    */
+    gcli.addCommand({
+      name: "addon enable",
+      description: gcli.lookup("addonEnableDesc"),
+      params: [nameParameter],
+      exec: function(aArgs, context) {
+        /**
+        * Enables the addon in the passed list which has a name that matches
+        * according to the passed name comparer, and resolves the promise which
+        * is the scope (this) of this function to display the result of this
+        * enable attempt.
+        */
+        function enable(aName, addons) {
+          // Find the add-on.
+          let addon = null;
+          addons.some(function(candidate) {
+            if (candidate.name == aName) {
+              addon = candidate;
+              return true;
+            } else {
+              return false;
+            }
+          });
+
+          let name = representAddon(addon);
+          let message = "";
+
+          if (!addon.userDisabled) {
+            message = gcli.lookupFormat("addonAlreadyEnabled", [name]);
+          } else {
+            addon.userDisabled = false;
+            message = gcli.lookupFormat("addonEnabled", [name]);
+          }
+          this.resolve(message);
+        }
+
+        let promise = context.createPromise();
+        // List the installed add-ons, enable one when done listing.
+        AddonManager.getAllAddons(enable.bind(promise, aArgs.name));
+        return promise;
+      }
+    });
+
+    /**
+    * 'addon disable' command.
+    */
+    gcli.addCommand({
+      name: "addon disable",
+      description: gcli.lookup("addonDisableDesc"),
+      params: [nameParameter],
+      exec: function(aArgs, context) {
+        /**
+        * Like enable, but ... you know ... the exact opposite.
+        */
+        function disable(aName, addons) {
+          // Find the add-on.
+          let addon = null;
+          addons.some(function(candidate) {
+            if (candidate.name == aName) {
+              addon = candidate;
+              return true;
+            } else {
+              return false;
+            }
+          });
+
+          let name = representAddon(addon);
+          let message = "";
+
+          if (addon.userDisabled) {
+            message = gcli.lookupFormat("addonAlreadyDisabled", [name]);
+          } else {
+            addon.userDisabled = true;
+            message = gcli.lookupFormat("addonDisabled", [name]);
+          }
+          this.resolve(message);
+        }
+
+        let promise = context.createPromise();
+        // List the installed add-ons, disable one when done listing.
+        AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
+        return promise;
+      }
+    });
+    module.CmdAddonFlags.addonsLoaded = true;
+    Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
+  });
+}(this));
+
+/* CmdBreak ---------------------------------------------------------------- */
+(function(module) {
+  XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
+                                    "resource:///modules/HUDService.jsm");
+
+  XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+                                    "resource:///modules/devtools/Target.jsm");
+
+  /**
+  * 'break' command
+  */
+  gcli.addCommand({
+    name: "break",
+    description: gcli.lookup("breakDesc"),
+    manual: gcli.lookup("breakManual")
+  });
+
+  /**
+  * 'break list' command
+  */
+  gcli.addCommand({
+    name: "break list",
+    description: gcli.lookup("breaklistDesc"),
+    returnType: "html",
+    exec: function(args, context) {
+      let dbg = getPanel(context, "jsdebugger");
+      if (!dbg) {
+        return gcli.lookup("debuggerStopped");
+      }
+
+      let breakpoints = dbg.getAllBreakpoints();
+
+      if (Object.keys(breakpoints).length === 0) {
+        return gcli.lookup("breaklistNone");
+      }
+
+      let reply = gcli.lookup("breaklistIntro");
+      reply += "<ol>";
+      for each (let breakpoint in breakpoints) {
+        let text = gcli.lookupFormat("breaklistLineEntry",
+                                    [breakpoint.location.url,
+                                      breakpoint.location.line]);
+        reply += "<li>" + text + "</li>";
+      };
+      reply += "</ol>";
+      return reply;
+    }
+  });
+
+  /**
+  * 'break add' command
+  */
+  gcli.addCommand({
+    name: "break add",
+    description: gcli.lookup("breakaddDesc"),
+    manual: gcli.lookup("breakaddManual")
+  });
+
+  /**
+  * 'break add line' command
+  */
+  gcli.addCommand({
+    name: "break add line",
+    description: gcli.lookup("breakaddlineDesc"),
+    params: [
+      {
+        name: "file",
+        type: {
+          name: "selection",
+          data: function(args, context) {
+            let files = [];
+            let dbg = getPanel(context, "jsdebugger");
+            if (dbg) {
+              let sourcesView = dbg.panelWin.DebuggerView.Sources;
+              for (let item in sourcesView) {
+                files.push(item.value);
+              }
+            }
+            return files;
+          }
+        },
+        description: gcli.lookup("breakaddlineFileDesc")
+      },
+      {
+        name: "line",
+        type: { name: "number", min: 1, step: 10 },
+        description: gcli.lookup("breakaddlineLineDesc")
+      }
+    ],
+    returnType: "html",
+    exec: function(args, context) {
+      args.type = "line";
+
+      let dbg = getPanel(context, "jsdebugger");
+      if (!dbg) {
+        return gcli.lookup("debuggerStopped");
+      }
+      var deferred = context.defer();
+      let position = { url: args.file, line: args.line };
+      dbg.addBreakpoint(position, function(aBreakpoint, aError) {
+        if (aError) {
+          deferred.resolve(gcli.lookupFormat("breakaddFailed", [aError]));
+          return;
+        }
+        deferred.resolve(gcli.lookup("breakaddAdded"));
+      });
+      return deferred.promise;
+    }
+  });
+
+
+  /**
+  * 'break del' command
+  */
+  gcli.addCommand({
+    name: "break del",
+    description: gcli.lookup("breakdelDesc"),
+    params: [
+      {
+        name: "breakid",
+        type: {
+          name: "number",
+          min: 0,
+          max: function(args, context) {
+            let dbg = getPanel(context, "jsdebugger");
+            return dbg == null ?
+                null :
+                Object.keys(dbg.getAllBreakpoints()).length - 1;
+          },
+        },
+        description: gcli.lookup("breakdelBreakidDesc")
+      }
+    ],
+    returnType: "html",
+    exec: function(args, context) {
+      let dbg = getPanel(context, "jsdebugger");
+      if (!dbg) {
+        return gcli.lookup("debuggerStopped");
+      }
+
+      let breakpoints = dbg.getAllBreakpoints();
+      let id = Object.keys(breakpoints)[args.breakid];
+      if (!id || !(id in breakpoints)) {
+        return gcli.lookup("breakNotFound");
+      }
+
+      let deferred = context.defer();
+      try {
+        dbg.removeBreakpoint(breakpoints[id], function() {
+          deferred.resolve(gcli.lookup("breakdelRemoved"));
+        });
+      } catch (ex) {
+        // If the debugger has been closed already, don't scare the user.
+        deferred.resolve(gcli.lookup("breakdelRemoved"));
+      }
+      return deferred.promise;
+    }
+  });
+
+  /**
+  * A helper to go from a command context to a debugger panel
+  */
+  function getPanel(context, id) {
+    if (context == null) {
+      return undefined;
+    }
+
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let toolbox = gDevTools.getToolbox(target);
+    return toolbox == null ? undefined : toolbox.getPanel(id);
+  }
+}(this));
+
+/* CmdCalllog -------------------------------------------------------------- */
+
+(function(module) {
+  XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
+    let JsDebugger = {};
+    Components.utils.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
+
+    let global = Components.utils.getGlobalForObject({});
+    JsDebugger.addDebuggerToGlobal(global);
+
+    return global.Debugger;
+  });
+
+  XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
+                                    "resource:///modules/devtools/Target.jsm");
+
+  let debuggers = [];
+
+  /**
+  * 'calllog' command
+  */
+  gcli.addCommand({
+    name: "calllog",
+    description: gcli.lookup("calllogDesc")
+  })
+
+  /**
+  * 'calllog start' command
+  */
+  gcli.addCommand({
+    name: "calllog start",
+    description: gcli.lookup("calllogStartDesc"),
+
+    exec: function(args, context) {
+      let contentWindow = context.environment.contentDocument.defaultView;
+
+      let dbg = new Debugger(contentWindow);
+      dbg.onEnterFrame = function(frame) {
+        // BUG 773652 -  Make the output from the GCLI calllog command nicer
+        contentWindow.console.log("Method call: " + this.callDescription(frame));
+      }.bind(this);
+
+      debuggers.push(dbg);
+
+      let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+      let target = TargetFactory.forTab(gBrowser.selectedTab);
+      gDevTools.showToolbox(target, "webconsole");
+
+      return gcli.lookup("calllogStartReply");
+    },
+
+    callDescription: function(frame) {
+      let name = "<anonymous>";
+      if (frame.callee.name) {
+        name = frame.callee.name;
+      }
+      else {
+        let desc = frame.callee.getOwnPropertyDescriptor("displayName");
+        if (desc && desc.value && typeof desc.value == "string") {
+          name = desc.value;
+        }
+      }
+
+      let args = frame.arguments.map(this.valueToString).join(", ");
+      return name + "(" + args + ")";
+    },
+
+    valueToString: function(value) {
+      if (typeof value !== "object" || value === null) {
+        return uneval(value);
+      }
+      return "[object " + value.class + "]";
+    }
+  });
+
+  /**
+  * 'calllog stop' command
+  */
+  gcli.addCommand({
+    name: "calllog stop",
+    description: gcli.lookup("calllogStopDesc"),
+
+    exec: function(args, context) {
+      let numDebuggers = debuggers.length;
+      if (numDebuggers == 0) {
+        return gcli.lookup("calllogStopNoLogging");
+      }
+
+      for (let dbg of debuggers) {
+        dbg.onEnterFrame = undefined;
+      }
+      debuggers = [];
+
+      return gcli.lookupFormat("calllogStopReply", [ numDebuggers ]);
+    }
+  });
+}(this));
+
+/* CmdCalllogChrome -------------------------------------------------------- */
+
+(function(module) {
+  XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
+    let JsDebugger = {};
+    Cu.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
+
+    let global = Components.utils.getGlobalForObject({});
+    JsDebugger.addDebuggerToGlobal(global);
+
+    return global.Debugger;
+  });
+
+  let debuggers = [];
+  let sandboxes = [];
+
+  /**
+  * 'calllog chromestart' command
+  */
+  gcli.addCommand({
+    name: "calllog chromestart",
+    description: gcli.lookup("calllogChromeStartDesc"),
+    get hidden() gcli.hiddenByChromePref(),
+    params: [
+      {
+        name: "sourceType",
+        type: {
+          name: "selection",
+          data: ["content-variable", "chrome-variable", "jsm", "javascript"]
+        }
+      },
+      {
+        name: "source",
+        type: "string",
+        description: gcli.lookup("calllogChromeSourceTypeDesc"),
+        manual: gcli.lookup("calllogChromeSourceTypeManual"),
+      }
+    ],
+    exec: function(args, context) {
+      let globalObj;
+      let contentWindow = context.environment.contentDocument.defaultView;
+
+      if (args.sourceType == "jsm") {
+        try {
+          globalObj = Cu.import(args.source);
+        }
+        catch (e) {
+          return gcli.lookup("callLogChromeInvalidJSM");
+        }
+      } else if (args.sourceType == "content-variable") {
+        if (args.source in contentWindow) {
+          globalObj = Cu.getGlobalForObject(contentWindow[args.source]);
+        } else {
+          throw new Error(gcli.lookup("callLogChromeVarNotFoundContent"));
+        }
+      } else if (args.sourceType == "chrome-variable") {
+        let chromeWin = context.environment.chromeDocument.defaultView;
+        if (args.source in chromeWin) {
+          globalObj = Cu.getGlobalForObject(chromeWin[args.source]);
+        } else {
+          return gcli.lookup("callLogChromeVarNotFoundChrome");
+        }
+      } else {
+        let chromeWin = context.environment.chromeDocument.defaultView;
+        let sandbox = new Cu.Sandbox(chromeWin,
+                                    {
+                                      sandboxPrototype: chromeWin,
+                                      wantXrays: false,
+                                      sandboxName: "gcli-cmd-calllog-chrome"
+                                    });
+        let returnVal;
+        try {
+          returnVal = Cu.evalInSandbox(args.source, sandbox, "ECMAv5");
+          sandboxes.push(sandbox);
+        } catch(e) {
+          // We need to save the message before cleaning up else e contains a dead
+          // object.
+          let msg = gcli.lookup("callLogChromeEvalException") + ": " + e;
+          Cu.nukeSandbox(sandbox);
+          return msg;
+        }
+
+        if (typeof returnVal == "undefined") {
+          return gcli.lookup("callLogChromeEvalNeedsObject");
+        }
+
+        globalObj = Cu.getGlobalForObject(returnVal);
+      }
+
+      let dbg = new Debugger(globalObj);
+      debuggers.push(dbg);
+
+      dbg.onEnterFrame = function(frame) {
+        // BUG 773652 -  Make the output from the GCLI calllog command nicer
+        contentWindow.console.log(gcli.lookup("callLogChromeMethodCall") +
+                                  ": " + this.callDescription(frame));
+      }.bind(this);
+
+      let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+      let target = TargetFactory.forTab(gBrowser.selectedTab);
+      gDevTools.showToolbox(target, "webconsole");
+
+      return gcli.lookup("calllogChromeStartReply");
+    },
+
+    valueToString: function(value) {
+      if (typeof value !== "object" || value === null)
+        return uneval(value);
+      return "[object " + value.class + "]";
+    },
+
+    callDescription: function(frame) {
+      let name = frame.callee.name || gcli.lookup("callLogChromeAnonFunction");
+      let args = frame.arguments.map(this.valueToString).join(", ");
+      return name + "(" + args + ")";
+    }
+  });
+
+  /**
+  * 'calllog chromestop' command
+  */
+  gcli.addCommand({
+    name: "calllog chromestop",
+    description: gcli.lookup("calllogChromeStopDesc"),
+    get hidden() gcli.hiddenByChromePref(),
+    exec: function(args, context) {
+      let numDebuggers = debuggers.length;
+      if (numDebuggers == 0) {
+        return gcli.lookup("calllogChromeStopNoLogging");
+      }
+
+      for (let dbg of debuggers) {
+        dbg.onEnterFrame = undefined;
+        dbg.enabled = false;
+      }
+      for (let sandbox of sandboxes) {
+        Cu.nukeSandbox(sandbox);
+      }
+      debuggers = [];
+      sandboxes = [];
+
+      return gcli.lookupFormat("calllogChromeStopReply", [ numDebuggers ]);
+    }
+  });
+}(this));
+
+/* CmdCmd ------------------------------------------------------------------ */
+
+(function(module) {
+  let prefSvc = "@mozilla.org/preferences-service;1";
+  XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
+    let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
+    return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
+  });
+
+  XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+                                    "resource://gre/modules/NetUtil.jsm");
+  XPCOMUtils.defineLazyModuleGetter(this, "console",
+                                    "resource://gre/modules/devtools/Console.jsm");
+
+  const PREF_DIR = "devtools.commands.dir";
+
+  /**
+  * A place to store the names of the commands that we have added as a result of
+  * calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
+  * added commands.
+  */
+  let commands = [];
+
+  /**
+  * Exported API
+  */
+  this.CmdCommands = {
+    /**
+    * Called to look in a directory pointed at by the devtools.commands.dir pref
+    * for *.mozcmd files which are then loaded.
+    * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
+    * we eval the script from the .mozcmd file. This should be a chrome window.
+    */
+    refreshAutoCommands: function GC_refreshAutoCommands(aSandboxPrincipal) {
+      // First get rid of the last set of commands
+      commands.forEach(function(name) {
+        gcli.removeCommand(name);
+      });
+
+      let dirName = prefBranch.getComplexValue(PREF_DIR,
+                                              Ci.nsISupportsString).data.trim();
+      if (dirName == "") {
+        return;
+      }
+
+      let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+      dir.initWithPath(dirName);
+      if (!dir.exists() || !dir.isDirectory()) {
+        throw new Error('\'' + dirName + '\' is not a directory.');
+      }
+
+      let en = dir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
+
+      while (true) {
+        let file = en.nextFile;
+        if (!file) {
+          break;
+        }
+        if (file.leafName.match(/.*\.mozcmd$/) && file.isFile() && file.isReadable()) {
+          loadCommandFile(file, aSandboxPrincipal);
+        }
+      }
+    },
+  };
+
+  /**
+  * Load the commands from a single file
+  * @param nsIFile aFile The file containing the commands that we should read
+  * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
+  * we eval the script from the .mozcmd file. This should be a chrome window.
+  */
+  function loadCommandFile(aFile, aSandboxPrincipal) {
+    NetUtil.asyncFetch(aFile, function refresh_fetch(aStream, aStatus) {
+      if (!Components.isSuccessCode(aStatus)) {
+        console.error("NetUtil.asyncFetch(" + aFile.path + ",..) failed. Status=" + aStatus);
+        return;
+      }
+
+      let source = NetUtil.readInputStreamToString(aStream, aStream.available());
+      aStream.close();
+
+      let sandbox = new Cu.Sandbox(aSandboxPrincipal, {
+        sandboxPrototype: aSandboxPrincipal,
+        wantXrays: false,
+        sandboxName: aFile.path
+      });
+      let data = Cu.evalInSandbox(source, sandbox, "1.8", aFile.leafName, 1);
+
+      if (!Array.isArray(data)) {
+        console.error("Command file '" + aFile.leafName + "' does not have top level array.");
+        return;
+      }
+
+      data.forEach(function(commandSpec) {
+        gcli.addCommand(commandSpec);
+        commands.push(commandSpec.name);
+      });
+    }.bind(this));
+  }
+
+  /**
+  * 'cmd' command
+  */
+  gcli.addCommand({
+    name: "cmd",
+    get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
+    description: gcli.lookup("cmdDesc")
+  });
+
+  /**
+  * 'cmd refresh' command
+  */
+  gcli.addCommand({
+    name: "cmd refresh",
+    description: gcli.lookup("cmdRefreshDesc"),
+    get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
+    exec: function Command_cmdRefresh(args, context) {
+      let chromeWindow = context.environment.chromeDocument.defaultView;
+      CmdCommands.refreshAutoCommands(chromeWindow);
+    }
+  });
+}(this));
+
+/* CmdConsole -------------------------------------------------------------- */
+
+(function(module) {
+  XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
+                                    "resource:///modules/HUDService.jsm");
+
+  /**
+  * 'console' command
+  */
+  gcli.addCommand({
+    name: "console",
+    description: gcli.lookup("consoleDesc"),
+    manual: gcli.lookup("consoleManual")
+  });
+
+  /**
+  * 'console clear' command
+  */
+  gcli.addCommand({
+    name: "console clear",
+    description: gcli.lookup("consoleclearDesc"),
+    exec: function Command_consoleClear(args, context) {
+      let window = context.environment.contentDocument.defaultView;
+      let hud = HUDService.getHudByWindow(window);
+      // hud will be null if the web console has not been opened for this window
+      if (hud) {
+        hud.jsterm.clearOutput();
+      }
+    }
+  });
+
+  /**
+  * 'console close' command
+  */
+  gcli.addCommand({
+    name: "console close",
+    description: gcli.lookup("consolecloseDesc"),
+    exec: function Command_consoleClose(args, context) {
+      let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+      let target = TargetFactory.forTab(gBrowser.selectedTab);
+      return gDevTools.closeToolbox(target);
+    }
+  });
+
+  /**
+  * 'console open' command
+  */
+  gcli.addCommand({
+    name: "console open",
+    description: gcli.lookup("consoleopenDesc"),
+    exec: function Command_consoleOpen(args, context) {
+      let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+      let target = TargetFactory.forTab(gBrowser.selectedTab);
+      return gDevTools.showToolbox(target, "webconsole");
+    }
+  });
+}(this));
+
+/* CmdCookie --------------------------------------------------------------- */
+
+(function(module) {
+  XPCOMUtils.defineLazyModuleGetter(this, "console",
+                                    "resource://gre/modules/devtools/Console.jsm");
+
+  // We should really be using nsICookieManager so we can read more than just the
+  // key/value of cookies. The difficulty is filtering the cookies that are
+  // relevant to the current page. See
+  // https://github.com/firebug/firebug/blob/master/extension/content/firebug/cookies/cookieObserver.js#L123
+  // For details on how this is done with Firebug
+
+  /**
+  * 'cookie' command
+  */
+  gcli.addCommand({
+    name: "cookie",
+    description: gcli.lookup("cookieDesc"),
+    manual: gcli.lookup("cookieManual")
+  });
+
+  /**
+  * The template for the 'cookie list' command.
+  */
+  var cookieListHtml = "" +
+    "<table>" +
+    "  <tr>" +
+    "    <th>" + gcli.lookup("cookieListOutKey") + "</th>" +
+    "    <th>" + gcli.lookup("cookieListOutValue") + "</th>" +
+    "    <th>" + gcli.lookup("cookieListOutActions") + "</th>" +
+    "  </tr>" +
+    "  <tr foreach='cookie in ${cookies}'>" +
+    "    <td>${cookie.key}</td>" +
+    "    <td>${cookie.value}</td>" +
+    "    <td>" +
+    "      <span class='gcli-out-shortcut' onclick='${onclick}'" +
+    "          data-command='cookie set ${cookie.key} '" +
+    "          >" + gcli.lookup("cookieListOutEdit") + "</span>" +
+    "      <span class='gcli-out-shortcut'" +
+    "          onclick='${onclick}' ondblclick='${ondblclick}'" +
+    "          data-command='cookie remove ${cookie.key}'" +
+    "          >" + gcli.lookup("cookieListOutRemove") + "</span>" +
+    "    </td>" +
+    "  </tr>" +
+    "</table>" +
+    "";
+
+  /**
+  * 'cookie list' command
+  */
+  gcli.addCommand({
+    name: "cookie list",
+    description: gcli.lookup("cookieListDesc"),
+    manual: gcli.lookup("cookieListManual"),
+    returnType: "string",
+    exec: function Command_cookieList(args, context) {
+      // Parse out an array of { key:..., value:... } objects for each cookie
+      var doc = context.environment.contentDocument;
+      var cookies = doc.cookie.split("; ").map(function(cookieStr) {
+        var equalsPos = cookieStr.indexOf("=");
+        return {
+          key: cookieStr.substring(0, equalsPos),
+          value: cookieStr.substring(equalsPos + 1)
+        };
+      });
+
+      return context.createView({
+        html: cookieListHtml,
+        data: {
+          cookies: cookies,
+          onclick: createUpdateHandler(context),
+          ondblclick: createExecuteHandler(context),
+        }
+      });
+    }
+  });
+
+  /**
+  * 'cookie remove' command
+  */
+  gcli.addCommand({
+    name: "cookie remove",
+    description: gcli.lookup("cookieRemoveDesc"),
+    manual: gcli.lookup("cookieRemoveManual"),
+    params: [
+      {
+        name: "key",
+        type: "string",
+        description: gcli.lookup("cookieRemoveKeyDesc"),
+      }
+    ],
+    exec: function Command_cookieRemove(args, context) {
+      let document = context.environment.contentDocument;
+      let expDate = new Date();
+      expDate.setDate(expDate.getDate() - 1);
+      document.cookie = escape(args.key) + "=; expires=" + expDate.toGMTString();
+    }
+  });
+
+  /**
+  * 'cookie set' command
+  */
+  gcli.addCommand({
+    name: "cookie set",
+    description: gcli.lookup("cookieSetDesc"),
+    manual: gcli.lookup("cookieSetManual"),
+    params: [
+      {
+        name: "key",
+        type: "string",
+        description: gcli.lookup("cookieSetKeyDesc")
+      },
+      {
+        name: "value",
+        type: "string",
+        description: gcli.lookup("cookieSetValueDesc")
+      },
+      {
+        group: gcli.lookup("cookieSetOptionsDesc"),
+        params: [
+          {
+            name: "path",
+            type: "string",
+            defaultValue: "/",
+            description: gcli.lookup("cookieSetPathDesc")
+          },
+          {
+            name: "domain",
+            type: "string",
+            defaultValue: null,
+            description: gcli.lookup("cookieSetDomainDesc")
+          },
+          {
+            name: "secure",
+            type: "boolean",
+            description: gcli.lookup("cookieSetSecureDesc")
+          }
+        ]
+      }
+    ],
+    exec: function Command_cookieSet(args, context) {
+      let document = context.environment.contentDocument;
+
+      document.cookie = escape(args.key) + "=" + escape(args.value) +
+              (args.domain ? "; domain=" + args.domain : "") +
+              (args.path ? "; path=" + args.path : "") +
+              (args.secure ? "; secure" : ""); 
+    }
+  });
+
+  /**
+  * Helper to find the 'data-command' attribute and call some action on it.
+  * @see |updateCommand()| and |executeCommand()|
+  */
+  function withCommand(element, action) {
+    var command = element.getAttribute("data-command");
+    if (!command) {
+      command = element.querySelector("*[data-command]")
+              .getAttribute("data-command");
+    }
+
+    if (command) {
+      action(command);
+    }
+    else {
+      console.warn("Missing data-command for " + util.findCssSelector(element));
+    }
+  }
+
+  /**
+  * Create a handler to update the requisition to contain the text held in the
+  * first matching data-command attribute under the currentTarget of the event.
+  * @param context Either a Requisition or an ExecutionContext or another object
+  * that contains an |update()| function that follows a similar contract.
+  */
+  function createUpdateHandler(context) {
+    return function(ev) {
+      withCommand(ev.currentTarget, function(command) {
+        context.update(command);
+      });
+    }
+  }
+
+  /**
+  * Create a handler to execute the text held in the data-command attribute
+  * under the currentTarget of the event.
+  * @param context Either a Requisition or an ExecutionContext or another object
+  * that contains an |update()| function that follows a similar contract.
+  */
+  function createExecuteHandler(context) {
+    return function(ev) {
+      withCommand(ev.currentTarget, function(command) {
+        context.exec({
+          visible: true,
+          typed: command
+        });
+      });
+    }
+  }
+}(this));
+
+/* CmdDbg ------------------------------------------------------------------ */
+
+(function(module) {
+  /**
+  * 'dbg' command
+  */
+  gcli.addCommand({
+    name: "dbg",
+    description: gcli.lookup("dbgDesc"),
+    manual: gcli.lookup("dbgManual")
+  });
+
+  /**
+  * 'dbg open' command
+  */
+  gcli.addCommand({
+    name: "dbg open",
+    description: gcli.lookup("dbgOpen"),
+    params: [],
+    exec: function (args, context) {
+      let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+      let target = TargetFactory.forTab(gBrowser.selectedTab);
+      return gDevTools.showToolbox(target, "jsdebugger");
+    }
+  });
+
+  /**
+  * 'dbg close' command
+  */
+  gcli.addCommand({
+    name: "dbg close",
+    description: gcli.lookup("dbgClose"),
+    params: [],
+    exec: function (args, context) {
+      let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+      let target = TargetFactory.forTab(gBrowser.selectedTab);
+      return gDevTools.closeToolbox(target);
+    }
+  });
+
+  /**
+  * 'dbg interrupt' command
+  */
+  gcli.addCommand({
+    name: "dbg interrupt",
+    description: gcli.lookup("dbgInterrupt"),
+    params: [],
+    exec: function(args, context) {
+      let dbg = getPanel(context, "jsdebugger");
+      if (!dbg) {
+        return gcli.lookup("debuggerStopped");
+      }
+
+      let controller = dbg._controller;
+      let thread = controller.activeThread;
+      if (!thread.paused) {
+        thread.interrupt();
+      }
+    }
+  });
+
+  /**
+  * 'dbg continue' command
+  */
+  gcli.addCommand({
+    name: "dbg continue",
+    description: gcli.lookup("dbgContinue"),
+    params: [],
+    exec: function(args, context) {
+      let dbg = getPanel(context, "jsdebugger");
+      if (!dbg) {
+        return gcli.lookup("debuggerStopped");
+      }
+
+      let controller = dbg._controller;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.resume();
+      }
+    }
+  });
+
+  /**
+  * 'dbg step' command
+  */
+  gcli.addCommand({
+    name: "dbg step",
+    description: gcli.lookup("dbgStepDesc"),
+    manual: gcli.lookup("dbgStepManual")
+  });
+
+  /**
+  * 'dbg step over' command
+  */
+  gcli.addCommand({
+    name: "dbg step over",
+    description: gcli.lookup("dbgStepOverDesc"),
+    params: [],
+    exec: function(args, context) {
+      let dbg = getPanel(context, "jsdebugger");
+      if (!dbg) {
+        return gcli.lookup("debuggerStopped");
+      }
+
+      let controller = dbg._controller;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepOver();
+      }
+    }
+  });
+
+  /**
+  * 'dbg step in' command
+  */
+  gcli.addCommand({
+    name: 'dbg step in',
+    description: gcli.lookup("dbgStepInDesc"),
+    params: [],
+    exec: function(args, context) {
+      let dbg = getPanel(context, "jsdebugger");
+      if (!dbg) {
+        return gcli.lookup("debuggerStopped");
+      }
+
+      let controller = dbg._controller;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepIn();
+      }
+    }
+  });
+
+  /**
+  * 'dbg step over' command
+  */
+  gcli.addCommand({
+    name: 'dbg step out',
+    description: gcli.lookup("dbgStepOutDesc"),
+    params: [],
+    exec: function(args, context) {
+      let dbg = getPanel(context, "jsdebugger");
+      if (!dbg) {
+        return gcli.lookup("debuggerStopped");
+      }
+
+      let controller = dbg._controller;
+      let thread = controller.activeThread;
+      if (thread.paused) {
+        thread.stepOut();
+      }
+    }
+  });
+
+  /**
+  * A helper to go from a command context to a debugger panel
+  */
+  function getPanel(context, id) {
+    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
+    let target = TargetFactory.forTab(gBrowser.selectedTab);
+    let toolbox = gDevTools.getToolbox(target);
+    return toolbox == null ? undefined : toolbox.getPanel(id);
+  }
+}(this));
+
+/* CmdEcho ----------------------------------------------------------------- */
+
+(function(module) {
+  /**
+  * 'echo' command
+  */
+  gcli.addCommand({
+    name: "echo",
+    description: gcli.lookup("echoDesc"),
+    params: [
+      {
+        name: "message",
+        type: "string",
+        description: gcli.lookup("echoMessageDesc")
+      }
+    ],
+    returnType: "string",
+    hidden: true,
+    exec: function Command_echo(args, context) {
+      return args.message;
+    }
+  });
+}(this));
+
+/* CmdExport --------------------------------------------------------------- */
+
+(function(module) {
+  /**
+  * 'export' command
+  */
+  gcli.addCommand({
+    name: "export",
+    description: gcli.lookup("exportDesc"),
+  });
+
+  /**
+  * The 'export html' command. This command allows the user to export the page to
+  * HTML after they do DOM changes.
+  */
+  gcli.addCommand({
+    name: "export html",
+    description: gcli.lookup("exportHtmlDesc"),
+    exec: function(args, context) {
+      let document = context.environment.contentDocument;
+      let window = document.defaultView;
+      let page = document.documentElement.outerHTML;
+      window.open('data:text/plain;charset=utf8,' + encodeURIComponent(page));
+    }
+  });
+}(this));
+
+/* CmdJsb ------------------------------------------------------------------ */
+
+(function(module) {
+  const XMLHttpRequest =
+    Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
+
+  XPCOMUtils.defineLazyModuleGetter(this, "js_beautify",
+                                    "resource:///modules/devtools/Jsbeautify.jsm");
+
+  /**
+  * jsb command.
+  */
+  gcli.addCommand({
+    name: 'jsb',
+    description: gcli.lookup('jsbDesc'),
+    returnValue:'string',
+    params: [
+      {
+        name: 'url',
+        type: 'string',
+        description: gcli.lookup('jsbUrlDesc')
+      },
+      {
+        group: gcli.lookup("jsbOptionsDesc"),
+        params: [
+          {
+            name: 'indentSize',
+            type: 'number',
+            description: gcli.lookup('jsbIndentSizeDesc'),
+            manual: gcli.lookup('jsbIndentSizeManual'),
+            defaultValue: 2
+          },
+          {
+            name: 'indentChar',
+            type: {
+              name: 'selection',
+              lookup: [
+                { name: "space", value: " " },
+                { name: "tab", value: "\t" }
+              ]
+            },
+            description: gcli.lookup('jsbIndentCharDesc'),
+            manual: gcli.lookup('jsbIndentCharManual'),
+            defaultValue: ' ',
+          },
+          {
+            name: 'doNotPreserveNewlines',
+            type: 'boolean',
+            description: gcli.lookup('jsbDoNotPreserveNewlinesDesc')
+          },
+          {
+            name: 'preserveMaxNewlines',
+            type: 'number',
+            description: gcli.lookup('jsbPreserveMaxNewlinesDesc'),
+            manual: gcli.lookup('jsbPreserveMaxNewlinesManual'),
+            defaultValue: -1
+          },
+          {
+            name: 'jslintHappy',
+            type: 'boolean',
+            description: gcli.lookup('jsbJslintHappyDesc'),
+            manual: gcli.lookup('jsbJslintHappyManual')
+          },
+          {
+            name: 'braceStyle',
+            type: {
+              name: 'selection',
+              data: ['collapse', 'expand', 'end-expand', 'expand-strict']
+            },
+            description: gcli.lookup('jsbBraceStyleDesc'),
+            manual: gcli.lookup('jsbBraceStyleManual'),
+            defaultValue: "collapse"
+          },
+          {
+            name: 'noSpaceBeforeConditional',
+            type: 'boolean',
+            description: gcli.lookup('jsbNoSpaceBeforeConditionalDesc')
+          },
+          {
+            name: 'unescapeStrings',
+            type: 'boolean',
+            description: gcli.lookup('jsbUnescapeStringsDesc'),
+            manual: gcli.lookup('jsbUnescapeStringsManual')
+          }
+        ]
+      }
+    ],
+    exec: function(args, context) {
+      let opts = {
+        indent_size: args.indentSize,
+        indent_char: args.indentChar,
+        preserve_newlines: !args.doNotPreserveNewlines,
+        max_preserve_newlines: args.preserveMaxNewlines == -1 ?
+                              undefined : args.preserveMaxNewlines,
+        jslint_happy: args.jslintHappy,
+        brace_style: args.braceStyle,
+        space_before_conditional: !args.noSpaceBeforeConditional,
+        unescape_strings: args.unescapeStrings
+      };
+
+      let xhr = new XMLHttpRequest();
+
+      try {
+        xhr.open("GET", args.url, true);
+      } catch(e) {
+        return gcli.lookup('jsbInvalidURL');
+      }
+
+      let promise = context.createPromise();
+
+      xhr.onreadystatechange = function(aEvt) {
+        if (xhr.readyState == 4) {
+          if (xhr.status == 200 || xhr.status == 0) {
+            let browserDoc = context.environment.chromeDocument;
+            let browserWindow = browserDoc.defaultView;
+            let gBrowser = browserWindow.gBrowser;
+            let result = js_beautify(xhr.responseText, opts);
+
+            browserWindow.Scratchpad.ScratchpadManager.openScratchpad({text: result});
+
+            promise.resolve();
+          } else {
+            promise.resolve("Unable to load page to beautify: " + args.url + " " +
+                            xhr.status + " " + xhr.statusText);
+          }
+        };
+      }
+      xhr.send(null);
+      return promise;
+    }
+  });
+}(this));
+
+/* CmdPagemod -------------------------------------------------------------- */
+
+(function(module) {
+  /**
+  * 'pagemod' command
+  */
+  gcli.addCommand({
+    name: "pagemod",
+    description: gcli.lookup("pagemodDesc"),
+  });
+
+  /**
+  * The 'pagemod replace' command. This command allows the user to search and
+  * replace within text nodes and attributes.
+  */
+  gcli.addCommand({
+    name: "pagemod replace",
+    description: gcli.lookup("pagemodReplaceDesc"),
+    params: [
+      {
+        name: "search",
+        type: "string",
+        description: gcli.lookup("pagemodReplaceSearchDesc"),
+      },
+      {
+        name: "replace",
+        type: "string",
+        description: gcli.lookup("pagemodReplaceReplaceDesc"),
+      },
+      {
+        name: "ignoreCase",
+        type: "boolean",
+        description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
+      },
+      {
+        name: "selector",
+        type: "string",
+        description: gcli.lookup("pagemodReplaceSelectorDesc"),
+        defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
+      },
+      {
+        name: "root",
+        type: "node",
+        description: gcli.lookup("pagemodReplaceRootDesc"),
+        defaultValue: null,
+      },
+      {
+        name: "attrOnly",
+        type: "boolean",
+        description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
+      },
+      {
+        name: "contentOnly",
+        type: "boolean",
+        description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
+      },
+      {
+        name: "attributes",
+        type: "string",
+        description: gcli.lookup("pagemodReplaceAttributesDesc"),
+        defaultValue: null,
+      },
+    ],
+    exec: function(args, context) {
+      let document = context.environment.contentDocument;
+      let searchTextNodes = !args.attrOnly;
+      let searchAttributes = !args.contentOnly;
+      let regexOptions = args.ignoreCase ? 'ig' : 'g';
+      let search = new RegExp(escapeRegex(args.search), regexOptions);
+      let attributeRegex = null;
+      if (args.attributes) {
+        attributeRegex = new RegExp(args.attributes, regexOptions);
+      }
+
+      let root = args.root || document;
+      let elements = root.querySelectorAll(args.selector);
+      elements = Array.prototype.slice.call(elements);
+
+      let replacedTextNodes = 0;
+      let replacedAttributes = 0;
+
+      function replaceAttribute() {
+        replacedAttributes++;
+        return args.replace;
+      }
+      function replaceTextNode() {
+        replacedTextNodes++;
+        return args.replace;
+      }
+
+      for (let i = 0; i < elements.length; i++) {
+        let element = elements[i];
+        if (searchTextNodes) {
+          for (let y = 0; y < element.childNodes.length; y++) {
+            let node = element.childNodes[y];
+            if (node.nodeType == node.TEXT_NODE) {
+              node.textContent = node.textContent.replace(search, replaceTextNode);
+            }
+          }
+        }
+
+        if (searchAttributes) {
+          if (!element.attributes) {
+            continue;
+          }
+          for (let y = 0; y < element.attributes.length; y++) {
+            let attr = element.attributes[y];
+            if (!attributeRegex || attributeRegex.test(attr.name)) {
+              attr.value = attr.value.replace(search, replaceAttribute);
+            }
+          }
+        }
+      }
+
+      return gcli.lookupFormat("pagemodReplaceResult",
+                              [elements.length, replacedTextNodes,
+                                replacedAttributes]);
+    }
+  });
+
+  /**
+  * 'pagemod remove' command
+  */
+  gcli.addCommand({
+    name: "pagemod remove",
+    description: gcli.lookup("pagemodRemoveDesc"),
+  });
+
+
+  /**
+  * The 'pagemod remove element' command.
+  */
+  gcli.addCommand({
+    name: "pagemod remove element",
+    description: gcli.lookup("pagemodRemoveElementDesc"),
+    params: [
+      {
+        name: "search",
+        type: "string",
+        description: gcli.lookup("pagemodRemoveElementSearchDesc"),
+      },
+      {
+        name: "root",
+        type: "node",
+        description: gcli.lookup("pagemodRemoveElementRootDesc"),
+        defaultValue: null,
+      },
+      {
+        name: 'stripOnly',
+        type: 'boolean',
+        description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
+      },
+      {
+        name: 'ifEmptyOnly',
+        type: 'boolean',
+        description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
+      },
+    ],
+    exec: function(args, context) {
+      let document = context.environment.contentDocument;
+      let root = args.root || document;
+      let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
+
+      let removed = 0;
+      for (let i = 0; i < elements.length; i++) {
+        let element = elements[i];
+        let parentNode = element.parentNode;
+        if (!parentNode || !element.removeChild) {
+          continue;
+        }
+        if (args.stripOnly) {
+          while (element.hasChildNodes()) {
+            parentNode.insertBefore(element.childNodes[0], element);
+          }
+        }
+        if (!args.ifEmptyOnly || !element.hasChildNodes()) {
+          element.parentNode.removeChild(element);
+          removed++;
+        }
+      }
+
+      return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
+                              [elements.length, removed]);
+    }
+  });
+
+  /**
+  * The 'pagemod remove attribute' command.
+  */
+  gcli.addCommand({
+    name: "pagemod remove attribute",
+    description: gcli.lookup("pagemodRemoveAttributeDesc"),
+    params: [
+      {
+        name: "searchAttributes",
+        type: "string",
+        description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
+      },
+      {
+        name: "searchElements",
+        type: "string",
+        description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
+      },
+      {
+        name: "root",
+        type: "node",
+        description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
+        defaultValue: null,
+      },
+      {
+        name: "ignoreCase",
+        type: "boolean",
+        description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
+      },
+    ],
+    exec: function(args, context) {
+      let document = context.environment.contentDocument;
+
+      let root = args.root || document;
+      let regexOptions = args.ignoreCase ? 'ig' : 'g';
+      let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
+      let elements = root.querySelectorAll(args.searchElements);
+      elements = Array.prototype.slice.call(elements);
+
+      let removed = 0;
+      for (let i = 0; i < elements.length; i++) {
+        let element = elements[i];
+        if (!element.attributes) {
+          continue;
+        }
+
+        var attrs = Array.prototype.slice.call(element.attributes);
+        for (let y = 0; y < attrs.length; y++) {
+          let attr = attrs[y];
+          if (attributeRegex.test(attr.name)) {
+            element.removeAttribute(attr.name);
+            removed++;
+          }
+        }
+      }
+
+      return gcli.lookupFormat("pagemodRemoveAttributeResult",
+                              [elements.length, removed]);
+    }
+  });
+
+  /**
+  * Make a given string safe to use  in a regular expression.
+  *
+  * @param string aString
+  *        The string you want to use in a regex.
+  * @return string
+  *         The equivalent of |aString| but safe to use in a regex.
+  */
+  function escapeRegex(aString) {
+    return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+  }
+}(this));
+
+/* CmdRestart -------------------------------------------------------------- */
+
+(function(module) {
+  /**
+  * Restart command
+  *
+  * @param boolean nocache
+  *        Disables loading content from cache upon restart.
+  *
+  * Examples :
+  * >> restart
+  * - restarts browser immediately
+  * >> restart --nocache
+  * - restarts immediately and starts Firefox without using cache
+  */
+  gcli.addCommand({
+    name: "restart",
+    description: gcli.lookup("restartFirefoxDesc"),
+    params: [
+      {
+        name: "nocache",
+        type: "boolean",
+        description: gcli.lookup("restartFirefoxNocacheDesc")
+      }
+    ],
+    returnType: "string",
+    exec: function Restart(args, context) {
+      let canceled = Cc["@mozilla.org/supports-PRBool;1"]
+                      .createInstance(Ci.nsISupportsPRBool);
+      Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
+      if (canceled.data) {
+        return gcli.lookup("restartFirefoxRequestCancelled");
+      }
+
+      // disable loading content from cache.
+      if (args.nocache) {
+        Services.appinfo.invalidateCachesOnRestart();
+      }
+
+      // restart
+      Cc['@mozilla.org/toolkit/app-startup;1']
+        .getService(Ci.nsIAppStartup)
+        .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
+      return gcli.lookup("restartFirefoxRestarting");
+    }
+  });
+}(this));
+
+/* CmdScreenshot ----------------------------------------------------------- */
+
+(function(module) {
+  XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
+                                    "resource:///modules/devtools/LayoutHelpers.jsm");
+
+  // String used as an indication to generate default file name in the following
+  // format: "Screen Shot yyyy-mm-dd at HH.MM.SS.png"
+  const FILENAME_DEFAULT_VALUE = " ";
+
+  /**
+  * 'screenshot' command
+  */
+  gcli.addCommand({
+    name: "screenshot",
+    description: gcli.lookup("screenshotDesc"),
+    manual: gcli.lookup("screenshotManual"),
+    returnType: "html",
+    params: [
+      {
+        name: "filename",
+        type: "string",
+        defaultValue: FILENAME_DEFAULT_VALUE,
+        description: gcli.lookup("screenshotFilenameDesc"),
+        manual: gcli.lookup("screenshotFilenameManual")
+      },
+      {
+        group: gcli.lookup("screenshotGroupOptions"),
+        params: [
+          {
+            name: "clipboard",
+            type: "boolean",
+            description: gcli.lookup("screenshotClipboardDesc"),
+            manual: gcli.lookup("screenshotClipboardManual")
+          },
+          {
+            name: "chrome",
+            type: "boolean",
+            description: gcli.lookup("screenshotChromeDesc"),
+            manual: gcli.lookup("screenshotChromeManual")
+          },
+          {
+            name: "delay",
+            type: { name: "number", min: 0 },
+            defaultValue: 0,
+            description: gcli.lookup("screenshotDelayDesc"),
+            manual: gcli.lookup("screenshotDelayManual")
+          },
+          {
+            name: "fullpage",
+            type: "boolean",
+            description: gcli.lookup("screenshotFullPageDesc"),
+            manual: gcli.lookup("screenshotFullPageManual")
+          },
+          {
+            name: "selector",
+            type: "node",
+            defaultValue: null,
+            description: gcli.lookup("inspectNodeDesc"),
+            manual: gcli.lookup("inspectNodeManual")
+          }
+        ]
+      }
+    ],
+    exec: function Command_screenshot(args, context) {
+      if (args.chrome && args.selector) {
+        // Node screenshot with chrome option does not work as inteded
+        // Refer https://bugzilla.mozilla.org/show_bug.cgi?id=659268#c7
+        // throwing for now.
+        throw new Error(gcli.lookup("screenshotSelectorChromeConflict"));
+      }
+      var document = args.chrome? context.environment.chromeDocument
+                                : context.environment.contentDocument;
+      if (args.delay > 0) {
+        var promise = context.createPromise();
+        document.defaultView.setTimeout(function Command_screenshotDelay() {
+          let reply = this.grabScreen(document, args.filename, args.clipboard,
+                                      args.fullpage);
+          promise.resolve(reply);
+        }.bind(this), args.delay * 1000);
+        return promise;
+      }
+      else {
+        return this.grabScreen(document, args.filename, args.clipboard,
+                              args.fullpage, args.selector);
+      }
+    },
+    grabScreen:
+    function Command_screenshotGrabScreen(document, filename, clipboard,
+                                          fullpage, node) {
+      let window = document.defaultView;
+      let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+      let left = 0;
+      let top = 0;
+      let width;
+      let height;
+      let div = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
+
+      if (!fullpage) {
+        if (!node) {
+          left = window.scrollX;
+          top = window.scrollY;
+          width = window.innerWidth;
+          height = window.innerHeight;
+        } else {
+          let rect = LayoutHelpers.getRect(node, window);
+          top = rect.top;
+          left = rect.left;
+          width = rect.width;
+          height = rect.height;
+        }
+      } else {
+        width = window.innerWidth + window.scrollMaxX;
+        height = window.innerHeight + window.scrollMaxY;
+      }
+      canvas.width = width;
+      canvas.height = height;
+
+      let ctx = canvas.getContext("2d");
+      ctx.drawWindow(window, left, top, width, height, "#fff");
+      let data = canvas.toDataURL("image/png", "");
+
+      let loadContext = document.defaultView
+                                .QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIWebNavigation)
+                                .QueryInterface(Ci.nsILoadContext);
+
+      try {
+        if (clipboard) {
+          let io = Cc["@mozilla.org/network/io-service;1"]
+                    .getService(Ci.nsIIOService);
+          let channel = io.newChannel(data, null, null);
+          let input = channel.open();
+          let imgTools = Cc["@mozilla.org/image/tools;1"]
+                          .getService(Ci.imgITools);
+
+          let container = {};
+          imgTools.decodeImageData(input, channel.contentType, container);
+
+          let wrapped = Cc["@mozilla.org/supports-interface-pointer;1"]
+                          .createInstance(Ci.nsISupportsInterfacePointer);
+          wrapped.data = container.value;
+
+          let trans = Cc["@mozilla.org/widget/transferable;1"]
+                        .createInstance(Ci.nsITransferable);
+          trans.init(loadContext);
+          trans.addDataFlavor(channel.contentType);
+          trans.setTransferData(channel.contentType, wrapped, -1);
+
+          let clipid = Ci.nsIClipboard;
+          let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
+          clip.setData(trans, null, clipid.kGlobalClipboard);
+          div.textContent = gcli.lookup("screenshotCopied");
+          return div;
+        }
+      }
+      catch (ex) {
+        div.textContent = gcli.lookup("screenshotErrorCopying");
+        return div;
+      }
+
+      let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
+
+      // Create a name for the file if not present
+      if (filename == FILENAME_DEFAULT_VALUE) {
+        let date = new Date();
+        let dateString = date.getFullYear() + "-" + (date.getMonth() + 1) +
+                        "-" + date.getDate();
+        dateString = dateString.split("-").map(function(part) {
+          if (part.length == 1) {
+            part = "0" + part;
+          }
+          return part;
+        }).join("-");
+        let timeString = date.toTimeString().replace(/:/g, ".").split(" ")[0];
+        filename = gcli.lookupFormat("screenshotGeneratedFilename",
+                                    [dateString, timeString]) + ".png";
+      }
+      // Check there is a .png extension to filename
+      else if (!filename.match(/.png$/i)) {
+        filename += ".png";
+      }
+
+      // If the filename is relative, tack it onto the download directory
+      if (!filename.match(/[\\\/]/)) {
+        let downloadMgr = Cc["@mozilla.org/download-manager;1"]
+                            .getService(Ci.nsIDownloadManager);
+        let tempfile = downloadMgr.userDownloadsDirectory;
+        tempfile.append(filename);
+        filename = tempfile.path;
+      }
+
+      try {
+        file.initWithPath(filename);
+      } catch (ex) {
+        div.textContent = gcli.lookup("screenshotErrorSavingToFile") + " " + filename;
+        return div;
+      }
+
+      let ioService = Cc["@mozilla.org/network/io-service;1"]
+                        .getService(Ci.nsIIOService);
+
+      let Persist = Ci.nsIWebBrowserPersist;
+      let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
+                      .createInstance(Persist);
+      persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
+                            Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
+
+      let source = ioService.newURI(data, "UTF8", null);
+      persist.saveURI(source, null, null, null, null, file, loadContext);
+
+      div.textContent = gcli.lookup("screenshotSavedToFile") + " \"" + filename +
+                        "\"";
+      div.addEventListener("click", function openFile() {
+        div.removeEventListener("click", openFile);
+        file.reveal();
+      });
+      div.style.cursor = "pointer";
+      let image = document.createElement("div");
+      let previewHeight = parseInt(256*height/width);
+      image.setAttribute("style",
+                        "width:256px; height:" + previewHeight + "px;" +
+                        "max-height: 256px;" +
+                        "background-image: url('" + data + "');" +
+                        "background-size: 256px " + previewHeight + "px;" +
+                        "margin: 4px; display: block");
+      div.appendChild(image);
+      return div;
+    }
+  });
+}(this));
deleted file mode 100644
--- a/browser/devtools/commandline/CmdAddon.jsm
+++ /dev/null
@@ -1,297 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ "Flags" ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
-                                  "resource://gre/modules/AddonManager.jsm");
-
-// We need to use an object in which to store any flags because a primitive
-// would remain undefined.
-this.Flags = {
-  addonsLoaded: false
-};
-
-/**
- * 'addon' command.
- */
-gcli.addCommand({
-  name: "addon",
-  description: gcli.lookup("addonDesc")
-});
-
-/**
- * 'addon list' command.
- */
-gcli.addCommand({
-  name: "addon list",
-  description: gcli.lookup("addonListDesc"),
-  params: [{
-    name: 'type',
-    type: {
-      name: 'selection',
-      data: ["dictionary", "extension", "locale", "plugin", "theme", "all"]
-    },
-    defaultValue: 'all',
-    description: gcli.lookup("addonListTypeDesc"),
-  }],
-  exec: function(aArgs, context) {
-    function representEnabledAddon(aAddon) {
-      return "<li><![CDATA[" + aAddon.name + "\u2002" + aAddon.version +
-      getAddonStatus(aAddon) + "]]></li>";
-    }
-
-    function representDisabledAddon(aAddon) {
-      return "<li class=\"gcli-addon-disabled\">" +
-        "<![CDATA[" + aAddon.name + "\u2002" + aAddon.version + aAddon.version +
-        "]]></li>";
-    }
-
-    function getAddonStatus(aAddon) {
-      let operations = [];
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_ENABLE) {
-        operations.push("PENDING_ENABLE");
-      }
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_DISABLE) {
-        operations.push("PENDING_DISABLE");
-      }
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_UNINSTALL) {
-        operations.push("PENDING_UNINSTALL");
-      }
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_INSTALL) {
-        operations.push("PENDING_INSTALL");
-      }
-
-      if (aAddon.pendingOperations & AddonManager.PENDING_UPGRADE) {
-        operations.push("PENDING_UPGRADE");
-      }
-
-      if (operations.length) {
-        return " (" + operations.join(", ") + ")";
-      }
-      return "";
-    }
-
-    /**
-     * Compares two addons by their name. Used in sorting.
-     */
-    function compareAddonNames(aNameA, aNameB) {
-      return String.localeCompare(aNameA.name, aNameB.name);
-    }
-
-    /**
-     * Resolves the promise which is the scope (this) of this function, filling
-     * it with an HTML representation of the passed add-ons.
-     */
-    function list(aType, aAddons) {
-      if (!aAddons.length) {
-        this.resolve(gcli.lookup("addonNoneOfType"));
-      }
-
-      // Separate the enabled add-ons from the disabled ones.
-      let enabledAddons = [];
-      let disabledAddons = [];
-
-      aAddons.forEach(function(aAddon) {
-        if (aAddon.isActive) {
-          enabledAddons.push(aAddon);
-        } else {
-          disabledAddons.push(aAddon);
-        }
-      });
-
-      let header;
-      switch(aType) {
-        case "dictionary":
-          header = gcli.lookup("addonListDictionaryHeading");
-          break;
-        case "extension":
-          header = gcli.lookup("addonListExtensionHeading");
-          break;
-        case "locale":
-          header = gcli.lookup("addonListLocaleHeading");
-          break;
-        case "plugin":
-          header = gcli.lookup("addonListPluginHeading");
-          break;
-        case "theme":
-          header = gcli.lookup("addonListThemeHeading");
-        case "all":
-          header = gcli.lookup("addonListAllHeading");
-          break;
-        default:
-          header = gcli.lookup("addonListUnknownHeading");
-      }
-
-      // Map and sort the add-ons, and create an HTML list.
-      let message = header +
-                    "<ol>" +
-                    enabledAddons.sort(compareAddonNames).map(representEnabledAddon).join("") +
-                    disabledAddons.sort(compareAddonNames).map(representDisabledAddon).join("") +
-                    "</ol>";
-
-      this.resolve(context.createView({ html: message }));
-    }
-
-    // Create the promise that will be resolved when the add-on listing has
-    // been finished.
-    let promise = context.createPromise();
-    let types = aArgs.type == "all" ? null : [aArgs.type];
-    AddonManager.getAddonsByTypes(types, list.bind(promise, aArgs.type));
-    return promise;
-  }
-});
-
-// We need a list of addon names for the enable and disable commands. Because
-// getting the name list is async we do not add the commands until we have the
-// list.
-AddonManager.getAllAddons(function addonAsync(aAddons) {
-  // We listen for installs to keep our addon list up to date. There is no need
-  // to listen for uninstalls because uninstalled addons are simply disabled
-  // until restart (to enable undo functionality).
-  AddonManager.addAddonListener({
-    onInstalled: function(aAddon) {
-      addonNameCache.push({
-        name: representAddon(aAddon).replace(/\s/g, "_"),
-        value: aAddon.name
-      });
-    },
-    onUninstalled: function(aAddon) {
-      let name = representAddon(aAddon).replace(/\s/g, "_");
-
-      for (let i = 0; i < addonNameCache.length; i++) {
-        if(addonNameCache[i].name == name) {
-          addonNameCache.splice(i, 1);
-          break;
-        }
-      }
-    },
-  });
-
-  /**
-   * Returns a string that represents the passed add-on.
-   */
-  function representAddon(aAddon) {
-    let name = aAddon.name + " " + aAddon.version;
-    return name.trim();
-  }
-
-  let addonNameCache = [];
-
-  // The name parameter, used in "addon enable" and "addon disable."
-  let nameParameter = {
-    name: "name",
-    type: {
-      name: "selection",
-      lookup: addonNameCache
-    },
-    description: gcli.lookup("addonNameDesc")
-  };
-
-  for (let addon of aAddons) {
-    addonNameCache.push({
-      name: representAddon(addon).replace(/\s/g, "_"),
-      value: addon.name
-    });
-  }
-
-  /**
-   * 'addon enable' command.
-   */
-  gcli.addCommand({
-    name: "addon enable",
-    description: gcli.lookup("addonEnableDesc"),
-    params: [nameParameter],
-    exec: function(aArgs, context) {
-      /**
-       * Enables the addon in the passed list which has a name that matches
-       * according to the passed name comparer, and resolves the promise which
-       * is the scope (this) of this function to display the result of this
-       * enable attempt.
-       */
-      function enable(aName, addons) {
-        // Find the add-on.
-        let addon = null;
-        addons.some(function(candidate) {
-          if (candidate.name == aName) {
-            addon = candidate;
-            return true;
-          } else {
-            return false;
-          }
-        });
-
-        let name = representAddon(addon);
-        let message = "";
-
-        if (!addon.userDisabled) {
-          message = gcli.lookupFormat("addonAlreadyEnabled", [name]);
-        } else {
-          addon.userDisabled = false;
-          message = gcli.lookupFormat("addonEnabled", [name]);
-        }
-        this.resolve(message);
-      }
-
-      let promise = context.createPromise();
-      // List the installed add-ons, enable one when done listing.
-      AddonManager.getAllAddons(enable.bind(promise, aArgs.name));
-      return promise;
-    }
-  });
-
-  /**
-   * 'addon disable' command.
-   */
-  gcli.addCommand({
-    name: "addon disable",
-    description: gcli.lookup("addonDisableDesc"),
-    params: [nameParameter],
-    exec: function(aArgs, context) {
-      /**
-       * Like enable, but ... you know ... the exact opposite.
-       */
-      function disable(aName, addons) {
-        // Find the add-on.
-        let addon = null;
-        addons.some(function(candidate) {
-          if (candidate.name == aName) {
-            addon = candidate;
-            return true;
-          } else {
-            return false;
-          }
-        });
-
-        let name = representAddon(addon);
-        let message = "";
-
-        if (addon.userDisabled) {
-          message = gcli.lookupFormat("addonAlreadyDisabled", [name]);
-        } else {
-          addon.userDisabled = true;
-          message = gcli.lookupFormat("addonDisabled", [name]);
-        }
-        this.resolve(message);
-      }
-
-      let promise = context.createPromise();
-      // List the installed add-ons, disable one when done listing.
-      AddonManager.getAllAddons(disable.bind(promise, aArgs.name));
-      return promise;
-    }
-  });
-  Flags.addonsLoaded = true;
-  Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdBreak.jsm
+++ /dev/null
@@ -1,184 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-                                  "resource:///modules/HUDService.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
-                                  "resource:///modules/devtools/Target.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
-                                  "resource:///modules/devtools/gDevTools.jsm");
-
-/**
- * 'break' command
- */
-gcli.addCommand({
-  name: "break",
-  description: gcli.lookup("breakDesc"),
-  manual: gcli.lookup("breakManual")
-});
-
-/**
- * 'break list' command
- */
-gcli.addCommand({
-  name: "break list",
-  description: gcli.lookup("breaklistDesc"),
-  returnType: "html",
-  exec: function(args, context) {
-    let dbg = getPanel(context, "jsdebugger");
-    if (!dbg) {
-      return gcli.lookup("debuggerStopped");
-    }
-
-    let breakpoints = dbg.getAllBreakpoints();
-
-    if (Object.keys(breakpoints).length === 0) {
-      return gcli.lookup("breaklistNone");
-    }
-
-    let reply = gcli.lookup("breaklistIntro");
-    reply += "<ol>";
-    for each (let breakpoint in breakpoints) {
-      let text = gcli.lookupFormat("breaklistLineEntry",
-                                   [breakpoint.location.url,
-                                    breakpoint.location.line]);
-      reply += "<li>" + text + "</li>";
-    };
-    reply += "</ol>";
-    return reply;
-  }
-});
-
-/**
- * 'break add' command
- */
-gcli.addCommand({
-  name: "break add",
-  description: gcli.lookup("breakaddDesc"),
-  manual: gcli.lookup("breakaddManual")
-});
-
-/**
- * 'break add line' command
- */
-gcli.addCommand({
-  name: "break add line",
-  description: gcli.lookup("breakaddlineDesc"),
-  params: [
-    {
-      name: "file",
-      type: {
-        name: "selection",
-        data: function(args, context) {
-          let files = [];
-          let dbg = getPanel(context, "jsdebugger");
-          if (dbg) {
-            let sourcesView = dbg.panelWin.DebuggerView.Sources;
-            for (let item in sourcesView) {
-              files.push(item.value);
-            }
-          }
-          return files;
-        }
-      },
-      description: gcli.lookup("breakaddlineFileDesc")
-    },
-    {
-      name: "line",
-      type: { name: "number", min: 1, step: 10 },
-      description: gcli.lookup("breakaddlineLineDesc")
-    }
-  ],
-  returnType: "html",
-  exec: function(args, context) {
-    args.type = "line";
-
-    let dbg = getPanel(context, "jsdebugger");
-    if (!dbg) {
-      return gcli.lookup("debuggerStopped");
-    }
-    var deferred = context.defer();
-    let position = { url: args.file, line: args.line };
-    dbg.addBreakpoint(position, function(aBreakpoint, aError) {
-      if (aError) {
-        deferred.resolve(gcli.lookupFormat("breakaddFailed", [aError]));
-        return;
-      }
-      deferred.resolve(gcli.lookup("breakaddAdded"));
-    });
-    return deferred.promise;
-  }
-});
-
-
-/**
- * 'break del' command
- */
-gcli.addCommand({
-  name: "break del",
-  description: gcli.lookup("breakdelDesc"),
-  params: [
-    {
-      name: "breakid",
-      type: {
-        name: "number",
-        min: 0,
-        max: function(args, context) {
-          let dbg = getPanel(context, "jsdebugger");
-          return dbg == null ?
-              null :
-              Object.keys(dbg.getAllBreakpoints()).length - 1;
-        },
-      },
-      description: gcli.lookup("breakdelBreakidDesc")
-    }
-  ],
-  returnType: "html",
-  exec: function(args, context) {
-    let dbg = getPanel(context, "jsdebugger");
-    if (!dbg) {
-      return gcli.lookup("debuggerStopped");
-    }
-
-    let breakpoints = dbg.getAllBreakpoints();
-    let id = Object.keys(breakpoints)[args.breakid];
-    if (!id || !(id in breakpoints)) {
-      return gcli.lookup("breakNotFound");
-    }
-
-    let deferred = context.defer();
-    try {
-      dbg.removeBreakpoint(breakpoints[id], function() {
-        deferred.resolve(gcli.lookup("breakdelRemoved"));
-      });
-    } catch (ex) {
-      // If the debugger has been closed already, don't scare the user.
-      deferred.resolve(gcli.lookup("breakdelRemoved"));
-    }
-    return deferred.promise;
-  }
-});
-
-/**
- * A helper to go from a command context to a debugger panel
- */
-function getPanel(context, id) {
-  if (context == null) {
-    return undefined;
-  }
-
-  let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-  let toolbox = gDevTools.getToolbox(target);
-  return toolbox == null ? undefined : toolbox.getPanel(id);
-}
deleted file mode 100644
--- a/browser/devtools/commandline/CmdCalllog.jsm
+++ /dev/null
@@ -1,107 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
-                                  "resource:///modules/devtools/gDevTools.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
-  let JsDebugger = {};
-  Components.utils.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
-
-  let global = Components.utils.getGlobalForObject({});
-  JsDebugger.addDebuggerToGlobal(global);
-
-  return global.Debugger;
-});
-
-XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
-                                  "resource:///modules/devtools/Target.jsm");
-
-let debuggers = [];
-
-/**
- * 'calllog' command
- */
-gcli.addCommand({
-  name: "calllog",
-  description: gcli.lookup("calllogDesc")
-})
-
-/**
- * 'calllog start' command
- */
-gcli.addCommand({
-  name: "calllog start",
-  description: gcli.lookup("calllogStartDesc"),
-
-  exec: function(args, context) {
-    let contentWindow = context.environment.contentDocument.defaultView;
-
-    let dbg = new Debugger(contentWindow);
-    dbg.onEnterFrame = function(frame) {
-      // BUG 773652 -  Make the output from the GCLI calllog command nicer
-      contentWindow.console.log("Method call: " + this.callDescription(frame));
-    }.bind(this);
-
-    debuggers.push(dbg);
-
-    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
-    let target = TargetFactory.forTab(gBrowser.selectedTab);
-    gDevTools.showToolbox(target, "webconsole");
-
-    return gcli.lookup("calllogStartReply");
-  },
-
-  callDescription: function(frame) {
-    let name = "<anonymous>";
-    if (frame.callee.name) {
-      name = frame.callee.name;
-    }
-    else {
-      let desc = frame.callee.getOwnPropertyDescriptor("displayName");
-      if (desc && desc.value && typeof desc.value == "string") {
-        name = desc.value;
-      }
-    }
-
-    let args = frame.arguments.map(this.valueToString).join(", ");
-    return name + "(" + args + ")";
-  },
-
-  valueToString: function(value) {
-    if (typeof value !== "object" || value === null) {
-      return uneval(value);
-    }
-    return "[object " + value.class + "]";
-  }
-});
-
-/**
- * 'calllog stop' command
- */
-gcli.addCommand({
-  name: "calllog stop",
-  description: gcli.lookup("calllogStopDesc"),
-
-  exec: function(args, context) {
-    let numDebuggers = debuggers.length;
-    if (numDebuggers == 0) {
-      return gcli.lookup("calllogStopNoLogging");
-    }
-
-    for (let dbg of debuggers) {
-      dbg.onEnterFrame = undefined;
-    }
-    debuggers = [];
-
-    return gcli.lookupFormat("calllogStopReply", [ numDebuggers ]);
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdCalllogChrome.jsm
+++ /dev/null
@@ -1,158 +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/. */
-
-
-this.EXPORTED_SYMBOLS = [ ];
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
-                                  "resource:///modules/devtools/gDevTools.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
-                                  "resource:///modules/devtools/Target.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "Debugger", function() {
-  let JsDebugger = {};
-  Cu.import("resource://gre/modules/jsdebugger.jsm", JsDebugger);
-
-  let global = Components.utils.getGlobalForObject({});
-  JsDebugger.addDebuggerToGlobal(global);
-
-  return global.Debugger;
-});
-
-let debuggers = [];
-let sandboxes = [];
-
-/**
- * 'calllog chromestart' command
- */
-gcli.addCommand({
-  name: "calllog chromestart",
-  description: gcli.lookup("calllogChromeStartDesc"),
-  get hidden() gcli.hiddenByChromePref(),
-  params: [
-    {
-      name: "sourceType",
-      type: {
-        name: "selection",
-        data: ["content-variable", "chrome-variable", "jsm", "javascript"]
-      }
-    },
-    {
-      name: "source",
-      type: "string",
-      description: gcli.lookup("calllogChromeSourceTypeDesc"),
-      manual: gcli.lookup("calllogChromeSourceTypeManual"),
-    }
-  ],
-  exec: function(args, context) {
-    let globalObj;
-    let contentWindow = context.environment.contentDocument.defaultView;
-
-    if (args.sourceType == "jsm") {
-      try {
-        globalObj = Cu.import(args.source);
-      }
-      catch (e) {
-        return gcli.lookup("callLogChromeInvalidJSM");
-      }
-    } else if (args.sourceType == "content-variable") {
-      if (args.source in contentWindow) {
-        globalObj = Cu.getGlobalForObject(contentWindow[args.source]);
-      } else {
-        throw new Error(gcli.lookup("callLogChromeVarNotFoundContent"));
-      }
-    } else if (args.sourceType == "chrome-variable") {
-      let chromeWin = context.environment.chromeDocument.defaultView;
-      if (args.source in chromeWin) {
-        globalObj = Cu.getGlobalForObject(chromeWin[args.source]);
-      } else {
-        return gcli.lookup("callLogChromeVarNotFoundChrome");
-      }
-    } else {
-      let chromeWin = context.environment.chromeDocument.defaultView;
-      let sandbox = new Cu.Sandbox(chromeWin,
-                                   {
-                                     sandboxPrototype: chromeWin,
-                                     wantXrays: false,
-                                     sandboxName: "gcli-cmd-calllog-chrome"
-                                   });
-      let returnVal;
-      try {
-        returnVal = Cu.evalInSandbox(args.source, sandbox, "ECMAv5");
-        sandboxes.push(sandbox);
-      } catch(e) {
-        // We need to save the message before cleaning up else e contains a dead
-        // object.
-        let msg = gcli.lookup("callLogChromeEvalException") + ": " + e;
-        Cu.nukeSandbox(sandbox);
-        return msg;
-      }
-
-      if (typeof returnVal == "undefined") {
-        return gcli.lookup("callLogChromeEvalNeedsObject");
-      }
-
-      globalObj = Cu.getGlobalForObject(returnVal);
-    }
-
-    let dbg = new Debugger(globalObj);
-    debuggers.push(dbg);
-
-    dbg.onEnterFrame = function(frame) {
-      // BUG 773652 -  Make the output from the GCLI calllog command nicer
-      contentWindow.console.log(gcli.lookup("callLogChromeMethodCall") +
-                                ": " + this.callDescription(frame));
-    }.bind(this);
-
-    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
-    let target = TargetFactory.forTab(gBrowser.selectedTab);
-    gDevTools.showToolbox(target, "webconsole");
-
-    return gcli.lookup("calllogChromeStartReply");
-  },
-
-  valueToString: function(value) {
-    if (typeof value !== "object" || value === null)
-      return uneval(value);
-    return "[object " + value.class + "]";
-  },
-
-  callDescription: function(frame) {
-    let name = frame.callee.name || gcli.lookup("callLogChromeAnonFunction");
-    let args = frame.arguments.map(this.valueToString).join(", ");
-    return name + "(" + args + ")";
-  }
-});
-
-/**
- * 'calllog chromestop' command
- */
-gcli.addCommand({
-  name: "calllog chromestop",
-  description: gcli.lookup("calllogChromeStopDesc"),
-  get hidden() gcli.hiddenByChromePref(),
-  exec: function(args, context) {
-    let numDebuggers = debuggers.length;
-    if (numDebuggers == 0) {
-      return gcli.lookup("calllogChromeStopNoLogging");
-    }
-
-    for (let dbg of debuggers) {
-      dbg.onEnterFrame = undefined;
-      dbg.enabled = false;
-    }
-    for (let sandbox of sandboxes) {
-      Cu.nukeSandbox(sandbox);
-    }
-    debuggers = [];
-    sandboxes = [];
-
-    return gcli.lookupFormat("calllogChromeStopReply", [ numDebuggers ]);
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdCmd.jsm
+++ /dev/null
@@ -1,129 +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/. */
-
-this.EXPORTED_SYMBOLS = [ "CmdCommands" ];
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-let prefSvc = "@mozilla.org/preferences-service;1";
-XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
-  let prefService = Cc[prefSvc].getService(Ci.nsIPrefService);
-  return prefService.getBranch(null).QueryInterface(Ci.nsIPrefBranch2);
-});
-
-XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
-                                  "resource://gre/modules/NetUtil.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "console",
-                                  "resource://gre/modules/devtools/Console.jsm");
-
-const PREF_DIR = "devtools.commands.dir";
-
-/**
- * A place to store the names of the commands that we have added as a result of
- * calling refreshAutoCommands(). Used by refreshAutoCommands to remove the
- * added commands.
- */
-let commands = [];
-
-/**
- * Exported API
- */
-this.CmdCommands = {
-  /**
-   * Called to look in a directory pointed at by the devtools.commands.dir pref
-   * for *.mozcmd files which are then loaded.
-   * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
-   * we eval the script from the .mozcmd file. This should be a chrome window.
-   */
-  refreshAutoCommands: function GC_refreshAutoCommands(aSandboxPrincipal) {
-    // First get rid of the last set of commands
-    commands.forEach(function(name) {
-      gcli.removeCommand(name);
-    });
-
-    let dirName = prefBranch.getComplexValue(PREF_DIR,
-                                             Ci.nsISupportsString).data.trim();
-    if (dirName == "") {
-      return;
-    }
-
-    let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
-    dir.initWithPath(dirName);
-    if (!dir.exists() || !dir.isDirectory()) {
-      throw new Error('\'' + dirName + '\' is not a directory.');
-    }
-
-    let en = dir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
-
-    while (true) {
-      let file = en.nextFile;
-      if (!file) {
-        break;
-      }
-      if (file.leafName.match(/.*\.mozcmd$/) && file.isFile() && file.isReadable()) {
-        loadCommandFile(file, aSandboxPrincipal);
-      }
-    }
-  },
-};
-
-/**
- * Load the commands from a single file
- * @param nsIFile aFile The file containing the commands that we should read
- * @param nsIPrincipal aSandboxPrincipal Scope object for the Sandbox in which
- * we eval the script from the .mozcmd file. This should be a chrome window.
- */
-function loadCommandFile(aFile, aSandboxPrincipal) {
-  NetUtil.asyncFetch(aFile, function refresh_fetch(aStream, aStatus) {
-    if (!Components.isSuccessCode(aStatus)) {
-      console.error("NetUtil.asyncFetch(" + aFile.path + ",..) failed. Status=" + aStatus);
-      return;
-    }
-
-    let source = NetUtil.readInputStreamToString(aStream, aStream.available());
-    aStream.close();
-
-    let sandbox = new Cu.Sandbox(aSandboxPrincipal, {
-      sandboxPrototype: aSandboxPrincipal,
-      wantXrays: false,
-      sandboxName: aFile.path
-    });
-    let data = Cu.evalInSandbox(source, sandbox, "1.8", aFile.leafName, 1);
-
-    if (!Array.isArray(data)) {
-      console.error("Command file '" + aFile.leafName + "' does not have top level array.");
-      return;
-    }
-
-    data.forEach(function(commandSpec) {
-      gcli.addCommand(commandSpec);
-      commands.push(commandSpec.name);
-    });
-  }.bind(this));
-}
-
-/**
- * 'cmd' command
- */
-gcli.addCommand({
-  name: "cmd",
-  get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
-  description: gcli.lookup("cmdDesc")
-});
-
-/**
- * 'cmd refresh' command
- */
-gcli.addCommand({
-  name: "cmd refresh",
-  description: gcli.lookup("cmdRefreshDesc"),
-  get hidden() { return !prefBranch.prefHasUserValue(PREF_DIR); },
-  exec: function Command_cmdRefresh(args, context) {
-    let chromeWindow = context.environment.chromeDocument.defaultView;
-    CmdCommands.refreshAutoCommands(chromeWindow);
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdConsole.jsm
+++ /dev/null
@@ -1,68 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "HUDService",
-                                  "resource:///modules/HUDService.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
-                                  "resource:///modules/devtools/gDevTools.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
-                                  "resource:///modules/devtools/Target.jsm");
-
-/**
- * 'console' command
- */
-gcli.addCommand({
-  name: "console",
-  description: gcli.lookup("consoleDesc"),
-  manual: gcli.lookup("consoleManual")
-});
-
-/**
- * 'console clear' command
- */
-gcli.addCommand({
-  name: "console clear",
-  description: gcli.lookup("consoleclearDesc"),
-  exec: function Command_consoleClear(args, context) {
-    let window = context.environment.contentDocument.defaultView;
-    let hud = HUDService.getHudByWindow(window);
-    // hud will be null if the web console has not been opened for this window
-    if (hud) {
-      hud.jsterm.clearOutput();
-    }
-  }
-});
-
-/**
- * 'console close' command
- */
-gcli.addCommand({
-  name: "console close",
-  description: gcli.lookup("consolecloseDesc"),
-  exec: function Command_consoleClose(args, context) {
-    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
-    let target = TargetFactory.forTab(gBrowser.selectedTab);
-    return gDevTools.closeToolbox(target);
-  }
-});
-
-/**
- * 'console open' command
- */
-gcli.addCommand({
-  name: "console open",
-  description: gcli.lookup("consoleopenDesc"),
-  exec: function Command_consoleOpen(args, context) {
-    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
-    let target = TargetFactory.forTab(gBrowser.selectedTab);
-    return gDevTools.showToolbox(target, "webconsole");
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdCookie.jsm
+++ /dev/null
@@ -1,207 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "console",
-                                  "resource://gre/modules/devtools/Console.jsm");
-
-// We should really be using nsICookieManager so we can read more than just the
-// key/value of cookies. The difficulty is filtering the cookies that are
-// relevant to the current page. See
-// https://github.com/firebug/firebug/blob/master/extension/content/firebug/cookies/cookieObserver.js#L123
-// For details on how this is done with Firebug
-
-/**
- * 'cookie' command
- */
-gcli.addCommand({
-  name: "cookie",
-  description: gcli.lookup("cookieDesc"),
-  manual: gcli.lookup("cookieManual")
-});
-
-/**
- * The template for the 'cookie list' command.
- */
-var cookieListHtml = "" +
-  "<table>" +
-  "  <tr>" +
-  "    <th>" + gcli.lookup("cookieListOutKey") + "</th>" +
-  "    <th>" + gcli.lookup("cookieListOutValue") + "</th>" +
-  "    <th>" + gcli.lookup("cookieListOutActions") + "</th>" +
-  "  </tr>" +
-  "  <tr foreach='cookie in ${cookies}'>" +
-  "    <td>${cookie.key}</td>" +
-  "    <td>${cookie.value}</td>" +
-  "    <td>" +
-  "      <span class='gcli-out-shortcut' onclick='${onclick}'" +
-  "          data-command='cookie set ${cookie.key} '" +
-  "          >" + gcli.lookup("cookieListOutEdit") + "</span>" +
-  "      <span class='gcli-out-shortcut'" +
-  "          onclick='${onclick}' ondblclick='${ondblclick}'" +
-  "          data-command='cookie remove ${cookie.key}'" +
-  "          >" + gcli.lookup("cookieListOutRemove") + "</span>" +
-  "    </td>" +
-  "  </tr>" +
-  "</table>" +
-  "";
-
-/**
- * 'cookie list' command
- */
-gcli.addCommand({
-  name: "cookie list",
-  description: gcli.lookup("cookieListDesc"),
-  manual: gcli.lookup("cookieListManual"),
-  returnType: "string",
-  exec: function Command_cookieList(args, context) {
-    // Parse out an array of { key:..., value:... } objects for each cookie
-    var doc = context.environment.contentDocument;
-    var cookies = doc.cookie.split("; ").map(function(cookieStr) {
-      var equalsPos = cookieStr.indexOf("=");
-      return {
-        key: cookieStr.substring(0, equalsPos),
-        value: cookieStr.substring(equalsPos + 1)
-      };
-    });
-
-    return context.createView({
-      html: cookieListHtml,
-      data: {
-        cookies: cookies,
-        onclick: createUpdateHandler(context),
-        ondblclick: createExecuteHandler(context),
-      }
-    });
-  }
-});
-
-/**
- * 'cookie remove' command
- */
-gcli.addCommand({
-  name: "cookie remove",
-  description: gcli.lookup("cookieRemoveDesc"),
-  manual: gcli.lookup("cookieRemoveManual"),
-  params: [
-    {
-      name: "key",
-      type: "string",
-      description: gcli.lookup("cookieRemoveKeyDesc"),
-    }
-  ],
-  exec: function Command_cookieRemove(args, context) {
-    let document = context.environment.contentDocument;
-    let expDate = new Date();
-    expDate.setDate(expDate.getDate() - 1);
-    document.cookie = escape(args.key) + "=; expires=" + expDate.toGMTString();
-  }
-});
-
-/**
- * 'cookie set' command
- */
-gcli.addCommand({
-  name: "cookie set",
-  description: gcli.lookup("cookieSetDesc"),
-  manual: gcli.lookup("cookieSetManual"),
-  params: [
-    {
-      name: "key",
-      type: "string",
-      description: gcli.lookup("cookieSetKeyDesc")
-    },
-    {
-      name: "value",
-      type: "string",
-      description: gcli.lookup("cookieSetValueDesc")
-    },
-    {
-      group: gcli.lookup("cookieSetOptionsDesc"),
-      params: [
-        {
-          name: "path",
-          type: "string",
-          defaultValue: "/",
-          description: gcli.lookup("cookieSetPathDesc")
-        },
-        {
-          name: "domain",
-          type: "string",
-          defaultValue: null,
-          description: gcli.lookup("cookieSetDomainDesc")
-        },
-        {
-          name: "secure",
-          type: "boolean",
-          description: gcli.lookup("cookieSetSecureDesc")
-        }
-      ]
-    }
-  ],
-  exec: function Command_cookieSet(args, context) {
-    let document = context.environment.contentDocument;
-
-    document.cookie = escape(args.key) + "=" + escape(args.value) +
-            (args.domain ? "; domain=" + args.domain : "") +
-            (args.path ? "; path=" + args.path : "") +
-            (args.secure ? "; secure" : ""); 
-  }
-});
-
-/**
- * Helper to find the 'data-command' attribute and call some action on it.
- * @see |updateCommand()| and |executeCommand()|
- */
-function withCommand(element, action) {
-  var command = element.getAttribute("data-command");
-  if (!command) {
-    command = element.querySelector("*[data-command]")
-            .getAttribute("data-command");
-  }
-
-  if (command) {
-    action(command);
-  }
-  else {
-    console.warn("Missing data-command for " + util.findCssSelector(element));
-  }
-}
-
-/**
- * Create a handler to update the requisition to contain the text held in the
- * first matching data-command attribute under the currentTarget of the event.
- * @param context Either a Requisition or an ExecutionContext or another object
- * that contains an |update()| function that follows a similar contract.
- */
-function createUpdateHandler(context) {
-  return function(ev) {
-    withCommand(ev.currentTarget, function(command) {
-      context.update(command);
-    });
-  }
-}
-
-/**
- * Create a handler to execute the text held in the data-command attribute
- * under the currentTarget of the event.
- * @param context Either a Requisition or an ExecutionContext or another object
- * that contains an |update()| function that follows a similar contract.
- */
-function createExecuteHandler(context) {
-  return function(ev) {
-    withCommand(ev.currentTarget, function(command) {
-      context.exec({
-        visible: true,
-        typed: command
-      });
-    });
-  }
-}
deleted file mode 100644
--- a/browser/devtools/commandline/CmdDbg.jsm
+++ /dev/null
@@ -1,176 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
-                                  "resource:///modules/devtools/gDevTools.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "TargetFactory",
-                                  "resource:///modules/devtools/Target.jsm");
-
-/**
- * 'dbg' command
- */
-gcli.addCommand({
-  name: "dbg",
-  description: gcli.lookup("dbgDesc"),
-  manual: gcli.lookup("dbgManual")
-});
-
-/**
- * 'dbg open' command
- */
-gcli.addCommand({
-  name: "dbg open",
-  description: gcli.lookup("dbgOpen"),
-  params: [],
-  exec: function (args, context) {
-    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
-    let target = TargetFactory.forTab(gBrowser.selectedTab);
-    return gDevTools.showToolbox(target, "jsdebugger");
-  }
-});
-
-/**
- * 'dbg close' command
- */
-gcli.addCommand({
-  name: "dbg close",
-  description: gcli.lookup("dbgClose"),
-  params: [],
-  exec: function (args, context) {
-    let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
-    let target = TargetFactory.forTab(gBrowser.selectedTab);
-    return gDevTools.closeToolbox(target);
-  }
-});
-
-/**
- * 'dbg interrupt' command
- */
-gcli.addCommand({
-  name: "dbg interrupt",
-  description: gcli.lookup("dbgInterrupt"),
-  params: [],
-  exec: function(args, context) {
-    let dbg = getPanel(context, "jsdebugger");
-    if (!dbg) {
-      return gcli.lookup("debuggerStopped");
-    }
-
-    let controller = dbg._controller;
-    let thread = controller.activeThread;
-    if (!thread.paused) {
-      thread.interrupt();
-    }
-  }
-});
-
-/**
- * 'dbg continue' command
- */
-gcli.addCommand({
-  name: "dbg continue",
-  description: gcli.lookup("dbgContinue"),
-  params: [],
-  exec: function(args, context) {
-    let dbg = getPanel(context, "jsdebugger");
-    if (!dbg) {
-      return gcli.lookup("debuggerStopped");
-    }
-
-    let controller = dbg._controller;
-    let thread = controller.activeThread;
-    if (thread.paused) {
-      thread.resume();
-    }
-  }
-});
-
-/**
- * 'dbg step' command
- */
-gcli.addCommand({
-  name: "dbg step",
-  description: gcli.lookup("dbgStepDesc"),
-  manual: gcli.lookup("dbgStepManual")
-});
-
-/**
- * 'dbg step over' command
- */
-gcli.addCommand({
-  name: "dbg step over",
-  description: gcli.lookup("dbgStepOverDesc"),
-  params: [],
-  exec: function(args, context) {
-    let dbg = getPanel(context, "jsdebugger");
-    if (!dbg) {
-      return gcli.lookup("debuggerStopped");
-    }
-
-    let controller = dbg._controller;
-    let thread = controller.activeThread;
-    if (thread.paused) {
-      thread.stepOver();
-    }
-  }
-});
-
-/**
- * 'dbg step in' command
- */
-gcli.addCommand({
-  name: 'dbg step in',
-  description: gcli.lookup("dbgStepInDesc"),
-  params: [],
-  exec: function(args, context) {
-    let dbg = getPanel(context, "jsdebugger");
-    if (!dbg) {
-      return gcli.lookup("debuggerStopped");
-    }
-
-    let controller = dbg._controller;
-    let thread = controller.activeThread;
-    if (thread.paused) {
-      thread.stepIn();
-    }
-  }
-});
-
-/**
- * 'dbg step over' command
- */
-gcli.addCommand({
-  name: 'dbg step out',
-  description: gcli.lookup("dbgStepOutDesc"),
-  params: [],
-  exec: function(args, context) {
-    let dbg = getPanel(context, "jsdebugger");
-    if (!dbg) {
-      return gcli.lookup("debuggerStopped");
-    }
-
-    let controller = dbg._controller;
-    let thread = controller.activeThread;
-    if (thread.paused) {
-      thread.stepOut();
-    }
-  }
-});
-
-/**
- * A helper to go from a command context to a debugger panel
- */
-function getPanel(context, id) {
-  let gBrowser = context.environment.chromeDocument.defaultView.gBrowser;
-  let target = TargetFactory.forTab(gBrowser.selectedTab);
-  let toolbox = gDevTools.getToolbox(target);
-  return toolbox == null ? undefined : toolbox.getPanel(id);
-}
deleted file mode 100644
--- a/browser/devtools/commandline/CmdEcho.jsm
+++ /dev/null
@@ -1,29 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-/**
- * 'echo' command
- */
-gcli.addCommand({
-  name: "echo",
-  description: gcli.lookup("echoDesc"),
-  params: [
-    {
-      name: "message",
-      type: "string",
-      description: gcli.lookup("echoMessageDesc")
-    }
-  ],
-  returnType: "string",
-  hidden: true,
-  exec: function Command_echo(args, context) {
-    return args.message;
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdExport.jsm
+++ /dev/null
@@ -1,32 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-/**
- * 'export' command
- */
-gcli.addCommand({
-  name: "export",
-  description: gcli.lookup("exportDesc"),
-});
-
-/**
- * The 'export html' command. This command allows the user to export the page to
- * HTML after they do DOM changes.
- */
-gcli.addCommand({
-  name: "export html",
-  description: gcli.lookup("exportHtmlDesc"),
-  exec: function(args, context) {
-    let document = context.environment.contentDocument;
-    let window = document.defaultView;
-    let page = document.documentElement.outerHTML;
-    window.open('data:text/plain;charset=utf8,' + encodeURIComponent(page));
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdJsb.jsm
+++ /dev/null
@@ -1,138 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-const XMLHttpRequest =
-  Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1");
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "js_beautify",
-                                  "resource:///modules/devtools/Jsbeautify.jsm");
-
-/**
- * jsb command.
- */
-gcli.addCommand({
-  name: 'jsb',
-  description: gcli.lookup('jsbDesc'),
-  returnValue:'string',
-  params: [
-    {
-      name: 'url',
-      type: 'string',
-      description: gcli.lookup('jsbUrlDesc')
-    },
-    {
-      group: gcli.lookup("jsbOptionsDesc"),
-      params: [
-        {
-          name: 'indentSize',
-          type: 'number',
-          description: gcli.lookup('jsbIndentSizeDesc'),
-          manual: gcli.lookup('jsbIndentSizeManual'),
-          defaultValue: 2
-        },
-        {
-          name: 'indentChar',
-          type: {
-            name: 'selection',
-            lookup: [
-              { name: "space", value: " " },
-              { name: "tab", value: "\t" }
-            ]
-          },
-          description: gcli.lookup('jsbIndentCharDesc'),
-          manual: gcli.lookup('jsbIndentCharManual'),
-          defaultValue: ' ',
-        },
-        {
-          name: 'doNotPreserveNewlines',
-          type: 'boolean',
-          description: gcli.lookup('jsbDoNotPreserveNewlinesDesc')
-        },
-        {
-          name: 'preserveMaxNewlines',
-          type: 'number',
-          description: gcli.lookup('jsbPreserveMaxNewlinesDesc'),
-          manual: gcli.lookup('jsbPreserveMaxNewlinesManual'),
-          defaultValue: -1
-        },
-        {
-          name: 'jslintHappy',
-          type: 'boolean',
-          description: gcli.lookup('jsbJslintHappyDesc'),
-          manual: gcli.lookup('jsbJslintHappyManual')
-        },
-        {
-          name: 'braceStyle',
-          type: {
-            name: 'selection',
-            data: ['collapse', 'expand', 'end-expand', 'expand-strict']
-          },
-          description: gcli.lookup('jsbBraceStyleDesc'),
-          manual: gcli.lookup('jsbBraceStyleManual'),
-          defaultValue: "collapse"
-        },
-        {
-          name: 'noSpaceBeforeConditional',
-          type: 'boolean',
-          description: gcli.lookup('jsbNoSpaceBeforeConditionalDesc')
-        },
-        {
-          name: 'unescapeStrings',
-          type: 'boolean',
-          description: gcli.lookup('jsbUnescapeStringsDesc'),
-          manual: gcli.lookup('jsbUnescapeStringsManual')
-        }
-      ]
-    }
-  ],
-  exec: function(args, context) {
-    let opts = {
-      indent_size: args.indentSize,
-      indent_char: args.indentChar,
-      preserve_newlines: !args.doNotPreserveNewlines,
-      max_preserve_newlines: args.preserveMaxNewlines == -1 ?
-                             undefined : args.preserveMaxNewlines,
-      jslint_happy: args.jslintHappy,
-      brace_style: args.braceStyle,
-      space_before_conditional: !args.noSpaceBeforeConditional,
-      unescape_strings: args.unescapeStrings
-    };
-
-    let xhr = new XMLHttpRequest();
-
-    try {
-      xhr.open("GET", args.url, true);
-    } catch(e) {
-      return gcli.lookup('jsbInvalidURL');
-    }
-
-    let promise = context.createPromise();
-
-    xhr.onreadystatechange = function(aEvt) {
-      if (xhr.readyState == 4) {
-        if (xhr.status == 200 || xhr.status == 0) {
-          let browserDoc = context.environment.chromeDocument;
-          let browserWindow = browserDoc.defaultView;
-          let gBrowser = browserWindow.gBrowser;
-          let result = js_beautify(xhr.responseText, opts);
-
-          browserWindow.Scratchpad.ScratchpadManager.openScratchpad({text: result});
-
-          promise.resolve();
-        } else {
-          promise.resolve("Unable to load page to beautify: " + args.url + " " +
-                          xhr.status + " " + xhr.statusText);
-        }
-      };
-    }
-    xhr.send(null);
-    return promise;
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdPagemod.jsm
+++ /dev/null
@@ -1,264 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-
-/**
- * 'pagemod' command
- */
-gcli.addCommand({
-  name: "pagemod",
-  description: gcli.lookup("pagemodDesc"),
-});
-
-/**
- * The 'pagemod replace' command. This command allows the user to search and
- * replace within text nodes and attributes.
- */
-gcli.addCommand({
-  name: "pagemod replace",
-  description: gcli.lookup("pagemodReplaceDesc"),
-  params: [
-    {
-      name: "search",
-      type: "string",
-      description: gcli.lookup("pagemodReplaceSearchDesc"),
-    },
-    {
-      name: "replace",
-      type: "string",
-      description: gcli.lookup("pagemodReplaceReplaceDesc"),
-    },
-    {
-      name: "ignoreCase",
-      type: "boolean",
-      description: gcli.lookup("pagemodReplaceIgnoreCaseDesc"),
-    },
-    {
-      name: "selector",
-      type: "string",
-      description: gcli.lookup("pagemodReplaceSelectorDesc"),
-      defaultValue: "*:not(script):not(style):not(embed):not(object):not(frame):not(iframe):not(frameset)",
-    },
-    {
-      name: "root",
-      type: "node",
-      description: gcli.lookup("pagemodReplaceRootDesc"),
-      defaultValue: null,
-    },
-    {
-      name: "attrOnly",
-      type: "boolean",
-      description: gcli.lookup("pagemodReplaceAttrOnlyDesc"),
-    },
-    {
-      name: "contentOnly",
-      type: "boolean",
-      description: gcli.lookup("pagemodReplaceContentOnlyDesc"),
-    },
-    {
-      name: "attributes",
-      type: "string",
-      description: gcli.lookup("pagemodReplaceAttributesDesc"),
-      defaultValue: null,
-    },
-  ],
-  exec: function(args, context) {
-    let document = context.environment.contentDocument;
-    let searchTextNodes = !args.attrOnly;
-    let searchAttributes = !args.contentOnly;
-    let regexOptions = args.ignoreCase ? 'ig' : 'g';
-    let search = new RegExp(escapeRegex(args.search), regexOptions);
-    let attributeRegex = null;
-    if (args.attributes) {
-      attributeRegex = new RegExp(args.attributes, regexOptions);
-    }
-
-    let root = args.root || document;
-    let elements = root.querySelectorAll(args.selector);
-    elements = Array.prototype.slice.call(elements);
-
-    let replacedTextNodes = 0;
-    let replacedAttributes = 0;
-
-    function replaceAttribute() {
-      replacedAttributes++;
-      return args.replace;
-    }
-    function replaceTextNode() {
-      replacedTextNodes++;
-      return args.replace;
-    }
-
-    for (let i = 0; i < elements.length; i++) {
-      let element = elements[i];
-      if (searchTextNodes) {
-        for (let y = 0; y < element.childNodes.length; y++) {
-          let node = element.childNodes[y];
-          if (node.nodeType == node.TEXT_NODE) {
-            node.textContent = node.textContent.replace(search, replaceTextNode);
-          }
-        }
-      }
-
-      if (searchAttributes) {
-        if (!element.attributes) {
-          continue;
-        }
-        for (let y = 0; y < element.attributes.length; y++) {
-          let attr = element.attributes[y];
-          if (!attributeRegex || attributeRegex.test(attr.name)) {
-            attr.value = attr.value.replace(search, replaceAttribute);
-          }
-        }
-      }
-    }
-
-    return gcli.lookupFormat("pagemodReplaceResult",
-                             [elements.length, replacedTextNodes,
-                              replacedAttributes]);
-  }
-});
-
-/**
- * 'pagemod remove' command
- */
-gcli.addCommand({
-  name: "pagemod remove",
-  description: gcli.lookup("pagemodRemoveDesc"),
-});
-
-
-/**
- * The 'pagemod remove element' command.
- */
-gcli.addCommand({
-  name: "pagemod remove element",
-  description: gcli.lookup("pagemodRemoveElementDesc"),
-  params: [
-    {
-      name: "search",
-      type: "string",
-      description: gcli.lookup("pagemodRemoveElementSearchDesc"),
-    },
-    {
-      name: "root",
-      type: "node",
-      description: gcli.lookup("pagemodRemoveElementRootDesc"),
-      defaultValue: null,
-    },
-    {
-      name: 'stripOnly',
-      type: 'boolean',
-      description: gcli.lookup("pagemodRemoveElementStripOnlyDesc"),
-    },
-    {
-      name: 'ifEmptyOnly',
-      type: 'boolean',
-      description: gcli.lookup("pagemodRemoveElementIfEmptyOnlyDesc"),
-    },
-  ],
-  exec: function(args, context) {
-    let document = context.environment.contentDocument;
-    let root = args.root || document;
-    let elements = Array.prototype.slice.call(root.querySelectorAll(args.search));
-
-    let removed = 0;
-    for (let i = 0; i < elements.length; i++) {
-      let element = elements[i];
-      let parentNode = element.parentNode;
-      if (!parentNode || !element.removeChild) {
-        continue;
-      }
-      if (args.stripOnly) {
-        while (element.hasChildNodes()) {
-          parentNode.insertBefore(element.childNodes[0], element);
-        }
-      }
-      if (!args.ifEmptyOnly || !element.hasChildNodes()) {
-        element.parentNode.removeChild(element);
-        removed++;
-      }
-    }
-
-    return gcli.lookupFormat("pagemodRemoveElementResultMatchedAndRemovedElements",
-                             [elements.length, removed]);
-  }
-});
-
-/**
- * The 'pagemod remove attribute' command.
- */
-gcli.addCommand({
-  name: "pagemod remove attribute",
-  description: gcli.lookup("pagemodRemoveAttributeDesc"),
-  params: [
-    {
-      name: "searchAttributes",
-      type: "string",
-      description: gcli.lookup("pagemodRemoveAttributeSearchAttributesDesc"),
-    },
-    {
-      name: "searchElements",
-      type: "string",
-      description: gcli.lookup("pagemodRemoveAttributeSearchElementsDesc"),
-    },
-    {
-      name: "root",
-      type: "node",
-      description: gcli.lookup("pagemodRemoveAttributeRootDesc"),
-      defaultValue: null,
-    },
-    {
-      name: "ignoreCase",
-      type: "boolean",
-      description: gcli.lookup("pagemodRemoveAttributeIgnoreCaseDesc"),
-    },
-  ],
-  exec: function(args, context) {
-    let document = context.environment.contentDocument;
-
-    let root = args.root || document;
-    let regexOptions = args.ignoreCase ? 'ig' : 'g';
-    let attributeRegex = new RegExp(args.searchAttributes, regexOptions);
-    let elements = root.querySelectorAll(args.searchElements);
-    elements = Array.prototype.slice.call(elements);
-
-    let removed = 0;
-    for (let i = 0; i < elements.length; i++) {
-      let element = elements[i];
-      if (!element.attributes) {
-        continue;
-      }
-
-      var attrs = Array.prototype.slice.call(element.attributes);
-      for (let y = 0; y < attrs.length; y++) {
-        let attr = attrs[y];
-        if (attributeRegex.test(attr.name)) {
-          element.removeAttribute(attr.name);
-          removed++;
-        }
-      }
-    }
-
-    return gcli.lookupFormat("pagemodRemoveAttributeResult",
-                             [elements.length, removed]);
-  }
-});
-
-/**
- * Make a given string safe to use  in a regular expression.
- *
- * @param string aString
- *        The string you want to use in a regex.
- * @return string
- *         The equivalent of |aString| but safe to use in a regex.
- */
-function escapeRegex(aString) {
-  return aString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
-}
deleted file mode 100644
--- a/browser/devtools/commandline/CmdRestart.jsm
+++ /dev/null
@@ -1,54 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-/**
- * Restart command
- *
- * @param boolean nocache
- *        Disables loading content from cache upon restart.
- *
- * Examples :
- * >> restart
- * - restarts browser immediately
- * >> restart --nocache
- * - restarts immediately and starts Firefox without using cache
- */
-gcli.addCommand({
-  name: "restart",
-  description: gcli.lookup("restartFirefoxDesc"),
-  params: [
-    {
-      name: "nocache",
-      type: "boolean",
-      description: gcli.lookup("restartFirefoxNocacheDesc")
-    }
-  ],
-  returnType: "string",
-  exec: function Restart(args, context) {
-    let canceled = Cc["@mozilla.org/supports-PRBool;1"]
-                     .createInstance(Ci.nsISupportsPRBool);
-    Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
-    if (canceled.data) {
-      return gcli.lookup("restartFirefoxRequestCancelled");
-    }
-
-    // disable loading content from cache.
-    if (args.nocache) {
-      Services.appinfo.invalidateCachesOnRestart();
-    }
-
-    // restart
-    Cc['@mozilla.org/toolkit/app-startup;1']
-      .getService(Ci.nsIAppStartup)
-      .quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
-    return gcli.lookup("restartFirefoxRestarting");
-  }
-});
deleted file mode 100644
--- a/browser/devtools/commandline/CmdScreenshot.jsm
+++ /dev/null
@@ -1,238 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-this.EXPORTED_SYMBOLS = [ ];
-
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "LayoutHelpers",
-                                  "resource:///modules/devtools/LayoutHelpers.jsm");
-
-// String used as an indication to generate default file name in the following
-// format: "Screen Shot yyyy-mm-dd at HH.MM.SS.png"
-const FILENAME_DEFAULT_VALUE = " ";
-
-/**
- * 'screenshot' command
- */
-gcli.addCommand({
-  name: "screenshot",
-  description: gcli.lookup("screenshotDesc"),
-  manual: gcli.lookup("screenshotManual"),
-  returnType: "html",
-  params: [
-    {
-      name: "filename",
-      type: "string",
-      defaultValue: FILENAME_DEFAULT_VALUE,
-      description: gcli.lookup("screenshotFilenameDesc"),
-      manual: gcli.lookup("screenshotFilenameManual")
-    },
-    {
-      group: gcli.lookup("screenshotGroupOptions"),
-      params: [
-        {
-          name: "clipboard",
-          type: "boolean",
-          description: gcli.lookup("screenshotClipboardDesc"),
-          manual: gcli.lookup("screenshotClipboardManual")
-        },
-        {
-          name: "chrome",
-          type: "boolean",
-          description: gcli.lookup("screenshotChromeDesc"),
-          manual: gcli.lookup("screenshotChromeManual")
-        },
-        {
-          name: "delay",
-          type: { name: "number", min: 0 },
-          defaultValue: 0,
-          description: gcli.lookup("screenshotDelayDesc"),
-          manual: gcli.lookup("screenshotDelayManual")
-        },
-        {
-          name: "fullpage",
-          type: "boolean",
-          description: gcli.lookup("screenshotFullPageDesc"),
-          manual: gcli.lookup("screenshotFullPageManual")
-        },
-        {
-          name: "selector",
-          type: "node",
-          defaultValue: null,
-          description: gcli.lookup("inspectNodeDesc"),
-          manual: gcli.lookup("inspectNodeManual")
-        }
-      ]
-    }
-  ],
-  exec: function Command_screenshot(args, context) {
-    if (args.chrome && args.selector) {
-      // Node screenshot with chrome option does not work as inteded
-      // Refer https://bugzilla.mozilla.org/show_bug.cgi?id=659268#c7
-      // throwing for now.
-      throw new Error(gcli.lookup("screenshotSelectorChromeConflict"));
-    }
-    var document = args.chrome? context.environment.chromeDocument
-                              : context.environment.contentDocument;
-    if (args.delay > 0) {
-      var promise = context.createPromise();
-      document.defaultView.setTimeout(function Command_screenshotDelay() {
-        let reply = this.grabScreen(document, args.filename, args.clipboard,
-                                    args.fullpage);
-        promise.resolve(reply);
-      }.bind(this), args.delay * 1000);
-      return promise;
-    }
-    else {
-      return this.grabScreen(document, args.filename, args.clipboard,
-                             args.fullpage, args.selector);
-    }
-  },
-  grabScreen:
-  function Command_screenshotGrabScreen(document, filename, clipboard,
-                                        fullpage, node) {
-    let window = document.defaultView;
-    let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
-    let left = 0;
-    let top = 0;
-    let width;
-    let height;
-    let div = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
-
-    if (!fullpage) {
-      if (!node) {
-        left = window.scrollX;
-        top = window.scrollY;
-        width = window.innerWidth;
-        height = window.innerHeight;
-      } else {
-        let rect = LayoutHelpers.getRect(node, window);
-        top = rect.top;
-        left = rect.left;
-        width = rect.width;
-        height = rect.height;
-      }
-    } else {
-      width = window.innerWidth + window.scrollMaxX;
-      height = window.innerHeight + window.scrollMaxY;
-    }
-    canvas.width = width;
-    canvas.height = height;
-
-    let ctx = canvas.getContext("2d");
-    ctx.drawWindow(window, left, top, width, height, "#fff");
-    let data = canvas.toDataURL("image/png", "");
-
-    let loadContext = document.defaultView
-                              .QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIWebNavigation)
-                              .QueryInterface(Ci.nsILoadContext);
-
-    try {
-      if (clipboard) {
-        let io = Cc["@mozilla.org/network/io-service;1"]
-                   .getService(Ci.nsIIOService);
-        let channel = io.newChannel(data, null, null);
-        let input = channel.open();
-        let imgTools = Cc["@mozilla.org/image/tools;1"]
-                         .getService(Ci.imgITools);
-
-        let container = {};
-        imgTools.decodeImageData(input, channel.contentType, container);
-
-        let wrapped = Cc["@mozilla.org/supports-interface-pointer;1"]
-                        .createInstance(Ci.nsISupportsInterfacePointer);
-        wrapped.data = container.value;
-
-        let trans = Cc["@mozilla.org/widget/transferable;1"]
-                      .createInstance(Ci.nsITransferable);
-        trans.init(loadContext);
-        trans.addDataFlavor(channel.contentType);
-        trans.setTransferData(channel.contentType, wrapped, -1);
-
-        let clipid = Ci.nsIClipboard;
-        let clip = Cc["@mozilla.org/widget/clipboard;1"].getService(clipid);
-        clip.setData(trans, null, clipid.kGlobalClipboard);
-        div.textContent = gcli.lookup("screenshotCopied");
-        return div;
-      }
-    }
-    catch (ex) {
-      div.textContent = gcli.lookup("screenshotErrorCopying");
-      return div;
-    }
-
-    let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
-
-    // Create a name for the file if not present
-    if (filename == FILENAME_DEFAULT_VALUE) {
-      let date = new Date();
-      let dateString = date.getFullYear() + "-" + (date.getMonth() + 1) +
-                       "-" + date.getDate();
-      dateString = dateString.split("-").map(function(part) {
-        if (part.length == 1) {
-          part = "0" + part;
-        }
-        return part;
-      }).join("-");
-      let timeString = date.toTimeString().replace(/:/g, ".").split(" ")[0];
-      filename = gcli.lookupFormat("screenshotGeneratedFilename",
-                                   [dateString, timeString]) + ".png";
-    }
-    // Check there is a .png extension to filename
-    else if (!filename.match(/.png$/i)) {
-      filename += ".png";
-    }
-
-    // If the filename is relative, tack it onto the download directory
-    if (!filename.match(/[\\\/]/)) {
-      let downloadMgr = Cc["@mozilla.org/download-manager;1"]
-                          .getService(Ci.nsIDownloadManager);
-      let tempfile = downloadMgr.userDownloadsDirectory;
-      tempfile.append(filename);
-      filename = tempfile.path;
-    }
-
-    try {
-      file.initWithPath(filename);
-    } catch (ex) {
-      div.textContent = gcli.lookup("screenshotErrorSavingToFile") + " " + filename;
-      return div;
-    }
-
-    let ioService = Cc["@mozilla.org/network/io-service;1"]
-                      .getService(Ci.nsIIOService);
-
-    let Persist = Ci.nsIWebBrowserPersist;
-    let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
-                    .createInstance(Persist);
-    persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
-                           Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
-
-    let source = ioService.newURI(data, "UTF8", null);
-    persist.saveURI(source, null, null, null, null, file, loadContext);
-
-    div.textContent = gcli.lookup("screenshotSavedToFile") + " \"" + filename +
-                      "\"";
-    div.addEventListener("click", function openFile() {
-      div.removeEventListener("click", openFile);
-      file.reveal();
-    });
-    div.style.cursor = "pointer";
-    let image = document.createElement("div");
-    let previewHeight = parseInt(256*height/width);
-    image.setAttribute("style",
-                       "width:256px; height:" + previewHeight + "px;" +
-                       "max-height: 256px;" +
-                       "background-image: url('" + data + "');" +
-                       "background-size: 256px " + previewHeight + "px;" +
-                       "margin: 4px; display: block");
-    div.appendChild(image);
-    return div;
-  }
-});
\ No newline at end of file
--- a/browser/devtools/commandline/Commands.jsm
+++ b/browser/devtools/commandline/Commands.jsm
@@ -2,26 +2,14 @@
  * 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/. */
 
 
 this.EXPORTED_SYMBOLS = [ ];
 
 const Cu = Components.utils;
 
-Cu.import("resource:///modules/devtools/CmdAddon.jsm");
-Cu.import("resource:///modules/devtools/CmdBreak.jsm");
-Cu.import("resource:///modules/devtools/CmdCalllog.jsm");
-Cu.import("resource:///modules/devtools/CmdCalllogChrome.jsm");
-Cu.import("resource:///modules/devtools/CmdConsole.jsm");
-Cu.import("resource:///modules/devtools/CmdCookie.jsm");
-Cu.import("resource:///modules/devtools/CmdDbg.jsm");
-Cu.import("resource:///modules/devtools/CmdEcho.jsm");
+Cu.import("resource:///modules/devtools/BuiltinCommands.jsm");
 Cu.import("resource:///modules/devtools/CmdEdit.jsm");
-Cu.import("resource:///modules/devtools/CmdExport.jsm");
 Cu.import("resource:///modules/devtools/CmdInspect.jsm");
-Cu.import("resource:///modules/devtools/CmdJsb.jsm");
-Cu.import("resource:///modules/devtools/CmdPagemod.jsm");
 Cu.import("resource:///modules/devtools/CmdResize.jsm");
-Cu.import("resource:///modules/devtools/CmdRestart.jsm");
-Cu.import("resource:///modules/devtools/CmdScreenshot.jsm");
 Cu.import("resource:///modules/devtools/CmdTilt.jsm");
 Cu.import("resource:///modules/devtools/CmdScratchpad.jsm");
--- a/browser/devtools/commandline/gcli.jsm
+++ b/browser/devtools/commandline/gcli.jsm
@@ -2431,77 +2431,85 @@ canon.Command = Command;
  * option switches
  */
 function Parameter(paramSpec, command, groupName) {
   this.command = command || { name: 'unnamed' };
   this.paramSpec = paramSpec;
   this.name = this.paramSpec.name;
   this.type = this.paramSpec.type;
   this.groupName = groupName;
-  this.defaultValue = this.paramSpec.defaultValue;
 
   if (!this.name) {
     throw new Error('In ' + this.command.name +
                     ': all params must have a name');
   }
 
   var typeSpec = this.type;
   this.type = types.getType(typeSpec);
   if (this.type == null) {
     console.error('Known types: ' + types.getTypeNames().join(', '));
     throw new Error('In ' + this.command.name + '/' + this.name +
                     ': can\'t find type for: ' + JSON.stringify(typeSpec));
   }
 
   // boolean parameters have an implicit defaultValue:false, which should
   // not be changed. See the docs.
-  if (this.type instanceof BooleanType) {
-    if (this.defaultValue !== undefined) {
-      throw new Error('In ' + this.command.name + '/' + this.name +
-                      ': boolean parameters can not have a defaultValue.' +
-                      ' Ignoring');
-    }
-    this.defaultValue = false;
+  if (this.type instanceof BooleanType &&
+      this.paramSpec.defaultValue !== undefined) {
+    throw new Error('In ' + this.command.name + '/' + this.name +
+                    ': boolean parameters can not have a defaultValue.' +
+                    ' Ignoring');
   }
 
   // Check the defaultValue for validity.
   // Both undefined and null get a pass on this test. undefined is used when
   // there is no defaultValue, and null is used when the parameter is
   // optional, neither are required to parse and stringify.
-  if (this.defaultValue != null) {
+  if (this._defaultValue != null) {
     try {
-      var defaultText = this.type.stringify(this.defaultValue);
+      var defaultText = this.type.stringify(this.paramSpec.defaultValue);
       var defaultConversion = this.type.parseString(defaultText);
       if (defaultConversion.getStatus() !== Status.VALID) {
         throw new Error('In ' + this.command.name + '/' + this.name +
                         ': Error round tripping defaultValue. status = ' +
                         defaultConversion.getStatus());
       }
     }
     catch (ex) {
       throw new Error('In ' + this.command.name + '/' + this.name +
                       ': ' + ex);
     }
   }
 
-  // Some types (boolean, array) have a non 'undefined' blank value. Give the
-  // type a chance to override the default defaultValue of undefined
-  if (this.defaultValue === undefined) {
-    this.defaultValue = this.type.getBlank().value;
-  }
-
   // All parameters that can only be set via a named parameter must have a
   // non-undefined default value
-  if (!this.isPositionalAllowed && this.defaultValue === undefined) {
+  if (!this.isPositionalAllowed && this.paramSpec.defaultValue === undefined &&
+      this.type.getBlank == null && !(this.type instanceof BooleanType)) {
     throw new Error('In ' + this.command.name + '/' + this.name +
                     ': Missing defaultValue for optional parameter.');
   }
 }
 
 /**
+ * type.getBlank can be expensive, so we delay execution where we can
+ */
+Object.defineProperty(Parameter.prototype, 'defaultValue', {
+  get: function() {
+    if (!('_defaultValue' in this)) {
+      this._defaultValue = (this.paramSpec.defaultValue !== undefined) ?
+          this.paramSpec.defaultValue :
+          this.type.getBlank().value;
+    }
+
+    return this._defaultValue;
+  },
+  enumerable : true
+});
+
+/**
  * Does the given name uniquely identify this param (among the other params
  * in this command)
  * @param name The name to check
  */
 Parameter.prototype.isKnownAs = function(name) {
   if (name === '--' + this.name) {
     return true;
   }
@@ -2684,34 +2692,27 @@ canon.getCommandSpecs = function getComm
  * Enable people to be notified of changes to the list of commands
  */
 canon.onCanonChange = util.createEvent('canon.onCanonChange');
 
 /**
  * CommandOutputManager stores the output objects generated by executed
  * commands.
  *
- * CommandOutputManager is exposed (via canon.commandOutputManager) to the the
- * outside world and could (but shouldn't) be used before gcli.startup() has
- * been called. This could should be defensive to that where possible, and we
- * should certainly document if the use of it or similar will fail if used too
- * soon.
+ * CommandOutputManager is exposed to the the outside world and could (but
+ * shouldn't) be used before gcli.startup() has been called.
+ * This could should be defensive to that where possible, and we should
+ * certainly document if the use of it or similar will fail if used too soon.
  */
 function CommandOutputManager() {
   this.onOutput = util.createEvent('CommandOutputManager.onOutput');
 }
 
 canon.CommandOutputManager = CommandOutputManager;
 
-/**
- * We maintain a global command output manager for the majority case where
- * there is only one important set of outputs.
- */
-canon.commandOutputManager = new CommandOutputManager();
-
 
 });
 /*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -2732,16 +2733,28 @@ define('gcli/util', ['require', 'exports
  */
 
 
 //------------------------------------------------------------------------------
 
 var eventDebug = false;
 
 /**
+ * Patch up broken console API from node
+ */
+if (eventDebug) {
+  if (console.group == null) {
+    console.group = function() { console.log(arguments); };
+  }
+  if (console.groupEnd == null) {
+    console.groupEnd = function() { console.log(arguments); };
+  }
+}
+
+/**
  * Useful way to create a name for a handler, used in createEvent()
  */
 function nameFunction(handler) {
   var scope = handler.scope ? handler.scope.constructor.name + '.' : '';
   var name = handler.func.name;
   if (name) {
     return scope + name;
   }
@@ -2812,36 +2825,44 @@ exports.createEvent = function(name) {
   };
 
   /**
    * Add a new handler function
    * @param func The function to call when this event is triggered
    * @param scope Optional 'this' object for the function call
    */
   event.add = function(func, scope) {
+    if (eventDebug) {
+      console.log('Adding listener to ' + name);
+    }
+
     handlers.push({ func: func, scope: scope });
   };
 
   /**
    * Remove a handler function added through add(). Both func and scope must
    * be strict equals (===) the values used in the call to add()
    * @param func The function to call when this event is triggered
    * @param scope Optional 'this' object for the function call
    */
   event.remove = function(func, scope) {
+    if (eventDebug) {
+      console.log('Removing listener from ' + name);
+    }
+
     var found = false;
     handlers = handlers.filter(function(test) {
-      var noMatch = (test.func !== func && test.scope !== scope);
-      if (!noMatch) {
+      var match = (test.func === func && test.scope === scope);
+      if (match) {
         found = true;
       }
-      return noMatch;
+      return !match;
     });
     if (!found) {
-      console.warn('Failed to remove handler from ' + name);
+      console.warn('Handler not found. Attached to ' + name);
     }
   };
 
   /**
    * Remove all handlers.
    * Reset the state of this event back to it's post create state
    */
   event.removeAll = function() {
@@ -4052,16 +4073,17 @@ exports.setDocument = function(document)
   }
 };
 
 /**
  * Undo the effects of setDocument()
  */
 exports.unsetDocument = function() {
   doc = undefined;
+  exports._empty = undefined;
 };
 
 /**
  * Getter for the document that contains the nodes we're matching
  * Most for changing things back to how they were for unit testing
  */
 exports.getDocument = function() {
   return doc;
@@ -4681,36 +4703,18 @@ imports.XPCOMUtils.defineLazyGetter(impo
   return Components.classes["@mozilla.org/supports-string;1"]
           .createInstance(Components.interfaces.nsISupportsString);
 });
 
 
 var util = require('gcli/util');
 var types = require('gcli/types');
 
-var allSettings = [];
-
-/**
- * Cache existing settings on startup
- */
-exports.startup = function() {
-  imports.prefBranch.getChildList('').forEach(function(name) {
-    allSettings.push(new Setting(name));
-  }.bind(this));
-  allSettings.sort(function(s1, s2) {
-    return s1.name.localeCompare(s2.name);
-  }.bind(this));
-};
-
-exports.shutdown = function() {
-  allSettings = [];
-};
-
-/**
- *
+/**
+ * All local settings have this prefix when used in Firefox
  */
 var DEVTOOLS_PREFIX = 'devtools.gcli.';
 
 /**
  * A class to wrap up the properties of a preference.
  * @see toolkit/components/viewconfig/content/config.js
  */
 function Setting(prefSpec) {
@@ -4819,73 +4823,146 @@ Object.defineProperty(Setting.prototype,
 /**
  * Reset this setting to it's initial default value
  */
 Setting.prototype.setDefault = function() {
   imports.prefBranch.clearUserPref(this.name);
   Services.prefs.savePrefFile(null);
 };
 
-/**
- * 'static' function to get an array containing all known Settings
+
+/**
+ * Collection of preferences for sorted access
+ */
+var settingsAll = [];
+
+/**
+ * Collection of preferences for fast indexed access
+ */
+var settingsMap = new Map();
+
+/**
+ * Flag so we know if we've read the system preferences
+ */
+var hasReadSystem = false;
+
+/**
+ * Clear out all preferences and return to initial state
+ */
+function reset() {
+  settingsMap = new Map();
+  settingsAll = [];
+  hasReadSystem = false;
+}
+
+/**
+ * Reset everything on startup and shutdown because we're doing lazy loading
+ */
+exports.startup = function() {
+  reset();
+};
+
+exports.shutdown = function() {
+  reset();
+};
+
+/**
+ * Load system prefs if they've not been loaded already
+ * @return true
+ */
+function readSystem() {
+  if (hasReadSystem) {
+    return;
+  }
+
+  imports.prefBranch.getChildList('').forEach(function(name) {
+    var setting = new Setting(name);
+    settingsAll.push(setting);
+    settingsMap.set(name, setting);
+  });
+
+  settingsAll.sort(function(s1, s2) {
+    return s1.name.localeCompare(s2.name);
+  });
+
+  hasReadSystem = true;
+}
+
+/**
+ * Get an array containing all known Settings filtered to match the given
+ * filter (string) at any point in the name of the setting
  */
 exports.getAll = function(filter) {
+  readSystem();
+
   if (filter == null) {
-    return allSettings;
-  }
-  return allSettings.filter(function(setting) {
+    return settingsAll;
+  }
+
+  return settingsAll.filter(function(setting) {
     return setting.name.indexOf(filter) !== -1;
   });
 };
 
 /**
  * Add a new setting.
  */
 exports.addSetting = function(prefSpec) {
   var setting = new Setting(prefSpec);
-  for (var i = 0; i < allSettings.length; i++) {
-    if (allSettings[i].name === setting.name) {
-      allSettings[i] = setting;
-    }
-  }
+
+  if (settingsMap.has(setting.name)) {
+    // Once exists already, we're going to need to replace it in the array
+    for (var i = 0; i < settingsAll.length; i++) {
+      if (settingsAll[i].name === setting.name) {
+        settingsAll[i] = setting;
+      }
+    }
+  }
+
+  settingsMap.set(setting.name, setting);
   exports.onChange({ added: setting.name });
+
   return setting;
 };
 
 /**
  * Getter for an existing setting. Generally use of this function should be
  * avoided. Systems that define a setting should export it if they wish it to
  * be available to the outside, or not otherwise. Use of this function breaks
  * that boundary and also hides dependencies. Acceptable uses include testing
  * and embedded uses of GCLI that pre-define all settings (e.g. Firefox)
  * @param name The name of the setting to fetch
  * @return The found Setting object, or undefined if the setting was not found
  */
 exports.getSetting = function(name) {
-  var found = undefined;
-  allSettings.some(function(setting) {
-    if (setting.name === name) {
-      found = setting;
-      return true;
-    }
-    return false;
-  });
-  return found;
+  // We might be able to give the answer without needing to read all system
+  // settings if this is an internal setting
+  var found = settingsMap.get(name);
+  if (found) {
+    return found;
+  }
+
+  if (hasReadSystem) {
+    return undefined;
+  }
+  else {
+    readSystem();
+    return settingsMap.get(name);
+  }
 };
 
 /**
  * Event for use to detect when the list of settings changes
  */
 exports.onChange = util.createEvent('Settings.onChange');
 
 /**
  * Remove a setting. A no-op in this case
  */
-exports.removeSetting = function(nameOrSpec) {
-};
+exports.removeSetting = function() { };
 
 
 });
 /*
  * Copyright 2012, Mozilla Foundation and contributors
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -5104,16 +5181,17 @@ define('gcli/cli', ['require', 'exports'
 
 
 var util = require('gcli/util');
 var view = require('gcli/ui/view');
 var l10n = require('gcli/l10n');
 
 var canon = require('gcli/canon');
 var Q = require('gcli/promise');
+var CommandOutputManager = require('gcli/canon').CommandOutputManager;
 
 var Status = require('gcli/types').Status;
 var Conversion = require('gcli/types').Conversion;
 var ArrayType = require('gcli/types/basic').ArrayType;
 var StringType = require('gcli/types/basic').StringType;
 var BooleanType = require('gcli/types/basic').BooleanType;
 var NumberType = require('gcli/types/basic').NumberType;
 
@@ -5462,29 +5540,32 @@ UnassignedAssignment.prototype.getStatus
  * <li>onTextChange: The text to be mirrored in a command line has changed.
  * </ul>
  *
  * @param environment An optional opaque object passed to commands in the
  * Execution Context.
  * @param doc A DOM Document passed to commands using the Execution Context in
  * order to allow creation of DOM nodes. If missing Requisition will use the
  * global 'document'.
+ * @param commandOutputManager A custom commandOutputManager to which output
+ * should be sent (optional)
  * @constructor
  */
-function Requisition(environment, doc) {
+function Requisition(environment, doc, commandOutputManager) {
   this.environment = environment;
   this.document = doc;
   if (this.document == null) {
     try {
       this.document = document;
     }
     catch (ex) {
       // Ignore
     }
   }
+  this.commandOutputManager = commandOutputManager || new CommandOutputManager();
 
   // The command that we are about to execute.
   // @see setCommandConversion()
   this.commandAssignment = new CommandAssignment();
   this.setAssignment(this.commandAssignment, null);
 
   // The object that stores of Assignment objects that we are filling out.
   // The Assignment objects are stored under their param.name for named
@@ -5505,18 +5586,16 @@ function Requisition(environment, doc) {
 
   // Temporarily set this to true to prevent _assignmentChanged resetting
   // argument positions
   this._structuralChangeInProgress = false;
 
   this.commandAssignment.onAssignmentChange.add(this._commandAssignmentChanged, this);
   this.commandAssignment.onAssignmentChange.add(this._assignmentChanged, this);
 
-  this.commandOutputManager = canon.commandOutputManager;
-
   this.onAssignmentChange = util.createEvent('Requisition.onAssignmentChange');
   this.onTextChange = util.createEvent('Requisition.onTextChange');
 }
 
 /**
  * Avoid memory leaks
  */
 Requisition.prototype.destroy = function() {
@@ -6987,31 +7066,31 @@ exports.shutdown = function() {
  * if either the command line or any of the inputs in the hint element has the
  * focus, and invisible at other times, without hiding and showing the hint
  * element even briefly as the focus changes between them.
  * It does this simply by postponing the hide events by 250ms to see if
  * something else takes focus.
  * @param options Object containing user customization properties, including:
  * - blurDelay (default=150ms)
  * - debug (default=false)
- * - commandOutputManager (default=canon.commandOutputManager)
  * @param components Object that links to other UI components. GCLI provided:
  * - document
+ * - requisition
  */
 function FocusManager(options, components) {
   options = options || {};
 
   this._document = components.document || document;
+  this._requisition = components.requisition;
+
   this._debug = options.debug || false;
   this._blurDelay = options.blurDelay || 150;
   this._window = this._document.defaultView;
 
-  this._commandOutputManager = options.commandOutputManager ||
-      canon.commandOutputManager;
-  this._commandOutputManager.onOutput.add(this._outputted, this);
+  this._requisition.commandOutputManager.onOutput.add(this._outputted, this);
 
   this._blurDelayTimeout = null; // Result of setTimeout in delaying a blur
   this._monitoredElements = [];  // See addMonitoredElement()
 
   this._isError = false;
   this._hasFocus = false;
   this._helpRequested = false;
   this._recentOutput = false;
@@ -7030,17 +7109,17 @@ function FocusManager(options, component
 
 /**
  * Avoid memory leaks
  */
 FocusManager.prototype.destroy = function() {
   eagerHelper.onChange.remove(this._eagerHelperChanged, this);
 
   this._document.removeEventListener('focus', this._focused, true);
-  this._commandOutputManager.onOutput.remove(this._outputted, this);
+  this._requisition.commandOutputManager.onOutput.remove(this._outputted, this);
 
   for (var i = 0; i < this._monitoredElements.length; i++) {
     var monitor = this._monitoredElements[i];
     console.error('Hanging monitored element: ', monitor.element);
 
     monitor.element.removeEventListener('focus', monitor.onFocus, true);
     monitor.element.removeEventListener('blur', monitor.onBlur, true);
   }
@@ -7048,17 +7127,17 @@ FocusManager.prototype.destroy = functio
   if (this._blurDelayTimeout) {
     this._window.clearTimeout(this._blurDelayTimeout);
     this._blurDelayTimeout = null;
   }
 
   delete this._focused;
   delete this._document;
   delete this._window;
-  delete this._commandOutputManager;
+  delete this._requisition;
 };
 
 /**
  * The easy way to include an element in the set of things that are part of the
  * aggregate focus. Using [add|remove]MonitoredElement() is a simpler way of
  * option than calling report[Focus|Blur]()
  * @param element The element on which to track focus|blur events
  * @param where Optional source string for debugging only
@@ -9007,17 +9086,17 @@ var Requisition = require('gcli/cli').Re
 
 var cli = require('gcli/cli');
 var jstype = require('gcli/types/javascript');
 var nodetype = require('gcli/types/node');
 var resource = require('gcli/types/resource');
 var host = require('gcli/host');
 var intro = require('gcli/ui/intro');
 
-var commandOutputManager = require('gcli/canon').commandOutputManager;
+var CommandOutputManager = require('gcli/canon').CommandOutputManager;
 
 /**
  * Handy utility to inject the content document (i.e. for the viewed page,
  * not for chrome) into the various components.
  */
 function setContentDocument(document) {
   if (document) {
     // TODO: this unwrapping smells
@@ -9043,31 +9122,38 @@ function setContentDocument(document) {
  * - completeElement
  * - backgroundElement
  * - outputDocument
  * - consoleWrap (optional)
  * - eval (optional)
  * - environment
  * - scratchpad (optional)
  * - chromeWindow
+ * - commandOutputManager (optional)
  */
 function FFDisplay(options) {
   if (options.eval) {
     cli.setEvalFunction(options.eval);
   }
   setContentDocument(options.contentDocument);
   host.chromeWindow = options.chromeWindow;
 
-  this.onOutput = commandOutputManager.onOutput;
-  this.requisition = new Requisition(options.environment, options.outputDocument);
-
-  // Create a FocusManager for the various parts to register with
+  this.commandOutputManager = options.commandOutputManager;
+  if (this.commandOutputManager == null) {
+    this.commandOutputManager = new CommandOutputManager();
+  }
+
+  this.onOutput = this.commandOutputManager.onOutput;
+  this.requisition = new Requisition(options.environment,
+                                     options.outputDocument,
+                                     this.commandOutputManager);
+
   this.focusManager = new FocusManager(options, {
-    // TODO: can we kill chromeDocument here?
-    document: options.chromeDocument
+    document: options.chromeDocument,
+    requisition: this.requisition,
   });
   this.onVisibilityChange = this.focusManager.onVisibilityChange;
 
   this.inputter = new Inputter(options, {
     requisition: this.requisition,
     focusManager: this.focusManager,
     element: options.inputElement
   });
@@ -9101,17 +9187,17 @@ function FFDisplay(options) {
 }
 
 /**
  * The main Display calls this as part of startup since it registers listeners
  * for output first. The firefox display can't do this, so it has to be a
  * separate method
  */
 FFDisplay.prototype.maybeShowIntro = function() {
-  intro.maybeShowIntro(commandOutputManager);
+  intro.maybeShowIntro(this.commandOutputManager);
 };
 
 /**
  * Called when the page to which we're attached changes
  * @params options Object with the following properties:
  * - contentDocument: Points to the page that we should now work against
  * - environment: A replacement environment for Requisition use
  * - chromeWindow: Allow node type to create overlay
@@ -9146,17 +9232,17 @@ FFDisplay.prototype.destroy = function()
 
   delete this.options;
 
   // We could also delete the following objects if we have hard-to-track-down
   // memory leaks, as a belt-and-braces approach, however this prevents our
   // DOM node hunter script from looking in all the nooks and crannies, so it's
   // better if we can be leak-free without deleting them:
   // - consoleWrap, resizer, tooltip, completer, inputter,
-  // - focusManager, onVisibilityChange, requisition
+  // - focusManager, onVisibilityChange, requisition, commandOutputManager
 };
 
 /**
  * Called on chrome window resize, or on divider slide
  */
 FFDisplay.prototype.resizer = function() {
   // Bug 705109: There are several numbers hard-coded in this function.
   // This is simpler than calculating them, but error-prone when the UI setup,
@@ -9940,17 +10026,18 @@ function Completer(options, components) 
   this.document = this.element.ownerDocument;
 
   this.inputter = components.inputter;
 
   this.inputter.onInputChange.add(this.update, this);
   this.inputter.onAssignmentChange.add(this.update, this);
   this.inputter.onChoiceChange.add(this.update, this);
 
-  if (components.autoResize) {
+  this.autoResize = components.autoResize;
+  if (this.autoResize) {
     this.inputter.onResize.add(this.resized, this);
 
     var dimensions = this.inputter.getDimensions();
     if (dimensions) {
       this.resized(dimensions);
     }
   }
 
@@ -9963,17 +10050,20 @@ function Completer(options, components) 
 
 /**
  * Avoid memory leaks
  */
 Completer.prototype.destroy = function() {
   this.inputter.onInputChange.remove(this.update, this);
   this.inputter.onAssignmentChange.remove(this.update, this);
   this.inputter.onChoiceChange.remove(this.update, this);
-  this.inputter.onResize.remove(this.resized, this);
+
+  if (this.autoResize) {
+    this.inputter.onResize.remove(this.resized, this);
+  }
 
   delete this.document;
   delete this.element;
   delete this.template;
   delete this.inputter;
 };
 
 /**
--- a/browser/devtools/commandline/test/browser_cmd_addon.js
+++ b/browser/devtools/commandline/test/browser_cmd_addon.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the addon commands works as they should
 
 let imported = {};
-Components.utils.import("resource:///modules/devtools/CmdAddon.jsm", imported);
+Components.utils.import("resource:///modules/devtools/BuiltinCommands.jsm", imported);
 
 function test() {
   DeveloperToolbarTest.test("about:blank", [ GAT_test ]);
 }
 
 function GAT_test() {
   var GAT_ready = DeveloperToolbarTest.checkCalled(function() {
     Services.obs.removeObserver(GAT_ready, "gcli_addon_commands_ready", false);
@@ -91,17 +91,17 @@ function GAT_test() {
       }
     });
 
     DeveloperToolbarTest.exec({ completed: false });
   });
 
   Services.obs.addObserver(GAT_ready, "gcli_addon_commands_ready", false);
 
-  if (imported.Flags.addonsLoaded) {
+  if (imported.CmdAddonFlags.addonsLoaded) {
     info("The getAllAddons command has already completed and we have missed ");
     info("the notification. Let's send the gcli_addon_commands_ready ");
     info("notification ourselves.");
 
     Services.obs.notifyObservers(null, "gcli_addon_commands_ready", null);
   } else {
     info("gcli_addon_commands_ready notification has not yet been received.");
   }
--- a/browser/devtools/commandline/test/browser_gcli_exec.js
+++ b/browser/devtools/commandline/test/browser_gcli_exec.js
@@ -37,51 +37,54 @@ function test() {
   tests = tests.map(function(test) { return exports[test]; });
   DeveloperToolbarTest.test(TEST_URI, tests, true);
 }
 
 // <INJECTED SOURCE:END>
 
 
 var Requisition = require('gcli/cli').Requisition;
-var canon = require('gcli/canon');
+var CommandOutputManager = require('gcli/canon').CommandOutputManager;
 // var mockCommands = require('gclitest/mockCommands');
 var nodetype = require('gcli/types/node');
 
 // var assert = require('test/assert');
 
 var actualExec;
 var actualOutput;
 var hideExec = false;
 var skip = 'skip';
 
-exports.setup = function() {
+var environment = { value: 'example environment data' };
+var commandOutputManager = new CommandOutputManager();
+var requisition = new Requisition(environment, null, commandOutputManager);
+
+exports.setup = function(options) {
   mockCommands.setup();
   mockCommands.onCommandExec.add(commandExeced);
-  canon.commandOutputManager.onOutput.add(commandOutputed);
+
+  commandOutputManager.onOutput.add(commandOutputed);
 };
 
-exports.shutdown = function() {
+exports.shutdown = function(options) {
   mockCommands.shutdown();
   mockCommands.onCommandExec.remove(commandExeced);
-  canon.commandOutputManager.onOutput.remove(commandOutputed);
+
+  commandOutputManager.onOutput.remove(commandOutputed);
 };
 
 function commandExeced(ev) {
   actualExec = ev;
 }
 
 function commandOutputed(ev) {
   actualOutput = ev.output;
 }
 
 function exec(command, expectedArgs) {
-  var environment = {};
-
-  var requisition = new Requisition(environment);
   var outputObject = requisition.exec({ typed: command, hidden: hideExec });
 
   assert.is(command.indexOf(actualExec.command.name), 0, 'Command name: ' + command);
 
   assert.is(command, outputObject.typed, 'outputObject.command for: ' + command);
   assert.ok(outputObject.completed, 'outputObject.completed false for: ' + command);
 
   if (expectedArgs == null) {
--- a/browser/devtools/debugger/debugger-panes.js
+++ b/browser/devtools/debugger/debugger-panes.js
@@ -1734,22 +1734,21 @@ create({ constructor: GlobalSearchView, 
   /**
    * Starts a bounce animation for a match.
    *
    * @param nsIDOMNode aMatch
    *        The match to start a bounce animation for.
    */
   _bounceMatch: function DVGS__bounceMatch(aMatch) {
     Services.tm.currentThread.dispatch({ run: function() {
-      aMatch.setAttribute("focused", "");
-
       aMatch.addEventListener("transitionend", function onEvent() {
         aMatch.removeEventListener("transitionend", onEvent);
         aMatch.removeAttribute("focused");
       });
+      aMatch.setAttribute("focused", "");
     }}, 0);
   },
 
   _splitter: null,
   _currentlyFocusedMatch: -1,
   _forceExpandResults: false,
   _searchTimeout: null,
   _searchFunction: null,
--- a/browser/devtools/debugger/debugger-toolbar.js
+++ b/browser/devtools/debugger/debugger-toolbar.js
@@ -108,17 +108,18 @@ ToolbarView.prototype = {
   },
 
   /**
    * Listener handling the toggle button click event.
    */
   _onTogglePanesPressed: function DVT__onTogglePanesPressed() {
     DebuggerView.togglePanes({
       visible: DebuggerView.panesHidden,
-      animated: true
+      animated: true,
+      delayed: true
     });
   },
 
   /**
    * Listener handling the pause/resume button click event.
    */
   _onResumePressed: function DVT__onResumePressed() {
     if (DebuggerController.activeThread.paused) {
@@ -1051,16 +1052,17 @@ create({ constructor: FilteredSourcesVie
    * Initialization function, called when the debugger is started.
    */
   initialize: function DVFS_initialize() {
     dumpn("Initializing the FilteredSourcesView");
 
     let panel = this._panel = document.createElement("panel");
     panel.id = "filtered-sources-panel";
     panel.setAttribute("noautofocus", "true");
+    panel.setAttribute("level", "top");
     panel.setAttribute("position", FILTERED_SOURCES_POPUP_POSITION);
     document.documentElement.appendChild(panel);
 
     this._searchbox = document.getElementById("searchbox");
     this._container = new StackList(panel);
 
     this._container.itemFactory = this._createItemView;
     this._container.itemType = "vbox";
--- a/browser/devtools/debugger/debugger-view.js
+++ b/browser/devtools/debugger/debugger-view.js
@@ -389,72 +389,87 @@ let DebuggerView = {
 
   /**
    * Sets all the panes hidden or visible.
    *
    * @param object aFlags [optional]
    *        An object containing some of the following boolean properties:
    *        - visible: true if the pane should be shown, false for hidden
    *        - animated: true to display an animation on toggle
+   *        - delayed: true to wait a few cycles before toggle
    *        - callback: a function to invoke when the panes toggle finishes
    */
   togglePanes: function DV__togglePanes(aFlags = {}) {
     // Avoid useless toggles.
     if (aFlags.visible == !this.panesHidden) {
-      aFlags.callback && aFlags.callback();
+      if (aFlags.callback) aFlags.callback();
       return;
     }
 
-    if (aFlags.visible) {
-      this._stackframesAndBreakpoints.style.marginLeft = "0";
-      this._variablesAndExpressions.style.marginRight = "0";
-      this._togglePanesButton.removeAttribute("panesHidden");
-      this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("collapsePanes"));
-    } else {
-      let marginL = ~~(this._stackframesAndBreakpoints.getAttribute("width")) + 1;
-      let marginR = ~~(this._variablesAndExpressions.getAttribute("width")) + 1;
-      this._stackframesAndBreakpoints.style.marginLeft = -marginL + "px";
-      this._variablesAndExpressions.style.marginRight = -marginR + "px";
-      this._togglePanesButton.setAttribute("panesHidden", "true");
-      this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("expandPanes"));
+    // Computes and sets the panes margins in order to hide or show them.
+    function set() {
+      if (aFlags.visible) {
+        this._stackframesAndBreakpoints.style.marginLeft = "0";
+        this._variablesAndExpressions.style.marginRight = "0";
+        this._togglePanesButton.removeAttribute("panesHidden");
+        this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("collapsePanes"));
+      } else {
+        let marginL = ~~(this._stackframesAndBreakpoints.getAttribute("width")) + 1;
+        let marginR = ~~(this._variablesAndExpressions.getAttribute("width")) + 1;
+        this._stackframesAndBreakpoints.style.marginLeft = -marginL + "px";
+        this._variablesAndExpressions.style.marginRight = -marginR + "px";
+        this._togglePanesButton.setAttribute("panesHidden", "true");
+        this._togglePanesButton.setAttribute("tooltiptext", L10N.getStr("expandPanes"));
+      }
+
+      if (aFlags.animated) {
+        // Displaying the panes may have the effect of triggering scrollbars to
+        // appear in the source editor, which would render the currently
+        // highlighted line to appear behind them in some cases.
+        window.addEventListener("transitionend", function onEvent() {
+          window.removeEventListener("transitionend", onEvent, false);
+          DebuggerView.updateEditor();
+
+          // Invoke the callback when the transition ended.
+          if (aFlags.callback) aFlags.callback();
+        }, false);
+      } else {
+        // Invoke the callback immediately since there's no transition.
+        if (aFlags.callback) aFlags.callback();
+      }
     }
 
     if (aFlags.animated) {
       this._stackframesAndBreakpoints.setAttribute("animated", "");
       this._variablesAndExpressions.setAttribute("animated", "");
-
-      // Displaying the panes may have the effect of triggering scrollbars to
-      // appear in the source editor, which would render the currently
-      // highlighted line to appear behind them in some cases.
-      let self = this;
-
-      window.addEventListener("transitionend", function onEvent() {
-        window.removeEventListener("transitionend", onEvent, false);
-        aFlags.callback && aFlags.callback();
-        self.updateEditor();
-      }, false);
     } else {
       this._stackframesAndBreakpoints.removeAttribute("animated");
       this._variablesAndExpressions.removeAttribute("animated");
-      aFlags.callback && aFlags.callback();
+    }
+
+    if (aFlags.delayed) {
+      window.setTimeout(set.bind(this), PANES_APPEARANCE_DELAY);
+    } else {
+      set.call(this);
     }
   },
 
   /**
    * Sets all the panes visible after a short period of time.
    *
    * @param function aCallback
    *        A function to invoke when the panes toggle finishes.
    */
   showPanesSoon: function DV__showPanesSoon(aCallback) {
     // Try to keep animations as smooth as possible, so wait a few cycles.
     window.setTimeout(function() {
       DebuggerView.togglePanes({
         visible: true,
         animated: true,
+        delayed: true,
         callback: aCallback
       });
     }, PANES_APPEARANCE_DELAY);
   },
 
   /**
    * Handles any initialization on a tab navigation event issued by the client.
    */
--- a/browser/devtools/debugger/debugger.xul
+++ b/browser/devtools/debugger/debugger.xul
@@ -233,16 +233,17 @@
                      tabindex="0"/>
       <toolbarbutton id="debugger-options"
                      class="devtools-option-toolbarbutton"
                      tooltiptext="&debuggerUI.optsButton.tooltip;"
                      popup="debuggerPrefsContextMenu"/>
     </toolbar>
 
     <panel id="searchbox-panel"
+           level="top"
            type="arrow"
            noautofocus="true"
            position="before_start">
       <vbox>
         <label class="description" value="&debuggerUI.searchPanelTitle;"/>
         <hbox align="center">
           <button id="global-operator-button" class="operator"
                   command="globalSearchCommand"/>
@@ -262,16 +263,17 @@
           <button id="variable-operator-button" class="operator"
                   command="variableSearchCommand"/>
           <label id="variable-operator-label" class="plain operator"/>
         </hbox>
       </vbox>
     </panel>
 
     <panel id="conditional-breakpoint-panel"
+           level="top"
            type="arrow"
            noautofocus="true"
            position="after_start">
       <vbox>
         <label class="description" value="&debuggerUI.condBreakPanelTitle;"/>
         <textbox id="conditional-breakpoint-textbox"/>
       </vbox>
     </panel>
--- a/browser/devtools/debugger/test/Makefile.in
+++ b/browser/devtools/debugger/test/Makefile.in
@@ -82,17 +82,17 @@ MOCHITEST_BROWSER_TESTS = \
 	browser_dbg_bug786070_hide_nonenums.js \
 	browser_dbg_displayName.js \
 	browser_dbg_iframes.js \
 	browser_dbg_pause-exceptions.js \
 	browser_dbg_multiple-windows.js \
 	browser_dbg_breakpoint-new-script.js \
 	browser_dbg_bug737803_editor_actual_location.js \
 	browser_dbg_progress-listener-bug.js \
-	$(filter disabled-for-intermittent-crashes--bug-821701, browser_dbg_chrome-debugging.js) \
+	browser_dbg_chrome-debugging.js \
 	$(filter disabled-for-intermittent-failures--bug-753225, browser_dbg_createRemote.js) \
 	head.js \
 	$(NULL)
 
 ifneq ($(OS_ARCH),WINNT)
 MOCHITEST_BROWSER_TESTS += \
 	browser_dbg_bfcache.js \
 	$(NULL)
--- a/browser/devtools/debugger/test/browser_dbg_chrome-debugging.js
+++ b/browser/devtools/debugger/test/browser_dbg_chrome-debugging.js
@@ -11,19 +11,16 @@ var gTab = null;
 var gThreadClient = null;
 var gNewGlobal = false;
 var gAttached = false;
 var gChromeScript = false;
 const DEBUGGER_TAB_URL = EXAMPLE_URL + "browser_dbg_debuggerstatement.html";
 
 function test()
 {
-  // Make sure there is enough time for findAllGlobals.
-  requestLongerTimeout(3);
-
   let transport = DebuggerServer.connectPipe();
   gClient = new DebuggerClient(transport);
   gClient.connect(function(aType, aTraits) {
     gTab = addTab(DEBUGGER_TAB_URL, function() {
       gClient.listTabs(function(aResponse) {
         let dbg = aResponse.chromeDebugger;
         ok(dbg, "Found a chrome debugging actor.");
 
--- a/browser/devtools/framework/Target.jsm
+++ b/browser/devtools/framework/Target.jsm
@@ -281,17 +281,18 @@ TabWebProgressListener.prototype = {
     let isNetwork = flag & Ci.nsIWebProgressListener.STATE_IS_NETWORK;
     let isRequest = flag & Ci.nsIWebProgressListener.STATE_IS_REQUEST;
 
     // Skip non-interesting states.
     if (!isStart || !isDocument || !isRequest || !isNetwork) {
       return;
     }
 
-    if (this.target) {
+    // emit event if the top frame is navigating
+    if (this.target && this.target.window == progress.DOMWindow) {
       this.target.emit("will-navigate", request);
     }
   },
 
   onProgressChange: function() {},
   onSecurityChange: function() {},
   onStatusChange: function() {},
 
--- a/browser/devtools/framework/ToolDefinitions.jsm
+++ b/browser/devtools/framework/ToolDefinitions.jsm
@@ -130,38 +130,34 @@ let styleEditorDefinition = {
   accesskey: l10n("open.accesskey", styleEditorStrings),
   modifiers: "shift",
   label: l10n("ToolboxStyleEditor.label", styleEditorStrings),
   icon: "chrome://browser/skin/devtools/tool-styleeditor.png",
   url: "chrome://browser/content/styleeditor.xul",
   tooltip: l10n("ToolboxStyleEditor.tooltip", styleEditorStrings),
 
   isTargetSupported: function(target) {
-    return !target.isRemote && !target.isChrome;
+    return target.isLocalTab;
   },
 
   build: function(iframeWindow, toolbox) {
     let panel = new StyleEditorPanel(iframeWindow, toolbox);
     return panel.open();
   }
 };
 
 let profilerDefinition = {
   id: "jsprofiler",
   killswitch: "devtools.profiler.enabled",
   url: "chrome://browser/content/profiler.xul",
   label: l10n("profiler.label", profilerStrings),
   tooltip: l10n("profiler.tooltip", profilerStrings),
 
   isTargetSupported: function (target) {
-    if (target.isRemote || target.isChrome) {
-      return false;
-    }
-
-    return true;
+    return !target.isRemote;
   },
 
   build: function (frame, target) {
     let panel = new ProfilerPanel(frame, target);
     return panel.open();
   }
 };
 
--- a/browser/devtools/framework/Toolbox.jsm
+++ b/browser/devtools/framework/Toolbox.jsm
@@ -11,35 +11,35 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/commonjs/promise/core.js");
 Cu.import("resource:///modules/devtools/EventEmitter.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Hosts",
                                   "resource:///modules/devtools/ToolboxHosts.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CommandUtils",
                                   "resource:///modules/devtools/DeveloperToolbar.jsm");
+
 XPCOMUtils.defineLazyGetter(this, "toolboxStrings", function() {
   let bundle = Services.strings.createBundle("chrome://browser/locale/devtools/toolbox.properties");
   let l10n = function(name) {
     try {
       return bundle.GetStringFromName(name);
     } catch (ex) {
       Services.console.logStringMessage("Error reading '" + name + "'");
     }
   };
   return l10n;
 });
 
-// DO NOT put Require.jsm or gcli.jsm into lazy getters as this breaks the
-// requisition import a few lines down.
-Cu.import("resource:///modules/devtools/gcli.jsm");
-Cu.import("resource://gre/modules/devtools/Require.jsm");
+XPCOMUtils.defineLazyGetter(this, "Requisition", function() {
+  Cu.import("resource://gre/modules/devtools/Require.jsm");
+  Cu.import("resource:///modules/devtools/gcli.jsm");
 
-let Requisition = require('gcli/cli').Requisition;
-let CommandOutputManager = require('gcli/canon').CommandOutputManager;
+  return require('gcli/cli').Requisition;
+});
 
 this.EXPORTED_SYMBOLS = [ "Toolbox" ];
 
 // This isn't the best place for this, but I don't know what is right now
 
 /**
  * Implementation of 'promised', while we wait for bug 790195 to be fixed.
  * @see Consuming promises in https://addons.mozilla.org/en-US/developers/docs/sdk/latest/packages/api-utils/promise.html
@@ -239,36 +239,41 @@ Toolbox.prototype = {
   },
 
   /**
    * Open the toolbox
    */
   open: function TBOX_open() {
     let deferred = Promise.defer();
 
-    this._host.open().then(function(iframe) {
-      let onload = function() {
-        iframe.removeEventListener("DOMContentLoaded", onload, true);
+    this._host.create().then(function(iframe) {
+      let domReady = function() {
+        iframe.removeEventListener("DOMContentLoaded", domReady, true);
+
+        let vbox = this.doc.getElementById("toolbox-panel-" + this._currentToolId);
+        if (vbox) {
+          this.doc.commandDispatcher.advanceFocusIntoSubtree(vbox);
+        }
 
         this.isReady = true;
 
         let closeButton = this.doc.getElementById("toolbox-close");
         closeButton.addEventListener("command", this.destroy, true);
 
         this._buildDockButtons();
         this._buildTabs();
-        this._buildButtons(this.frame);
+        this._buildButtons();
 
         this.selectTool(this._defaultToolId).then(function(panel) {
           this.emit("ready");
           deferred.resolve();
         }.bind(this));
       }.bind(this);
 
-      iframe.addEventListener("DOMContentLoaded", onload, true);
+      iframe.addEventListener("DOMContentLoaded", domReady, true);
       iframe.setAttribute("src", this._URL);
     }.bind(this));
 
     return deferred.promise;
   },
 
   /**
    * Build the buttons for changing hosts. Called every time
@@ -312,31 +317,27 @@ Toolbox.prototype = {
   _buildTabs: function TBOX_buildTabs() {
     for (let [id, definition] of gDevTools.getToolDefinitions()) {
       this._buildTabForTool(definition);
     }
   },
 
   /**
    * Add buttons to the UI as specified in the devtools.window.toolbarSpec pref
-   *
-   * @param {iframe} frame
-   *        The iframe to contain the buttons
    */
-  _buildButtons: function TBOX_buildButtons(frame) {
-    if (this.target.isRemote) {
+  _buildButtons: function TBOX_buildButtons() {
+    if (!this.target.isLocalTab) {
       return;
     }
 
     let toolbarSpec = CommandUtils.getCommandbarSpec("devtools.toolbox.toolbarSpec");
-    let environment = { chromeDocument: frame.ownerDocument };
+    let environment = { chromeDocument: this.target.tab.ownerDocument };
     let requisition = new Requisition(environment);
-    requisition.commandOutputManager = new CommandOutputManager();
 
-    let buttons = CommandUtils.createButtons(toolbarSpec, this.doc, requisition);
+    let buttons = CommandUtils.createButtons(toolbarSpec, this._target, this.doc, requisition);
 
     let container = this.doc.getElementById("toolbox-buttons");
     buttons.forEach(function(button) {
       container.appendChild(button);
     }.bind(this));
   },
 
   /**
@@ -468,21 +469,20 @@ Toolbox.prototype = {
    *
    * @param {string} hostType
    *        The host type of the new host object
    *
    * @return {Host} host
    *        The created host object
    */
   _createHost: function TBOX_createHost(hostType) {
-    let hostTab = this._getHostTab();
     if (!Hosts[hostType]) {
       throw new Error('Unknown hostType: '+ hostType);
     }
-    let newHost = new Hosts[hostType](hostTab);
+    let newHost = new Hosts[hostType](this.target.tab);
 
     // clean up the toolbox if its window is closed
     newHost.on("window-closed", this.destroy);
 
     return newHost;
   },
 
   /**
@@ -497,17 +497,17 @@ Toolbox.prototype = {
       return;
     }
 
     if (!this._target.isLocalTab) {
       return;
     }
 
     let newHost = this._createHost(hostType);
-    return newHost.open().then(function(iframe) {
+    return newHost.create().then(function(iframe) {
       // change toolbox document's parent to the new host
       iframe.QueryInterface(Ci.nsIFrameLoaderOwner);
       iframe.swapFrameLoaders(this.frame);
 
       this._host.off("window-closed", this.destroy);
       this._host.destroy();
 
       this._host = newHost;
@@ -516,28 +516,16 @@ Toolbox.prototype = {
 
       this._buildDockButtons();
 
       this.emit("host-changed");
     }.bind(this));
   },
 
   /**
-   * Get the most appropriate host tab, either the target or the current tab
-   */
-  _getHostTab: function TBOX_getHostTab() {
-    if (!this._target.isRemote && !this._target.isChrome) {
-      return this._target.tab;
-    } else {
-      let win = Services.wm.getMostRecentWindow("navigator:browser");
-      return win.gBrowser.selectedTab;
-    }
-  },
-
-  /**
    * Handler for the tool-registered event.
    * @param  {string} event
    *         Name of the event ("tool-registered")
    * @param  {string} toolId
    *         Id of the tool that was registered
    */
   _toolRegistered: function TBOX_toolRegistered(event, toolId) {
     let defs = gDevTools.getToolDefinitions();
--- a/browser/devtools/framework/ToolboxHosts.jsm
+++ b/browser/devtools/framework/ToolboxHosts.jsm
@@ -12,17 +12,17 @@ Cu.import("resource:///modules/devtools/
 
 this.EXPORTED_SYMBOLS = [ "Hosts" ];
 
 /**
  * A toolbox host represents an object that contains a toolbox (e.g. the
  * sidebar or a separate window). Any host object should implement the
  * following functions:
  *
- * open() - create the UI and emit a 'ready' event when the UI is ready to use
+ * create() - create the UI and emit a 'ready' event when the UI is ready to use
  * destroy() - destroy the host's UI
  */
 
 this.Hosts = {
   "bottom": BottomHost,
   "side": SidebarHost,
   "window": WindowHost
 }
@@ -39,27 +39,27 @@ function BottomHost(hostTab) {
 BottomHost.prototype = {
   type: "bottom",
 
   heightPref: "devtools.toolbox.footer.height",
 
   /**
    * Create a box at the bottom of the host tab.
    */
-  open: function BH_open() {
+  create: function BH_create() {
     let deferred = Promise.defer();
 
     let gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
     let ownerDocument = gBrowser.ownerDocument;
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-horizontal-splitter");
 
     this.frame = ownerDocument.createElement("iframe");
-    this.frame.id = "devtools-toolbox-bottom-iframe";
+    this.frame.className = "devtools-toolbox-bottom-iframe";
     this.frame.height = Services.prefs.getIntPref(this.heightPref);
 
     this._nbox = gBrowser.getNotificationBox(this.hostTab.linkedBrowser);
     this._nbox.appendChild(this._splitter);
     this._nbox.appendChild(this.frame);
 
     let frameLoad = function() {
       this.frame.removeEventListener("DOMContentLoaded", frameLoad, true);
@@ -107,27 +107,27 @@ function SidebarHost(hostTab) {
 SidebarHost.prototype = {
   type: "side",
 
   widthPref: "devtools.toolbox.sidebar.width",
 
   /**
    * Create a box in the sidebar of the host tab.
    */
-  open: function RH_open() {
+  create: function SH_create() {
     let deferred = Promise.defer();
 
     let gBrowser = this.hostTab.ownerDocument.defaultView.gBrowser;
     let ownerDocument = gBrowser.ownerDocument;
 
     this._splitter = ownerDocument.createElement("splitter");
     this._splitter.setAttribute("class", "devtools-side-splitter");
 
     this.frame = ownerDocument.createElement("iframe");
-    this.frame.id = "devtools-toolbox-side-iframe";
+    this.frame.className = "devtools-toolbox-side-iframe";
     this.frame.width = Services.prefs.getIntPref(this.widthPref);
 
     this._sidebar = gBrowser.getSidebarContainer(this.hostTab.linkedBrowser);
     this._sidebar.appendChild(this._splitter);
     this._sidebar.appendChild(this.frame);
 
     let frameLoad = function() {
       this.frame.removeEventListener("DOMContentLoaded", frameLoad, true);
@@ -142,17 +142,17 @@ SidebarHost.prototype = {
     focusTab(this.hostTab);
 
     return deferred.promise;
   },
 
   /**
    * Destroy the sidebar.
    */
-  destroy: function RH_destroy() {
+  destroy: function SH_destroy() {
     if (!this._destroyed) {
       this._destroyed = true;
 
       Services.prefs.setIntPref(this.widthPref, this.frame.width);
       this._sidebar.removeChild(this._splitter);
       this._sidebar.removeChild(this.frame);
     }
 
@@ -172,17 +172,17 @@ function WindowHost() {
 WindowHost.prototype = {
   type: "window",
 
   WINDOW_URL: "chrome://browser/content/devtools/framework/toolbox-window.xul",
 
   /**
    * Create a new xul window to contain the toolbox.
    */
-  open: function WH_open() {
+  create: function WH_create() {
     let deferred = Promise.defer();
 
     let flags = "chrome,centerscreen,resizable,dialog=no";
     let win = Services.ww.openWindow(null, this.WINDOW_URL, "_blank",
                                      flags, null);
 
     let frameLoad = function(event) {
       win.removeEventListener("load", frameLoad, true);
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -424,17 +424,17 @@ let gDevToolsBrowser = {
 
       let mp = doc.getElementById("menuWebDeveloperPopup");
       let mps = doc.getElementById("menu_devtools_separator");
       mp.insertBefore(menuitem, mps);
     }
   },
 
   /**
-   * Update the "Toggle Toolbox" checkbox in the developer tools menu. This is
+   * Update the "Toggle Tools" checkbox in the developer tools menu. This is
    * called when a toolbox is created or destroyed.
    */
   _updateMenuCheckbox: function DT_updateMenuCheckbox() {
     for (let win of gDevToolsBrowser._trackedBrowserWindows) {
 
       let hasToolbox = false;
       if (TargetFactory.isKnownTab(win.gBrowser.selectedTab)) {
         let target = TargetFactory.forTab(win.gBrowser.selectedTab);
--- a/browser/devtools/framework/test/browser_toolbox_hosts.js
+++ b/browser/devtools/framework/test/browser_toolbox_hosts.js
@@ -33,45 +33,48 @@ function test()
 
 function testBottomHost(aToolbox)
 {
   toolbox = aToolbox;
 
   checkHostType(Toolbox.HostType.BOTTOM);
 
   // test UI presence
-  let iframe = document.getElementById("devtools-toolbox-bottom-iframe");
+  let nbox = gBrowser.getNotificationBox();
+  let iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
   ok(iframe, "toolbox bottom iframe exists");
 
   checkToolboxLoaded(iframe);
 
   toolbox.switchHost(Toolbox.HostType.SIDE).then(testSidebarHost);
 }
 
 function testSidebarHost()
 {
   checkHostType(Toolbox.HostType.SIDE);
 
   // test UI presence
-  let bottom = document.getElementById("devtools-toolbox-bottom-iframe");
+  let nbox = gBrowser.getNotificationBox();
+  let bottom = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-bottom-iframe");
   ok(!bottom, "toolbox bottom iframe doesn't exist");
 
-  let iframe = document.getElementById("devtools-toolbox-side-iframe");
+  let iframe = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-side-iframe");
   ok(iframe, "toolbox side iframe exists");
 
   checkToolboxLoaded(iframe);
 
   toolbox.switchHost(Toolbox.HostType.WINDOW).then(testWindowHost);
 }
 
 function testWindowHost()
 {
   checkHostType(Toolbox.HostType.WINDOW);
 
-  let sidebar = document.getElementById("devtools-toolbox-side-iframe");
+  let nbox = gBrowser.getNotificationBox();
+  let sidebar = document.getAnonymousElementByAttribute(nbox, "class", "devtools-toolbox-side-iframe");
   ok(!sidebar, "toolbox sidebar iframe doesn't exist");
 
   let win = Services.wm.getMostRecentWindow("devtools:toolbox");
   ok(win, "toolbox separate window exists");
 
   let iframe = win.document.getElementById("toolbox-iframe");
   checkToolboxLoaded(iframe);
 
--- a/browser/devtools/inspector/InspectorPanel.jsm
+++ b/browser/devtools/inspector/InspectorPanel.jsm
@@ -223,17 +223,25 @@ InspectorPanel.prototype = {
    */
   preventNavigateAway: function InspectorPanel_preventNavigateAway(event, request) {
     if (!this.isDirty) {
       return;
     }
 
     request.suspend();
 
-    let notificationBox = this._toolbox.getNotificationBox();
+    let notificationBox = null;
+    if (this.target.isLocalTab) {
+      let gBrowser = this.target.tab.ownerDocument.defaultView.gBrowser;
+      notificationBox = gBrowser.getNotificationBox();
+    }
+    else {
+      notificationBox = this._toolbox.getNotificationBox();
+    }
+
     let notification = notificationBox.
       getNotificationWithValue("inspector-page-navigation");
 
     if (notification) {
       notificationBox.removeNotification(notification, true);
     }
 
     let cancelRequest = function onCancelRequest() {
@@ -254,19 +262,17 @@ InspectorPanel.prototype = {
       {
         id: "inspector.confirmNavigationAway.buttonLeave",
         label: this.strings.GetStringFromName("confirmNavigationAway.buttonLeave"),
         accessKey: this.strings.GetStringFromName("confirmNavigationAway.buttonLeaveAccesskey"),
         callback: function onButtonLeave() {
           if (request) {
             request.resume();
             request = null;
-            return true;
           }
-          return false;
         }.bind(this),
       },
       {
         id: "inspector.confirmNavigationAway.buttonStay",
         label: this.strings.GetStringFromName("confirmNavigationAway.buttonStay"),
         accessKey: this.strings.GetStringFromName("confirmNavigationAway.buttonStayAccesskey"),
         callback: cancelRequest
       },
--- a/browser/devtools/inspector/test/browser_inspector_bug_566084_location_changed.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_566084_location_changed.js
@@ -20,17 +20,17 @@ function test() {
     let para = content.document.querySelector("p");
     ok(para, "found the paragraph element");
     is(para.textContent, "init", "paragraph content is correct");
 
     inspector.markDirty();
 
     let target = TargetFactory.forTab(gBrowser.selectedTab);
     let toolbox = gDevTools.getToolbox(target);
-    notificationBox = toolbox.getNotificationBox();
+    notificationBox = gBrowser.getNotificationBox();
     notificationBox.addEventListener("AlertActive", alertActive1, false);
 
     ok(toolbox, "We have access to the notificationBox");
 
     gBrowser.selectedBrowser.addEventListener("load", onPageLoad, true);
 
     content.location = "data:text/html,<div>location change test 1 for " +
       "inspector</div><p>test1</p>";
--- a/browser/devtools/inspector/test/browser_inspector_bug_665880.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_665880.js
@@ -31,18 +31,20 @@ function test()
     inspector.highlighter.once("locked", performTestComparison);
     inspector.selection.setNode(objectNode, "");
   }
 
   function performTestComparison()
   {
     is(getActiveInspector().selection.node, objectNode, "selection matches node");
     let target = TargetFactory.forTab(gBrowser.selectedTab);
-    gDevTools.closeToolbox(target);
-    finishUp();
+    executeSoon(function() {
+      gDevTools.closeToolbox(target);
+      finishUp();
+    });
   }
 
 
   function finishUp() {
     doc = objectNode = null;
     gBrowser.removeCurrentTab();
     finish();
   }
--- a/browser/devtools/inspector/test/browser_inspector_bug_672902_keyboard_shortcuts.js
+++ b/browser/devtools/inspector/test/browser_inspector_bug_672902_keyboard_shortcuts.js
@@ -25,17 +25,17 @@ function test()
                      "</h1><p><strong>Greetings, earthlings!</strong> I come" +
                      " in peace.</body></html>";
 
   function setupKeyBindingsTest()
   {
     openInspector(findAndHighlightNode);
   }
 
-  function findAndHighlightNode(aInspector)
+  function findAndHighlightNode(aInspector, aToolbox)
   {
     inspector = aInspector;
 
     executeSoon(function() {
       inspector.selection.once("new-node", highlightBodyNode);
       // Test that navigating around without a selected node gets us to the
       // body element.
       node = doc.querySelector("body");
--- a/browser/devtools/inspector/test/head.js
+++ b/browser/devtools/inspector/test/head.js
@@ -14,17 +14,17 @@ let console = tempScope.console;
 // Import the GCLI test helper
 let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
 Services.scriptloader.loadSubScript(testDir + "/helpers.js", this);
 
 function openInspector(callback)
 {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
-    callback(toolbox.getCurrentPanel());
+    callback(toolbox.getCurrentPanel(), toolbox);
   }).then(null, console.error);
 }
 
 function getActiveInspector()
 {
   let target = TargetFactory.forTab(gBrowser.selectedTab);
   return gDevTools.getToolbox(target).getPanel("inspector");
 }
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -35,19 +35,17 @@ browser.jar:
     content/browser/devtools/profiler/cleopatra/css/devtools.css        (profiler/cleopatra/css/devtools.css)
     content/browser/devtools/profiler/cleopatra/js/parser.js            (profiler/cleopatra/js/parser.js)
     content/browser/devtools/profiler/cleopatra/js/parserWorker.js      (profiler/cleopatra/js/parserWorker.js)
     content/browser/devtools/profiler/cleopatra/js/tree.js              (profiler/cleopatra/js/tree.js)
     content/browser/devtools/profiler/cleopatra/js/ui.js                (profiler/cleopatra/js/ui.js)
     content/browser/devtools/profiler/cleopatra/js/ProgressReporter.js  (profiler/cleopatra/js/ProgressReporter.js)
     content/browser/devtools/profiler/cleopatra/js/devtools.js          (profiler/cleopatra/js/devtools.js)
     content/browser/devtools/profiler/cleopatra/images/circlearrow.svg  (profiler/cleopatra/images/circlearrow.svg)
-    content/browser/devtools/profiler/cleopatra/images/filter.png       (profiler/cleopatra/images/filter.png)
     content/browser/devtools/profiler/cleopatra/images/noise.png        (profiler/cleopatra/images/noise.png)
-    content/browser/devtools/profiler/cleopatra/images/showall.png      (profiler/cleopatra/images/showall.png)
     content/browser/devtools/profiler/cleopatra/images/throbber.svg     (profiler/cleopatra/images/throbber.svg)
     content/browser/devtools/profiler/cleopatra/images/treetwisty.svg   (profiler/cleopatra/images/treetwisty.svg)
     content/browser/devtools/commandline.css      (commandline/commandline.css)
     content/browser/devtools/commandlineoutput.xhtml  (commandline/commandlineoutput.xhtml)
     content/browser/devtools/commandlinetooltip.xhtml  (commandline/commandlinetooltip.xhtml)
     content/browser/devtools/framework/toolbox-window.xul    (framework/toolbox-window.xul)
 *   content/browser/devtools/framework/toolbox.xul           (framework/toolbox.xul)
     content/browser/devtools/framework/toolbox.css           (framework/toolbox.css)
--- a/browser/devtools/profiler/cleopatra/cleopatra.html
+++ b/browser/devtools/profiler/cleopatra/cleopatra.html
@@ -12,18 +12,16 @@
     <link rel="stylesheet" type="text/css" href="profiler/cleopatra/css/tree.css">
     <link rel="stylesheet" type="text/css" href="profiler/cleopatra/css/devtools.css">
 
     <script src="profiler/cleopatra/js/parser.js"></script>
     <script src="profiler/cleopatra/js/tree.js"></script>
     <script src="profiler/cleopatra/js/ui.js"></script>
     <script src="profiler/cleopatra/js/ProgressReporter.js"></script>
     <script src="profiler/cleopatra/js/devtools.js"></script>
-
-    <link rel="shortcut icon" href="favicon.png" />
   </head>
 
   <body onload="notifyParent('loaded');">
     <script>
       initUI();
     </script>
   </body>
 </html>
--- a/browser/devtools/profiler/cleopatra/css/tree.css
+++ b/browser/devtools/profiler/cleopatra/css/tree.css
@@ -1,15 +1,14 @@
 /* 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/. */
 
 .treeViewContainer {
   -moz-user-select: none;
-  -webkit-user-select: none;
   user-select: none;
   cursor: default;
   line-height: 16px;
   height: 100%;
   outline: none; /* override the browser's focus styling */
   position: relative;
 }
 
@@ -21,18 +20,16 @@
   height: 16px;
   margin: 0;
   padding: 0;
 }
 
 .treeColumnHeader {
   position: absolute;
   display: block;
-  background: -moz-linear-gradient(#FFF 45%, #EEE 60%);
-  background: -webkit-linear-gradient(#FFF 45%, #EEE 60%);
   background: linear-gradient(#FFF 45%, #EEE 60%);
   margin: 0;
   padding: 0;
   top: 0;
   height: 15px;
   line-height: 15px;
   border: 0 solid #CCC;
   border-bottom-width: 1px;
@@ -88,27 +85,21 @@
 
 .treeViewHorizontalScrollbox {
   padding-left: 150px;
   overflow: hidden;
 }
 
 .treeViewVerticalScrollbox,
 .treeViewHorizontalScrollbox {
-  background: -moz-linear-gradient(white, white 50%, #F0F5FF 50%, #F0F5FF);
-  background: -webkit-linear-gradient(white, white 50%, #F0F5FF 50%, #F0F5FF);
   background: linear-gradient(white, white 50%, #F0F5FF 50%, #F0F5FF);
   background-size: 100px 32px;
 }
 
 .leftColumnBackground {
-  background: -moz-linear-gradient(left, transparent, transparent 98px, #CCC 98px, #CCC 99px, transparent 99px),
-    -moz-linear-gradient(white, white 50%, #F0F5FF 50%, #F0F5FF);
-  background: -webkit-linear-gradient(left, transparent, transparent 98px, #CCC 98px, #CCC 99px, transparent 99px),
-    -webkit-linear-gradient(white, white 50%, #F0F5FF 50%, #F0F5FF);
   background: linear-gradient(left, transparent, transparent 98px, #CCC 98px, #CCC 99px, transparent 99px),
     linear-gradient(white, white 50%, #F0F5FF 50%, #F0F5FF);
   background-size: auto, 100px 32px;
   position: absolute;
   top: 0;
   left: 0;
   width: 146px;
   min-height: 100%;
--- a/browser/devtools/profiler/cleopatra/css/ui.css
+++ b/browser/devtools/profiler/cleopatra/css/ui.css
@@ -27,20 +27,16 @@ body {
 .profileEntryPane {
   overflow: auto;
 }
 .profileEntryPane,
 .profileProgressPane {
   padding: 20px;
   background-color: rgb(229,229,229);
   background-image: url(../images/noise.png),
-                    -moz-linear-gradient(rgba(255,255,255,.5),rgba(255,255,255,.2));
-  background-image: url(../images/noise.png),
-                    -webkit-linear-gradient(rgba(255,255,255,.5),rgba(255,255,255,.2));
-  background-image: url(../images/noise.png),
                     linear-gradient(rgba(255,255,255,.5),rgba(255,255,255,.2));
   text-shadow: rgba(255, 255, 255, 0.4) 0 1px;
 }
 .profileEntryPane h1 {
   margin-top: 0;
   font-size: 13px;
   font-weight: normal;
 }
@@ -57,99 +53,108 @@ body {
 .profileProgressPane progress {
   position: absolute;
   top: 40%;
   left: 30%;
   width: 40%;
   height: 16px;
 }
 .finishedProfilePaneBackgroundCover {
-  -webkit-animation: darken 300ms cubic-bezier(0, 0, 1, 0);
-  -moz-animation: darken 300ms cubic-bezier(0, 0, 1, 0);
+  animation: darken 300ms cubic-bezier(0, 0, 1, 0);
   background-color: rgba(0, 0, 0, 0.5);
 }
+
 .finishedProfilePane {
-  -webkit-animation: appear 300ms ease-out;
-  -moz-animation: appear 300ms ease-out;
+  animation: appear 300ms ease-out;
 }
 
+@keyframes darken {
+  from {
+    opacity: 0;
+  }
+  to {
+    opacity: 1;
+  }
+}
+@keyframes appear {
+  from {
+    transform: scale(0.3);
+    opacity: 0;
+    pointer-events: none;
+  }
+  to {
+    transform: scale(1);
+    opacity: 1;
+    pointer-events: auto;
+  }
+}
 .breadcrumbTrail {
   top: 0;
   right: 0;
   height: 29px;
   left: 0;
-  background: -moz-linear-gradient(#FFF 50%, #F3F3F3 55%);
-  background: -webkit-linear-gradient(#FFF 50%, #F3F3F3 55%);
   background: linear-gradient(#FFF 50%, #F3F3F3 55%);
   border-bottom: 1px solid #CCC;
   margin: 0;
   padding: 0;
   overflow: hidden;
 }
 .breadcrumbTrailItem {
-  background: -moz-linear-gradient(#FFF 50%, #F3F3F3 55%);
-  background: -webkit-linear-gradient(#FFF 50%, #F3F3F3 55%);
   background: linear-gradient(#FFF 50%, #F3F3F3 55%);
   display: block;
   margin: 0;
   padding: 0;
   float: left;
   line-height: 29px;
   padding: 0 10px;
   font-size: 12px;
   -moz-user-select: none;
-  -webkit-user-select: none;
   user-select: none;
   cursor: default;
   border-right: 1px solid #CCC;
   max-width: 250px;
   overflow: hidden;
   text-overflow: ellipsis;
   white-space: nowrap;
   position: relative;
 }
-@-webkit-keyframes slide-out {
+@keyframes slide-out {
   from {
     margin-left: -270px;
     opacity: 0;
   }
   to {
     margin-left: 0;
     opacity: 1;
   }
 }
-@-moz-keyframes slide-out {
+@keyframes slide-out {
   from {
     margin-left: -270px;
     opacity: 0;
   }
   to {
     margin-left: 0;
     opacity: 1;
   }
 }
 .breadcrumbTrailItem:not(:first-child) {
-  -moz-animation: slide-out;
-  -moz-animation-duration: 400ms;
-  -moz-animation-timing-function: ease-out;
-  -webkit-animation: slide-out;
-  -webkit-animation-duration: 400ms;
-  -webkit-animation-timing-function: ease-out;
+  animation: slide-out;
+  animation-duration: 400ms;
+  animation-timing-function: ease-out;
 }
 .breadcrumbTrailItem.selected {
   background: linear-gradient(#E5E5E5 50%, #DADADA 55%);
 }
 .breadcrumbTrailItem:not(.selected):active:hover {
   background: linear-gradient(#F2F2F2 50%, #E6E6E6 55%);
 }
 .breadcrumbTrailItem.deleted {
-  -moz-transition: 400ms ease-out;
-  -moz-transition-property: opacity, margin-left;
-  -webkit-transition: 400ms ease-out;
-  -webkit-transition-property: opacity, margin-left;
+  transition: 400ms ease-out;
+  transition-property: opacity, margin-left;
   opacity: 0;
   margin-left: -270px;
 }
 .treeContainer {
   /*For asbolute position child*/
   position: relative;
 }
 .tree {
@@ -194,17 +199,16 @@ body {
   margin-left: 0;
 }
 #infoBar dd::after {
   content: "\a";
   white-space:pre;
 }
 .sideBar {
   -moz-box-sizing: border-box;
-  -webkit-box-sizing: border-box;
   box-sizing: border-box;
   position: absolute;
   left: 0;
   bottom: 0;
   width: 200px;
   height: 480px;
   overflow: auto;
   padding: 3px;
@@ -241,18 +245,16 @@ body {
   height: 100%;
 }
 .histogram {
   position: relative;
   height: 60px;
   right: 0;
   left: 0;
   border-bottom: 1px solid #CCC;
-  background: -moz-linear-gradient(#EEE, #CCC);
-  background: -webkit-linear-gradient(#EEE, #CCC);
   background: linear-gradient(#EEE, #CCC);
 }
 .histogramHilite {
   position: absolute;
   pointer-events: none;
 }
 .histogramHilite:not(.collapsed) {
   background: rgba(150, 150, 150, 0.5);
@@ -282,18 +284,16 @@ body {
 .fileListItem {
   display: block;
   margin: 0;
   padding: 0;
   height: 40px;
   text-indent: 8px;
 }
 .fileListItem.selected {
-  background: -moz-linear-gradient(#4B91D7 1px, #5FA9E4 1px, #5FA9E4 2px, #58A0DE 3px, #2B70C7 39px, #2763B4 39px);
-  background: -webkit-linear-gradient(#4B91D7 1px, #5FA9E4 1px, #5FA9E4 2px, #58A0DE 3px, #2B70C7 39px, #2763B4 39px);
   background: linear-gradient(#4B91D7 1px, #5FA9E4 1px, #5FA9E4 2px, #58A0DE 3px, #2B70C7 39px, #2763B4 39px);
   color: #FFF;
   text-shadow: 0 1px rgba(0, 0, 0, 0.3);
 }
 .fileListItemTitle {
   display: block;
   padding-top: 6px;
   font-size: 12px;
@@ -308,34 +308,31 @@ body {
   top: 0;
   right: 0;
   bottom: 0;
   left: 0;
   visibility: hidden;
   opacity: 0;
   pointer-events: none;
   background: rgba(120, 120, 120, 0.2);
-  -moz-transition: 200ms ease-in-out;
-  -moz-transition-property: visibility, opacity;
-  -webkit-transition: 200ms ease-in-out;
-  -webkit-transition-property: visibility, opacity;
+  transition: 200ms ease-in-out;
+  transition-property: visibility, opacity;
 }
 .busyCover.busy {
   visibility: visible;
   opacity: 1;
 }
 .busyCover::before {
   content: url(../images/throbber.svg);
   position: absolute;
   top: 50%;
   left: 50%;
   margin: -12px;
 }
 label {
-  -webkit-user-select: none;
   -moz-user-select: none;
 }
 .videoPane {
   background-color: white;
   width: 100%;
 }
 .video {
   display: block;
deleted file mode 100755
deleted file mode 100755
--- a/browser/devtools/responsivedesign/CmdResize.jsm
+++ b/browser/devtools/responsivedesign/CmdResize.jsm
@@ -30,16 +30,35 @@ gcli.addCommand({
 
 gcli.addCommand({
   name: 'resize toggle',
   buttonId: "command-button-responsive",
   buttonClass: "command-button",
   tooltipText: gcli.lookup("resizeModeToggleTooltip"),
   description: gcli.lookup('resizeModeToggleDesc'),
   manual: gcli.lookup('resizeModeManual'),
+  state: {
+    isChecked: function(aTarget) {
+      let browserWindow = aTarget.tab.ownerDocument.defaultView;
+      let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager;
+      return mgr.isActiveForTab(aTarget.tab);
+    },
+    onChange: function(aTarget, aChangeHandler) {
+      let browserWindow = aTarget.tab.ownerDocument.defaultView;
+      let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager;
+      mgr.on("on", aChangeHandler);
+      mgr.on("off", aChangeHandler);
+    },
+    offChange: function(aTarget, aChangeHandler) {
+      let browserWindow = aTarget.tab.ownerDocument.defaultView;
+      let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager;
+      mgr.off("on", aChangeHandler);
+      mgr.off("off", aChangeHandler);
+    },
+  },
   exec: gcli_cmd_resize
 });
 
 gcli.addCommand({
   name: 'resize to',
   description: gcli.lookup('resizeModeToDesc'),
   params: [
     {
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -30,39 +30,48 @@ this.ResponsiveUIManager = {
    *
    * @param aWindow the main window.
    * @param aTab the tab targeted.
    */
   toggle: function(aWindow, aTab) {
     if (aTab.__responsiveUI) {
       aTab.__responsiveUI.close();
     } else {
-      aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+      new ResponsiveUI(aWindow, aTab);
     }
   },
 
   /**
+   * Returns true if responsive view is active for the provided tab.
+   *
+   * @param aTab the tab targeted.
+   */
+  isActiveForTab: function(aTab) {
+    return !!aTab.__responsiveUI;
+  },
+
+  /**
    * Handle gcli commands.
    *
    * @param aWindow the browser window.
    * @param aTab the tab targeted.
    * @param aCommand the command name.
    * @param aArgs command arguments.
    */
   handleGcliCommand: function(aWindow, aTab, aCommand, aArgs) {
     switch (aCommand) {
       case "resize to":
         if (!aTab.__responsiveUI) {
-          aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+          new ResponsiveUI(aWindow, aTab);
         }
         aTab.__responsiveUI.setSize(aArgs.width, aArgs.height);
         break;
       case "resize on":
         if (!aTab.__responsiveUI) {
-          aTab.__responsiveUI = new ResponsiveUI(aWindow, aTab);
+          new ResponsiveUI(aWindow, aTab);
         }
         break;
       case "resize off":
         if (aTab.__responsiveUI) {
           aTab.__responsiveUI.close();
         }
         break;
       case "resize toggle":
@@ -162,16 +171,18 @@ function ResponsiveUI(aWindow, aTab)
     if (Services.prefs.getBoolPref("devtools.responsiveUI.rotate")) {
       this.rotate();
     }
   } catch(e) {}
 
   if (this._floatingScrollbars)
     switchToFloatingScrollbars(this.tab);
 
+  this.tab.__responsiveUI = this;
+
   ResponsiveUIManager.emit("on", this.tab, this);
 }
 
 ResponsiveUI.prototype = {
   _transitionsEnabled: true,
   _floatingScrollbars: false, // See bug 799471
   get transitionsEnabled() this._transitionsEnabled,
   set transitionsEnabled(aValue) {
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -23,17 +23,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 XPCOMUtils.defineLazyModuleGetter(this, "CmdCommands",
                                   "resource:///modules/devtools/CmdCmd.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PageErrorListener",
                                   "resource://gre/modules/devtools/WebConsoleUtils.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
-  var prefService = Components.classes["@mozilla.org/preferences-service;1"]
+  let prefService = Components.classes["@mozilla.org/preferences-service;1"]
           .getService(Components.interfaces.nsIPrefService);
   return prefService.getBranch(null)
           .QueryInterface(Components.interfaces.nsIPrefBranch2);
 });
 
 /**
  * A collection of utilities to help working with commands
  */
@@ -46,32 +46,36 @@ this.CommandUtils = {
     let value = prefBranch.getComplexValue(aPref,
                                Components.interfaces.nsISupportsString).data;
     return JSON.parse(value);
   },
 
   /**
    * A toolbarSpec is an array of buttonSpecs. A buttonSpec is an array of
    * strings each of which is a GCLI command (including args if needed).
+   *
+   * Warning: this method uses the unload event of the window that owns the
+   * buttons that are of type checkbox. this means that we don't properly
+   * unregister event handlers until the window is destroyed.
    */
-  createButtons: function CU_createButtons(toolbarSpec, document, requisition) {
-    var reply = [];
+  createButtons: function CU_createButtons(toolbarSpec, target, document, requisition) {
+    let reply = [];
 
     toolbarSpec.forEach(function(buttonSpec) {
-      var button = document.createElement("toolbarbutton");
+      let button = document.createElement("toolbarbutton");
       reply.push(button);
 
       if (typeof buttonSpec == "string") {
         buttonSpec = { typed: buttonSpec };
       }
       // Ask GCLI to parse the typed string (doesn't execute it)
       requisition.update(buttonSpec.typed);
 
       // Ignore invalid commands
-      var command = requisition.commandAssignment.value;
+      let command = requisition.commandAssignment.value;
       if (command == null) {
         // TODO: Have a broken icon
         // button.icon = 'Broken';
         button.setAttribute("label", "X");
         button.setAttribute("tooltip", "Unknown command: " + buttonSpec.typed);
         button.setAttribute("disabled", "true");
       }
       else {
@@ -96,25 +100,34 @@ this.CommandUtils = {
           }
           else {
             console.error('incomplete commands not yet supported');
           }
           */
         }, false);
 
         // Allow the command button to be toggleable
-        /*
-        if (command.checkedState) {
-          button.setAttribute("type", "checkbox");
-          button.setAttribute("checked", command.checkedState.get() ? "true" : "false");
-          command.checkedState.on("change", function() {
-            button.checked = command.checkedState.get();
-          });
+        if (command.state) {
+          button.setAttribute("autocheck", false);
+          let onChange = function(event, eventTab) {
+            if (eventTab == target.tab) {
+              if (command.state.isChecked(target)) {
+                button.setAttribute("checked", true);
+              }
+              else if (button.hasAttribute("checked")) {
+                button.removeAttribute("checked");
+              }
+            }
+          };
+          command.state.onChange(target, onChange);
+          onChange(null, target.tab);
+          document.defaultView.addEventListener("unload", function() {
+            command.state.offChange(target, onChange);
+          }, false);
         }
-        */
       }
     });
 
     requisition.update('');
 
     return reply;
   }
 };
@@ -187,17 +200,17 @@ DeveloperToolbar.prototype.NOTIFICATIONS
  */
 Object.defineProperty(DeveloperToolbar.prototype, 'visible', {
   get: function DT_visible() {
     return !this._element.hidden;
   },
   enumerable: true
 });
 
-var _gSequenceId = 0;
+let _gSequenceId = 0;
 
 /**
  * Getter for a unique ID.
  */
 Object.defineProperty(DeveloperToolbar.prototype, 'sequenceId', {
   get: function DT_visible() {
     return _gSequenceId++;
   },
@@ -234,18 +247,18 @@ DeveloperToolbar.prototype.focus = funct
  * Called from browser.xul in response to menu-click or keyboard shortcut to
  * toggle the toolbar
  */
 DeveloperToolbar.prototype.focusToggle = function DT_focusToggle()
 {
   if (this.visible) {
     // If we have focus then the active element is the HTML input contained
     // inside the xul input element
-    var active = this._chromeWindow.document.activeElement;
-    var position = this._input.compareDocumentPosition(active);
+    let active = this._chromeWindow.document.activeElement;
+    let position = this._input.compareDocumentPosition(active);
     if (position & Node.DOCUMENT_POSITION_CONTAINED_BY) {
       this.hide();
     }
     else {
       this._input.focus();
     }
   } else {
     this.show(true);
@@ -438,17 +451,22 @@ DeveloperToolbar.prototype.hide = functi
   this._notify(NOTIFICATIONS.HIDE);
 };
 
 /**
  * Hide the developer toolbar
  */
 DeveloperToolbar.prototype.destroy = function DT_destroy()
 {
+  if (this._lastState == NOTIFICATIONS.HIDE) {
+    return;
+  }
+
   this._chromeWindow.getBrowser().tabContainer.removeEventListener("TabSelect", this, false);
+  this._chromeWindow.getBrowser().tabContainer.removeEventListener("TabClose", this, false);
   this._chromeWindow.getBrowser().removeEventListener("load", this, true); 
   this._chromeWindow.getBrowser().removeEventListener("beforeunload", this, true);
 
   let tabs = this._chromeWindow.getBrowser().tabs;
   Array.prototype.forEach.call(tabs, this._stopErrorsCount, this);
 
   this.display.focusManager.removeMonitoredElement(this.outputPanel._frame);
   this.display.focusManager.removeMonitoredElement(this._element);
@@ -465,16 +483,18 @@ DeveloperToolbar.prototype.destroy = fun
   // leaks as a belt-and-braces approach, however this prevents our DOM node
   // hunter from looking in all the nooks and crannies, so it's better if we
   // can be leak-free without
   /*
   delete this.display;
   delete this.outputPanel;
   delete this.tooltipPanel;
   */
+
+  this._lastState = NOTIFICATIONS.HIDE;
 };
 
 /**
  * Utility for sending notifications
  * @param aTopic a NOTIFICATION constant
  */
 DeveloperToolbar.prototype._notify = function DT_notify(aTopic)
 {
--- a/browser/devtools/shared/VariablesView.jsm
+++ b/browser/devtools/shared/VariablesView.jsm
@@ -1678,22 +1678,21 @@ VariablesView.prototype.commitHierarchy 
     if (!changed) {
       continue;
     }
 
     // Apply an attribute determining the flash type and duration.
     // Dispatch this action after all the nodes have been drawn, so that
     // the transition efects can take place.
     this.window.setTimeout(function(aTarget) {
-      aTarget.setAttribute("changed", "");
-
       aTarget.addEventListener("transitionend", function onEvent() {
         aTarget.removeEventListener("transitionend", onEvent, false);
         aTarget.removeAttribute("changed");
       }, false);
+      aTarget.setAttribute("changed", "");
     }.bind(this, currVariable.target), LAZY_EMPTY_DELAY + 1);
   }
 };
 
 // Some variables are likely to contain a very large number of properties.
 // It would be a bad idea to re-expand them or perform expensive operations.
 VariablesView.prototype.commitHierarchyIgnoredItems = Object.create(null, {
   "window": { value: true },
--- a/browser/devtools/styleeditor/StyleEditorChrome.jsm
+++ b/browser/devtools/styleeditor/StyleEditorChrome.jsm
@@ -395,17 +395,17 @@ StyleEditorChrome.prototype = {
       // We are in the main initialization phase so we wait for the editor
       // containing the target stylesheet to be added and select the target
       // stylesheet, optionally moving the cursor to a selected line.
       let self = this;
       this.addChromeListener({
         onEditorAdded: function SEC_selectSheet_onEditorAdded(aChrome, aEditor) {
           let sheet = self._styleSheetToSelect.sheet;
           if ((sheet && aEditor.styleSheet == sheet) ||
-              aEditor.styleSheetIndex == 0) {
+              (aEditor.styleSheetIndex == 0 && sheet == null)) {
             aChrome.removeChromeListener(this);
             select(aEditor);
           }
         }
       });
     } else if (aSheet) {
       // We are already initialized and a stylesheet has been specified. Here
       // we iterate through the editors and select the one containing the target
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -57,17 +57,17 @@ function UpdateProcess(aWin, aGenerator,
 }
 
 UpdateProcess.prototype = {
   /**
    * Schedule a new batch on the main loop.
    */
   schedule: function UP_schedule()
   {
-    if (this.cancelled) {
+    if (this.canceled) {
       return;
     }
     this._timeout = this.win.setTimeout(this._timeoutHandler.bind(this), 0);
   },
 
   /**
    * Cancel the running process.  onItem will not be called again,
    * and onCancel will be called.
@@ -95,17 +95,17 @@ UpdateProcess.prototype = {
       }
       throw e;
     }
   },
 
   _runBatch: function Y_runBatch()
   {
     let time = Date.now();
-    while(!this.cancelled) {
+    while(!this.canceled) {
       // Continue until iter.next() throws...
       let next = this.iter.next();
       this.onItem(next[1]);
       if ((Date.now() - time) > this.threshold) {
         this.onBatch();
         return;
       }
     }
@@ -142,17 +142,16 @@ this.CssHtmlTree = function CssHtmlTree(
 
   this.styleDocument.addEventListener("copy", this.siBoundCopy);
   this.styleDocument.addEventListener("mousedown", this.siFocusWindow);
 
   // Nodes used in templating
   this.root = this.styleDocument.getElementById("root");
   this.templateRoot = this.styleDocument.getElementById("templateRoot");
   this.propertyContainer = this.styleDocument.getElementById("propertyContainer");
-  this.panel = aStyleInspector.panel;
 
   // No results text.
   this.noResults = this.styleDocument.getElementById("noResults");
 
   // The element that we're inspecting, and the document that it comes from.
   this.viewedElement = null;
   this.createStyleViews();
   this.createContextMenu();
@@ -252,16 +251,23 @@ CssHtmlTree.prototype = {
    * @param {nsIDOMElement} aElement The highlighted node to get styles for.
    */
   highlight: function CssHtmlTree_highlight(aElement)
   {
     this.viewedElement = aElement;
     this._unmatchedProperties = null;
     this._matchedProperties = null;
 
+    if (!aElement) {
+      if (this._refreshProcess) {
+        this._refreshProcess.cancel();
+      }
+      return;
+    }
+
     if (this.htmlComplete) {
       this.refreshSourceFilter();
       this.refreshPanel();
     } else {
       if (this._refreshProcess) {
         this._refreshProcess.cancel();
       }
 
--- a/browser/devtools/styleinspector/StyleInspector.jsm
+++ b/browser/devtools/styleinspector/StyleInspector.jsm
@@ -75,16 +75,17 @@ this.RuleViewTool = function RVT_RuleVie
       viewSourceUtils.viewSource(href, null, contentDoc, line);
     }
   }.bind(this);
 
   this.view.element.addEventListener("CssRuleViewCSSLinkClicked",
                                      this._cssLinkHandler);
 
   this._onSelect = this.onSelect.bind(this);
+  this.inspector.selection.on("detached", this._onSelect);
   this.inspector.selection.on("new-node", this._onSelect);
   this.refresh = this.refresh.bind(this);
   this.inspector.on("layout-change", this.refresh);
   this.inspector.sidebar.on("ruleview-selected", this.refresh);
   this.inspector.selection.on("pseudoclass", this.refresh);
   if (this.inspector.highlighter) {
     this.inspector.highlighter.on("locked", this._onSelect);
   }
@@ -154,16 +155,17 @@ this.ComputedViewTool = function CVT_Com
   this.inspector = aInspector;
   this.window = aWindow;
   this.document = aWindow.document;
   this.outerIFrame = aIFrame;
   this.cssLogic = new CssLogic();
   this.view = new CssHtmlTree(this);
 
   this._onSelect = this.onSelect.bind(this);
+  this.inspector.selection.on("detached", this._onSelect);
   this.inspector.selection.on("new-node", this._onSelect);
   if (this.inspector.highlighter) {
     this.inspector.highlighter.on("locked", this._onSelect);
   }
   this.refresh = this.refresh.bind(this);
   this.inspector.on("layout-change", this.refresh);
   this.inspector.sidebar.on("computedview-selected", this.refresh);
   this.inspector.selection.on("pseudoclass", this.refresh);
@@ -174,17 +176,17 @@ this.ComputedViewTool = function CVT_Com
   this.onSelect();
 }
 
 ComputedViewTool.prototype = {
   onSelect: function CVT_onSelect(aEvent)
   {
     if (!this.inspector.selection.isConnected() ||
         !this.inspector.selection.isElementNode()) {
-      // FIXME: We should hide view's content
+      this.view.highlight(null);
       return;
     }
 
     if (!aEvent || aEvent == "new-node") {
       if (this.inspector.selection.reason == "highlighter") {
         // FIXME: We should hide view's content
       } else {
         this.cssLogic.highlight(this.inspector.selection.node);
--- a/browser/devtools/tilt/CmdTilt.jsm
+++ b/browser/devtools/tilt/CmdTilt.jsm
@@ -1,20 +1,20 @@
 /* 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/. */
 
 
 this.EXPORTED_SYMBOLS = [ ];
 
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
 Components.utils.import("resource:///modules/devtools/gcli.jsm");
-Components.utils.import("resource:///modules/HUDService.jsm");
-Components.utils.import("resource:///modules/devtools/Tilt.jsm");
 
-
+XPCOMUtils.defineLazyModuleGetter(this, "TiltManager",
+                                  "resource:///modules/devtools/Tilt.jsm");
 /**
  * 'tilt' command
  */
 gcli.addCommand({
   name: 'tilt',
   description: gcli.lookup("tiltDesc"),
   manual: gcli.lookup("tiltManual")
 });
@@ -41,16 +41,32 @@ gcli.addCommand({
  * 'tilt toggle' command
  */
 gcli.addCommand({
   name: "tilt toggle",
   buttonId: "command-button-tilt",
   buttonClass: "command-button",
   tooltipText: gcli.lookup("tiltToggleTooltip"),
   hidden: true,
+  state: {
+    isChecked: function(aTarget) {
+      let browserWindow = aTarget.tab.ownerDocument.defaultView;
+      return !!TiltManager.getTiltForBrowser(browserWindow).currentInstance;
+    },
+    onChange: function(aTarget, aChangeHandler) {
+      let browserWindow = aTarget.tab.ownerDocument.defaultView;
+      let tilt = TiltManager.getTiltForBrowser(browserWindow);
+      tilt.on("change", aChangeHandler);
+    },
+    offChange: function(aTarget, aChangeHandler) {
+      let browserWindow = aTarget.tab.ownerDocument.defaultView;
+      let tilt = TiltManager.getTiltForBrowser(browserWindow);
+      tilt.off("change", aChangeHandler);
+    },
+  },
   exec: function(args, context) {
     let chromeWindow = context.environment.chromeDocument.defaultView;
     let Tilt = TiltManager.getTiltForBrowser(chromeWindow);
     Tilt.toggle();
   }
 });
 
 
--- a/browser/devtools/tilt/Tilt.jsm
+++ b/browser/devtools/tilt/Tilt.jsm
@@ -41,16 +41,17 @@ const TILT_NOTIFICATIONS = {
 
   // Fires when a node is removed from the 3D mesh.
   NODE_REMOVED: "tilt-node-removed"
 };
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/TiltGL.jsm");
 Cu.import("resource:///modules/devtools/TiltUtils.jsm");
+Cu.import("resource:///modules/devtools/EventEmitter.jsm");
 Cu.import("resource:///modules/devtools/TiltVisualizer.jsm");
 
 this.EXPORTED_SYMBOLS = ["TiltManager"];
 
 this.TiltManager = {
   _instances: new WeakMap(),
   getTiltForBrowser: function(aChromeWindow)
   {
@@ -82,16 +83,18 @@ this.Tilt = function Tilt(aWindow)
    */
   this.visualizers = {};
 
   /**
    * Shortcut for accessing notifications strings.
    */
   this.NOTIFICATIONS = TILT_NOTIFICATIONS;
 
+  EventEmitter.decorate(this);
+
   this.setup();
 }
 
 Tilt.prototype = {
 
   /**
    * Initializes a visualizer for the current tab or closes it if already open.
    */
@@ -123,16 +126,17 @@ Tilt.prototype = {
 
     // make sure the visualizer object was initialized properly
     if (!this.visualizers[id].isInitialized()) {
       this.destroy(id);
       this.failureCallback && this.failureCallback();
       return;
     }
 
+    this.emit("change", this.chromeWindow.gBrowser.selectedTab);
     Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.INITIALIZING, null);
   },
 
   /**
    * Starts destroying a specific instance of the visualizer.
    *
    * @param {String} aId
    *                 the identifier of the instance in the visualizers array
@@ -178,16 +182,17 @@ Tilt.prototype = {
   _finish: function T__finish(aId)
   {
     this.visualizers[aId].removeOverlay();
     this.visualizers[aId].cleanup();
     this.visualizers[aId] = null;
 
     this._isDestroying = false;
     this.chromeWindow.gBrowser.selectedBrowser.focus();
+    this.emit("change", this.chromeWindow.gBrowser.selectedTab);
     Services.obs.notifyObservers(null, TILT_NOTIFICATIONS.DESTROYED, null);
   },
 
   /**
    * Handles the event fired when a tab is selected.
    */
   _onTabSelect: function T__onTabSelect()
   {
--- a/browser/devtools/webconsole/WebConsolePanel.jsm
+++ b/browser/devtools/webconsole/WebConsolePanel.jsm
@@ -25,20 +25,20 @@ function WebConsolePanel(iframeWindow, t
   EventEmitter.decorate(this);
 }
 
 WebConsolePanel.prototype = {
   /**
    * open is effectively an asynchronous constructor
    */
   open: function StyleEditor_open() {
-    let tab = this._toolbox._getHostTab();
     let parentDoc = this._frameWindow.document.defaultView.parent.document;
     let iframe = parentDoc.getElementById("toolbox-panel-iframe-webconsole");
-    this.hud = HUDService.activateHUDForContext(tab, iframe, this._toolbox.target);
+    this.hud = HUDService.activateHUDForContext(this.target.tab, iframe,
+                                                this._toolbox.target);
 
     let deferred = Promise.defer();
 
     let hudId = this.hud.hudId;
     let onOpen = function _onWebConsoleOpen(aSubject) {
       aSubject.QueryInterface(Ci.nsISupportsString);
       if (hudId == aSubject.data) {
         Services.obs.removeObserver(onOpen, "web-console-created");
--- a/browser/devtools/webconsole/test/Makefile.in
+++ b/browser/devtools/webconsole/test/Makefile.in
@@ -99,17 +99,17 @@ MOCHITEST_BROWSER_FILES = \
 	browser_webconsole_bug_659907_console_dir.js \
 	browser_webconsole_bug_664131_console_group.js \
 	browser_webconsole_bug_704295.js \
 	browser_webconsole_bug_658368_time_methods.js \
 	browser_webconsole_bug_764572_output_open_url.js \
 	browser_webconsole_bug_622303_persistent_filters.js \
 	browser_webconsole_bug_770099_bad_policyuri.js \
 	browser_webconsole_bug_770099_violation.js \
-	$(filter disabled-temporarily--bug-808264, browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js) \
+	browser_webconsole_bug_782653_CSS_links_in_Style_Editor.js \
 	browser_cached_messages.js \
 	browser_bug664688_sandbox_update_after_navigation.js \
 	browser_result_format_as_string.js \
 	browser_webconsole_bug_737873_mixedcontent.js \
 	browser_output_breaks_after_console_dir_uninspectable.js \
 	browser_console_log_inspectable_object.js \
 	browser_bug_638949_copy_link_location.js \
 	browser_output_longstring_expand.js \
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -229,21 +229,22 @@ These should match what Safari and other
 <!ENTITY scratchpad.keycode           "VK_F4">
 <!ENTITY scratchpad.keytext           "F4">
 
 <!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
 <!ENTITY devToolbarMenu.label              "Developer Toolbar">
 <!ENTITY devToolbarMenu.accesskey          "v">
 <!ENTITY devToolbar.keycode                "VK_F2">
 <!ENTITY devToolbar.keytext                "F2">
-<!ENTITY devToolbarToolsButton.label       "Toggle Toolbox">
+<!ENTITY devToolboxMenuItem.label          "Toggle Tools">
+<!ENTITY devToolboxMenuItem.accesskey      "T">
+
+<!ENTITY devToolbarToolsButton.tooltip     "Toggle developer tools">
 <!ENTITY devToolbarOtherToolsButton.label  "More Tools">
 
-<!ENTITY devToolbox.accesskey              "B">
-
 <!ENTITY getMoreDevtoolsCmd.label        "Get More Tools">
 <!ENTITY getMoreDevtoolsCmd.accesskey    "M">
 
 <!ENTITY fileMenu.label         "File"> 
 <!ENTITY fileMenu.accesskey       "F">
 <!ENTITY newNavigatorCmd.label        "New Window">
 <!ENTITY newNavigatorCmd.key        "N">
 <!ENTITY newNavigatorCmd.accesskey      "N">
--- a/browser/themes/gnomestripe/browser.css
+++ b/browser/themes/gnomestripe/browser.css
@@ -2285,16 +2285,24 @@ html|*#gcli-output-frame {
 }
 
 .web-console-frame[animated] {
   transition: height 100ms;
 }
 
 /* Developer Toolbar */
 
+#developer-toolbar-toolbox-button {
+  min-width: 18px;
+}
+
+#developer-toolbar-toolbox-button > .toolbarbutton-text {
+  display: none;
+}
+
 .developer-toolbar-button {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border-radius: 3px;
   color: inherit;
   border: 1px solid transparent;
--- a/browser/themes/gnomestripe/devtools/toolbox.css
+++ b/browser/themes/gnomestripe/devtools/toolbox.css
@@ -67,64 +67,64 @@
 .command-button:hover {
   background-color: hsla(206,37%,4%,.2);
 }
 .command-button:hover:active {
   background-color: hsla(206,37%,4%,.4);
 }
 
 #command-button-responsive {
-  list-style-image: url(chrome://browser/skin/devtools/command-responsivemode.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-responsivemode.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 #command-button-responsive:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 #command-button-responsive:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 #command-button-responsive[checked=true] {
   -moz-image-region: rect(0px, 64px, 16px, 48px);
 }
 
 #command-button-tilt {
-  list-style-image: url(chrome://browser/skin/devtools/command-tilt.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-tilt.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 #command-button-tilt:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-tilt:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 #command-button-tilt[checked=true] {
   -moz-image-region: rect(0px, 64px, 16px, 48px);
 }
 
 #command-button-scratchpad {
-  list-style-image: url(chrome://browser/skin/devtools/command-scratchpad.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-scratchpad.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 #command-button-scratchpad:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-scratchpad:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 
 /* Tabs */
 
 .devtools-tabbar {
   -moz-appearance: none;
-  background-image: url(background-noise-toolbar.png),
+  background-image: url("background-noise-toolbar.png"),
                     linear-gradient(#303840, #2d3640);
   border-top: 1px solid #060a0d;
   box-shadow: 0 1px 0 hsla(204,45%,98%,.05) inset,
               0 -1px 0 hsla(206,37%,4%,.1) inset;
   min-height: 32px;
   padding: 0;
 }
 
@@ -168,34 +168,34 @@
 .radio-icon {
   opacity: 1;
 }
 
 .devtools-tab:hover {
   background-image: linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(206,37%,4%,.1), hsla(206,37%,4%,.2));
-  background size: 1px 100%,
+  background-size: 1px 100%,
                    1px 100%,
                    100%;
   background-repeat: no-repeat,
                      no-repeat,
                      repeat-x;
   background-position: left, right;
   color: #ced3d9;
 }
 .devtools-tab:hover:active {
   background-color: hsla(206,37%,4%,.2);
   color: #f5f7fa;
 }
 
 .devtools-tab[selected=true] {
   color: #f5f7fa;
-  background-image: radial-gradient(ellipse farthest-corner at center top, #9fdfff, hsla(200,100%,70%,.3)),
-                    radial-gradient(ellipse farthest-side at center top, hsla(200,100%,70%,.4), hsla(200,100%,70%,0)),
+  background-image: radial-gradient(farthest-corner at center top, #9fdfff, hsla(200,100%,70%,.3)),
+                    radial-gradient(farthest-side at center top, hsla(200,100%,70%,.4), hsla(200,100%,70%,0)),
                     linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(204,45%,98%,.02), hsla(204,45%,98%,.04)),
                     linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.3));
   background-size: 100% 1px,
                    100% 5px,
                    1px 100%,
                    1px 100%,
                    100%;
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -3747,16 +3747,24 @@ html|*#gcli-output-frame {
 }
 
 .web-console-frame[animated] {
   transition: height 100ms;
 }
 
 /* Developer Toolbar */
 
+#developer-toolbar-toolbox-button {
+  min-width: 18px;
+}
+
+#developer-toolbar-toolbox-button > .toolbarbutton-text {
+  display: none;
+}
+
 .developer-toolbar-button {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border-radius: @toolbarbuttonCornerRadius@;
   color: inherit;
   border: 1px solid transparent;
--- a/browser/themes/pinstripe/devtools/toolbox.css
+++ b/browser/themes/pinstripe/devtools/toolbox.css
@@ -54,64 +54,64 @@
 .command-button:hover {
   background-color: hsla(206,37%,4%,.2);
 }
 .command-button:hover:active {
   background-color: hsla(206,37%,4%,.4);
 }
 
 #command-button-responsive {
-  list-style-image: url(chrome://browser/skin/devtools/command-responsivemode.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-responsivemode.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 #command-button-responsive:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 #command-button-responsive:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 #command-button-responsive[checked=true] {
   -moz-image-region: rect(0px, 64px, 16px, 48px);
 }
 
 #command-button-tilt {
-  list-style-image: url(chrome://browser/skin/devtools/command-tilt.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-tilt.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 #command-button-tilt:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-tilt:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 #command-button-tilt[checked=true] {
   -moz-image-region: rect(0px, 64px, 16px, 48px);
 }
 
 #command-button-scratchpad {
-  list-style-image: url(chrome://browser/skin/devtools/command-scratchpad.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-scratchpad.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 #command-button-scratchpad:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-scratchpad:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 
 /* Tabs */
 
 .devtools-tabbar {
   -moz-appearance: none;
-  background-image: url(background-noise-toolbar.png),
+  background-image: url("background-noise-toolbar.png"),
                     linear-gradient(#303840, #2d3640);
   border-top: 1px solid #060a0d;
   box-shadow: 0 1px 0 hsla(204,45%,98%,.05) inset,
               0 -1px 0 hsla(206,37%,4%,.1) inset;
   min-height: 32px;
   padding: 0;
 }
 
@@ -152,34 +152,34 @@
 .devtools-tab[selected=true] > .radio-label-box > .radio-icon {
   opacity: 1;
 }
 
 .devtools-tab:hover {
   background-image: linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(206,37%,4%,.1), hsla(206,37%,4%,.2));
-  background size: 1px 100%,
+  background-size: 1px 100%,
                    1px 100%,
                    100%;
   background-repeat: no-repeat,
                      no-repeat,
                      repeat-x;
   background-position: left, right;
   color: #ced3d9;
 }
 .devtools-tab:hover:active {
   background-color: hsla(206,37%,4%,.2);
   color: #f5f7fa;
 }
 
 .devtools-tab[selected=true] {
   color: #f5f7fa;
-  background-image: radial-gradient(ellipse farthest-corner at center top, #9fdfff, hsla(200,100%,70%,.3)),
-                    radial-gradient(ellipse farthest-side at center top, hsla(200,100%,70%,.4), hsla(200,100%,70%,0)),
+  background-image: radial-gradient(farthest-corner at center top, #9fdfff, hsla(200,100%,70%,.3)),
+                    radial-gradient(farthest-side at center top, hsla(200,100%,70%,.4), hsla(200,100%,70%,0)),
                     linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(204,45%,98%,.02), hsla(204,45%,98%,.04)),
                     linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.3));
   background-size: 100% 1px,
                    100% 5px,
                    1px 100%,
                    1px 100%,
                    100%;
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -2968,16 +2968,24 @@ html|*#gcli-output-frame {
 }
 
 .web-console-frame[animated] {
   transition: height 100ms;
 }
 
 /* Developer Toolbar */
 
+#developer-toolbar-toolbox-button {
+  min-width: 18px;
+}
+
+#developer-toolbar-toolbox-button > .toolbarbutton-text {
+  display: none;
+}
+
 .developer-toolbar-button {
   -moz-appearance: none;
   min-width: 78px;
   min-height: 22px;
   text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
   border-radius: 3px;
   color: inherit;
   border: 1px solid transparent;
--- a/browser/themes/winstripe/devtools/toolbox.css
+++ b/browser/themes/winstripe/devtools/toolbox.css
@@ -70,64 +70,64 @@
 .command-button:hover {
   background-color: hsla(206,37%,4%,.2);
 }
 .command-button:hover:active {
   background-color: hsla(206,37%,4%,.4);
 }
 
 #command-button-responsive {
-  list-style-image: url(chrome://browser/skin/devtools/command-responsivemode.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-responsivemode.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 #command-button-responsive:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 #command-button-responsive:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 #command-button-responsive[checked=true] {
   -moz-image-region: rect(0px, 64px, 16px, 48px);
 }
 
 #command-button-tilt {
-  list-style-image: url(chrome://browser/skin/devtools/command-tilt.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-tilt.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 #command-button-tilt:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-tilt:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 #command-button-tilt[checked=true] {
   -moz-image-region: rect(0px, 64px, 16px, 48px);
 }
 
 #command-button-scratchpad {
-  list-style-image: url(chrome://browser/skin/devtools/command-scratchpad.png);
+  list-style-image: url("chrome://browser/skin/devtools/command-scratchpad.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 #command-button-scratchpad:hover {
   -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 
 #command-button-scratchpad:hover:active {
   -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 
 /* Tabs */
 
 .devtools-tabbar {
   -moz-appearance: none;
-  background-image: url(background-noise-toolbar.png),
+  background-image: url("background-noise-toolbar.png"),
                     linear-gradient(#303840, #2d3640);
   border: none;
   box-shadow: 0 1px 0 hsla(204,45%,98%,.05) inset,
               0 -1px 0 hsla(206,37%,4%,.1) inset;
   min-height: 32px;
   padding: 0;
 }
 
@@ -169,34 +169,34 @@
 .devtools-tab[selected=true] > .radio-label-box > .radio-icon {
   opacity: 1;
 }
 
 .devtools-tab:hover {
   background-image: linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(206,37%,4%,.1), hsla(206,37%,4%,.2));
-  background size: 1px 100%,
+  background-size: 1px 100%,
                    1px 100%,
                    100%;
   background-repeat: no-repeat,
                      no-repeat,
                      repeat-x;
   background-position: left, right;
   color: #ced3d9;
 }
 .devtools-tab:hover:active {
   background-color: hsla(206,37%,4%,.2);
   color: #f5f7fa;
 }
 
 .devtools-tab[selected=true] {
   color: #f5f7fa;
-  background-image: radial-gradient(ellipse farthest-corner at center top, #9fdfff, hsla(200,100%,70%,.3)),
-                    radial-gradient(ellipse farthest-side at center top, hsla(200,100%,70%,.4), hsla(200,100%,70%,0)),
+  background-image: radial-gradient(farthest-corner at center top, #9fdfff, hsla(200,100%,70%,.3)),
+                    radial-gradient(farthest-side at center top, hsla(200,100%,70%,.4), hsla(200,100%,70%,0)),
                     linear-gradient(hsla(204,45%,98%,.05), hsla(204,45%,98%,.1)),
                     linear-gradient(hsla(204,45%,98%,.02), hsla(204,45%,98%,.04)),
                     linear-gradient(hsla(206,37%,4%,.2), hsla(206,37%,4%,.3));
   background-size: 100% 1px,
                    100% 5px,
                    1px 100%,
                    1px 100%,
                    100%;
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Debugger-debuggees-20.js
@@ -0,0 +1,28 @@
+// addAllGlobalsAsDebuggees adds all the globals as debuggees.
+
+var g1 = newGlobal();           // Created before the Debugger; debuggee.
+var g2 = newGlobal();           // Created before the Debugger; not debuggee.
+
+var dbg = new Debugger;
+
+var g3 = newGlobal();           // Created after the Debugger; debuggee.
+var g4 = newGlobal();           // Created after the Debugger; not debuggee.
+
+var g1w = dbg.addDebuggee(g1);
+assertEq(dbg.addAllGlobalsAsDebuggees(), undefined);
+
+// Get Debugger.Objects viewing the globals from their own compartments;
+// this is the sort that findAllGlobals and addDebuggee return.
+var g1w = g1w.makeDebuggeeValue(g1).unwrap();
+var g2w = g1w.makeDebuggeeValue(g2).unwrap();
+var g3w = g1w.makeDebuggeeValue(g3).unwrap();
+var g4w = g1w.makeDebuggeeValue(g4).unwrap();
+var thisw = g1w.makeDebuggeeValue(this).unwrap();
+
+// Check that they're all there.
+assertEq(dbg.hasDebuggee(g1w), true);
+assertEq(dbg.hasDebuggee(g2w), true);
+assertEq(dbg.hasDebuggee(g3w), true);
+assertEq(dbg.hasDebuggee(g4w), true);
+// The debugger's global is not a debuggee.
+assertEq(dbg.hasDebuggee(thisw), false);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -879,45 +879,62 @@ JSCompartment::updateForDebugMode(FreeOp
     if (!rt->isHeapBusy())
         dmgc.scheduleGC(this);
 #endif
 }
 
 bool
 JSCompartment::addDebuggee(JSContext *cx, js::GlobalObject *global)
 {
+    AutoDebugModeGC dmgc(cx->runtime);
+    return addDebuggee(cx, global, dmgc);
+}
+
+bool
+JSCompartment::addDebuggee(JSContext *cx,
+                           js::GlobalObject *global,
+                           AutoDebugModeGC &dmgc)
+{
     bool wasEnabled = debugMode();
     if (!debuggees.put(global)) {
         js_ReportOutOfMemory(cx);
         return false;
     }
     debugModeBits |= DebugFromJS;
     if (!wasEnabled) {
-        AutoDebugModeGC dmgc(cx->runtime);
         updateForDebugMode(cx->runtime->defaultFreeOp(), dmgc);
     }
     return true;
 }
 
 void
 JSCompartment::removeDebuggee(FreeOp *fop,
                               js::GlobalObject *global,
                               js::GlobalObjectSet::Enum *debuggeesEnum)
 {
+    AutoDebugModeGC dmgc(rt);
+    return removeDebuggee(fop, global, dmgc, debuggeesEnum);
+}
+
+void
+JSCompartment::removeDebuggee(FreeOp *fop,
+                              js::GlobalObject *global,
+                              AutoDebugModeGC &dmgc,
+                              js::GlobalObjectSet::Enum *debuggeesEnum)
+{
     bool wasEnabled = debugMode();
     JS_ASSERT(debuggees.has(global));
     if (debuggeesEnum)
         debuggeesEnum->removeFront();
     else
         debuggees.remove(global);
 
     if (debuggees.empty()) {
         debugModeBits &= ~DebugFromJS;
         if (wasEnabled && !debugMode()) {
-            AutoDebugModeGC dmgc(rt);
             DebugScopes::onCompartmentLeaveDebugMode(this);
             updateForDebugMode(fop, dmgc);
         }
     }
 }
 
 void
 JSCompartment::clearBreakpointsIn(FreeOp *fop, js::Debugger *dbg, JSObject *handler)
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -495,18 +495,23 @@ struct JSCompartment : private JS::shado
 
   private:
     /* This is called only when debugMode() has just toggled. */
     void updateForDebugMode(js::FreeOp *fop, js::AutoDebugModeGC &dmgc);
 
   public:
     js::GlobalObjectSet &getDebuggees() { return debuggees; }
     bool addDebuggee(JSContext *cx, js::GlobalObject *global);
+    bool addDebuggee(JSContext *cx, js::GlobalObject *global,
+                     js::AutoDebugModeGC &dmgc);
     void removeDebuggee(js::FreeOp *fop, js::GlobalObject *global,
                         js::GlobalObjectSet::Enum *debuggeesEnum = NULL);
+    void removeDebuggee(js::FreeOp *fop, js::GlobalObject *global,
+                        js::AutoDebugModeGC &dmgc,
+                        js::GlobalObjectSet::Enum *debuggeesEnum = NULL);
     bool setDebugModeFromC(JSContext *cx, bool b, js::AutoDebugModeGC &dmgc);
 
     void clearBreakpointsIn(js::FreeOp *fop, js::Debugger *dbg, JSObject *handler);
     void clearTraps(js::FreeOp *fop);
 
   private:
     void sweepBreakpoints(js::FreeOp *fop);
 
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -1877,16 +1877,36 @@ Debugger::addDebuggee(JSContext *cx, uns
     Value v = ObjectValue(*global);
     if (!dbg->wrapDebuggeeValue(cx, &v))
         return false;
     args.rval().set(v);
     return true;
 }
 
 JSBool
+Debugger::addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGGER(cx, argc, vp, "addAllGlobalsAsDebuggees", args, dbg);
+    AutoDebugModeGC dmgc(cx->runtime);
+    for (CompartmentsIter c(cx->runtime); !c.done(); c.next()) {
+        if (c == dbg->object->compartment())
+            continue;
+        c->scheduledForDestruction = false;
+        GlobalObject *global = c->maybeGlobal();
+        if (global) {
+            Rooted<GlobalObject*> rg(cx, global);
+            dbg->addDebuggeeGlobal(cx, rg, dmgc);
+        }
+    }
+
+    args.rval().setUndefined();
+    return true;
+}
+
+JSBool
 Debugger::removeDebuggee(JSContext *cx, unsigned argc, Value *vp)
 {
     REQUIRE_ARGC("Debugger.removeDebuggee", 1);
     THIS_DEBUGGER(cx, argc, vp, "removeDebuggee", args, dbg);
     GlobalObject *global = dbg->unwrapDebuggeeArgument(cx, args[0]);
     if (!global)
         return false;
     if (dbg->debuggees.has(global))
@@ -1894,18 +1914,19 @@ Debugger::removeDebuggee(JSContext *cx, 
     args.rval().setUndefined();
     return true;
 }
 
 JSBool
 Debugger::removeAllDebuggees(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGGER(cx, argc, vp, "removeAllDebuggees", args, dbg);
+    AutoDebugModeGC dmgc(cx->runtime);
     for (GlobalObjectSet::Enum e(dbg->debuggees); !e.empty(); e.popFront())
-        dbg->removeDebuggeeGlobal(cx->runtime->defaultFreeOp(), e.front(), NULL, &e);
+        dbg->removeDebuggeeGlobal(cx->runtime->defaultFreeOp(), e.front(), dmgc, NULL, &e);
     args.rval().setUndefined();
     return true;
 }
 
 JSBool
 Debugger::hasDebuggee(JSContext *cx, unsigned argc, Value *vp)
 {
     REQUIRE_ARGC("Debugger.hasDebuggee", 1);
@@ -2022,16 +2043,25 @@ Debugger::construct(JSContext *cx, unsig
 
     args.rval().setObject(*obj);
     return true;
 }
 
 bool
 Debugger::addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> global)
 {
+    AutoDebugModeGC dmgc(cx->runtime);
+    return addDebuggeeGlobal(cx, global, dmgc);
+}
+
+bool
+Debugger::addDebuggeeGlobal(JSContext *cx,
+                            Handle<GlobalObject*> global,
+                            AutoDebugModeGC &dmgc)
+{
     if (debuggees.has(global))
         return true;
 
     JSCompartment *debuggeeCompartment = global->compartment();
 
     /*
      * Check for cycles. If global's compartment is reachable from this
      * Debugger object's compartment by following debuggee-to-debugger links,
@@ -2077,33 +2107,43 @@ Debugger::addDebuggeeGlobal(JSContext *c
     if (!v || !v->append(this)) {
         js_ReportOutOfMemory(cx);
     } else {
         if (!debuggees.put(global)) {
             js_ReportOutOfMemory(cx);
         } else {
             if (global->getDebuggers()->length() > 1)
                 return true;
-            if (debuggeeCompartment->addDebuggee(cx, global))
+            if (debuggeeCompartment->addDebuggee(cx, global, dmgc))
                 return true;
 
             /* Maintain consistency on error. */
             debuggees.remove(global);
         }
         JS_ASSERT(v->back() == this);
         v->popBack();
     }
     return false;
 }
 
 void
 Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
                                GlobalObjectSet::Enum *compartmentEnum,
                                GlobalObjectSet::Enum *debugEnum)
 {
+    AutoDebugModeGC dmgc(global->compartment()->rt);
+    return removeDebuggeeGlobal(fop, global, dmgc, compartmentEnum, debugEnum);
+}
+
+void
+Debugger::removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
+                               AutoDebugModeGC &dmgc,
+                               GlobalObjectSet::Enum *compartmentEnum,
+                               GlobalObjectSet::Enum *debugEnum)
+{
     /*
      * Each debuggee is in two HashSets: one for its compartment and one for
      * its debugger (this). The caller might be enumerating either set; if so,
      * use HashSet::Enum::removeFront rather than HashSet::remove below, to
      * avoid invalidating the live enumerator.
      */
     JS_ASSERT(global->compartment()->getDebuggees().has(global));
     JS_ASSERT_IF(compartmentEnum, compartmentEnum->front() == global);
@@ -2146,17 +2186,17 @@ Debugger::removeDebuggeeGlobal(FreeOp *f
         debuggees.remove(global);
 
     /*
      * The debuggee needs to be removed from the compartment last, as this can
      * trigger GCs if the compartment's debug mode is being changed, and the
      * global cannot be rooted on the stack without a cx.
      */
     if (v->empty())
-        global->compartment()->removeDebuggee(fop, global, compartmentEnum);
+        global->compartment()->removeDebuggee(fop, global, dmgc, compartmentEnum);
 }
 
 /*
  * A class for parsing 'findScripts' query arguments and searching for
  * scripts that match the criteria they represent.
  */
 class Debugger::ScriptQuery {
   public:
@@ -2533,16 +2573,17 @@ JSPropertySpec Debugger::properties[] = 
     JS_PSGS("onNewGlobalObject", Debugger::getOnNewGlobalObject, Debugger::setOnNewGlobalObject, 0),
     JS_PSGS("uncaughtExceptionHook", Debugger::getUncaughtExceptionHook,
             Debugger::setUncaughtExceptionHook, 0),
     JS_PS_END
 };
 
 JSFunctionSpec Debugger::methods[] = {
     JS_FN("addDebuggee", Debugger::addDebuggee, 1, 0),
+    JS_FN("addAllGlobalsAsDebuggees", Debugger::addAllGlobalsAsDebuggees, 0, 0),
     JS_FN("removeDebuggee", Debugger::removeDebuggee, 1, 0),
     JS_FN("removeAllDebuggees", Debugger::removeAllDebuggees, 0, 0),
     JS_FN("hasDebuggee", Debugger::hasDebuggee, 1, 0),
     JS_FN("getDebuggees", Debugger::getDebuggees, 0, 0),
     JS_FN("getNewestFrame", Debugger::getNewestFrame, 0, 0),
     JS_FN("clearAllBreakpoints", Debugger::clearAllBreakpoints, 1, 0),
     JS_FN("findScripts", Debugger::findScripts, 1, 0),
     JS_FN("findAllGlobals", Debugger::findAllGlobals, 0, 0),
--- a/js/src/vm/Debugger.h
+++ b/js/src/vm/Debugger.h
@@ -220,19 +220,25 @@ class Debugger : private mozilla::Linked
 
     /* The map from debuggee Envs to Debugger.Environment instances. */
     ObjectWeakMap environments;
 
     class FrameRange;
     class ScriptQuery;
 
     bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj);
+    bool addDebuggeeGlobal(JSContext *cx, Handle<GlobalObject*> obj,
+                           AutoDebugModeGC &dmgc);
     void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
                               GlobalObjectSet::Enum *compartmentEnum,
                               GlobalObjectSet::Enum *debugEnum);
+    void removeDebuggeeGlobal(FreeOp *fop, GlobalObject *global,
+                              AutoDebugModeGC &dmgc,
+                              GlobalObjectSet::Enum *compartmentEnum,
+                              GlobalObjectSet::Enum *debugEnum);
 
     /*
      * Cope with an error or exception in a debugger hook.
      *
      * If callHook is true, then call the uncaughtExceptionHook, if any. If, in
      * addition, vp is non-null, then parse the value returned by
      * uncaughtExceptionHook as a resumption value.
      *
@@ -295,16 +301,17 @@ class Debugger : private mozilla::Linked
     static JSBool setOnNewScript(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getOnEnterFrame(JSContext *cx, unsigned argc, Value *vp);
     static JSBool setOnEnterFrame(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getOnNewGlobalObject(JSContext *cx, unsigned argc, Value *vp);
     static JSBool setOnNewGlobalObject(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
     static JSBool setUncaughtExceptionHook(JSContext *cx, unsigned argc, Value *vp);
     static JSBool addDebuggee(JSContext *cx, unsigned argc, Value *vp);
+    static JSBool addAllGlobalsAsDebuggees(JSContext *cx, unsigned argc, Value *vp);
     static JSBool removeDebuggee(JSContext *cx, unsigned argc, Value *vp);
     static JSBool removeAllDebuggees(JSContext *cx, unsigned argc, Value *vp);
     static JSBool hasDebuggee(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getDebuggees(JSContext *cx, unsigned argc, Value *vp);
     static JSBool getNewestFrame(JSContext *cx, unsigned argc, Value *vp);
     static JSBool clearAllBreakpoints(JSContext *cx, unsigned argc, Value *vp);
     static JSBool findScripts(JSContext *cx, unsigned argc, Value *vp);
     static JSBool findAllGlobals(JSContext *cx, unsigned argc, Value *vp);
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js
+++ b/toolkit/devtools/debugger/server/dbg-script-actors.js
@@ -2261,20 +2261,18 @@ update(ChromeDebuggerActor.prototype, {
    /**
    * An object that will be used by ThreadActors to tailor their behavior
    * depending on the debugging context being required (chrome or content).
    * The methods that this object provides must be bound to the ThreadActor
    * before use.
    */
   globalManager: {
     findGlobals: function CDA_findGlobals() {
-      // Fetch the list of globals from the debugger.
-      for (let g of this.dbg.findAllGlobals()) {
-        this.addDebuggee(g);
-      }
+      // Add every global known to the debugger as debuggee.
+      this.dbg.addAllGlobalsAsDebuggees();
     },
 
     /**
      * A function that the engine calls when a new global object has been
      * created.
      *
      * @param aGlobal Debugger.Object
      *        The new global object that was created.