Bug 1169179 - Run mozscreenshots as a mochitest-browser-chrome test. r=felipe,glandium draft
authorMatthew Noorenberghe <mozilla@noorenberghe.ca>
Thu, 10 Dec 2015 13:52:39 -0500
changeset 314979 65f34a2b16bf22ce718d4bc0fb5a0971e89b489b
parent 314091 badf9e19d881a54c7aa577414c4b9fb067de96b2
child 511949 2a03c9e09ad83c96b8e2fb7e8951487983e704f4
push id8315
push usermozilla@noorenberghe.ca
push dateFri, 11 Dec 2015 09:17:46 +0000
reviewersfelipe, glandium
bugs1169179
milestone45.0a1
Bug 1169179 - Run mozscreenshots as a mochitest-browser-chrome test. r=felipe,glandium
.eslintignore
browser/moz.build
browser/tools/mozscreenshots/browser.ini
browser/tools/mozscreenshots/browser_screenshots.js
browser/tools/mozscreenshots/head.js
browser/tools/mozscreenshots/moz.build
browser/tools/mozscreenshots/mozscreenshots/extension/Makefile.in
browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/bootstrap.js
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/AppMenu.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Buttons.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/CustomizeMode.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/LightweightThemes.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/TabsInTitlebar.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/configurations/WindowSize.jsm
browser/tools/mozscreenshots/mozscreenshots/extension/install.rdf
browser/tools/mozscreenshots/mozscreenshots/extension/jar.mn
browser/tools/mozscreenshots/mozscreenshots/extension/lib/black_theme.png
browser/tools/mozscreenshots/mozscreenshots/extension/lib/white_theme.png
browser/tools/mozscreenshots/mozscreenshots/extension/moz.build
--- a/.eslintignore
+++ b/.eslintignore
@@ -103,16 +103,18 @@ browser/components/tabview/**
 browser/components/translation/**
 browser/components/uitour/**
 browser/experiments/**
 browser/extensions/pdfjs/**
 browser/extensions/shumway/**
 browser/fuel/**
 browser/locales/**
 browser/modules/**
+browser/tools/mozscreenshots/mozscreenshots/extension/bootstrap.js
+browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
 
 # Loop specific exclusions
 
 # This file currently uses a non-standard (and not on a standards track)
 # if statement within catch.
 browser/extensions/loop/content/modules/MozLoopWorker.js
 # This file currently uses es7 features eslint issue:
 # https://github.com/eslint/espree/issues/125
--- a/browser/moz.build
+++ b/browser/moz.build
@@ -21,10 +21,14 @@ DIRS += [
 
 DIRS += [
     'app',
 ]
 
 if CONFIG['MAKENSISU']:
     DIRS += ['installer/windows']
 
+TEST_DIRS += [
+    'tools/mozscreenshots',
+]
+
 DIST_SUBDIR = 'browser'
 export('DIST_SUBDIR')
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/browser.ini
@@ -0,0 +1,7 @@
+[DEFAULT]
+subsuite = screenshots
+support-files =
+  head.js
+
+[browser_screenshots.js]
+tags = screenshots
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/browser_screenshots.js
@@ -0,0 +1,14 @@
+"use strict";
+
+const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+
+function test() {
+  let { TestRunner } = Cu.import("chrome://mozscreenshots/content/TestRunner.jsm", {});
+  let sets = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "LightweightThemes"];
+  let setsEnv = env.get("MOZSCREENSHOTS_SETS");
+  if (setsEnv) {
+    sets = setsEnv.trim().split(",");
+  }
+
+  TestRunner.start(sets);
+}
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/head.js
@@ -0,0 +1,27 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {AddonWatcher} = Cu.import("resource://gre/modules/AddonWatcher.jsm", {});
+let TestRunner;
+
+function setup() {
+  waitForExplicitFinish();
+  requestLongerTimeout(10);
+
+  info("Checking for mozscreenshots extension");
+  AddonManager.getAddonByID("mozscreenshots@mozilla.org", function(aAddon) {
+    isnot(aAddon, null, "The mozscreenshots extension should be installed");
+    AddonWatcher.ignoreAddonPermanently(aAddon.id);
+  });
+}
+
+Services.obs.addObserver(function observer(subject, topic, data) {
+  Services.obs.removeObserver(observer, topic);
+  ok(true, "Screenshots completed");
+  finish();
+}, "mozscreenshots-finished", false);
+
+setup();
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/moz.build
@@ -0,0 +1,11 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+BROWSER_CHROME_MANIFESTS += ['browser.ini']
+
+TEST_DIRS += [
+    'mozscreenshots/extension',
+]
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/Makefile.in
@@ -0,0 +1,17 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+TEST_EXTENSIONS_DIR = $(DEPTH)/testing/mozscreenshots
+XPI_PKGNAME = mozscreenshots@mozilla.org
+
+include $(topsrcdir)/config/rules.mk
+
+libs-preqs = \
+  $(call mkdir_deps,$(TEST_EXTENSIONS_DIR)) \
+  $(NULL)
+
+libs:: $(libs-preqs)
+	(cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - $(XPI_NAME)) | (cd $(TEST_EXTENSIONS_DIR) && tar -xf -)
+	$(NSINSTALL) -D $(DEPTH)/_tests/testing/mochitest/extensions/mozscreenshots
+	cp -RL $(DEPTH)/testing/mozscreenshots/mozscreenshots $(DEPTH)/_tests/testing/mochitest/extensions
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm
@@ -0,0 +1,187 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "Screenshot" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
+
+Cu.importGlobalProperties(["btoa"]);
+
+// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
+// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
+const PREF_LOG_LEVEL = "extensions.mozscreenshots@mozilla.org.loglevel";
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+  let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+  let consoleOptions = {
+    maxLogLevel: "info",
+    maxLogLevelPref: PREF_LOG_LEVEL,
+    prefix: "mozscreenshots",
+  };
+  return new ConsoleAPI(consoleOptions);
+});
+
+let Screenshot = {
+  _extensionPath: null,
+  _path: null,
+  _imagePrefix: "",
+  _imageExtension: ".png",
+  _screenshotFunction: null,
+
+  init(path, extensionPath, imagePrefix = "") {
+    this._path = path;
+
+    let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+    dir.initWithPath(this._path);
+    if (!dir.exists()) {
+      dir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
+    }
+
+    this._extensionPath = extensionPath;
+    this._imagePrefix = imagePrefix;
+    switch (Services.appinfo.OS) {
+      case "WINNT":
+        this._screenshotFunction = this._screenshotWindows;
+        break;
+      case "Darwin":
+        this._screenshotFunction = this._screenshotOSX;
+        break;
+      case "Linux":
+        this._screenshotFunction = this._screenshotLinux;
+        break;
+      default:
+        throw new Error("Unsupported operating system");
+        break;
+    }
+  },
+
+  _buildImagePath(baseName) {
+    return OS.Path.join(this._path, this._imagePrefix + baseName + this._imageExtension);
+  },
+
+  // Capture the whole screen using an external application.
+  captureExternal(filename) {
+    let imagePath = this._buildImagePath(filename);
+    return this._screenshotFunction(imagePath).then(() => {
+      log.debug("saved screenshot: " + filename);
+    });
+  },
+
+  ///// helpers /////
+
+  _screenshotWindows(filename) {
+    return new Promise((resolve, reject) => {
+      let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile);
+      exe.append("screenshot.exe");
+      if (!exe.exists()) {
+        exe = this._extensionPath.QueryInterface(Ci.nsIFileURL).file;
+        exe.append("lib");
+        exe.append("screenshot.exe");
+      }
+      let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+      process.init(exe);
+
+      let args = [filename];
+      process.runAsync(args, args.length, this._processObserver(resolve, reject));
+    });
+  },
+
+  _screenshotOSX: Task.async(function*(filename) {
+    let screencapture = (windowID = null) => {
+      return new Promise((resolve, reject) => {
+        // Get the screencapture executable
+        let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+        file.initWithPath("/usr/sbin/screencapture");
+
+        let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+        process.init(file);
+
+        // Run the process.
+        let args = ['-x', '-t', 'png'];
+        // Darwin version number for OS X 10.6 is 10.x
+        if (windowID && Services.sysinfo.getProperty("version").indexOf("10.") !== 0) {
+          // Capture only that window on 10.7+
+          args.push('-l');
+          args.push(windowID);
+        }
+        args.push(filename);
+        process.runAsync(args, args.length, this._processObserver(resolve, reject));
+      });
+    };
+
+    function readWindowID() {
+      return new Promise((resolve, reject) => {
+        let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+        file.initWithPath("/tmp/mozscreenshots-windowid");
+
+        NetUtil.asyncFetch(file, (inputStream, status) => {
+          if (!Components.isSuccessCode(status)) {
+            reject("Error reading windowid");
+            return;
+          }
+          resolve(NetUtil.readInputStreamToString(inputStream,
+                                                  inputStream.available()));
+        });
+      });
+    }
+
+    let promiseWindowID = () => {
+      return new Promise((resolve, reject) => {
+        // Get the window ID of the application (assuming its front-most)
+        let osascript = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+        osascript.initWithPath("/bin/bash");
+
+        let osascriptP = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+        osascriptP.init(osascript);
+        let osaArgs = ['-c', "/usr/bin/osascript -e 'tell application (path to frontmost application as text) to set winID to id of window 1' > /tmp/mozscreenshots-windowid"];
+        osascriptP.runAsync(osaArgs, osaArgs.length, this._processObserver(resolve, reject));
+      });
+    };
+
+    yield promiseWindowID();
+    let windowID = yield readWindowID();
+    yield screencapture(windowID);
+  }),
+
+  _screenshotLinux(filename) {
+    return new Promise((resolve, reject) => {
+      let file = Services.dirsvc.get("GreBinD", Ci.nsIFile);
+      file.append("screentopng");
+      let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
+      process.init(file);
+
+      let args = [filename];
+      process.runAsync(args, args.length, this._processObserver(resolve, reject));
+    });
+  },
+
+  _processObserver(resolve, reject) {
+    return {
+      // nsIObserver implementation
+      observe(subject, topic, data) {
+        switch (topic) {
+          case "process-finished":
+            try {
+              // Wait 1s after process to resolve
+              setTimeout(resolve, 1000);
+            } catch (ex) {
+              reject(ex);
+            }
+            break;
+          default:
+            reject(topic);
+            break;
+        };
+      },
+    };
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
@@ -0,0 +1,284 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "TestRunner" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+const defaultSetNames = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "LightweightThemes"];
+const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+
+Cu.import("resource://gre/modules/FileUtils.jsm");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/osfile.jsm");
+Cu.import("chrome://mozscreenshots/content/Screenshot.jsm");
+
+// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
+// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
+const PREF_LOG_LEVEL = "extensions.mozscreenshots@mozilla.org.loglevel";
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+  let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+  let consoleOptions = {
+    maxLogLevel: "info",
+    maxLogLevelPref: PREF_LOG_LEVEL,
+    prefix: "mozscreenshots",
+  };
+  return new ConsoleAPI(consoleOptions);
+});
+
+this.TestRunner = {
+  completedCombos: 0,
+  currentCombo: 0,
+  _comboGen: null,
+  _lastCombo: null,
+
+  init(extensionPath) {
+    let screenshotPath;
+    switch (Services.appinfo.OS) {
+      case "WINNT":
+        screenshotPath = FileUtils.getFile("TmpD", ["mozscreenshots"]).path + "\\";
+        break;
+      case "Darwin":
+      case "Linux":
+        screenshotPath = "/tmp/mozscreenshots/";
+        break;
+      default:
+        throw new Error("Unknown operating system");
+        break;
+    }
+    screenshotPath += (new Date()).toISOString().replace(/:/g, "-") + "_" + Services.appinfo.OS;
+
+    const MOZ_UPLOAD_DIR = env.get("MOZ_UPLOAD_DIR");
+    if (MOZ_UPLOAD_DIR) {
+      screenshotPath = MOZ_UPLOAD_DIR;
+    }
+
+    log.info("Saving screenshots to:", screenshotPath);
+    log.debug("TestRunner.init");
+
+    let screenshotPrefix = Services.appinfo.appBuildID + "_";
+    Screenshot.init(screenshotPath, extensionPath, screenshotPrefix);
+    this._libDir = extensionPath.QueryInterface(Ci.nsIFileURL).file.clone();
+    this._libDir.append("chrome");
+    this._libDir.append("mozscreenshots");
+    this._libDir.append("lib");
+
+    // Setup some prefs
+    Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl", "data:");
+    Services.prefs.setCharPref("extensions.ui.lastCategory", "addons://list/extension");
+    // Don't let the caret blink since it causes false positives for image diffs
+    Services.prefs.setIntPref("ui.caretBlinkTime", -1);
+  },
+
+  start(setNames = null) {
+    setNames = setNames || defaultSetNames;
+    let sets = this.loadSets(setNames);
+
+    log.info(sets.length + " sets:", setNames);
+    this.combos = new LazyProduct(sets);
+    log.info(this.combos.length + " combinations");
+
+    // Create a generator for all combinations.
+    function comboGenerator() {
+      for (let i = 0; i < this.combos.length; i++){
+        yield this.combos.item(i);
+      }
+    };
+
+    this._comboGen = comboGenerator.bind(this)();
+    this.currentCombo = this.completedCombos = 0;
+    this._lastCombo = null;
+    this._performCombo();
+  },
+
+  loadSets(setNames) {
+    let sets = [];
+    for (let setName of setNames) {
+      try {
+        let imported = {};
+        Cu.import("chrome://mozscreenshots/content/configurations/" + setName + ".jsm",
+                  imported);
+        imported[setName].init(this._libDir);
+        let configurationNames = Object.keys(imported[setName].configurations);
+        if (!configurationNames.length) {
+          throw new Error(setName + " has no configurations for this environment");
+        }
+        for (let config of configurationNames) {
+          // Automatically set the name property of the configuration object to
+          // its name from the configuration object.
+          imported[setName].configurations[config].name = config;
+        }
+        sets.push(imported[setName].configurations);
+      } catch (ex) {
+        log.error("Error loading set: " + setName);
+        log.error(ex);
+        throw ex;
+      }
+    }
+    return sets;
+  },
+
+  cleanup() {
+    let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+    let gBrowser = browserWindow.gBrowser;
+    while (gBrowser.tabs.length > 1) {
+      gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
+    }
+    gBrowser.unpinTab(gBrowser.selectedTab);
+    gBrowser.selectedBrowser.loadURI("data:text/html;charset=utf-8,<h1>Done!");
+    browserWindow.restore();
+    Services.obs.notifyObservers(null, "mozscreenshots-finished", null);
+  },
+
+  ///// helpers /////
+
+  _performCombo() {
+    let combo;
+    try {
+      combo = this._comboGen.next();
+    } catch (ex) {
+      if (ex instanceof StopIteration) {
+        log.info("Done: Completed " + this.completedCombos + " out of " +
+                 this.combos.length + " configurations.");
+        this.cleanup();
+        return;
+      }
+      log.error(ex);
+    }
+    let paddedComboIndex = padLeft(++this.currentCombo, String(this.combos.length).length);
+    log.info("Combination " + paddedComboIndex + "/" + this.combos.length + ": " +
+             this._comboName(combo).substring(1));
+
+    function changeConfig(config) {
+      return function (fullfillmentVal) {
+        log.debug("calling " + config.name, "after receiving fullfillmentVal:", fullfillmentVal);
+        let promise = config.applyConfig();
+        log.debug("called " + config.name);
+        return promise;
+      };
+    }
+
+    let resolve = null;
+    let promise = new Promise(r => resolve = r);
+
+    // First go through and actually apply all of the configs
+    combo.forEach(function(config, i) {
+      if (!this._lastCombo || combo[i] !== this._lastCombo[i]) {
+        log.debug("promising", config.name);
+        promise = promise.then(changeConfig(config),
+                               (reason) => {
+                                 log.debug("first rejection handler: ", reason);
+                                 this._configurationRejected.bind(this)(reason);
+                               });
+      }
+    }.bind(this));
+
+    // Update the lastCombo since it's now been applied regardless of whether it's accepted below.
+    promise = promise.then((fullfillment) => {
+                             log.debug("fulfilled all applyConfig so setting lastCombo. Ff: ", fullfillment);
+                             this._lastCombo = combo;
+                             return "set this._lastCombo";
+                           },
+                           (reason) => {
+                             log.debug("second rejection handler: ", reason);
+                             this._configurationRejected.bind(this)(reason);
+                           });
+
+    // Then ask configs if the current setup is valid. We can't can do this in
+    // the applyConfig methods of the config since it doesn't know what configs
+    // later in the loop will do that may invalidate the combo.
+    combo.forEach(function(config, i) {
+      // A configuration can specify an optional verifyConfig method to indicate
+      // if the current config is valid for a screenshot. This gets called even
+      // if the this config was used in the lastCombo since another config may
+      // have invalidated it.
+      if (config.verifyConfig) {
+        log.debug("checking if the combo is valid with", config.name);
+        promise = promise.then((fullfillment) => {
+          log.debug("fulfilled before verifyConfig", fullfillment);
+          return config.verifyConfig();
+        },
+                     (reason) => {
+                       log.debug("third rejection handler: ", reason);
+                       this._configurationRejected.bind(this)(reason);
+                     });
+      }
+    }.bind(this));
+
+    promise = promise.then(this._onConfigurationReady(combo),
+                           (reason) => {
+                             log.debug("fourth rejection handler: ", reason);
+                             this._configurationRejected.bind(this)(reason);
+                           });
+    promise.then(undefined, (reason) => {log.error("Unhandled: " + reason);});
+    resolve("resolving initial promise to start the execution");
+  },
+
+  _onConfigurationReady(combo) {
+    // TODO: this can be simplified more
+    return function configurationReadyInner(fullfillment) {
+      return new Promise((resolve, reject) => {
+        let delayedScreenshot = () => {
+          let filename = padLeft(this.currentCombo,
+                                 String(this.combos.length).length) + this._comboName(combo);
+          Screenshot.captureExternal(filename)
+            .then(() => {
+              this.completedCombos++;
+              this._performCombo();
+              resolve();
+            });
+        };
+
+        log.debug("_onConfigurationReady received fullfillment: ", fullfillment);
+        setTimeout(delayedScreenshot, 0);
+      });
+    }.bind(this);
+  },
+
+  _configurationRejected(reason) {
+    log.warn("\tskipped configuration: " + reason);
+    // Don't set lastCombo here so that we properly know which configurations
+    // need to be applied since the last screenshot
+    this._performCombo();
+  },
+
+  _comboName(combo) {
+    return combo.reduce(function(a, b) {
+      return a + "_" + b.name;
+    }, "");
+  },
+};
+
+
+/**
+ * Helper to lazily compute the Cartesian product of all of the sets of configurations.
+ * Source: http://stackoverflow.com/a/9422496 by Phrogz. CC BY-SA 3.0
+ **/
+function LazyProduct(sets) {
+  // Build the lookup table with an entry for each set with the value being:
+  // [the number of permutations of the sets with lower index, the number of items in the set at the index]
+  for (var dm = [], f = 1, l, i = sets.length; i--; f *= l){
+    dm[i] = [f, l = Object.keys(sets[i]).length];
+  }
+
+  this.length = f;
+  this.item = function(n) {
+    for (var c = [], i = sets.length; i--; ) {
+      // For set i, get the item from the set with the floored value of (n / the number of permutations of the sets already chosen from) modulo the length of set i
+      let keyIndex = ((n / dm[i][0]) << 0) % dm[i][1];
+      let keys = Object.keys(sets[i]);
+      c[i] = sets[i][keys[keyIndex]];
+    }
+    // The result is an array containing one from each set
+    return c;
+  };
+};
+
+function padLeft(number, width, padding = "0") {
+  return padding.repeat(Math.max(0, width - String(number).length)) + number;
+}
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/bootstrap.js
@@ -0,0 +1,94 @@
+#if 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/.
+#endif
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AddonManager.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "TestRunner",
+                                  "chrome://mozscreenshots/content/TestRunner.jsm");
+
+// Path to unpacked extension directory
+let extensionPath = null;
+
+function install(data, reason) {
+  if (!isAppSupported()) {
+    uninstallExtension(data);
+    return;
+  }
+
+  AddonManager.getAddonByID(data.id, function(addon) {
+    // Enable on install in case the user disabled a prior version
+    if (addon) {
+      addon.userDisabled = false;
+    }
+  });
+}
+
+function startup(data, reason) {
+  if (!isAppSupported()) {
+    uninstallExtension(data);
+    return;
+  }
+
+  AddonManager.getAddonByID(data.id, function(addon) {
+    extensionPath = addon.getResourceURI();
+
+    // Start immediately if the add-on was installed at runtime for mochitest-broswer-chrome.
+    if (env.get("MOZ_UPLOAD_DIR")) {
+      startRun();
+    } else {
+      Services.obs.addObserver(observer, "sessionstore-windows-restored", false);
+    }
+  });
+}
+
+function shutdown(data, reason) {
+  if (!env.get("MOZ_UPLOAD_DIR")) {
+    Services.obs.removeObserver(observer, "sessionstore-windows-restored");
+  }
+}
+
+function uninstall(data, reason) { }
+
+/**
+ * @return boolean whether the test suite applies to the application.
+ */
+function isAppSupported() {
+  return true;
+}
+
+function uninstallExtension(data) {
+  AddonManager.getAddonByID(data.id, function(addon) {
+    addon.uninstall();
+  });
+}
+
+let observer = {
+  // nsIObserver implementation
+  observe: function BG_observe(subject, topic, data) {
+    switch (topic) {
+      case "sessionstore-windows-restored":
+        setTimeout(startRun, 500);
+        break;
+    };
+  },
+};
+
+function startRun() {
+  let env = Cc["@mozilla.org/process/environment;1"]
+              .getService(Ci.nsIEnvironment);
+  let setsEnv = env.get("MOZSCREENSHOTS_SETS");
+  let sets = setsEnv ? setsEnv.split(",") : null;
+  TestRunner.init(extensionPath); // TODO
+//  TestRunner.start(sets);
+}
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/AppMenu.jsm
@@ -0,0 +1,88 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "AppMenu" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.AppMenu = {
+
+  init(libDir) {},
+
+  configurations: {
+    appMenuClosed: {
+      applyConfig: deferred => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        browserWindow.PanelUI.hide();
+        deferred.resolve();
+      },
+    },
+
+    appMenuMainView: {
+      applyConfig: deferred => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        let promise = browserWindow.PanelUI.show();
+        browserWindow.PanelUI.showMainView();
+        deferred.resolve(promise);
+      },
+    },
+
+    appMenuHistorySubview: {
+      applyConfig: deferred => {
+        // History has a footer
+        if (rejectIfCustomizing(deferred)) {
+          return;
+        }
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        let promise = browserWindow.PanelUI.show();
+        promise.then(() => {
+          browserWindow.PanelUI.showMainView();
+          browserWindow.document.getElementById("history-panelmenu").click();
+          // TODO: add a hover effect on an item
+          deferred.resolve();
+        });
+      },
+
+      verifyConfig: verifyConfigHelper,
+    },
+
+    appMenuHelpSubview: {
+      applyConfig: deferred => {
+        if (rejectIfCustomizing(deferred)) {
+          return;
+        }
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        let promise = browserWindow.PanelUI.show();
+        promise.then(() => {
+          browserWindow.PanelUI.showMainView();
+          browserWindow.document.getElementById("PanelUI-help").click();
+          // TODO: add a hover effect on an item
+          deferred.resolve();
+        });
+      },
+
+      verifyConfig: verifyConfigHelper,
+    },
+
+  },
+};
+
+function verifyConfigHelper(deferred) {
+  if (!rejectIfCustomizing(deferred)) {
+    deferred.resolve("AppMenu verifyConfigHelper");
+  }
+}
+
+function rejectIfCustomizing(deferred) {
+  let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+  if (browserWindow.document.documentElement.hasAttribute("customizing")) {
+    deferred.reject("Can't show subviews while customizing");
+    return true;
+  }
+  return false;
+}
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Buttons.jsm
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "Buttons" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource:///modules/CustomizableUI.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.Buttons = {
+
+  init(libDir) {
+    createWidget();
+  },
+
+  configurations: {
+    navBarButtons: {
+      applyConfig: deferred => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_NAVBAR);
+        deferred.resolve();
+      },
+    },
+
+    tabsToolbarButtons: {
+      applyConfig: deferred => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_TABSTRIP);
+        deferred.resolve();
+      },
+    },
+
+    menuPanelButtons: {
+      applyConfig: deferred => {
+        CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_PANEL);
+        deferred.resolve();
+      },
+
+      verifyConfig: deferred => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        if (browserWindow.PanelUI.panel.state == "closed") {
+          deferred.reject("The button isn't shown when the panel isn't open.");
+          return;
+        }
+        deferred.resolve("menuPanelButtons.verifyConfig");
+      },
+    },
+
+    custPaletteButtons: {
+      applyConfig: (deferred) => {
+        CustomizableUI.removeWidgetFromArea("screenshot-widget");
+        deferred.resolve();
+      },
+
+      verifyConfig: deferred => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        if (browserWindow.document.documentElement.getAttribute("customizing") != "true") {
+          deferred.reject("The button isn't shown when we're not in customize mode.");
+          return;
+        }
+        deferred.resolve("custPaletteButtons.verifyConfig");
+      },
+    },
+  },
+};
+
+function createWidget() {
+  let id = "screenshot-widget";
+  let spec = {
+    id: id,
+    label: "My Button",
+    removable: true,
+    tooltiptext: "",
+    type: "button",
+  };
+  CustomizableUI.createWidget(spec);
+
+  // Append a <style> for the image
+  let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+  let st = browserWindow.document.createElementNS("http://www.w3.org/1999/xhtml", "style");
+  let styles = "" +
+        "#screenshot-widget > .toolbarbutton-icon {" +
+        "  list-style-image: url(chrome://browser/skin/Toolbar.png);" +
+        "  -moz-image-region: rect(0px, 18px, 18px, 0px);" +
+        "}";
+  st.appendChild(browserWindow.document.createTextNode(styles));
+  browserWindow.document.documentElement.appendChild(st);
+}
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/CustomizeMode.jsm
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "CustomizeMode" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+this.CustomizeMode = {
+
+  init(libDir) {},
+
+  configurations: {
+    notCustomizing: {
+      applyConfig: (deferred) => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        if (!browserWindow.document.documentElement.hasAttribute("customizing")) {
+          deferred.resolve("notCustomizing: already not customizing");
+          return;
+        }
+        function onCustomizationEnds() {
+          browserWindow.gNavToolbox.removeEventListener("aftercustomization", onCustomizationEnds);
+          setTimeout(() => deferred.resolve("notCustomizing: onCustomizationEnds"), 500); // Wait for final changes
+        }
+        browserWindow.gNavToolbox.addEventListener("aftercustomization", onCustomizationEnds);
+        browserWindow.gCustomizeMode.exit();
+      },
+    },
+
+    customizing: {
+      applyConfig: (deferred) => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        if (browserWindow.document.documentElement.hasAttribute("customizing")) {
+          deferred.resolve("customizing: already customizing");
+          return;
+        }
+        function onCustomizing() {
+          browserWindow.gNavToolbox.removeEventListener("customizationready", onCustomizing);
+          setTimeout(() => deferred.resolve("customizing: onCustomizing"), 500); // Wait for final changes
+        }
+        browserWindow.gNavToolbox.addEventListener("customizationready", onCustomizing);
+        browserWindow.gCustomizeMode.enter();
+      },
+    },
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevEdition.jsm
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "DevEdition" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+this.DevEdition = {
+  init(libDir) {},
+
+  configurations: {
+    devEditionLight: {
+      applyConfig: (deferred) => {
+        Services.prefs.setCharPref("devtools.theme", "light");
+        LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-devedition@mozilla.org");
+        Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true);
+        deferred.resolve("devEditionLight");
+      }
+    },
+    devEditionDark: {
+      applyConfig: (deferred) => {
+        Services.prefs.setCharPref("devtools.theme", "dark");
+        LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme("firefox-devedition@mozilla.org");
+        Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true);
+        deferred.resolve("devEditionDark");
+      }
+    },
+    devEditionOff: {
+      applyConfig: (deferred) => {
+        Services.prefs.clearUserPref("devtools.theme");
+        LightweightThemeManager.currentTheme = null;
+        Services.prefs.clearUserPref("browser.devedition.theme.showCustomizeButton");
+        deferred.resolve("devEditionOff");
+      }
+    },
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/DevTools.jsm
@@ -0,0 +1,59 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "DevTools" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://devtools/client/framework/gDevTools.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+let TargetFactory = devtools.TargetFactory;
+
+function getTargetForSelectedTab() {
+  let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+  let target = TargetFactory.forTab(browserWindow.gBrowser.selectedTab);
+  return target;
+}
+
+this.DevTools = {
+  init(libDir) {
+    let panels = ["options", "webconsole", "inspector", "jsdebugger", "netmonitor"];
+    panels.forEach(panel => {
+      this.configurations[panel] = {};
+      this.configurations[panel].applyConfig = (deferred) => {
+        gDevTools.showToolbox(getTargetForSelectedTab(), panel, "bottom").then(() => {
+          deferred.resolve(panel);
+        });
+      };
+    });
+  },
+
+  configurations: {
+    bottomToolbox: {
+      applyConfig: (deferred) => {
+        gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "bottom").then(() => {
+          deferred.resolve("bottomToolbox");
+        });
+      },
+    },
+    sideToolbox: {
+      applyConfig: (deferred) => {
+        gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "side").then(() => {
+          deferred.resolve("sideToolbox");
+        });
+      },
+    },
+    undockedToolbox: {
+      applyConfig: (deferred) => {
+        gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "window").then(() => {
+          deferred.resolve("undockedToolbox");
+        });
+      },
+    }
+  },
+};
+
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/LightweightThemes.jsm
@@ -0,0 +1,92 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "LightweightThemes" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+this.LightweightThemes = {
+  init(libDir) {
+    // convert -size 3000x200 canvas:black black_theme.png
+    let blackImage = libDir.clone();
+    blackImage.append("black_theme.png");
+    this._blackImageURL = Services.io.newFileURI(blackImage).spec;
+
+    // convert -size 3000x200 canvas:white white_theme.png
+    let whiteImage = libDir.clone();
+    whiteImage.append("white_theme.png");
+    this._whiteImageURL = Services.io.newFileURI(whiteImage).spec;
+  },
+
+  configurations: {
+    noLWT: {
+      applyConfig: Task.async(function*() {
+        LightweightThemeManager.currentTheme = null;
+      }),
+    },
+
+    darkLWT: {
+      applyConfig: () => {
+        LightweightThemeManager.setLocalTheme({
+          id:          "black",
+          name:        "black",
+          headerURL:   LightweightThemes._blackImageURL,
+          footerURL:   LightweightThemes._blackImageURL,
+          textcolor:   "#ffffff",
+          accentcolor: "#111111",
+        });
+
+        // Wait for LWT listener
+        return new Promise(resolve => {
+          setTimeout(() => {
+            resolve("darkLWT");
+          }, 500);
+        });
+      },
+
+      verifyConfig: verifyConfigHelper,
+    },
+
+    lightLWT: {
+      applyConfig: () => {
+        LightweightThemeManager.setLocalTheme({
+          id:          "white",
+          name:        "white",
+          headerURL:   LightweightThemes._whiteImageURL,
+          footerURL:   LightweightThemes._whiteImageURL,
+          textcolor:   "#000000",
+          accentcolor: "#eeeeee",
+        });
+        // Wait for LWT listener
+        return new Promise(resolve => {
+          setTimeout(() => {
+            resolve("lightLWT");
+          }, 500);
+        });
+      },
+
+      verifyConfig: verifyConfigHelper,
+    },
+
+  },
+};
+
+
+function verifyConfigHelper() {
+  return new Promise((resolve, reject) => {
+    let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+    if (browserWindow.document.documentElement.hasAttribute("lwtheme")) {
+      resolve("verifyConfigHelper");
+    } else {
+      reject("The @lwtheme attribute wasn't present so themes may not be available");
+    }
+  });
+}
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Preferences.jsm
@@ -0,0 +1,51 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "Preferences" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+this.Preferences = {
+
+  init(libDir) {
+    Services.prefs.setBoolPref("browser.preferences.inContent", true);
+
+    let panes = [
+      ["paneGeneral", null],
+      ["paneSearch", null],
+      ["paneContent", null],
+      ["paneApplications", null],
+      ["panePrivacy", null],
+      ["paneSecurity", null],
+      ["paneSync", null],
+      ["paneAdvanced", "generalTab"],
+      ["paneAdvanced", "dataChoicesTab"],
+      ["paneAdvanced", "networkTab"],
+      ["paneAdvanced", "updateTab"],
+      ["paneAdvanced", "encryptionTab"],
+    ];
+    for (let [primary, advanced] of panes) {
+      let configName = primary + ("-" + advanced || "");
+      this.configurations[configName] = {};
+      this.configurations[configName].applyConfig = prefHelper.bind(null, primary, advanced);
+    }
+  },
+
+  configurations: {},
+};
+
+function prefHelper(primary, advanced, deferred) {
+  let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+  if (primary == "paneAdvanced") {
+    browserWindow.openAdvancedPreferences(advanced);
+  } else {
+    browserWindow.openPreferences(primary);
+  }
+  setTimeout(deferred.resolve, 50);
+}
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Tabs.jsm
@@ -0,0 +1,145 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "Tabs" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+this.Tabs = {
+  init(libDir) {},
+
+  configurations: {
+    fiveTabs: {
+      applyConfig: Task.async(function*() {
+        fiveTabsHelper();
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        hoverTab(browserWindow.gBrowser.tabs[3]);
+      }),
+    },
+
+    fourPinned: {
+      applyConfig: Task.async(function*() {
+        fiveTabsHelper();
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        let tab = browserWindow.gBrowser.addTab(TWITTER_FAVICON);
+        browserWindow.gBrowser.pinTab(tab);
+        tab = browserWindow.gBrowser.addTab(GOOGLE_FAVICON);
+        browserWindow.gBrowser.pinTab(tab);
+        tab = browserWindow.gBrowser.addTab(SHORLANDER_FAVICON);
+        browserWindow.gBrowser.pinTab(tab);
+        tab = browserWindow.gBrowser.addTab("about:home");
+        browserWindow.gBrowser.pinTab(tab);
+        browserWindow.gBrowser.selectTabAtIndex(5);
+        hoverTab(browserWindow.gBrowser.tabs[2]);
+        // also hover the new tab button
+        let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.gBrowser.tabContainer, "class", "tabs-newtab-button");
+        hoverTab(newTabButton);
+        browserWindow.gBrowser.tabs[browserWindow.gBrowser.tabs.length - 1].setAttribute("beforehovered", true);
+      }),
+    },
+
+    twoPinnedWithOverflow: {
+      applyConfig: Task.async(function*() {
+        fiveTabsHelper();
+
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        browserWindow.gBrowser.loadTabs([
+          "about:addons",
+          "about:home",
+          FIREFOX_TAB,
+          "about:newtab",
+          "about:addons",
+          "about:home",
+          FIREFOX_TAB,
+          "about:newtab",
+          "about:addons",
+          "about:home",
+          FIREFOX_TAB,
+          "about:newtab",
+          "about:addons",
+          "about:home",
+          FIREFOX_TAB,
+          "about:newtab",
+          "about:addons",
+          "about:home",
+          FIREFOX_TAB,
+          "about:newtab",
+          "about:addons",
+          "about:home",
+          FIREFOX_TAB,
+          "about:newtab",
+          "about:addons",
+          "about:home",
+          FIREFOX_TAB,
+          "about:newtab",
+        ], true, true);
+        let tab = browserWindow.gBrowser.addTab(TWITTER_FAVICON);
+        browserWindow.gBrowser.pinTab(tab);
+        tab = browserWindow.gBrowser.addTab(GOOGLE_FAVICON);
+        browserWindow.gBrowser.pinTab(tab);
+        browserWindow.gBrowser.selectTabAtIndex(4);
+        hoverTab(browserWindow.gBrowser.tabs[6]);
+      }),
+    },
+  },
+};
+
+
+/* helpers */
+
+function fiveTabsHelper() {
+  // some with no favicon and some with. Selected tab in middle.
+  closeAllButOneTab("about:addons");
+
+  let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+  browserWindow.gBrowser.loadTabs([
+    "about:addons",
+    "about:home",
+    FIREFOX_TAB,
+    "about:newtab",
+    GOOGLE_FAVICON,
+  ], true, true);
+  browserWindow.gBrowser.selectTabAtIndex(1);
+}
+
+function closeAllButOneTab(url = "about:blank") {
+  let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+  let gBrowser = browserWindow.gBrowser;
+  // Close all tabs except the last so we don't quit the browser.
+  while (gBrowser.tabs.length > 1)
+    gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
+  gBrowser.selectedBrowser.loadURI(url);
+  if (gBrowser.selectedTab.pinned)
+    gBrowser.unpinTab(gBrowser.selectedTab);
+  let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.gBrowser.tabContainer, "class", "tabs-newtab-button");
+  hoverTab(newTabButton, false);
+}
+
+function hoverTab(tab, hover = true) {
+  var inIDOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
+  if (hover) {
+    inIDOMUtils.addPseudoClassLock(tab, ":hover");
+  } else {
+    inIDOMUtils.clearPseudoClassLocks(tab);
+  }
+  // XXX TODO: this isn't necessarily testing what we ship
+  if (tab.nextElementSibling)
+    tab.nextElementSibling.setAttribute("afterhovered", hover || null);
+  if (tab.previousElementSibling)
+    tab.previousElementSibling.setAttribute("beforehovered", hover || null);
+}
+
+// Favicons
+const TWITTER_FAVICON = "data:image/x-icon,%00%00%01%00%01%00%10%10%00%00%01%00%20%00h%04%00%00%16%00%00%00(%00%00%00%10%00%00%00%20%00%00%00%01%00%20%00%00%00%00%00%00%04%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%0C%FF%FF%FF%1F%FF%FF%FF%1F%FF%FF%FF%1F%FF%FF%FF%18%FF%FF%FF%07%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%03%FF%FF%FF(%FB%EF%CF%60%F6%D5~%A1%F6%D5~%A1%F6%D5~%A1%F8%DF%9E%89%FC%F4%DEW%FF%FF%FF(%FF%FF%FF%03%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FA%F7%EE%0F%CF%B0%60%9F%B6%88%10%EE%BD%89%00%FF%DB%9F%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%F4%CB_%B6%FD%F9%EF%3F%FF%FF%FF%03%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%0F%F9%ED%CEZ%F3%C5P%C2%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%F1%BC0%DB%FD%F9%EF%3F%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%F3%E4%BEW%ED%B8%2F%DB%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%F1%BC0%DB%FF%FF%FF%18%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%0C%F4%D3~%9F%EE%B0%0F%F3%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%F4%DC%9E%81%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%F8%ED%CFV%EE%B0%0F%F3%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%F1%BC0%DB%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%D6%AC%40%C5%EE%AC%00%FF%EE%AC%00%FF%EA%A9%00%FF%D8%9C%00%FF%D4%99%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%FF%FF%FF%14%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%F3%DB%9E~%EE%AC%00%FF%D8%9C%00%FF%BA%8B%10%EE%CF%B0%60%9F%D9%BCo%94%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%F8%E4%AFx%FF%FF%FF%0C%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%E3%B6%3F%CA%C9%91%00%FF%CF%B0%60%9F%FA%F7%EE%0F%FF%FF%FF%00%F0%E7%CE0%E3%A4%00%FF%EE%AC%00%FF%EE%AC%00%FF%EE%AC%00%FF%DF%A1%00%FF%E8%AC%0F%F3%F4%EA%CFB%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%CC%A9O%B1%E1%CF%9E%60%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%C3%9A%2F%D0%CC%94%00%FF%D0%96%00%FF%C9%91%00%FF%C5%A0%40%BF%BE%92%1F%E0%E3%D0%9Eb%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FA%F7%EE%0F%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FA%F7%EE%0F%DD%C7%8Ep%D8%BF~%81%E1%CF%9E%60%FF%FF%FF%00%FA%F7%EE%0F%FA%F7%EE%0F%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%FF%00%FF%FF%00%00%FF%FF%00%00%FF%FF%00%00%F0%FF%00%00%C0%3F%00%00%F8%1F%00%00%F0%0F%00%00%E0%07%00%00%E0%07%00%00%C0%07%00%00%E0%07%00%00%C7%03%00%00%DF%03%00%00%FF%DF%00%00%FF%FF%00%00%FF%FF%00%00";
+const SHORLANDER_FAVICON = "data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%10%00%00%00%10%08%06%00%00%00%1F%F3%FFa%00%00%00%19tEXtSoftware%00Adobe%20ImageReadyq%C9e%3C%00%00%01%ACIDATx%DA%AC%921o%141%10%85%DF%D8%EB%BD%BB%EC%06mC%83%AE%A1%0B%15P%D3S%F0%07%90(%D2%20%91%1E%C4%3F%A0%0E%12T)%D2%A4%A4A%B4%F4%A1%86%02AGs%1D%5Dt%5Cn%BD%B6%87%19%FB%16iis%23%ED%CA~%EB%99y%F3%AD%89%99q%93%A8%F4%B5%3A%BB%C7%ED%DCda%BDMX%9E%FC%A0_%C7G%DC%B8%A2%FD%19%12%EE%5E%FC%A4%AF%8F%EF%F3%81%B5Y%DB%C4%88%07%9F%BFQ.%A0%C9%5D%23%1F%0C%01u%CC%07%9A%D6%A2%9B%95%C3%E8%8B%D6%CE%1Dn%19%03N%3Cu%90C%93w.4haA%F3R%80v%B2%99%11%8C%14H%7D%9A%16P%DBc%E7%F5%C0%E8%D4%B6%B2%89%E5%A0%AEo%ABm%D5RD%12%07%3AB.%BE%17%88%CF%5E%3D%E1%E6p%86%C5%A1%95%F9%22%DE%BF%FEH%AB%D5%8A%DB%B6-%AE%D6k%2C%97K%FA%20%10%9D%CC%D3%FB%84%AB%3E%E0%C5%97%EF%05%A2%AB%2B%CC%16N%9E%0A1%0C%05%98%24w%5D7%E9%B6%A8%AC%602%A8%12%C1%872%9E%C1%0D%23%3B%18%7C%40%7F%3D%C0T)%8F0%DA%1EC%D7%EA%E6%3AD%04b%F4%D2%7D%BB%03%BC%1F%88%0F%8FO%B8n%0E%E0%84%01s%C4%E5%DBSz%F4%FC%25%5BW%E7Cq%F0%B8%3C%3F%A5ww%9E%B2%81%C5%26%05%5C%C5%1Eo~%7F*%10mU%83%AC%CB%0F%A2%2F%D6%C8%C2%E8%5E%22%85%B8%03f%E1%24%A5%D2%0Bk%E2%F4%26%B2%CC4%08%07%8E!%EF%87m%10%1E%E5%8F%04_4%ED%AC%C9%91%FF%BB%CA1%F8%7F%C2%B8%F6%9B%8D%98%09%13Mm%8F%9D%7D%0A%FB%81%F8W%80%01%00%94%0D%CA2-%BD%DF%EF%00%00%00%00IEND%AEB%60%82";
+const GOOGLE_FAVICON = "data:image/x-icon,%00%00%01%00%02%00%10%10%00%00%01%00%20%00h%04%00%00%26%00%00%00%20%20%00%00%01%00%20%00%A8%10%00%00%8E%04%00%00(%00%00%00%10%00%00%00%20%00%00%00%01%00%20%00%00%00%00%00%00%04%00%00%12%0B%00%00%12%0B%00%00%00%00%00%00%00%00%00%00%F4%85BJ%F4%85B%E7%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%E4%F4%85BJ%F4%85B%E6%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%E7%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F5%8DN%FF%FA%C8%AB%FF%FE%EF%E7%FF%FD%E5%D7%FF%FB%D4%BD%FF%FB%CF%B5%FF%F7%A1n%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FB%D8%C2%FF%FD%EC%E1%FF%F5%94Y%FF%F4%85B%FF%F4%85B%FF%F4%88F%FF%FC%DB%C7%FF%F7%A2n%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FD%EE%E5%FF%F9%BB%96%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F9%BA%94%FF%FB%D3%BA%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F9%BE%9B%FF%FC%DE%CC%FF%F4%88G%FF%F4%85B%FF%F4%85B%FF%F5%92W%FF%FD%EC%E1%FF%FB%CF%B4%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F7%A9z%FF%FA%C8%AA%FF%F9%BC%96%FF%F9%C2%A0%FF%FE%F4%EE%FF%FD%ED%E3%FF%F5%92V%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%87F%FF%FE%F6%F1%FF%FC%E2%D3%FF%F5%8FQ%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F6%9Ei%FF%F9%B9%92%FF%FF%FF%FE%FF%F8%B0%85%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F9%B8%91%FF%FF%FB%F9%FF%F7%A8y%FF%F5%8DO%FF%FB%CD%B2%FF%F6%9Fj%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FE%F5%F0%FF%FB%CE%B3%FF%F4%85B%FF%F4%85B%FF%F7%A4q%FF%FD%EB%E0%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FE%F6%F2%FF%F8%B0%85%FF%F4%85B%FF%F4%85B%FF%F8%B3%89%FF%FF%FB%F8%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FA%C8%A9%FF%F9%BC%97%FF%F4%85B%FF%F4%86D%FF%FD%E4%D5%FF%FB%D6%BF%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%86D%FF%F9%BA%94%FF%F9%BB%96%FF%FC%E1%D0%FF%FF%FE%FD%FF%FA%CB%AF%FF%F7%A7w%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%E6%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%E6%F4%85BI%F4%85B%E6%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%E6%F4%85BI%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00(%00%00%00%20%00%00%00%40%00%00%00%01%00%20%00%00%00%00%00%00%10%00%00%12%0B%00%00%12%0B%00%00%00%00%00%00%00%00%00%00%F4%85B%00%F4%85B'%F4%85B%AD%F4%85B%F2%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%F2%F4%85B%AD%F4%85B'%F4%85B%00%F4%85B(%F4%85B%EF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%EF%F4%85B(%F4%85B%AD%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%AD%F4%85B%F1%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%F3%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F5%8BK%FF%F8%B6%8E%FF%FC%DB%C7%FF%FE%F2%EB%FF%FF%FB%F8%FF%FF%FC%FB%FF%FE%F4%EE%FF%FD%E7%DA%FF%FA%CD%B1%FF%F7%A3p%FF%F4%85C%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F7%A4r%FF%FE%F3%EC%FF%FF%FF%FF%FF%FF%FF%FF%FF%FE%F5%F0%FF%FB%D2%B9%FF%F9%BD%99%FF%F8%B6%8E%FF%F9%BB%95%FF%FB%D2%B9%FF%FE%F8%F4%FF%FC%E3%D3%FF%F6%98%60%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F6%97%5D%FF%FF%FA%F7%FF%FF%FF%FF%FF%FF%FD%FB%FF%F9%BD%99%FF%F4%88F%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F5%8DO%FF%FC%E0%CF%FF%FE%F5%EF%FF%F6%99a%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FB%CF%B4%FF%FF%FF%FF%FF%FF%FF%FF%FF%F8%B4%8B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F5%90R%FF%FF%FC%FA%FF%FC%E3%D4%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FD%E4%D5%FF%FF%FF%FF%FF%FE%F4%EE%FF%F4%85C%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FD%E6%D8%FF%FF%FF%FF%FF%F6%9Ab%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FB%D7%C1%FF%FF%FF%FF%FF%FD%EC%E1%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FE%F0%E7%FF%FF%FF%FF%FF%F8%B2%88%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F7%AB%7D%FF%FF%FF%FF%FF%FF%FD%FC%FF%F5%93X%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F8%B3%8A%FF%FF%FF%FF%FF%FF%FF%FF%FF%F8%B0%85%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FA%CC%B0%FF%FF%FF%FF%FF%FD%E5%D6%FF%F5%92V%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F8%B1%86%FF%FF%FC%FB%FF%FF%FF%FF%FF%FF%FC%FB%FF%F5%91U%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F8%B1%86%FF%FE%F0%E7%FF%FE%F9%F5%FF%FA%CC%B0%FF%F8%AC%7F%FF%F6%99a%FF%F5%90R%FF%F5%8FR%FF%FA%CD%B1%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%F9%BD%99%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%86C%FF%F6%9Ei%FF%F9%BB%96%FF%FB%CD%B2%FF%FC%DA%C6%FF%FD%ED%E3%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FE%FF%F9%C1%9F%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FC%DC%C8%FF%FF%FF%FF%FF%FF%FF%FF%FF%FE%F9%F6%FF%F8%AF%82%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F5%94Y%FF%FF%FF%FF%FF%FF%FF%FF%FF%FE%F4%ED%FF%F6%9Ab%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F5%94Z%FF%FF%FF%FF%FF%FF%FF%FF%FF%FA%C6%A7%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F7%A1m%FF%FB%D1%B8%FF%FD%E9%DD%FF%FD%E8%DB%FF%FF%FE%FD%FF%FF%FF%FF%FF%FD%E5%D7%FF%F4%88F%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F9%C2%A0%FF%FF%FF%FF%FF%FF%FF%FF%FF%FD%EA%DE%FF%F7%A6v%FF%F5%8EP%FF%F6%9Dg%FF%FC%DB%C7%FF%FC%DC%C8%FF%F5%8BL%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F7%A9z%FF%FF%FF%FF%FF%FF%FF%FF%FF%FE%F2%EB%FF%F5%8FQ%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%87F%FF%FD%E9%DD%FF%FD%E4%D5%FF%F4%89I%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FC%DF%CE%FF%FF%FF%FF%FF%FF%FF%FF%FF%F8%B1%87%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FA%C3%A2%FF%FF%FF%FF%FF%F9%C1%9F%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FF%FA%F7%FF%FF%FF%FF%FF%FE%F8%F5%FF%F4%88G%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F9%BE%9A%FF%FF%FF%FF%FF%FD%ED%E3%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FF%FA%F7%FF%FF%FF%FF%FF%FC%DF%CE%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FA%CC%B0%FF%FF%FF%FF%FF%FE%F9%F6%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FD%E4%D5%FF%FF%FF%FF%FF%FB%D4%BC%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%FD%EC%E1%FF%FF%FF%FF%FF%FE%F2%EB%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F8%B6%8E%FF%FF%FF%FF%FF%FC%DF%CE%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F7%A3q%FF%FF%FF%FF%FF%FF%FF%FF%FF%FA%CD%B1%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%87E%FF%FC%E1%D0%FF%FF%FB%F8%FF%F5%92V%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%8AJ%FF%FD%EA%DE%FF%FF%FF%FF%FF%FE%F7%F2%FF%F5%93W%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F5%8CM%FF%FB%D4%BD%FF%FD%EB%E0%FF%F7%A6t%FF%F5%8DO%FF%F7%A2o%FF%FD%E6%D8%FF%FF%FF%FF%FF%FF%FC%FB%FF%F8%B2%88%FF%F5%95%5B%FF%F4%87E%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F6%A0l%FF%FB%CD%B2%FF%FD%E9%DC%FF%FE%F8%F4%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FF%FD%EB%E0%FF%F7%A7w%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%F1%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%F3%F4%85B%AD%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%AD%F4%85B'%F4%85B%EF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%EF%F4%85B'%F4%85B%00%F4%85B%25%F4%85B%AD%F4%85B%F1%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%FF%F4%85B%F1%F4%85B%AD%F4%85B%25%F4%85B%00%80%00%00%01%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%80%00%00%01";
+const FIREFOX_FAVICON = "data:image/x-icon;base64,AAABAAMAEBAAAAEAIABoBAAANgAAACAgAAABACAAqBAAAJ4EAAAwMAAAAQAgAKglAABGFQAAKAAAABAAAAAgAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJAAAAHQAAADMAAABCAAAARQAAADgAAAAjAAAADQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAqBAAieBIUc88eIZ%2F2Hymy%2Fh4tsf4cKp30FiaI2g0RUZYAAAA5AAAACQAAAAAAAAAAAAAAAAAAAAAAAAAOEhJniiIlqvglN8P%2FJUPN%2FyVM0%2F8lT9f%2FJVPZ%2FyVQ0v8fOKz%2BDhtsmwAAABoAAAAAAAAAAAAAAAAAAAAAICaRViEquf4lPsj%2FJUvT%2FyVU2v8lWt3%2FJV%2Ff%2FyVm4v8lbeT%2FJWTg%2Fx5R0%2F4eRcGMAAAAAAAAAAAAAAAAGhprEx8xteolP8r%2FJU3W%2FyVY3f8mYN%2F%2FK1Kv%2FzU5av8zSov%2FJnrj%2FyOJ7P8ldeH%2FIk6y%2FhRMwj8AAAAAAAAAACI3oHclPsj%2FJU3W%2FyVZ3f8lXd3%2FK0Se%2FzUnVP9KIh7%2FTiIV%2F0EhIv8jodX%2FG6zu%2FyGG2f8lUKx8AAAAAAAAAAAgQbDRJUvT%2FyVX3P8lWdv%2FJmfg%2Fyhy3v8meOD%2FJ2O3%2F1FQTf9YKBH%2FOnd%2B%2FxrF9v8QyPX%2FGYLQtAAAAAAAAAAAH03I%2FSVU2v8mX9%2F%2FJ0LJ%2FzhZpf9rQBf%2Fc0wc%2F2VkR%2F91RBP%2FZzIN%2F1k0H%2F9D2Pf%2FJuH8%2Fxqn1fUAAAAAAAAAAB5Y0fwlW97%2FJmbg%2FyZY0%2F82SH7%2Fclct%2F5paC%2F%2BYWQv%2Fi00G%2F4BFB%2F9tNwf%2Fo%2FD6%2F3vu%2Fv89m7P%2BAH9%2FAgAAAAAhYdXlJl%2Fg%2FyZr4f8md%2BT%2FI4%2Fn%2F1BlhP%2BpcCb%2Fs3Ic%2F6poFf%2BZWQ3%2FjE8I%2F520q%2F%2BW7f7%2FI7TW5QAAAAAAAAAAHV7EkSVl4v8mbuL%2FJn7l%2FyKF4P9AcNf%2Fa4CT%2F8OJE%2F%2B8fhX%2FtXQY%2F6NlGf%2Btspr%2FiOz%2F%2FwDI440AAAAAAAAAAB1TskYlWdj%2FJnDj%2FySC5f8gkuD%2Fing3%2F7COG%2F%2FSnQX%2F0ZoJ%2F8WJEP%2BweS%2F%2FxOzw%2F4vj8v8NxudNAAAAAAAAAAAZWdgUIWbc%2FXZ5ff1ygGf%2FTZun%2F3aLUf%2FWphv%2F4a8h%2F9ypDP%2FIkh3%2FxKVo%2F7nf3%2F9lr8q3AAAAAAAAAAAAAAAAAAAAACKC5lK%2Fm1FkxJlC9cGSJf%2FEpTf%2F5rZB%2F%2Bu8SP%2FltDj%2F06lA%2F9fJnu%2BSqad6AAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOTBaR3lwGKY6MBf5OzBYP7uw2D%2B6b9f4eK9Z5HNsE4aAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD%2F%2FwAA%2BA8AAOAHAADgAwAAwAMAAMADAACAAQAAgAEAAIABAACAAQAAgAEAAMADAADAAwAA8A8AAPgfAAD%2F%2FwAAKAAAACAAAABAAAAAAQAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAEAAAABQAAAAcAAAAHAAAABgAAAAQAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAADQAAABkAAAAnAAAANQAAAEEAAABJAAAATgAAAFAAAABLAAAAQwAAADgAAAArAAAAHQAAABAAAAAGAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAFwAAAC4AAABJAAAAZgoFQZcUFXvJGxeW6hwemOkeIaz9HyOq%2BhsekuIWH47aEhh3xA0SWKcAABx2AAAAUAAAADUAAAAcAAAACgAAAAEAAAAAAAAAAAAAAA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AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FgB%2F%2F%2FgAD%2F%2FwAAf%2F4AAH%2F8AAA%2F%2BAAAH%2FAAAA%2FwAAAH4AAAB%2BAAAAfgAAAHwAAAB8AAAAPAAAADwAAAA8AAAAPAAAADwAAAB%2BAAAAfgAAAH8AAAB%2FAAAA%2FwAAAP8AAAH%2F4AAD%2F%2FAAD%2F%2F8AD%2F%2F%2FwD%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FygAAAAwAAAAYAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8AAAAAAQAAAAQAAAAHAAAACAAAAAsAAAAOAAAADQAAAAwAAAAMAAAAEAAAAA8AAAAMAAAACgAAAAcAAAAEAAAAAv%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwAAAAABAAAABAAAAAsAAAASAAAAGQAAAB8AAAAtAAAmQwAAIkwAADRTDglhbhUTf4cRD3SIAAAmWAAADkoAAARDAAAANgAAACoAAAAgAAAAFwAAABEAAAALAAAABQAAAAH%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8AAAAAAgAAAAgAAAATAAAAIAAAACsAAAA5AAAvXBAOd5QbGZnNGxiZ4Bwbm%2BEhIaz1JCaz%2FycpvP8jKLL%2FHyap7CAoqegeJqfjHCSi1xshnMMYHomiDxNtegAALk4AAAAsAAAAHQAAABMAAAAJAAAAAv%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAAAAAAEA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FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F9WqBvbVhjf00H149Mx4s%2FLLc9nwyHHt8slv%2BfHJbf%2FxyG3%2F8shv9%2FLKcOryy3LW9c53qvPOeW700oIt%2F%2F%2F%2FAv%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2FMgArv1oQf89GFLOvOezTw0n0z89CCK%2FbRiRz%2FtpIH%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F8A%2F%2F%2F%2FAP%2F%2F%2FwD%2F%2F%2F%2F%2F%2F%2F8AAP%2F%2F%2F%2F%2F%2F%2FwAA%2F%2F%2F%2Bf%2F%2F%2FAAD%2F%2F4AB%2F%2F8AAP%2F%2BAAA%2F%2FwAA%2F%2FgAAA%2F%2FAAD%2F4AAAB%2F8AAP%2FAAAAD%2FwAA%2F4AAAAH%2FAAD%2FAAAAAP8AAP4AAAAAfwAA%2FgAAAAA%2FAAD8AAAAAB8AAPgAAAAADwAA%2BAAAAAAPAADwAAAAAA8AAPAAAAAADwAA8AAAAAAPAADgAAAAAA8AAOAAAAAABwAA4AAAAAAHAADAAAAAAAMAAMAAAAAAAwAAwAAAAAADAADAAAAAAAMAAMAAAAAAAwAAwAAAAAADAADAAAAAAAMAAMAAAAAAAwAA4AAAAAAHAADgAAAAAAcAAOAAAAAABwAA8AAAAAAHAADwAAAAAA8AAPgAAAAADwAA%2BAAAAAAPAAD4AAAAAB8AAPgAAAAAHwAA%2BAAAAAA%2FAAD4AAAAAH8AAP3AAAAB%2FwAA%2F%2BAAAAf%2FAAD%2F8AAAD%2F8AAP%2F8AAA%2F%2FwAA%2F%2F8AAP%2F%2FAAD%2F%2F%2BAH%2F%2F8AAP%2F%2F%2F%2F%2F%2F%2FwAA%2F%2F%2F%2F%2F%2F%2F%2FAAA%3D";
+
+// Tabs
+const FIREFOX_TAB = "data:text/html,<meta charset='utf-8'><title>Welcome to the new Firefox</title><link rel='icon' href='" + FIREFOX_FAVICON + "'/>";
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/TabsInTitlebar.jsm
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "TabsInTitlebar" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+const PREF_TABS_IN_TITLEBAR = "browser.tabs.drawInTitlebar";
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+this.TabsInTitlebar = {
+
+  init(libDir) {},
+
+  configurations: {
+    tabsInTitlebar: {
+      applyConfig: Task.async(function*() {
+        if (Services.appinfo.OS == "Linux") {
+          return Promise.reject("TabsInTitlebar isn't supported on Linux");
+        }
+        Services.prefs.setBoolPref(PREF_TABS_IN_TITLEBAR, true);
+      }),
+    },
+
+    tabsOutsideTitlebar: {
+      applyConfig: Task.async(function*() {
+        Services.prefs.setBoolPref(PREF_TABS_IN_TITLEBAR, false);
+      }),
+    },
+
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm
@@ -0,0 +1,56 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "Toolbars" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+this.Toolbars = {
+  init(libDir) {},
+
+  configurations: {
+    onlyNavBar: {
+      applyConfig: Task.async(function*() {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        var personalToolbar = browserWindow.document.getElementById("PersonalToolbar");
+        browserWindow.setToolbarVisibility(personalToolbar, false);
+        toggleMenubarIfNecessary(false);
+      }),
+    },
+
+    allToolbars: {
+      applyConfig: Task.async(function*() { // Boookmarks and menubar
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        var personalToolbar = browserWindow.document.getElementById("PersonalToolbar");
+        browserWindow.setToolbarVisibility(personalToolbar, true);
+        toggleMenubarIfNecessary(true);
+      }),
+
+      verifyConfig: Task.async(function*() {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        if (browserWindow.fullScreen) {
+          return Promise.reject("The bookmark toolbar and menubar are not shown in fullscreen.");
+        }
+      }),
+    },
+
+  },
+};
+
+
+///// helpers /////
+
+function toggleMenubarIfNecessary(visible) {
+  let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+  // The menubar is not shown on OS X or while in fullScreen
+  if (Services.appinfo.OS != "Darwin" /*&& !browserWindow.fullScreen*/) {
+    var menubar = browserWindow.document.getElementById("toolbar-menubar");
+    browserWindow.setToolbarVisibility(menubar, visible);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/WindowSize.jsm
@@ -0,0 +1,60 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = [ "WindowSize" ];
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import("resource://gre/modules/Timer.jsm");
+
+this.WindowSize = {
+
+  init(libDir) {
+    Services.prefs.setBoolPref("browser.fullscreen.autohide", false);
+  },
+
+  configurations: {
+    maximized: {
+      applyConfig: Task.async(function*() {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        browserWindow.fullScreen = false;
+
+        // Wait for the Lion fullscreen transition to end as there doesn't seem to be an event
+        // and trying to maximize while still leaving fullscreen doesn't work.
+        yield new Promise((resolve, reject) => {
+          setTimeout(function waitToLeaveFS() {
+            browserWindow.maximize();
+            resolve();
+          }, Services.appinfo.OS == "Darwin" ? 1500 : 0);
+        });
+      }),
+    },
+
+    normal: {
+      applyConfig: Task.async(() => {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        browserWindow.fullScreen = false;
+        browserWindow.restore();
+      }),
+    },
+
+    fullScreen: {
+      applyConfig: Task.async(function*() {
+        let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
+        browserWindow.fullScreen = true;
+        // OS X Lion fullscreen transition takes a while
+        yield new Promise((resolve, reject) => {
+          setTimeout(function waitAfterEnteringFS() {
+            resolve();
+          }, Services.appinfo.OS == "Darwin" ? 1500 : 0);
+        });
+      }),
+    },
+
+  },
+};
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/install.rdf
@@ -0,0 +1,33 @@
+<?xml version="1.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/. -->
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>mozscreenshots@mozilla.org</em:id>
+#expand <em:version>__MOZILLA_VERSION_U__</em:version>
+    <em:bootstrap>true</em:bootstrap>
+
+    <!-- for running custom screenshot binaries -->
+    <em:unpack>true</em:unpack>
+
+    <!-- Front End MetaData -->
+    <em:name>mozscreenshots</em:name>
+    <em:description>Take screenshots of Mozilla applications in various UI configurations.</em:description>
+    <em:creator>Mozilla</em:creator>
+
+    <em:targetApplication>
+      <Description>
+        <!-- Firefox -->
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+#expand <em:minVersion>__MOZILLA_VERSION_U__</em:minVersion>
+        <em:maxVersion>*</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/jar.mn
@@ -0,0 +1,6 @@
+mozscreenshots.jar:
+% content mozscreenshots chrome/mozscreenshots/
+  Screenshot.jsm
+  TestRunner.jsm
+  configurations/ (configurations/*.jsm)
+  lib/            (lib/*.png)
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..810420d967a6aa6211494f67cab112b161e300d2
GIT binary patch
literal 343
zc%17D@N?(olHy`uVBq!ia0y~y;NAgbpI`(M3<2H~-vcR@bVpxD28NCO+<y{TfqaEz
zk04(LhAK4%hK3dfhF?ITh8GMBr3MTPuM!v-tY$DUh!@P+6=(yLU@!6Xb!ETLDlV!d
z(km{03Mj;s<n8Xlz<9SycnOdf@9E+gA|d(qpdrZ0Lkho_$MMJ~Fi;5`@Krs}!07F#
zGa1NHEpd$~Nl7e8wMs5Z1yT$~28O1(2Bx}3#vw+AR>me)Mh3bD=2iv<;aAwWP&DM`
Zr(~v8;?|(nxo;cDK2KLamvv4FO#t)_Lrnkx
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ee0ef460df4c9b82a548628d756ac93ba4e3f5f0
GIT binary patch
literal 522
zc%17D@N?(olHy`uVBq!ia0y~y;NAgbpI`(M3<2H~-vcR@bVpxD28NCO+<y{TfqaEz
zk04(LhAK4%hK3dfhF?ITh8GMBr3MTPuM!v-tY$DUh!@P+6=(yLU@!6Xb!ETLDlV$b
zmcBLoFi?mo$=lt9f$?sa@Dc_FMj=lZ$B>F!Z!Z`Et>ihp;FtN_lQ)=!B5GzZy}$SI
zoh+QVYkhC;V>nTLe0TXCB;tEt`TGhufk)%xyF_aQ68JQ(J3uXyP&9_H$JRU%TU(m>
z78q8lC9V-ADTyViR>?)FK#IZ0z|d6Jz*N`BIK;@%%GlJ(z)aV`+{(aU=HvKc6b-rg
aDVb@NxHY`k_xwC4l09AhT-G@yGywq3srZrr
new file mode 100644
--- /dev/null
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/moz.build
@@ -0,0 +1,17 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+XPI_NAME = 'mozscreenshots'
+
+JAR_MANIFESTS += ['jar.mn']
+
+USE_EXTENSION_MANIFEST = True
+NO_JS_MANIFEST = True
+
+FINAL_TARGET_PP_FILES += [
+    'bootstrap.js',
+    'install.rdf',
+]