Merge latest green inbound changeset and mozilla-central
authorEd Morley <emorley@mozilla.com>
Wed, 21 Aug 2013 12:59:33 +0100
changeset 156568 ba6c02fc1fe65230f289ca9eeed9c42af3edde6a
parent 156567 8ab3659863d7d2d97f4e4a5a40a028938be53327 (current diff)
parent 156501 e78c725d45bd197d87c8732f8877925f2967a5d4 (diff)
child 156575 d4754ae964dc8906971d73eec888fd90a18577bd
child 156595 3d355303f4da4e5682d1c0df2bc04d154c4a0f4f
child 156610 ab6bc4d9e4c0fe907bcef53ff725fc83c62a1800
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone26.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge latest green inbound changeset and mozilla-central
CLOBBER
addon-sdk/source/python-lib/cuddlefish/tests/preferences-files/packages/curly-id/lib/main.js
addon-sdk/source/python-lib/cuddlefish/tests/preferences-files/packages/curly-id/package.json
addon-sdk/source/python-lib/cuddlefish/tests/preferences-files/packages/preferences-branch/lib/main.js
addon-sdk/source/python-lib/cuddlefish/tests/preferences-files/packages/preferences-branch/package.json
addon-sdk/source/test/addons/curly-id/lib/main.js
addon-sdk/source/test/addons/curly-id/package.json
addon-sdk/source/test/addons/predefined-id-with-at/lib/main.js
addon-sdk/source/test/addons/predefined-id-with-at/package.json
addon-sdk/source/test/addons/preferences-branch/lib/main.js
addon-sdk/source/test/addons/preferences-branch/package.json
addon-sdk/source/test/addons/standard-id/lib/main.js
addon-sdk/source/test/addons/standard-id/package.json
mobile/android/base/AwesomeBar.java
mobile/android/base/AwesomeBarTabs.java
mobile/android/base/AwesomebarResultHandler.java
mobile/android/base/SearchEngine.java
mobile/android/base/SearchEngineRow.java
mobile/android/base/SuggestClient.java
mobile/android/base/awesomebar/AllPagesTab.java
mobile/android/base/awesomebar/AwesomeBarTab.java
mobile/android/base/awesomebar/BookmarksTab.java
mobile/android/base/awesomebar/HistoryTab.java
mobile/android/base/resources/anim/awesomebar_fade_in.xml
mobile/android/base/resources/anim/awesomebar_fade_out.xml
mobile/android/base/resources/anim/awesomebar_hold_still.xml
mobile/android/base/resources/color/abouthome_section_more_text.xml
mobile/android/base/resources/color/abouthome_section_subtitle.xml
mobile/android/base/resources/color/abouthome_section_title.xml
mobile/android/base/resources/color/awesome_bar_title.xml
mobile/android/base/resources/color/awesome_bar_title_hint.xml
mobile/android/base/resources/drawable-hdpi/abouthome_icon.png
mobile/android/base/resources/drawable-hdpi/abouthome_logo_dark.png
mobile/android/base/resources/drawable-hdpi/abouthome_logo_light.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_logo_apps.png
mobile/android/base/resources/drawable-hdpi/abouthome_promo_logo_sync.png
mobile/android/base/resources/drawable-hdpi/abouthome_thumbnail_add.png
mobile/android/base/resources/drawable-hdpi/abouthome_thumbnail_bg.png
mobile/android/base/resources/drawable-hdpi/address_bar_bg_shadow.png
mobile/android/base/resources/drawable-hdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-hdpi/address_bar_url_default_pb.9.png
mobile/android/base/resources/drawable-hdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-hdpi/address_bar_url_pressed_pb.9.png
mobile/android/base/resources/drawable-hdpi/ic_addons_empty.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_reader.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_star.png
mobile/android/base/resources/drawable-hdpi/ic_awesomebar_tab.png
mobile/android/base/resources/drawable-mdpi/abouthome_icon.png
mobile/android/base/resources/drawable-mdpi/abouthome_logo_dark.png
mobile/android/base/resources/drawable-mdpi/abouthome_logo_light.png
mobile/android/base/resources/drawable-mdpi/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable-mdpi/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable-mdpi/abouthome_promo_logo_apps.png
mobile/android/base/resources/drawable-mdpi/abouthome_promo_logo_sync.png
mobile/android/base/resources/drawable-mdpi/abouthome_thumbnail_add.png
mobile/android/base/resources/drawable-mdpi/abouthome_thumbnail_bg.png
mobile/android/base/resources/drawable-mdpi/address_bar_bg_shadow.png
mobile/android/base/resources/drawable-mdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-mdpi/address_bar_url_default_pb.9.png
mobile/android/base/resources/drawable-mdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-mdpi/address_bar_url_pressed_pb.9.png
mobile/android/base/resources/drawable-mdpi/ic_addons_empty.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_reader.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_star.png
mobile/android/base/resources/drawable-mdpi/ic_awesomebar_tab.png
mobile/android/base/resources/drawable-xhdpi/abouthome_icon.png
mobile/android/base/resources/drawable-xhdpi/abouthome_logo_dark.png
mobile/android/base/resources/drawable-xhdpi/abouthome_logo_light.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_box_bg.9.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_box_pressed_bg.9.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_logo_apps.png
mobile/android/base/resources/drawable-xhdpi/abouthome_promo_logo_sync.png
mobile/android/base/resources/drawable-xhdpi/abouthome_thumbnail_add.png
mobile/android/base/resources/drawable-xhdpi/abouthome_thumbnail_bg.png
mobile/android/base/resources/drawable-xhdpi/address_bar_bg_shadow.png
mobile/android/base/resources/drawable-xhdpi/address_bar_url_default.9.png
mobile/android/base/resources/drawable-xhdpi/address_bar_url_default_pb.9.png
mobile/android/base/resources/drawable-xhdpi/address_bar_url_pressed.9.png
mobile/android/base/resources/drawable-xhdpi/address_bar_url_pressed_pb.9.png
mobile/android/base/resources/drawable-xhdpi/ic_addons_empty.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_go.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_reader.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_search.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_star.png
mobile/android/base/resources/drawable-xhdpi/ic_awesomebar_tab.png
mobile/android/base/resources/drawable/abouthome_logo.xml
mobile/android/base/resources/drawable/abouthome_promo_box.xml
mobile/android/base/resources/drawable/address_bar_bg.xml
mobile/android/base/resources/drawable/address_bar_bg_shadow_repeat.xml
mobile/android/base/resources/drawable/address_bar_nav_button.xml
mobile/android/base/resources/drawable/address_bar_right_edge.xml
mobile/android/base/resources/drawable/address_bar_url.xml
mobile/android/base/resources/drawable/awesomebar_header_row.xml
mobile/android/base/resources/drawable/awesomebar_listview_divider.xml
mobile/android/base/resources/drawable/awesomebar_tab_indicator.xml
mobile/android/base/resources/drawable/awesomebar_tab_selected.xml
mobile/android/base/resources/drawable/awesomebar_tab_unselected.xml
mobile/android/base/resources/layout-large-v11/awesomebar_search.xml
mobile/android/base/resources/layout-xlarge-land-v11/abouthome_content.xml
mobile/android/base/resources/layout-xlarge-v11/awesomebar_search.xml
mobile/android/base/resources/layout/abouthome_addon_row.xml
mobile/android/base/resources/layout/abouthome_content.xml
mobile/android/base/resources/layout/abouthome_last_tabs_row.xml
mobile/android/base/resources/layout/abouthome_remote_tab_row.xml
mobile/android/base/resources/layout/abouthome_section.xml
mobile/android/base/resources/layout/abouthome_topsite_item.xml
mobile/android/base/resources/layout/awesomebar.xml
mobile/android/base/resources/layout/awesomebar_allpages_list.xml
mobile/android/base/resources/layout/awesomebar_folder_row.xml
mobile/android/base/resources/layout/awesomebar_header_row.xml
mobile/android/base/resources/layout/awesomebar_row.xml
mobile/android/base/resources/layout/awesomebar_search.xml
mobile/android/base/resources/layout/awesomebar_suggestion_prompt.xml
mobile/android/base/resources/layout/awesomebar_tab_indicator.xml
mobile/android/base/resources/layout/awesomebar_tabs.xml
mobile/android/base/resources/menu/abouthome_topsites_contextmenu.xml
mobile/android/base/resources/menu/awesomebar_contextmenu.xml
mobile/android/base/tests/testAllPagesTab.java.in
mobile/android/base/tests/testBookmarksTab.java.in
mobile/android/base/tests/testHistoryTab.java.in
mobile/android/base/tests/testInputAwesomeBar.java.in
mobile/android/base/widget/AboutHome.java
mobile/android/base/widget/AboutHomeSection.java
mobile/android/base/widget/AboutHomeView.java
mobile/android/base/widget/AddonsSection.java
mobile/android/base/widget/LastTabsSection.java
mobile/android/base/widget/LinkTextView.java
mobile/android/base/widget/PromoBox.java
mobile/android/base/widget/RemoteTabsSection.java
mobile/android/base/widget/TopSitesView.java
--- a/addon-sdk/source/app-extension/bootstrap.js
+++ b/addon-sdk/source/app-extension/bootstrap.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
 /* 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/. */
 
 // @see http://mxr.mozilla.org/mozilla-central/source/js/src/xpconnect/loader/mozJSComponentLoader.cpp
 
 'use strict';
 
@@ -217,18 +216,16 @@ function startup(data, reasonCode) {
       prefixURI: prefixURI,
       // Add-on URI.
       rootURI: rootURI,
       // options used by system module.
       // File to write 'OK' or 'FAIL' (exit code emulation).
       resultFile: options.resultFile,
       // Arguments passed as --static-args
       staticArgs: options.staticArgs,
-      // Add-on preferences branch name
-      preferencesBranch: options.preferencesBranch,
 
       // Arguments related to test runner.
       modules: {
         '@test/options': {
           allTestModules: options.allTestModules,
           iterations: options.iterations,
           filter: options.filter,
           profileMemory: options.profileMemory,
--- a/addon-sdk/source/lib/method/core.js
+++ b/addon-sdk/source/lib/method/core.js
@@ -94,17 +94,17 @@ function Method(hint) {
                  ((type = builtin[(value.constructor || "").name]) &&
                   type[name]) ||
                  // Otherwise assume it's a host object. For host objects
                  // actual method implementations are stored in the `host`
                  // array and only index for the implementation is stored
                  // in the host object's prototype chain. This avoids memory
                  // leaks that otherwise could happen when saving JS objects
                  // on host object.
-                 host[value["!" + name]] ||
+                 host[value["!" + name] || void(0)] ||
                  // Otherwise attempt to lookup implementation for builtins by
                  // a type of the value. This basically makes sure that all
                  // non primitive values will delegate to an `Object`.
                  ((type = builtin[types[typeof(value)]]) && type[name])
 
 
     // If method implementation for the type is still not found then
     // just fallback for default implementation.
--- a/addon-sdk/source/lib/sdk/addon/installer.js
+++ b/addon-sdk/source/lib/sdk/addon/installer.js
@@ -1,18 +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/. */
 
 module.metadata = {
-  "stability": "experimental",
-  "engines": {
-    // TODO Fennec Support in bug 894515
-    "Firefox": "*"
-  }
+  "stability": "experimental"
 };
 
 const { Cc, Ci, Cu } = require("chrome");
 const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm");
 const { defer } = require("../core/promise");
 const { setTimeout } = require("../timers");
 
 /**
--- a/addon-sdk/source/lib/sdk/addon/runner.js
+++ b/addon-sdk/source/lib/sdk/addon/runner.js
@@ -1,25 +1,24 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
 /* 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/.
- */
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 module.metadata = {
   "stability": "experimental"
 };
 
 const { Cc, Ci } = require('chrome');
 const { descriptor, Sandbox, evaluate, main, resolveURI } = require('toolkit/loader');
 const { once } = require('../system/events');
 const { exit, env, staticArgs } = require('../system');
 const { when: unload } = require('../system/unload');
 const { loadReason } = require('../self');
 const { rootURI } = require("@loader/options");
+const cfxArgs = require("@test/options");
 const globals = require('../system/globals');
 const xulApp = require('../system/xul-app');
 const appShellService = Cc['@mozilla.org/appshell/appShellService;1'].
                         getService(Ci.nsIAppShellService);
 
 const NAME2TOPIC = {
   'Firefox': 'sessionstore-windows-restored',
   'Fennec': 'sessionstore-windows-restored',
@@ -98,25 +97,33 @@ function startup(reason, options) {
 
   // NOTE: Module is intentionally required only now because it relies
   // on existence of hidden window, which does not exists until startup.
   let { ready } = require('../addon/window');
   // Load localization manifest and .properties files.
   // Run the addon even in case of error (best effort approach)
   require('../l10n/loader').
     load(rootURI).
-    then(null, function failure(error) {
+    then(function l10nSuccess() {
+      if (cfxArgs.parseable) {
+        console.info("localization information has loaded successfully.");
+      }
+    }, function l10nFailure(error) {
       console.info("Error while loading localization: " + error.message);
     }).
     then(function onLocalizationReady(data) {
       // Exports data to a pseudo module so that api-utils/l10n/core
       // can get access to it
       definePseudo(options.loader, '@l10n/data', data ? data : null);
       return ready;
     }).then(function() {
+      if (cfxArgs.parseable) {
+        console.info("addon window has loaded successfully.");
+      }
+
       run(options);
     }).then(null, console.exception);
 }
 
 function run(options) {
   try {
     // Try initializing HTML localization before running main module. Just print
     // an exception in case of error, instead of preventing addon to be run.
@@ -125,16 +132,17 @@ function run(options) {
       // disable. Because unit tests are evaluated in a another Loader who
       // doesn't have access to this current loader.
       if (options.main !== 'test-harness/run-tests')
         require('../l10n/html').enable();
     }
     catch(error) {
       console.exception(error);
     }
+
     // Initialize inline options localization, without preventing addon to be
     // run in case of error
     try {
       require('../l10n/prefs');
     }
     catch(error) {
       console.exception(error);
     }
@@ -154,17 +162,18 @@ function run(options) {
       program.main({
         loadReason: loadReason,
         staticArgs: staticArgs
       }, {
         print: function print(_) { dump(_ + '\n') },
         quit: exit
       });
     }
-  } catch (error) {
+  }
+  catch (error) {
     console.exception(error);
     throw error;
   }
 }
 exports.startup = startup;
 
 // If add-on is lunched via `cfx run` we need to use `system.exit` to let
 // cfx know we're done (`cfx test` will take care of exit so we don't do
--- a/addon-sdk/source/lib/sdk/addon/window.js
+++ b/addon-sdk/source/lib/sdk/addon/window.js
@@ -1,13 +1,11 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
 
 const { Ci, Cc } = require("chrome");
 const { make: makeWindow, getHiddenWindow } = require("../window/utils");
--- a/addon-sdk/source/lib/sdk/clipboard.js
+++ b/addon-sdk/source/lib/sdk/clipboard.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "stable",
--- a/addon-sdk/source/lib/sdk/console/plain-text.js
+++ b/addon-sdk/source/lib/sdk/console/plain-text.js
@@ -15,17 +15,17 @@ const { merge } = require("../util/objec
 const { ConsoleAPI } = Cu.import("resource://gre/modules/devtools/Console.jsm");
 
 const DEFAULT_LOG_LEVEL = "error";
 const ADDON_LOG_LEVEL_PREF = "extensions." + self.id + ".sdk.console.logLevel";
 const SDK_LOG_LEVEL_PREF = "extensions.sdk.console.logLevel";
 
 let logLevel = DEFAULT_LOG_LEVEL;
 function setLogLevel() {
-  logLevel = prefs.get(ADDON_LOG_LEVEL_PREF, 
+  logLevel = prefs.get(ADDON_LOG_LEVEL_PREF,
                            prefs.get(SDK_LOG_LEVEL_PREF,
                                      DEFAULT_LOG_LEVEL));
 }
 setLogLevel();
 
 let logLevelObserver = {
   QueryInterface: function(iid) {
     if (!iid.equals(Ci.nsIObserver) &&
--- a/addon-sdk/source/lib/sdk/content/content.js
+++ b/addon-sdk/source/lib/sdk/content/content.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/sdk/content/loader.js
+++ b/addon-sdk/source/lib/sdk/content/loader.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/content/mod.js
+++ b/addon-sdk/source/lib/sdk/content/mod.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
--- a/addon-sdk/source/lib/sdk/content/symbiont.js
+++ b/addon-sdk/source/lib/sdk/content/symbiont.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/sdk/content/utils.js
+++ b/addon-sdk/source/lib/sdk/content/utils.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/sdk/content/worker.js
+++ b/addon-sdk/source/lib/sdk/content/worker.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/sdk/core/heritage.js
+++ b/addon-sdk/source/lib/sdk/core/heritage.js
@@ -1,14 +1,11 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   "stability": "unstable"
 };
 
 var getPrototypeOf = Object.getPrototypeOf;
 var getNames = Object.getOwnPropertyNames;
--- a/addon-sdk/source/lib/sdk/core/promise.js
+++ b/addon-sdk/source/lib/sdk/core/promise.js
@@ -1,12 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
-/*jshint undef: true es5: true node: true browser: true devel: true
-         forin: true latedef: false */
-/*global define: true, Cu: true, __URI__: true */
 ;(function(id, factory) { // Module boilerplate :(
   if (typeof(define) === 'function') { // RequireJS
     define(factory);
   } else if (typeof(require) === 'function') { // CommonJS
     factory.call(this, require, exports, module);
   } else if (String(this).indexOf('BackstagePass') >= 0) { // JSM
     this[factory.name] = {};
     try {
--- a/addon-sdk/source/lib/sdk/deprecated/api-utils.js
+++ b/addon-sdk/source/lib/sdk/deprecated/api-utils.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 module.metadata = {
   "stability": "deprecated"
 };
--- a/addon-sdk/source/lib/sdk/deprecated/cortex.js
+++ b/addon-sdk/source/lib/sdk/deprecated/cortex.js
@@ -1,10 +1,9 @@
-/* vim:set ts=2 sw=2 sts=2
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "deprecated"
 };
--- a/addon-sdk/source/lib/sdk/deprecated/events/assembler.js
+++ b/addon-sdk/source/lib/sdk/deprecated/events/assembler.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { Trait } = require("../light-traits");
 const { removeListener, on } = require("../../dom/events");
--- a/addon-sdk/source/lib/sdk/deprecated/light-traits.js
+++ b/addon-sdk/source/lib/sdk/deprecated/light-traits.js
@@ -1,10 +1,9 @@
-/* vim:ts=2:sts=2:sw=2:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "deprecated"
 };
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js
@@ -1,10 +1,9 @@
-/* vim:st=2:sts=2:sw=2:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "deprecated"
 };
--- a/addon-sdk/source/lib/sdk/dom/events.js
+++ b/addon-sdk/source/lib/sdk/dom/events.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/dom/events/keys.js
+++ b/addon-sdk/source/lib/sdk/dom/events/keys.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/event/core.js
+++ b/addon-sdk/source/lib/sdk/event/core.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/event/target.js
+++ b/addon-sdk/source/lib/sdk/event/target.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 'use strict';
 
 module.metadata = {
   "stability": "stable"
--- a/addon-sdk/source/lib/sdk/frame/hidden-frame.js
+++ b/addon-sdk/source/lib/sdk/frame/hidden-frame.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
--- a/addon-sdk/source/lib/sdk/hotkeys.js
+++ b/addon-sdk/source/lib/sdk/hotkeys.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "stable"
--- a/addon-sdk/source/lib/sdk/io/buffer.js
+++ b/addon-sdk/source/lib/sdk/io/buffer.js
@@ -1,12 +1,11 @@
 /* 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/.
- */
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
 
 
 const { Cu } = require("chrome");
--- a/addon-sdk/source/lib/sdk/io/byte-streams.js
+++ b/addon-sdk/source/lib/sdk/io/byte-streams.js
@@ -1,11 +1,9 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et filetype=javascript
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "experimental"
 };
--- a/addon-sdk/source/lib/sdk/io/fs.js
+++ b/addon-sdk/source/lib/sdk/io/fs.js
@@ -1,12 +1,11 @@
 /* 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/.
- */
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
 
 const { Cc, Ci, CC } = require("chrome");
 
@@ -922,9 +921,9 @@ exports.watchFile = watchFile;
 function unwatchFile(path, listener) {
   throw Error("Not implemented");
 }
 exports.unwatchFile = unwatchFile;
 
 function watch(path, options, listener) {
   throw Error("Not implemented");
 }
-exports.watch = watch;
\ No newline at end of file
+exports.watch = watch;
--- a/addon-sdk/source/lib/sdk/io/stream.js
+++ b/addon-sdk/source/lib/sdk/io/stream.js
@@ -1,12 +1,11 @@
 /* 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/.
- */
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
 
 const { CC, Cc, Ci, Cu, Cr, components } = require("chrome");
 const { EventTarget } = require("../event/target");
--- a/addon-sdk/source/lib/sdk/io/text-streams.js
+++ b/addon-sdk/source/lib/sdk/io/text-streams.js
@@ -1,11 +1,9 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et filetype=javascript
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "experimental"
 };
--- a/addon-sdk/source/lib/sdk/keyboard/hotkeys.js
+++ b/addon-sdk/source/lib/sdk/keyboard/hotkeys.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/keyboard/observer.js
+++ b/addon-sdk/source/lib/sdk/keyboard/observer.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/keyboard/utils.js
+++ b/addon-sdk/source/lib/sdk/keyboard/utils.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/lang/type.js
+++ b/addon-sdk/source/lib/sdk/lang/type.js
@@ -1,10 +1,9 @@
-/* vim:ts=2:sts=2:sw=2:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/sdk/loader/cuddlefish.js
+++ b/addon-sdk/source/lib/sdk/loader/cuddlefish.js
@@ -1,14 +1,11 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   "stability": "unstable"
 };
 
 // This module is manually loaded by bootstrap.js in a sandbox and immediatly
 // put in module cache so that it is never loaded in any other way.
--- a/addon-sdk/source/lib/sdk/loader/sandbox.js
+++ b/addon-sdk/source/lib/sdk/loader/sandbox.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
--- a/addon-sdk/source/lib/sdk/notifications.js
+++ b/addon-sdk/source/lib/sdk/notifications.js
@@ -1,11 +1,9 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et filetype=javascript
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "stable"
 };
--- a/addon-sdk/source/lib/sdk/page-mod.js
+++ b/addon-sdk/source/lib/sdk/page-mod.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "stable"
 };
--- a/addon-sdk/source/lib/sdk/page-worker.js
+++ b/addon-sdk/source/lib/sdk/page-worker.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "stable"
 };
--- a/addon-sdk/source/lib/sdk/passwords.js
+++ b/addon-sdk/source/lib/sdk/passwords.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   "stability": "stable"
 };
--- a/addon-sdk/source/lib/sdk/passwords/utils.js
+++ b/addon-sdk/source/lib/sdk/passwords/utils.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/places/contract.js
+++ b/addon-sdk/source/lib/sdk/places/contract.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/self.js
+++ b/addon-sdk/source/lib/sdk/self.js
@@ -1,10 +1,9 @@
-/* vim:st=2:sts=2:sw=2:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "stable"
 };
 
--- a/addon-sdk/source/lib/sdk/simple-prefs.js
+++ b/addon-sdk/source/lib/sdk/simple-prefs.js
@@ -6,21 +6,19 @@
 module.metadata = {
   "stability": "experimental"
 };
 
 const { emit, off } = require("./event/core");
 const { when: unload } = require("./system/unload");
 const { PrefsTarget } = require("./preferences/event-target");
 const { id } = require("./self");
-const { preferencesBranch } = require('@loader/options');
-
 const observers = require("./deprecated/observer-service");
 
-const ADDON_BRANCH = "extensions." + preferencesBranch + ".";
+const ADDON_BRANCH = "extensions." + id + ".";
 const BUTTON_PRESSED = id + "-cmdPressed";
 
 const target = PrefsTarget({ branchName: ADDON_BRANCH });
 
 // Listen to clicks on buttons
 function buttonClick(subject, data) {
   emit(target, data);
 }
--- a/addon-sdk/source/lib/sdk/simple-storage.js
+++ b/addon-sdk/source/lib/sdk/simple-storage.js
@@ -1,11 +1,9 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et filetype=javascript
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "stable"
 };
--- a/addon-sdk/source/lib/sdk/stylesheet/style.js
+++ b/addon-sdk/source/lib/sdk/stylesheet/style.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
--- a/addon-sdk/source/lib/sdk/system.js
+++ b/addon-sdk/source/lib/sdk/system.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
 /* 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';
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/system/environment.js
+++ b/addon-sdk/source/lib/sdk/system/environment.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
 /* 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';
 
 module.metadata = {
   "stability": "stable"
--- a/addon-sdk/source/lib/sdk/system/globals.js
+++ b/addon-sdk/source/lib/sdk/system/globals.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
 /* 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";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/system/runtime.js
+++ b/addon-sdk/source/lib/sdk/system/runtime.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/tabs/observer.js
+++ b/addon-sdk/source/lib/sdk/tabs/observer.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/sdk/tabs/utils.js
+++ b/addon-sdk/source/lib/sdk/tabs/utils.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 module.metadata = {
   'stability': 'unstable'
 };
--- a/addon-sdk/source/lib/sdk/test.js
+++ b/addon-sdk/source/lib/sdk/test.js
@@ -1,10 +1,9 @@
-/* vim:ts=2:sts=2:sw=2:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/sdk/test/assert.js
+++ b/addon-sdk/source/lib/sdk/test/assert.js
@@ -1,10 +1,9 @@
-/* vim:ts=2:sts=2:sw=2:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "unstable"
 };
 
--- a/addon-sdk/source/lib/sdk/test/harness.js
+++ b/addon-sdk/source/lib/sdk/test/harness.js
@@ -421,17 +421,17 @@ function nextIteration(tests) {
     setTimeout(cleanup, 0);
   }
 }
 
 var POINTLESS_ERRORS = [
   'Invalid chrome URI:',
   'OpenGL LayerManager Initialized Succesfully.',
   '[JavaScript Error: "TelemetryStopwatch:',
-  '[JavaScript Warning: "ReferenceError: reference to undefined property',
+  'reference to undefined property',
   '[JavaScript Error: "The character encoding of the HTML document was ' +
     'not declared.',
   '[Javascript Warning: "Error: Failed to preserve wrapper of wrapped ' +
     'native weak map key',
   '[JavaScript Warning: "Duplicate resource declaration for',
   'file: "chrome://browser/content/',
   'file: "chrome://global/content/',
   '[JavaScript Warning: "The character encoding of a framed document was ' +
--- a/addon-sdk/source/lib/sdk/test/httpd.js
+++ b/addon-sdk/source/lib/sdk/test/httpd.js
@@ -1,10 +1,8 @@
-/* -*- Mode: JavaScript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /*
 * An implementation of an HTTP server both as a loadable script and as an XPCOM
 * component. See the accompanying README file for user documentation on
 * httpd.js.
--- a/addon-sdk/source/lib/sdk/test/utils.js
+++ b/addon-sdk/source/lib/sdk/test/utils.js
@@ -1,10 +1,9 @@
-/* vim:ts=2:sts=2:sw=2:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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';
 
 module.metadata = {
   'stability': 'unstable'
 };
--- a/addon-sdk/source/lib/sdk/util/array.js
+++ b/addon-sdk/source/lib/sdk/util/array.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
 };
--- a/addon-sdk/source/lib/sdk/util/collection.js
+++ b/addon-sdk/source/lib/sdk/util/collection.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "experimental"
--- a/addon-sdk/source/lib/sdk/util/match-pattern.js
+++ b/addon-sdk/source/lib/sdk/util/match-pattern.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/util/registry.js
+++ b/addon-sdk/source/lib/sdk/util/registry.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/sdk/util/rules.js
+++ b/addon-sdk/source/lib/sdk/util/rules.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/view/core.js
+++ b/addon-sdk/source/lib/sdk/view/core.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
--- a/addon-sdk/source/lib/sdk/widget.js
+++ b/addon-sdk/source/lib/sdk/widget.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 // The widget module currently supports only Firefox.
 // See: https://bugzilla.mozilla.org/show_bug.cgi?id=560716
--- a/addon-sdk/source/lib/sdk/windows/observer.js
+++ b/addon-sdk/source/lib/sdk/windows/observer.js
@@ -1,9 +1,8 @@
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/test.js
+++ b/addon-sdk/source/lib/test.js
@@ -1,10 +1,9 @@
-/* vim:ts=2:sts=2:sw=2:
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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";
 
 module.metadata = {
   "stability": "unstable"
 };
--- a/addon-sdk/source/lib/toolkit/loader.js
+++ b/addon-sdk/source/lib/toolkit/loader.js
@@ -1,13 +1,12 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
 /* 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/.
- */
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
 ;(function(id, factory) { // Module boilerplate :(
   if (typeof(define) === 'function') { // RequireJS
     define(factory);
   } else if (typeof(require) === 'function') { // CommonJS
     factory.call(this, require, exports, module);
   } else if (~String(this).indexOf('BackstagePass')) { // JSM
     this[factory.name] = {};
     factory(function require(uri) {
--- a/addon-sdk/source/python-lib/cuddlefish/options_defaults.py
+++ b/addon-sdk/source/python-lib/cuddlefish/options_defaults.py
@@ -1,13 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-def parse_options_defaults(options, preferencesBranch):
+def parse_options_defaults(options, jetpack_id):
     # this returns a unicode string
     pref_list = []
 
     for pref in options:
         if ('value' in pref):
             value = pref["value"]
 
             if isinstance(value, float):
@@ -16,11 +16,11 @@ def parse_options_defaults(options, pref
                 value = str(pref["value"]).lower()
             elif isinstance(value, str): # presumably ASCII
                 value = "\"" + unicode(pref["value"]) + "\""
             elif isinstance(value, unicode):
                 value = "\"" + pref["value"] + "\""
             else:
                 value = str(pref["value"])
 
-            pref_list.append("pref(\"extensions." + preferencesBranch + "." + pref["name"] + "\", " + value + ");")
+            pref_list.append("pref(\"extensions." + jetpack_id + "." + pref["name"] + "\", " + value + ");")
 
     return "\n".join(pref_list) + "\n"
--- a/addon-sdk/source/python-lib/cuddlefish/options_xul.py
+++ b/addon-sdk/source/python-lib/cuddlefish/options_xul.py
@@ -40,30 +40,30 @@ def validate_prefs(options):
             for item in pref["options"]:
                 if ("value" not in item):
                     raise MissingPrefAttr("'options' requires a 'value'")
                 if ("label" not in item):
                     raise MissingPrefAttr("'options' requires a 'label'")
 
         # TODO: Check that pref["type"] matches default value type
 
-def parse_options(options, jetpack_id, preferencesBranch):
+def parse_options(options, jetpack_id):
     doc = Document()
     root = doc.createElement("vbox")
     root.setAttribute("xmlns", "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul")
     doc.appendChild(root)
 
     for pref in options:
         if ("hidden" in pref and pref["hidden"] == True):
             continue;
 
         setting = doc.createElement("setting")
         setting.setAttribute("pref-name", pref["name"])
         setting.setAttribute("data-jetpack-id", jetpack_id)
-        setting.setAttribute("pref", "extensions." + preferencesBranch + "." + pref["name"])
+        setting.setAttribute("pref", "extensions." + jetpack_id + "." + pref["name"])
         setting.setAttribute("type", pref["type"])
         setting.setAttribute("title", pref["title"])
 
         if ("description" in pref):
             setting.appendChild(doc.createTextNode(pref["description"]))
 
         if (pref["type"] == "control"):
             button = doc.createElement("button")
--- a/addon-sdk/source/python-lib/cuddlefish/packaging.py
+++ b/addon-sdk/source/python-lib/cuddlefish/packaging.py
@@ -391,31 +391,16 @@ def generate_build_for_target(pkg_cfg, t
 
     if 'icon64' in target_cfg:
         build['icon64'] = os.path.join(target_cfg.root_dir, target_cfg.icon64)
         del target_cfg['icon64']
 
     if ('preferences' in target_cfg):
         build['preferences'] = target_cfg.preferences
 
-    if 'id' in target_cfg:
-        # NOTE: logic duplicated from buildJID()
-        jid = target_cfg['id']
-        if not ('@' in jid or jid.startswith('{')):
-            jid += '@jetpack'
-        build['preferencesBranch'] = jid
-
-    if 'preferences-branch' in target_cfg:
-        # check it's a non-empty, valid branch name
-        preferencesBranch = target_cfg['preferences-branch']
-        if re.match('^[\w{@}-]+$', preferencesBranch):
-            build['preferencesBranch'] = preferencesBranch
-        elif not is_running_tests:
-            print >>sys.stderr, "IGNORING preferences-branch (not a valid branch name)"
-
     return build
 
 def _get_files_in_dir(path):
     data = {}
     files = os.listdir(path)
     for filename in files:
         fullpath = os.path.join(path, filename)
         if os.path.isdir(fullpath):
deleted file mode 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/preferences-files/packages/curly-id/lib/main.js
+++ /dev/null
@@ -1,4 +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/. */
-
deleted file mode 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/preferences-files/packages/curly-id/package.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "id": "{34a1eae1-c20a-464f-9b0e-000000000000}",
-    "fullName": "curly ID test",
-    "author": "Tomislav Jovanovic",
-
-    "preferences": [{
-        "name": "test13",
-        "type": "integer",
-        "title": "test13",
-        "value": 26
-    }],
-
-    "preferences-branch": "invalid^branch*name"
-}
deleted file mode 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/preferences-files/packages/preferences-branch/lib/main.js
+++ /dev/null
@@ -1,4 +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/. */
-
deleted file mode 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/preferences-files/packages/preferences-branch/package.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "id": "test-preferences-branch",
-    "fullName": "preferences-branch test",
-    "author": "Tomislav Jovanovic",
-
-    "preferences": [{
-        "name": "test42",
-        "type": "bool",
-        "title": "test42",
-        "value": true
-    }],
-
-    "preferences-branch": "human-readable"
-}
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_packaging.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_packaging.py
@@ -17,18 +17,17 @@ def get_configs(pkg_name, dirname='stati
     if not (os.path.exists(pkg_path) and os.path.isdir(pkg_path)):
         raise Exception('path does not exist: %s' % pkg_path)
     target_cfg = packaging.get_config_in_dir(pkg_path)
     pkg_cfg = packaging.build_config(root_path, target_cfg)
     deps = packaging.get_deps_for_targets(pkg_cfg, [pkg_name])
     build = packaging.generate_build_for_target(
         pkg_cfg=pkg_cfg,
         target=pkg_name,
-        deps=deps,
-        is_running_tests=True,
+        deps=deps
         )
     return Bunch(target_cfg=target_cfg, pkg_cfg=pkg_cfg, build=build)
 
 class PackagingTests(unittest.TestCase):
     def test_bug_588661(self):
         configs = get_configs('foo', 'bug-588661-files')
         self.assertEqual(configs.build.loader,
                          'foo/lib/foo-loader.js')
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_xpi.py
@@ -35,30 +35,30 @@ class PrefsTests(unittest.TestCase):
     def tearDown(self):
         if self.xpi:
             self.xpi.close()
         if self.xpiname and os.path.exists(self.xpiname):
             os.remove(self.xpiname)
 
     def testPackageWithSimplePrefs(self):
         self.makexpi('simple-prefs')
-        packageName = 'jid1-fZHqN9JfrDBa8A@jetpack'
         self.failUnless('options.xul' in self.xpi.namelist())
         optsxul = self.xpi.read('options.xul').decode("utf-8")
-        self.failUnlessEqual(self.xpi_harness_options["jetpackID"], packageName)
-        self.failUnlessEqual(self.xpi_harness_options["preferencesBranch"], packageName)
+        self.failUnlessEqual(self.xpi_harness_options["jetpackID"],
+                             "jid1-fZHqN9JfrDBa8A@jetpack")
 
         root = ElementTree.XML(optsxul.encode('utf-8'))
 
         xulNamespacePrefix = \
             "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}"
         
         settings = root.findall(xulNamespacePrefix + 'setting')
 
         def assertPref(setting, name, prefType, title):
+            packageName = 'jid1-fZHqN9JfrDBa8A@jetpack'
             self.failUnlessEqual(setting.get('data-jetpack-id'), packageName)
             self.failUnlessEqual(setting.get('pref'),
                                  'extensions.' + packageName + '.' + name)
             self.failUnlessEqual(setting.get('pref-name'), name)
             self.failUnlessEqual(setting.get('type'), prefType)
             self.failUnlessEqual(setting.get('title'), title)
 
         assertPref(settings[0], 'test', 'bool', u't\u00EBst')
@@ -83,70 +83,24 @@ class PrefsTests(unittest.TestCase):
         prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8")
         exp = [u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test", false);',
                u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test2", "\u00FCnic\u00F8d\u00E9");',
                u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test3", "1");',
                u'pref("extensions.jid1-fZHqN9JfrDBa8A@jetpack.test4", "red");',
                ]
         self.failUnlessEqual(prefsjs, "\n".join(exp)+"\n")
 
-    def testPackageWithPreferencesBranch(self):
-        self.makexpi('preferences-branch')
-        self.failUnless('options.xul' in self.xpi.namelist())
-        optsxul = self.xpi.read('options.xul').decode("utf-8")
-        self.failUnlessEqual(self.xpi_harness_options["preferencesBranch"], 
-                             "human-readable")
-
-        root = ElementTree.XML(optsxul.encode('utf-8'))
-        xulNamespacePrefix = \
-            "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}"
-        
-        setting = root.find(xulNamespacePrefix + 'setting')
-        self.failUnlessEqual(setting.get('pref'),
-                             'extensions.human-readable.test42')
-
-        prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8")
-        self.failUnlessEqual(prefsjs, 
-                            'pref("extensions.human-readable.test42", true);\n')
-
     def testPackageWithNoPrefs(self):
         self.makexpi('no-prefs')
         self.failIf('options.xul' in self.xpi.namelist())
         self.failUnlessEqual(self.xpi_harness_options["jetpackID"],
                              "jid1-fZHqN9JfrDBa8A@jetpack")
         prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8")
         self.failUnlessEqual(prefsjs, "")
 
-    def testPackageWithInvalidPreferencesBranch(self):
-        self.makexpi('curly-id')
-        self.failIfEqual(self.xpi_harness_options["preferencesBranch"], 
-                         "invalid^branch*name")
-        self.failUnlessEqual(self.xpi_harness_options["preferencesBranch"], 
-                             "{34a1eae1-c20a-464f-9b0e-000000000000}")
-
-    def testPackageWithCurlyID(self):
-        self.makexpi('curly-id')
-        self.failUnlessEqual(self.xpi_harness_options["jetpackID"], 
-                             "{34a1eae1-c20a-464f-9b0e-000000000000}")
-
-        self.failUnless('options.xul' in self.xpi.namelist())
-        optsxul = self.xpi.read('options.xul').decode("utf-8")
-
-        root = ElementTree.XML(optsxul.encode('utf-8'))
-        xulNamespacePrefix = \
-            "{http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul}"
-        
-        setting = root.find(xulNamespacePrefix + 'setting')
-        self.failUnlessEqual(setting.get('pref'),
-                             'extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test13')
-
-        prefsjs = self.xpi.read('defaults/preferences/prefs.js').decode("utf-8")
-        self.failUnlessEqual(prefsjs, 
-                            'pref("extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test13", 26);\n')
-
 
 class Bug588119Tests(unittest.TestCase):
     def makexpi(self, pkg_name):
         self.xpiname = "%s.xpi" % pkg_name
         create_xpi(self.xpiname, pkg_name, 'bug-588119-files')
         self.xpi = zipfile.ZipFile(self.xpiname, 'r')
         options = self.xpi.read('harness-options.json')
         self.xpi_harness_options = json.loads(options)
--- a/addon-sdk/source/python-lib/cuddlefish/xpi.py
+++ b/addon-sdk/source/python-lib/cuddlefish/xpi.py
@@ -72,25 +72,24 @@ def build_xpi(template_root_dir, manifes
 
     # Handle simple-prefs
     if 'preferences' in harness_options:
         from options_xul import parse_options, validate_prefs
 
         validate_prefs(harness_options["preferences"])
 
         opts_xul = parse_options(harness_options["preferences"],
-                                 harness_options["jetpackID"],
-                                 harness_options["preferencesBranch"])
+                                 harness_options["jetpackID"])
         open('.options.xul', 'wb').write(opts_xul.encode("utf-8"))
         zf.write('.options.xul', 'options.xul')
         os.remove('.options.xul')
 
         from options_defaults import parse_options_defaults
         prefs_js = parse_options_defaults(harness_options["preferences"],
-                                          harness_options["preferencesBranch"])
+                                          harness_options["jetpackID"])
         open('.prefs.js', 'wb').write(prefs_js.encode("utf-8"))
 
     else:
         open('.prefs.js', 'wb').write("")
 
     zf.write('.prefs.js', 'defaults/preferences/prefs.js')
     os.remove('.prefs.js')
 
deleted file mode 100644
--- a/addon-sdk/source/test/addons/curly-id/lib/main.js
+++ /dev/null
@@ -1,45 +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/. */
-
-'use strict';
-
-const { id } = require('sdk/self');
-const simple = require('sdk/simple-prefs');
-const service = require('sdk/preferences/service');
-const { preferencesBranch } = require('@loader/options');
-const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm');
-
-exports.testCurlyID = function(assert) {
-  assert.equal(id, '{34a1eae1-c20a-464f-9b0e-000000000000}', 'curly ID is curly');
-
-  assert.equal(simple.prefs.test13, 26, 'test13 is 26');
-
-  simple.prefs.test14 = '15';
-  assert.equal(service.get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test14'), '15', 'test14 is 15');
-
-  assert.equal(service.get('extensions.{34a1eae1-c20a-464f-9b0e-000000000000}.test14'), simple.prefs.test14, 'simple test14 also 15');
-  
-}
-
-exports.testInvalidPreferencesBranch = function(assert) {
-  assert.notEqual(preferencesBranch, 'invalid^branch*name', 'invalid preferences-branch value ignored');
-
-  assert.equal(preferencesBranch, '{34a1eae1-c20a-464f-9b0e-000000000000}', 'preferences-branch is {34a1eae1-c20a-464f-9b0e-000000000000}');
-
-}
-
-// from `/test/test-self.js`, adapted to `sdk/test/assert` API
-exports.testSelfID = function(assert, done) {
-
-  assert.equal(typeof(id), 'string', 'self.id is a string');
-  assert.ok(id.length > 0, 'self.id not empty');
-
-  AddonManager.getAddonByID(id, function(addon) {
-    assert.ok(addon, 'found addon with self.id');
-    done();
-  });
-
-}
-
-require('sdk/test/runner').runTestsFromModule(module);
deleted file mode 100644
--- a/addon-sdk/source/test/addons/curly-id/package.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "id": "{34a1eae1-c20a-464f-9b0e-000000000000}",
-    "fullName": "curly ID test",
-    "author": "Tomislav Jovanovic",
-
-    "preferences": [{
-        "name": "test13",
-        "type": "integer",
-        "title": "test13",
-        "value": 26
-    }],
-
-    "preferences-branch": "invalid^branch*name"
-}
deleted file mode 100644
--- a/addon-sdk/source/test/addons/predefined-id-with-at/lib/main.js
+++ /dev/null
@@ -1,35 +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/. */
-'use strict';
-
-const { id } = require('sdk/self');
-const simple = require('sdk/simple-prefs');
-const service = require('sdk/preferences/service');
-const { preferencesBranch } = require('@loader/options');
-const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm', {});
-
-const expected_id = 'predefined-id@test';
-
-exports.testExpectedID = function(assert) {
-  assert.equal(id, expected_id, 'ID is as expected');
-  assert.equal(preferencesBranch, expected_id, 'preferences-branch is ' + expected_id);
-
-  assert.equal(simple.prefs.test, 5, 'test pref is 5');
-
-  simple.prefs.test2 = '25';
-  assert.equal(service.get('extensions.'+expected_id+'.test2'), '25', 'test pref is 25');
-  assert.equal(service.get('extensions.'+expected_id+'.test2'), simple.prefs.test2, 'test pref is 25');
-}
-
-exports.testSelfID = function(assert, done) {
-  assert.equal(typeof(id), 'string', 'self.id is a string');
-  assert.ok(id.length > 0, 'self.id not empty');
-
-  AddonManager.getAddonByID(id, function(addon) {
-    assert.equal(addon.id, id, 'found addon with self.id');
-    done();
-  });
-}
-
-require('sdk/test/runner').runTestsFromModule(module);
deleted file mode 100644
--- a/addon-sdk/source/test/addons/predefined-id-with-at/package.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "id": "predefined-id@test",
-    "fullName": "predefined ID test",
-    "author": "Erik Vold",
-    "preferences": [{
-        "name": "test",
-        "type": "integer",
-        "title": "test",
-        "value": 5
-    }]
-}
deleted file mode 100644
--- a/addon-sdk/source/test/addons/preferences-branch/lib/main.js
+++ /dev/null
@@ -1,36 +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/. */
-
-'use strict';
-
-const { id } = require('sdk/self');
-const simple = require('sdk/simple-prefs');
-const service = require('sdk/preferences/service');
-const { preferencesBranch } = require('@loader/options');
-const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm');
-
-exports.testPreferencesBranch = function(assert) {
-  assert.equal(preferencesBranch, 'human-readable', 'preferencesBranch is human-readable');
-
-  assert.equal(simple.prefs.test42, true, 'test42 is true');
-
-  simple.prefs.test43 = 'movie';
-  assert.equal(service.get('extensions.human-readable.test43'), 'movie', 'test43 is a movie');
-  
-}
-
-// from `/test/test-self.js`, adapted to `sdk/test/assert` API
-exports.testSelfID = function(assert, done) {
-
-  assert.equal(typeof(id), 'string', 'self.id is a string');
-  assert.ok(id.length > 0, 'self.id not empty');
-
-  AddonManager.getAddonByID(id, function(addon) {
-    assert.ok(addon, 'found addon with self.id');
-    done();
-  });
-
-}
-
-require('sdk/test/runner').runTestsFromModule(module);
deleted file mode 100644
--- a/addon-sdk/source/test/addons/preferences-branch/package.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "id": "test-preferences-branch",
-    "fullName": "preferences-branch test",
-    "author": "Tomislav Jovanovic",
-
-    "preferences": [{
-        "name": "test42",
-        "type": "bool",
-        "title": "test42",
-        "value": true
-    }],
-
-    "preferences-branch": "human-readable"
-}
--- a/addon-sdk/source/test/addons/simple-prefs/lib/main.js
+++ b/addon-sdk/source/test/addons/simple-prefs/lib/main.js
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 const { Cu } = require('chrome');
 const sp = require('sdk/simple-prefs');
 const app = require('sdk/system/xul-app');
 const self = require('sdk/self');
 const tabs = require('sdk/tabs');
-const { preferencesBranch } = require('@loader/options');
 
 const { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
 
 exports.testDefaultValues = function (assert) {
   assert.equal(sp.prefs.myHiddenInt, 5, 'myHiddenInt default is 5');
   assert.equal(sp.prefs.myInteger, 8, 'myInteger default is 8');
   assert.equal(sp.prefs.somePreference, 'TEST', 'somePreference default is correct');
 }
@@ -85,13 +84,9 @@ if (app.is('Firefox')) {
               tab.close(done);
             }
           });
       	}
       });
   }
 }
 
-exports.testDefaultPreferencesBranch = function(assert) {
-  assert.equal(preferencesBranch, self.id, 'preferencesBranch default the same as self.id');
-}
-
 require('sdk/test/runner').runTestsFromModule(module);
deleted file mode 100644
--- a/addon-sdk/source/test/addons/standard-id/lib/main.js
+++ /dev/null
@@ -1,45 +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/. */
-
-'use strict';
-
-const { id } = require('sdk/self');
-const simple = require('sdk/simple-prefs');
-const service = require('sdk/preferences/service');
-const { preferencesBranch } = require('@loader/options');
-const { AddonManager } = require('chrome').Cu.import('resource://gre/modules/AddonManager.jsm');
-
-exports.testStandardID = function(assert) {
-  assert.equal(id, 'standard-id@jetpack', 'standard ID is standard');
-
-  assert.equal(simple.prefs.test13, 26, 'test13 is 26');
-
-  simple.prefs.test14 = '15';
-  assert.equal(service.get('extensions.standard-id@jetpack.test14'), '15', 'test14 is 15');
-
-  assert.equal(service.get('extensions.standard-id@jetpack.test14'), simple.prefs.test14, 'simple test14 also 15');
-  
-}
-
-exports.testInvalidPreferencesBranch = function(assert) {
-  assert.notEqual(preferencesBranch, 'invalid^branch*name', 'invalid preferences-branch value ignored');
-
-  assert.equal(preferencesBranch, 'standard-id@jetpack', 'preferences-branch is standard-id@jetpack');
-
-}
-
-// from `/test/test-self.js`, adapted to `sdk/test/assert` API
-exports.testSelfID = function(assert, done) {
-
-  assert.equal(typeof(id), 'string', 'self.id is a string');
-  assert.ok(id.length > 0, 'self.id not empty');
-
-  AddonManager.getAddonByID(id, function(addon) {
-    assert.ok(addon, 'found addon with self.id');
-    done();
-  });
-
-}
-
-require('sdk/test/runner').runTestsFromModule(module);
deleted file mode 100644
--- a/addon-sdk/source/test/addons/standard-id/package.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-    "id": "standard-id",
-    "fullName": "standard ID test",
-    "author": "Tomislav Jovanovic",
-
-    "preferences": [{
-        "name": "test13",
-        "type": "integer",
-        "title": "test13",
-        "value": 26
-    }],
-
-    "preferences-branch": "invalid^branch*name"
-}
index c7cfccd7abd114c59a8b12f1fc9e8caf5803b081..48945af0577a41d56f7b789fb64331bcacf8b388
GIT binary patch
literal 1692
zc${^VdpOg39LImmWsEHMOLTCK!pvwz=r;Flm6j<)rjlEmC?zVl(L$CI&84ssB9B`r
zj!VSJu*PVktVm->Xs*Yhp65Judd~Oze4p><`^V?~{p0g~y`3;1F+~6XzyO^nVU1j=
zeVGRWfOIeb$N-xFZxZQT$hlxb5Zpfm?<@s?klrG=^>h9r1P~FM69Is4-NpFEV2%T{
zZbr$&A_{`3I_TcXX3GoAox#<K<?zk+xEQ_dG-hWa)zM(Jeo!|`q`Wd5p|Y2?vN)H~
zS3E4!IS<-Qn$p{rexUVfd5cj*X6MV}oLgF%jmLenkc;Z|Zx8ZJ>#>ucmJI409!?}<
zq~BM+6xH6w$@{vYLq0-V6ZQZFRc`F%U+A#9Xe|jo&X6m(9l2zIH;pOiaIzd=dz%-E
zUEYvX+wA*UWXHoeT;N^}x$P}~vK!K54CQbN@ntyNCz+g^^<J<zzLWRGNd$IGoD4xf
z+F``=Py}~{k%hhIQ;_==(u{ch{dg4WcMle%d{$PNh8Zo!1|;w7v9J#Z>|sKXOlmJQ
zNg3g4LzUh#NM&a0CEpu;r^WM|{fwaP+TFaYkm%F(`IPB1HBp>dY=UvBt-ZWEbwK~4
z2@EP6H(|f7P&`Jydn~0D{Rwa60yZqSD|+A=m0A=H$9&p!8}>jY`^AMP%W9{KxNnWR
z^bh*ycm;mx<|<sD+xNl-W2`?U(f0^z>zh?i!ddDDnGR@h<=bG=Z2iGl`cvP>^XVl<
zNML0eD1pPTa6RWT=2h*`jn>==kVQoRuK0tcURPX#N!64@-}1GlX|i*UfzZy)lsko=
zzag%<Tw_3XHdzoPZ}6sD>7&OE)iDr3=DVZ>&lKO(F2Qq#Q$T8k&rV*6Fk6zi@Q8^s
z%pVmi=@-9VQ8xIv+rchId)J_U<8Oz{AhydY%CZ9+IThp+Fxu^hR9BI^LB)Lr0qoc0
zr7?J#aNlTcsmA;r8(U?D4Vr<Ou)3bfL`Cy<V%if;uy+U*8hq)uP?SC^R>X|g&{V4%
zcK;#MzuA|RYDJx<_9FVTRN6|YyrcH3AXWT|Fl7sxe7?0BH`-G`VyPMAw?m-AA2umn
z%C6DnM*~qQEochN*FBD*graO6RLDDv^{Tx`oSt&y^c~viADSOXM7@d<C)S<C#?ZAJ
zur4W?8qXK^yy%afn1#}+3R*#a2M&$<<X;92b`lTNT^)k)=X87;Uu~OV#(R>mOIe@&
zs@`)jBi@|o3iHK{XKZt6+Ghl*Ep%j9arYk(T4+jl%R3LpDXJ&Qbv#ihLy#UHFT4ja
zj_aujvXdJ+E$5YX0;e*g1T&jKK9(I{tab4R-)sxX>w42OoI67c?X0mM)wLLltl>PV
zyW|nL>fwJ*E;*n&_iK&c?2_V}T+Jgn_l1H}l6~w2NvD57zq<xHJTJnsa*f`dVgLYH
z1Kp1pa*hxf2oFB#^Nn+zHO6&*<(%Q%cq0R`&N)21XxK}JD`wMQLi>0J^Wf|5hSC5j
zZd<w@w{X?dTU3fs89yR6^H!rPT>aLrtdrJPa`~|??t6}ztm+G&3%JCC5;o`ES9>`-
zWTQV!S6kQ_p7D%EIHp8SM~3(p(n3jpHBkyD8-;BPXPXp9P=<5HOyrPyQ0seO#C2t8
zG-fN8a73NSAxMjoCnwlbNoeC-=SQ6=mXj2^r{8sp`pK<_4~;nC-Ix@XA)!Fi;a<Kj
z#;Dwj-dUC~5)mXQ<%jF_KUEHyL<lWFWOh}#1ZRMzrO9*qV#kq0w|lBSo})NjVkve&
zIHOf(Y@|YWlhhiVGgekwgPV0+p7^z^b<ZC@#-e*UG=p^<5U%za^Ic8v>32{o>6sQy
z`w5P*Eaz2o`6pz*)*)h>Np|?*KE(~SP}#qep+N2zlVR=R`$I^dHohJ#s$}E*i6mRK
zI6+oishOMW7d(DAQaRL%u<@EGWnm_a(te849(L8^cs!$H?4w|+IondJpi(=*axcAP
z(Pw}$MjXgFsxDTv|B5OJypX%UC@F(W(OVYqHotU5ENcW$89QM_M72Qw7xJpW`dS+>
yK#y9levW+c?~(r>8~mvFtDAmQ<gfknlefgbd+QfLaf$UN(Y2koc7G6GfBge0?DkLq
--- a/addon-sdk/source/test/fixtures/chrome-worker/addEventListener.js
+++ b/addon-sdk/source/test/fixtures/chrome-worker/addEventListener.js
@@ -1,8 +1,6 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 postMessage('Hello');
--- a/addon-sdk/source/test/fixtures/chrome-worker/jsctypes.js
+++ b/addon-sdk/source/test/fixtures/chrome-worker/jsctypes.js
@@ -1,8 +1,6 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 postMessage(typeof ctypes.open);
--- a/addon-sdk/source/test/fixtures/chrome-worker/onerror.js
+++ b/addon-sdk/source/test/fixtures/chrome-worker/onerror.js
@@ -1,8 +1,6 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 throw new Error('ok');
--- a/addon-sdk/source/test/fixtures/chrome-worker/onmessage.js
+++ b/addon-sdk/source/test/fixtures/chrome-worker/onmessage.js
@@ -1,10 +1,8 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 onmessage = function (event) {
   postMessage(event.data);
 };
--- a/addon-sdk/source/test/fixtures/chrome-worker/setTimeout.js
+++ b/addon-sdk/source/test/fixtures/chrome-worker/setTimeout.js
@@ -1,10 +1,8 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 setTimeout(function () {
   postMessage('ok');
 }, 0);
--- a/addon-sdk/source/test/fixtures/chrome-worker/xhr.js
+++ b/addon-sdk/source/test/fixtures/chrome-worker/xhr.js
@@ -1,13 +1,11 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 let xhr = XMLHttpRequest();
 xhr.open("GET", "data:text/plain,ok", true);
 xhr.onload = function () {
   postMessage(xhr.responseText);
 };
 xhr.send(null);
--- a/addon-sdk/source/test/tabs/test-firefox-tabs.js
+++ b/addon-sdk/source/test/tabs/test-firefox-tabs.js
@@ -8,20 +8,17 @@ const { Loader } = require('sdk/test/loa
 const timer = require('sdk/timers');
 const { getOwnerWindow } = require('sdk/private-browsing/window/utils');
 const { windows, onFocus, getMostRecentBrowserWindow } = require('sdk/window/utils');
 const { open, focus, close } = require('sdk/window/helpers');
 const { StringBundle } = require('sdk/deprecated/app-strings');
 const tabs = require('sdk/tabs');
 const { browserWindows } = require('sdk/windows');
 
-const base64png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYA" +
-                  "AABzenr0AAAASUlEQVRYhe3O0QkAIAwD0eyqe3Q993AQ3cBSUKpygfsNTy" +
-                  "N5ugbQpK0BAADgP0BRDWXWlwEAAAAAgPsA3rzDaAAAAHgPcGrpgAnzQ2FG" +
-                  "bWRR9AAAAABJRU5ErkJggg%3D%3D";
+const base64png = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAA";
 
 // Bug 682681 - tab.title should never be empty
 exports.testBug682681_aboutURI = function(assert, done) {
   let tabStrings = StringBundle('chrome://browser/locale/tabbrowser.properties');
 
   tabs.on('ready', function onReady(tab) {
     tabs.removeListener('ready', onReady);
 
@@ -859,60 +856,55 @@ exports['test unique tab ids'] = functio
     results[0].win.close();
     results[1].win.close();
     done();
   });
 }
 
 // related to Bug 671305
 exports.testOnLoadEventWithDOM = function(assert, done) {
-  openBrowserWindow(function(window, browser) {
-    let count = 0;
-    tabs.on('load', function onLoad(tab) {
-      assert.equal(tab.title, 'tab', 'tab passed in as arg, load called');
-      if (!count++) {
-        tab.reload();
+  let count = 0;
+  let title = 'testOnLoadEventWithDOM';
+
+  // open a about: url
+  tabs.open({
+    url: 'data:text/html;charset=utf-8,<title>' + title + '</title>',
+    inBackground: true,
+    onLoad: function(tab) {
+      assert.equal(tab.title, title, 'tab passed in as arg, load called');
+
+      if (++count > 1) {
+        assert.pass('onLoad event called on reload');
+        tab.close(done);
       }
       else {
-        // end of test
-        tabs.removeListener('load', onLoad);
-        assert.pass('onLoad event called on reload');
-        close(window).then(done);
+        assert.pass('first onLoad event occured');
+        tab.reload();
       }
-    });
-
-    // open a about: url
-    tabs.open({
-      url: 'data:text/html;charset=utf-8,<title>tab</title>',
-      inBackground: true
-    });
+    }
   });
 };
 
 // related to Bug 671305
 exports.testOnLoadEventWithImage = function(assert, done) {
-  openBrowserWindow(function(window, browser) {
-    let count = 0;
-    tabs.on('load', function onLoad(tab) {
-      if (!count++) {
-        tab.reload();
+  let count = 0;
+
+  tabs.open({
+    url: base64png,
+    inBackground: true,
+    onLoad: function(tab) {
+      if (++count > 1) {
+        assert.pass('onLoad event called on reload with image');
+        tab.close(done);
       }
       else {
-        // end of test
-        tabs.removeListener('load', onLoad);
-        assert.pass('onLoad event called on reload with image');
-        close(window).then(done);
+        assert.pass('first onLoad event occured');
+        tab.reload();
       }
-    });
-
-    // open a image url
-    tabs.open({
-      url: base64png,
-      inBackground: true
-    });
+    }
   });
 };
 
 exports.testFaviconGetterDeprecation = function (assert, done) {
   const { LoaderWithHookedConsole } = require("sdk/test/loader");
   let { loader, messages } = LoaderWithHookedConsole(module);
   let tabs = loader.require('sdk/tabs');
 
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/test-addon-window.js
@@ -0,0 +1,22 @@
+/* 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';
+
+let { Loader } = require('sdk/test/loader');
+
+exports.testReady = function(assert, done) {
+  let loader = Loader(module);
+  let { ready, window } = loader.require('sdk/addon/window');
+  let windowIsReady = false;
+
+  ready.then(function() {
+    assert.equal(windowIsReady, false, 'ready promise was resolved only once');
+    windowIsReady = true;
+
+    loader.unload();
+    done();
+  }).then(null, assert.fail);
+}
+
+require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-api-utils.js
+++ b/addon-sdk/source/test/test-api-utils.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const apiUtils = require("sdk/deprecated/api-utils");
 
 exports.testPublicConstructor = function (assert) {
   function PrivateCtor() {}
--- a/addon-sdk/source/test/test-byte-streams.js
+++ b/addon-sdk/source/test/test-byte-streams.js
@@ -1,11 +1,9 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et filetype=javascript
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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 byteStreams = require("sdk/io/byte-streams");
 const file = require("sdk/io/file");
 const { pathFor } = require("sdk/system");
 const { Loader } = require("sdk/test/loader");
 
--- a/addon-sdk/source/test/test-chrome.js
+++ b/addon-sdk/source/test/test-chrome.js
@@ -1,13 +1,11 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 'use strict';
 
 let chrome = require('chrome');
 
 const FIXTURES_URL = module.uri.substr(0, module.uri.lastIndexOf('/') + 1) +
                      'fixtures/chrome-worker/'
 
 exports['test addEventListener'] = function(assert, done) {
@@ -67,20 +65,20 @@ exports['test XMLHttpRequest'] = functio
 };
 
 exports['test onerror'] = function(assert, done) {
   let uri = FIXTURES_URL + 'onerror.js';
 
   let worker = new chrome.ChromeWorker(uri);
   worker.onerror = function(event) {
     assert.equal(event.filename, uri, 'event reports the correct uri');
-    assert.equal(event.lineno, 8, 'event reports the correct line number');
+    assert.equal(event.lineno, 6, 'event reports the correct line number');
     assert.equal(event.target, worker, 'event reports the correct worker');
     assert.ok(event.message.match(/ok/),
                 'event contains the exception message');
     // Call preventDefault in order to avoid being displayed in JS console.
     event.preventDefault();
     worker.terminate();
     done();
   };
 };
 
-require('test').run(exports);
+require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-clipboard.js
+++ b/addon-sdk/source/test/test-clipboard.js
@@ -1,12 +1,11 @@
 /* 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";
 
 require("sdk/clipboard");
 
 const { Cc, Ci } = require("chrome");
 
 const imageTools = Cc["@mozilla.org/image/tools;1"].
                     getService(Ci.imgITools);
--- a/addon-sdk/source/test/test-collection.js
+++ b/addon-sdk/source/test/test-collection.js
@@ -1,127 +1,128 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
 
 const collection = require("sdk/util/collection");
 
-exports.testAddRemove = function (test) {
+exports.testAddRemove = function (assert) {
   let coll = new collection.Collection();
-  compare(test, coll, []);
-  addRemove(test, coll, [], false);
+  compare(assert, coll, []);
+  addRemove(assert, coll, [], false);
 };
 
-exports.testAddRemoveBackingArray = function (test) {
+exports.testAddRemoveBackingArray = function (assert) {
   let items = ["foo"];
   let coll = new collection.Collection(items);
-  compare(test, coll, items);
-  addRemove(test, coll, items, true);
+  compare(assert, coll, items);
+  addRemove(assert, coll, items, true);
 
   items = ["foo", "bar"];
   coll = new collection.Collection(items);
-  compare(test, coll, items);
-  addRemove(test, coll, items, true);
+  compare(assert, coll, items);
+  addRemove(assert, coll, items, true);
 };
 
-exports.testProperty = function (test) {
+exports.testProperty = function (assert) {
   let obj = makeObjWithCollProp();
-  compare(test, obj.coll, []);
-  addRemove(test, obj.coll, [], false);
+  compare(assert, obj.coll, []);
+  addRemove(assert, obj.coll, [], false);
 
   // Test single-value set.
   let items = ["foo"];
   obj.coll = items[0];
-  compare(test, obj.coll, items);
-  addRemove(test, obj.coll, items, false);
+  compare(assert, obj.coll, items);
+  addRemove(assert, obj.coll, items, false);
 
   // Test array set.
   items = ["foo", "bar"];
   obj.coll = items;
-  compare(test, obj.coll, items);
-  addRemove(test, obj.coll, items, false);
+  compare(assert, obj.coll, items);
+  addRemove(assert, obj.coll, items, false);
 };
 
-exports.testPropertyBackingArray = function (test) {
+exports.testPropertyBackingArray = function (assert) {
   let items = ["foo"];
   let obj = makeObjWithCollProp(items);
-  compare(test, obj.coll, items);
-  addRemove(test, obj.coll, items, true);
+  compare(assert, obj.coll, items);
+  addRemove(assert, obj.coll, items, true);
 
   items = ["foo", "bar"];
   obj = makeObjWithCollProp(items);
-  compare(test, obj.coll, items);
-  addRemove(test, obj.coll, items, true);
+  compare(assert, obj.coll, items);
+  addRemove(assert, obj.coll, items, true);
 };
 
 // Adds some values to coll and then removes them.  initialItems is an array
 // containing coll's initial items.  isBacking is true if initialItems is coll's
 // backing array; the point is that updates to coll should affect initialItems
 // if that's the case.
-function addRemove(test, coll, initialItems, isBacking) {
+function addRemove(assert, coll, initialItems, isBacking) {
   let items = isBacking ? initialItems : initialItems.slice(0);
   let numInitialItems = items.length;
 
   // Test add(val).
   let numInsertions = 5;
   for (let i = 0; i < numInsertions; i++) {
-    compare(test, coll, items);
+    compare(assert, coll, items);
     coll.add(i);
     if (!isBacking)
       items.push(i);
   }
-  compare(test, coll, items);
+  compare(assert, coll, items);
 
   // Add the items we just added to make sure duplicates aren't added.
   for (let i = 0; i < numInsertions; i++)
     coll.add(i);
-  compare(test, coll, items);
+  compare(assert, coll, items);
 
   // Test remove(val).  Do a kind of shuffled remove.  Remove item 1, then
   // item 0, 3, 2, 5, 4, ...
   for (let i = 0; i < numInsertions; i++) {
     let val = i % 2 ? i - 1 :
               i === numInsertions - 1 ? i : i + 1;
     coll.remove(val);
     if (!isBacking)
       items.splice(items.indexOf(val), 1);
-    compare(test, coll, items);
+    compare(assert, coll, items);
   }
-  test.assertEqual(coll.length, numInitialItems,
-                   "All inserted items should be removed");
+  assert.equal(coll.length, numInitialItems,
+               "All inserted items should be removed");
 
   // Remove the items we just removed.  coll should be unchanged.
   for (let i = 0; i < numInsertions; i++)
     coll.remove(i);
-  compare(test, coll, items);
+  compare(assert, coll, items);
 
   // Test add and remove([val1, val2]).
   let newItems = [0, 1];
   coll.add(newItems);
-  compare(test, coll, isBacking ? items : items.concat(newItems));
+  compare(assert, coll, isBacking ? items : items.concat(newItems));
   coll.remove(newItems);
-  compare(test, coll, items);
-  test.assertEqual(coll.length, numInitialItems,
-                   "All inserted items should be removed");
+  compare(assert, coll, items);
+  assert.equal(coll.length, numInitialItems,
+               "All inserted items should be removed");
 }
 
 // Asserts that the items in coll are the items of array.
-function compare(test, coll, array) {
-  test.assertEqual(coll.length, array.length,
-                   "Collection length should be correct");
+function compare(assert, coll, array) {
+  assert.equal(coll.length, array.length,
+               "Collection length should be correct");
   let numItems = 0;
   for (let item in coll) {
-    test.assertEqual(item, array[numItems], "Items should be equal");
+    assert.equal(item, array[numItems], "Items should be equal");
     numItems++;
   }
-  test.assertEqual(numItems, array.length,
-                   "Number of items in iteration should be correct");
+  assert.equal(numItems, array.length,
+               "Number of items in iteration should be correct");
 }
 
 // Returns a new object with a collection property named "coll".  backingArray,
 // if defined, will create the collection with that backing array.
 function makeObjWithCollProp(backingArray) {
   let obj = {};
   collection.addCollectionProperty(obj, "coll", backingArray);
   return obj;
 }
+
+require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-context-menu.js
+++ b/addon-sdk/source/test/test-context-menu.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  'use strict';
 
 let { Cc, Ci } = require("chrome");
 
 require("sdk/context-menu");
--- a/addon-sdk/source/test/test-cortex.js
+++ b/addon-sdk/source/test/test-cortex.js
@@ -1,14 +1,12 @@
 /* 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/. */
 
-// vim:set ts=2 sw=2 sts=2
-
 "use strict";
 
 var Cortex = require("sdk/deprecated/cortex").Cortex;
 
 exports["test property changes propagate"] = function (assert) {
   var source = {
     _foo: "secret",
     get foo() {
--- a/addon-sdk/source/test/test-events.js
+++ b/addon-sdk/source/test/test-events.js
@@ -1,145 +1,144 @@
 /* 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 { LoaderWithHookedConsole } = require("sdk/test/loader");
 
 // Exposing private methods as public in order to test
 const EventEmitter = require('sdk/deprecated/events').EventEmitter.compose({
   listeners: function(type) this._listeners(type),
   emit: function() this._emit.apply(this, arguments),
   emitOnObject: function() this._emitOnObject.apply(this, arguments),
   removeAllListeners: function(type) this._removeAllListeners(type)
 });
 
-exports['test:add listeners'] = function(test) {
+exports['test:add listeners'] = function(assert) {
   let e = new EventEmitter();
 
   let events_new_listener_emited = [];
   let times_hello_emited = 0;
 
   e.on("newListener", function (event, listener) {
     events_new_listener_emited.push(event)
   })
 
   e.on("hello", function (a, b) {
     times_hello_emited += 1
-    test.assertEqual("a", a)
-    test.assertEqual("b", b)
-    test.assertEqual(this, e, '`this` pseudo-variable is bound to instance');
+    assert.equal("a", a)
+    assert.equal("b", b)
+    assert.equal(this, e, '`this` pseudo-variable is bound to instance');
   })
 
   e.emit("hello", "a", "b")
 };
 
-exports['test:removeListener'] = function(test) {
+exports['test:removeListener'] = function(assert) {
   let count = 0;
 
   function listener1 () {
     count++;
   }
   function listener2 () {
     count++;
   }
 
   // test adding and removing listener
   let e1 = new EventEmitter();
-  test.assertEqual(0, e1.listeners('hello').length);
+  assert.equal(0, e1.listeners('hello').length);
   e1.on("hello", listener1);
-  test.assertEqual(1, e1.listeners('hello').length);
-  test.assertEqual(listener1, e1.listeners('hello')[0]);
+  assert.equal(1, e1.listeners('hello').length);
+  assert.equal(listener1, e1.listeners('hello')[0]);
   e1.removeListener("hello", listener1);
-  test.assertEqual(0, e1.listeners('hello').length);
+  assert.equal(0, e1.listeners('hello').length);
   e1.emit("hello", "");
-  test.assertEqual(0, count);
+  assert.equal(0, count);
 
   // test adding one listener and removing another which was not added
   let e2 = new EventEmitter();
-  test.assertEqual(0, e2.listeners('hello').length);
+  assert.equal(0, e2.listeners('hello').length);
   e2.on("hello", listener1);
-  test.assertEqual(1, e2.listeners('hello').length);
+  assert.equal(1, e2.listeners('hello').length);
   e2.removeListener("hello", listener2);
-  test.assertEqual(1, e2.listeners('hello').length);
-  test.assertEqual(listener1, e2.listeners('hello')[0]);
+  assert.equal(1, e2.listeners('hello').length);
+  assert.equal(listener1, e2.listeners('hello')[0]);
   e2.emit("hello", "");
-  test.assertEqual(1, count);
+  assert.equal(1, count);
 
   // test adding 2 listeners, and removing one
   let e3 = new EventEmitter();
-  test.assertEqual(0, e3.listeners('hello').length);
+  assert.equal(0, e3.listeners('hello').length);
   e3.on("hello", listener1);
-  test.assertEqual(1, e3.listeners('hello').length);
+  assert.equal(1, e3.listeners('hello').length);
   e3.on("hello", listener2);
-  test.assertEqual(2, e3.listeners('hello').length);
+  assert.equal(2, e3.listeners('hello').length);
   e3.removeListener("hello", listener1);
-  test.assertEqual(1, e3.listeners('hello').length);
-  test.assertEqual(listener2, e3.listeners('hello')[0]);
+  assert.equal(1, e3.listeners('hello').length);
+  assert.equal(listener2, e3.listeners('hello')[0]);
   e3.emit("hello", "");
-  test.assertEqual(2, count);
+  assert.equal(2, count);
 };
 
-exports['test:removeAllListeners'] = function(test) {
+exports['test:removeAllListeners'] = function(assert) {
   let count = 0;
 
   function listener1 () {
     count++;
   }
   function listener2 () {
     count++;
   }
 
   // test adding a listener and removing all of that type
   let e1 = new EventEmitter();
   e1.on("hello", listener1);
-  test.assertEqual(1, e1.listeners('hello').length);
+  assert.equal(1, e1.listeners('hello').length);
   e1.removeAllListeners("hello");
-  test.assertEqual(0, e1.listeners('hello').length);
+  assert.equal(0, e1.listeners('hello').length);
   e1.emit("hello", "");
-  test.assertEqual(0, count);
+  assert.equal(0, count);
 
   // test adding a listener and removing all of another type
   let e2 = new EventEmitter();
   e2.on("hello", listener1);
-  test.assertEqual(1, e2.listeners('hello').length);
+  assert.equal(1, e2.listeners('hello').length);
   e2.removeAllListeners('goodbye');
-  test.assertEqual(1, e2.listeners('hello').length);
+  assert.equal(1, e2.listeners('hello').length);
   e2.emit("hello", "");
-  test.assertEqual(1, count);
+  assert.equal(1, count);
 
   // test adding 1+ listeners and removing all of that type
   let e3 = new EventEmitter();
   e3.on("hello", listener1);
-  test.assertEqual(1, e3.listeners('hello').length);
+  assert.equal(1, e3.listeners('hello').length);
   e3.on("hello", listener2);
-  test.assertEqual(2, e3.listeners('hello').length);
+  assert.equal(2, e3.listeners('hello').length);
   e3.removeAllListeners("hello");
-  test.assertEqual(0, e3.listeners('hello').length);
+  assert.equal(0, e3.listeners('hello').length);
   e3.emit("hello", "");
-  test.assertEqual(1, count);
+  assert.equal(1, count);
 
   // test adding 2 listeners for 2 types and removing all listeners
   let e4 = new EventEmitter();
   e4.on("hello", listener1);
-  test.assertEqual(1, e4.listeners('hello').length);
+  assert.equal(1, e4.listeners('hello').length);
   e4.on('goodbye', listener2);
-  test.assertEqual(1, e4.listeners('goodbye').length);
+  assert.equal(1, e4.listeners('goodbye').length);
   e4.emit("goodbye", "");
   e4.removeAllListeners();
-  test.assertEqual(0, e4.listeners('hello').length);
-  test.assertEqual(0, e4.listeners('goodbye').length);
+  assert.equal(0, e4.listeners('hello').length);
+  assert.equal(0, e4.listeners('goodbye').length);
   e4.emit("hello", "");
   e4.emit("goodbye", "");
-  test.assertEqual(2, count);
+  assert.equal(2, count);
 };
 
-exports['test: modify in emit'] = function(test) {
+exports['test: modify in emit'] = function(assert) {
   let callbacks_called = [ ];
   let e = new EventEmitter();
 
   function callback1() {
     callbacks_called.push("callback1");
     e.on("foo", callback2);
     e.on("foo", callback3);
     e.removeListener("foo", callback1);
@@ -149,116 +148,116 @@ exports['test: modify in emit'] = functi
     e.removeListener("foo", callback2);
   }
   function callback3() {
     callbacks_called.push("callback3");
     e.removeListener("foo", callback3);
   }
 
   e.on("foo", callback1);
-  test.assertEqual(1, e.listeners("foo").length);
+  assert.equal(1, e.listeners("foo").length);
 
   e.emit("foo");
-  test.assertEqual(2, e.listeners("foo").length);
-  test.assertEqual(1, callbacks_called.length);
-  test.assertEqual('callback1', callbacks_called[0]);
+  assert.equal(2, e.listeners("foo").length);
+  assert.equal(1, callbacks_called.length);
+  assert.equal('callback1', callbacks_called[0]);
 
   e.emit("foo");
-  test.assertEqual(0, e.listeners("foo").length);
-  test.assertEqual(3, callbacks_called.length);
-  test.assertEqual('callback1', callbacks_called[0]);
-  test.assertEqual('callback2', callbacks_called[1]);
-  test.assertEqual('callback3', callbacks_called[2]);
+  assert.equal(0, e.listeners("foo").length);
+  assert.equal(3, callbacks_called.length);
+  assert.equal('callback1', callbacks_called[0]);
+  assert.equal('callback2', callbacks_called[1]);
+  assert.equal('callback3', callbacks_called[2]);
 
   e.emit("foo");
-  test.assertEqual(0, e.listeners("foo").length);
-  test.assertEqual(3, callbacks_called.length);
-  test.assertEqual('callback1', callbacks_called[0]);
-  test.assertEqual('callback2', callbacks_called[1]);
-  test.assertEqual('callback3', callbacks_called[2]);
+  assert.equal(0, e.listeners("foo").length);
+  assert.equal(3, callbacks_called.length);
+  assert.equal('callback1', callbacks_called[0]);
+  assert.equal('callback2', callbacks_called[1]);
+  assert.equal('callback3', callbacks_called[2]);
 
   e.on("foo", callback1);
   e.on("foo", callback2);
-  test.assertEqual(2, e.listeners("foo").length);
+  assert.equal(2, e.listeners("foo").length);
   e.removeAllListeners("foo");
-  test.assertEqual(0, e.listeners("foo").length);
+  assert.equal(0, e.listeners("foo").length);
 
   // Verify that removing callbacks while in emit allows emits to propagate to
   // all listeners
   callbacks_called = [ ];
 
   e.on("foo", callback2);
   e.on("foo", callback3);
-  test.assertEqual(2, e.listeners("foo").length);
+  assert.equal(2, e.listeners("foo").length);
   e.emit("foo");
-  test.assertEqual(2, callbacks_called.length);
-  test.assertEqual('callback2', callbacks_called[0]);
-  test.assertEqual('callback3', callbacks_called[1]);
-  test.assertEqual(0, e.listeners("foo").length);
+  assert.equal(2, callbacks_called.length);
+  assert.equal('callback2', callbacks_called[0]);
+  assert.equal('callback3', callbacks_called[1]);
+  assert.equal(0, e.listeners("foo").length);
 };
 
-exports['test:adding same listener'] = function(test) {
+exports['test:adding same listener'] = function(assert) {
   function foo() {}
   let e = new EventEmitter();
   e.on("foo", foo);
   e.on("foo", foo);
-  test.assertEqual(
+  assert.equal(
     1,
     e.listeners("foo").length,
     "listener reregistration is ignored"
  );
 }
 
-exports['test:errors are reported if listener throws'] = function(test) {
+exports['test:errors are reported if listener throws'] = function(assert) {
   let e = new EventEmitter(),
       reported = false;
   e.on('error', function(e) reported = true)
   e.on('boom', function() { throw new Error('Boom!') });
   e.emit('boom', 3);
-  test.assert(reported, 'error should be reported through event');
+  assert.ok(reported, 'error should be reported through event');
 };
 
-exports['test:emitOnObject'] = function(test) {
+exports['test:emitOnObject'] = function(assert) {
   let e = new EventEmitter();
 
   e.on("foo", function() {
-    test.assertEqual(this, e, "`this` should be emitter");
+    assert.equal(this, e, "`this` should be emitter");
   });
   e.emitOnObject(e, "foo");
 
   e.on("bar", function() {
-    test.assertEqual(this, obj, "`this` should be other object");
+    assert.equal(this, obj, "`this` should be other object");
   });
   let obj = {};
   e.emitOnObject(obj, "bar");
 };
 
-exports['test:once'] = function(test) {
+exports['test:once'] = function(assert) {
   let e = new EventEmitter();
   let called = false;
 
   e.once('foo', function(value) {
-    test.assert(!called, "listener called only once");
-    test.assertEqual(value, "bar", "correct argument was passed");
+    assert.ok(!called, "listener called only once");
+    assert.equal(value, "bar", "correct argument was passed");
   });
 
   e.emit('foo', 'bar');
   e.emit('foo', 'baz');
 };
 
-exports["test:removing once"] = function(test) {
+exports["test:removing once"] = function(assert) {
   let e = require("sdk/deprecated/events").EventEmitterTrait.create();
-  e.once("foo", function() { test.pass("listener was called"); });
-  e.once("error", function() { test.fail("error event was emitted"); });
+  e.once("foo", function() { assert.pass("listener was called"); });
+  e.once("error", function() { assert.fail("error event was emitted"); });
   e._emit("foo", "bug-656684");
 };
 
 // Bug 726967: Ensure that `emit` doesn't do an infinite loop when `error`
 // listener throws an exception
-exports['test:emitLoop'] = function(test) {
+exports['test:emitLoop'] = function(assert) {
   // Override the console for this test so it doesn't log the exception to the
   // test output
   let { loader } = LoaderWithHookedConsole(module);
 
   let EventEmitter = loader.require('sdk/deprecated/events').EventEmitter.compose({
     listeners: function(type) this._listeners(type),
     emit: function() this._emit.apply(this, arguments),
     emitOnObject: function() this._emitOnObject.apply(this, arguments),
@@ -271,10 +270,12 @@ exports['test:emitLoop'] = function(test
     throw new Error("foo");
   });
 
   e.on("error", function() {
     throw new Error("error");
   });
   e.emit("foo");
 
-  test.pass("emit didn't looped");
+  assert.pass("emit didn't looped");
 };
+
+require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-globals.js
+++ b/addon-sdk/source/test/test-globals.js
@@ -1,22 +1,23 @@
 /* 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';
 
-Object.defineProperty(this, "global", { value: this });
+Object.defineProperty(this, 'global', { value: this });
 
-exports.testGlobals = function(test) {
+exports.testGlobals = function(assert) {
   // the only globals in module scope should be:
-  //   module, exports, require, dump, console
-  test.assertObject(module, "have 'module', good");
-  test.assertObject(exports, "have 'exports', good");
-  test.assertFunction(require, "have 'require', good");
-  test.assertFunction(dump, "have 'dump', good");
-  test.assertObject(console, "have 'console', good");
+  assert.equal(typeof module, 'object', 'have "module" global');
+  assert.equal(typeof exports, 'object', 'have "exports" global');
+  assert.equal(typeof require, 'function', 'have "require" global');
+  assert.equal(typeof dump, 'function', 'have "dump" global');
+  assert.equal(typeof console, 'object', 'have "console" global');
 
   // in particular, these old globals should no longer be present
-  test.assert(!('packaging' in global), "no 'packaging', good");
-  test.assert(!('memory' in global), "no 'memory', good");
+  assert.ok(!('packaging' in global), 'no "packaging" global was found');
+  assert.ok(!('memory' in global), 'no "memory" global was found');
 
-  test.assertMatches(module.uri, /test-globals\.js$/,
-                     'should contain filename');
+  assert.ok(/test-globals\.js$/.test(module.uri), 'should contain filename');
 };
+
+require("test").run(exports);
--- a/addon-sdk/source/test/test-hidden-frame.js
+++ b/addon-sdk/source/test/test-hidden-frame.js
@@ -1,12 +1,11 @@
 /* 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 { Loader } = require("sdk/test/loader");
 const hiddenFrames = require("sdk/frame/hidden-frame");
 const { HiddenFrame } = hiddenFrames;
 
 exports["test Frame"] = function(assert, done) {
   let url = "data:text/html;charset=utf-8,<!DOCTYPE%20html>";
@@ -39,17 +38,16 @@ exports["test frame removed properly"] =
       assert.ok(frame.parentNode, "frame has a parent node");
       hiddenFrames.remove(hiddenFrame);
       assert.ok(!frame.parentNode, "frame no longer has a parent node");
       done();
     }
   }));
 };
 
-
 exports["test unload detaches panels"] = function(assert, done) {
   let loader = Loader(module);
   let { add, remove, HiddenFrame } = loader.require("sdk/frame/hidden-frame");
   let frames = []
 
   function ready() {
     frames.push(this.element);
     if (frames.length === 2) complete();
@@ -65,11 +63,9 @@ exports["test unload detaches panels"] =
     loader.unload();
     frames.forEach(function(frame) {
       assert.ok(!frame.parentNode, "frame isn't in the document'");
     });
     done();
   }
 };
 
-
-
 require("test").run(exports);
--- a/addon-sdk/source/test/test-match-pattern.js
+++ b/addon-sdk/source/test/test-match-pattern.js
@@ -1,10 +1,8 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { MatchPattern } = require("sdk/util/match-pattern");
 
 exports.testMatchPatternTestTrue = function(test) {
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/test-method.js
@@ -0,0 +1,7 @@
+/* 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";
+
+module.exports = require("method/test/common");
--- a/addon-sdk/source/test/test-notifications.js
+++ b/addon-sdk/source/test/test-notifications.js
@@ -1,11 +1,9 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et filetype=javascript
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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 { Loader } = require('sdk/test/loader');
 
 exports.testOnClick = function (test) {
   let [loader, mockAlertServ] = makeLoader(module);
   let notifs = loader.require("sdk/notifications");
--- a/addon-sdk/source/test/test-panel.js
+++ b/addon-sdk/source/test/test-panel.js
@@ -127,34 +127,36 @@ exports["test Show Hide Panel"] = functi
 };
 
 exports["test Document Reload"] = function(assert, done) {
   const { Panel } = require('sdk/panel');
 
   let url2 = "data:text/html;charset=utf-8,page2";
   let content =
     "<script>" +
-    "window.addEventListener('message', function() {"+
-    "  window.location = '" + url2 + "';" +
+    "window.addEventListener('message', function({ data }) {"+
+    "  if (data == 'move') window.location = '" + url2 + "';" +
     '}, false);' +
     "</script>";
   let messageCount = 0;
   let panel = Panel({
     // using URL here is intentional, see bug 859009
     contentURL: URL("data:text/html;charset=utf-8," + encodeURIComponent(content)),
     contentScript: "self.postMessage(window.location.href);" +
                    // initiate change to url2
                    "self.port.once('move', function() document.defaultView.postMessage('move', '*'));",
     onMessage: function (message) {
       messageCount++;
       assert.notEqual(message, "about:blank", "about:blank is not a message " + messageCount);
 
       if (messageCount == 1) {
         assert.ok(/data:text\/html/.test(message), "First document had a content script; " + message);
         panel.port.emit('move');
+        assert.pass('move message was sent');
+        return;
       }
       else if (messageCount == 2) {
         assert.equal(message, url2, "Second document too; " + message);
         panel.destroy();
         done();
       }
     }
   });
--- a/addon-sdk/source/test/test-places-bookmarks.js
+++ b/addon-sdk/source/test/test-places-bookmarks.js
@@ -312,22 +312,22 @@ exports.testAddingToExistingParent = fun
   firstBatch, secondBatch;
 
   saveP(bookmarks).then(data => {
     firstBatch = data;
     return saveP([
       { title: 'moz4', url: 'http://moz4.com', type: 'bookmark', group: group },
       { title: 'moz5', url: 'http://moz5.com', type: 'bookmark', group: group }
     ]);
-  }, console.error).then(data => {
+  }, assert.fail).then(data => {
     secondBatch = data;
     assert.equal(firstBatch[0].group.id, secondBatch[0].group.id,
       'successfully saved to the same parent');
     done();
-  }, console.error);
+  }, assert.fail);
 };
 
 exports.testUpdateParent = function (assert, done) {
   let group = { type: 'group', title: 'mozgroup' };
   saveP(group).then(item => {
     item[0].title = 'mozgroup-resave';
     return saveP(item[0]);
   }).then(item => {
@@ -621,17 +621,17 @@ exports.testSearchByGroupSimple = functi
   }).then(results => {
     let groups = results.filter(({type}) => type === 'group');
     assert.equal(groups.length, 1, 'returns one subfolder');
     assert.equal(results.length, 6,
       'returns all children bookmarks/folders');
     assert.ok(results.filter(({url}) => url === 'http://w3schools.com/'),
       'returns nested children');
     done();
-  }).then(null, console.error);
+  }).then(null, assert.fail);
 };
 
 exports.testSearchByGroupComplex = function (assert, done) {
   let mozgroup;
   createBookmarkTree().then(results => {
     mozgroup = results.filter(({title}) => title === 'mozgroup')[0];
     return searchP({ group: mozgroup, query: 'javascript' });
   }).then(results => {
@@ -639,17 +639,17 @@ exports.testSearchByGroupComplex = funct
     assert.equal(results[0].url, 'http://w3schools.com/', 'correct result');
     return searchP({ group: mozgroup, url: '*.mozilla.org' });
   }).then(results => {
     assert.equal(results.length, 2, 'expected results');
     assert.ok(
       !results.filter(({url}) => /developer.mozilla/.test(url)).length,
       'does not find results from other folders');
     done();
-  }, console.error);
+  }, assert.fail);
 };
 
 exports.testSearchEmitters = function (assert, done) {
   createBookmarkTree().then(() => {
     let count = 0;
     search({ tags: ['mozilla', 'firefox'] }).on('data', data => {
       assert.ok(/mozilla|firefox/.test(data.title), 'one of the correct items');
       assert.ok(data.tags.has('firefox'), 'has firefox tag');
@@ -768,24 +768,24 @@ exports.testSearchQuery = function (asse
  * and if implementation changes, this could increase or decrease
  */
 
 exports.testCaching = function (assert, done) {
   let count = 0;
   let stream = filter(request, ({event}) =>
     /sdk-places-bookmarks-get/.test(event));
   on(stream, 'data', handle);
- 
+
   let group = { type: 'group', title: 'mozgroup' };
   let bookmarks = [
     { title: 'moz1', url: 'http://moz1.com', type: 'bookmark', group: group },
     { title: 'moz2', url: 'http://moz2.com', type: 'bookmark', group: group },
     { title: 'moz3', url: 'http://moz3.com', type: 'bookmark', group: group }
   ];
-  
+
   /*
    * Use timeout in tests since the platform calls are synchronous
    * and the counting event shim may not have occurred yet
    */
 
   saveP(bookmarks).then(() => {
     assert.equal(count, 0, 'all new items and root group, no fetches should occur');
     count = 0;
@@ -811,17 +811,17 @@ exports.testCaching = function (assert, 
 };
 
 /*
  * Search Query Options
  */
 
 exports.testSearchCount = function (assert, done) {
   let max = 8;
-  createBookmarkTree()  
+  createBookmarkTree()
   .then(testCount(1))
   .then(testCount(2))
   .then(testCount(3))
   .then(testCount(5))
   .then(testCount(10))
   .then(() => {
     done();
   });
@@ -837,17 +837,17 @@ exports.testSearchCount = function (asse
   }
 };
 
 exports.testSearchSort = function (assert, done) {
   let urls = [
     'http://mozilla.com/', 'http://webaud.io/', 'http://mozilla.com/webfwd/',
     'http://developer.mozilla.com/', 'http://bandcamp.com/'
   ];
-  
+
   saveP(
     urls.map(url =>
       Bookmark({ url: url, title: url.replace(/http:\/\/|\//g,'')}))
   ).then(() => {
     return searchP({}, { sort: 'title' });
   }).then(results => {
     checkOrder(results, [4,3,0,2,1]);
     return searchP({}, { sort: 'title', descending: true });
@@ -863,17 +863,17 @@ exports.testSearchSort = function (asser
   }).then(() =>
     saveP(Bookmark({ url: 'http://github.com', title: 'github.com' }))
   ).then(() => addVisits('http://bandcamp.com/'))
   .then(() => searchP({ query: 'webfwd' }))
   .then(results => {
     results[0].title = 'new title for webfwd';
     return saveP(results[0]);
   })
-  .then(() => 
+  .then(() =>
     searchP({}, { sort: 'visitCount' })
   ).then(results => {
     assert.equal(results[5].url, 'http://mozilla.com/',
       'last entry is the highest visit count');
     return searchP({}, { sort: 'visitCount', descending: true });
   }).then(results => {
     assert.equal(results[0].url, 'http://mozilla.com/',
       'first entry is the highest visit count');
@@ -899,17 +899,17 @@ exports.testSearchSort = function (asser
       'last modified should be last');
     return searchP({}, { sort: 'lastModified', descending: true });
   }).then(results => {
     assert.equal(results[0].url, 'http://mozilla.com/webfwd/',
       'last modified should be first');
   }).then(() => {
     done();
   });
-  
+
   function checkOrder (results, nums) {
     assert.equal(results.length, nums.length, 'expected return count');
     for (let i = 0; i < nums.length; i++) {
       assert.equal(results[i].url, urls[nums[i]], 'successful order');
     }
   }
 };
 
--- a/addon-sdk/source/test/test-places-host.js
+++ b/addon-sdk/source/test/test-places-host.js
@@ -41,17 +41,17 @@ exports.testBookmarksCreate = function (
   }, {
     title: 'my folder',
     type: 'group',
     group: bmsrv.bookmarksMenuFolder
   }, {
     type: 'separator',
     group: bmsrv.unfiledBookmarksFolder
   }];
-  
+
   all(items.map(function (item) {
     return send('sdk-places-bookmarks-create', item).then(function (data) {
       compareWithHost(assert, data);
     }, invalidReject(assert));
   })).then(function () {
     done();
   }, invalidReject(assert));
 };
@@ -106,17 +106,17 @@ exports.testBookmarkRemove = function (a
     compareWithHost(assert, data); // ensure bookmark exists
     bmsrv.getItemTitle(id); // does not throw an error
     return send('sdk-places-bookmarks-remove', data);
   }).then(function () {
     assert.throws(function () {
       bmsrv.getItemTitle(id);
     }, 'item should no longer exist');
     done();
-  }, console.error);
+  }, assert.fail);
 };
 
 exports.testBookmarkGet = function (assert, done) {
   let bookmark;
   createBookmark({
     url: 'http://test-places-host.com/testBookmarkGet/'
   }).then(function (data) {
     bookmark = data;
@@ -222,25 +222,25 @@ exports.testHostQuery = function (assert
     }),
     createBookmark({
       url: 'http://mozilla.com/testHostQuery/',
       tags: ['mozilla']
     }),
     createBookmark({ url: 'http://thunderbird.com/testHostQuery/' })
   ]).then(data => {
     return send('sdk-places-query', {
-      queries: { tags: ['mozilla'] }, 
+      queries: { tags: ['mozilla'] },
       options: { sortingMode: 6, queryType: 1 } // sort by URI ascending, bookmarks only
     });
   }).then(results => {
     assert.equal(results.length, 2, 'should only return two');
     assert.equal(results[0].url,
       'http://mozilla.com/testHostQuery/', 'is sorted by URI asc');
     return send('sdk-places-query', {
-      queries: { tags: ['mozilla'] }, 
+      queries: { tags: ['mozilla'] },
       options: { sortingMode: 5, queryType: 1 } // sort by URI descending, bookmarks only
     });
   }).then(results => {
     assert.equal(results.length, 2, 'should only return two');
     assert.equal(results[0].url,
       'http://firefox.com/testHostQuery/', 'is sorted by URI desc');
     done();
   });
@@ -274,22 +274,22 @@ exports.testHostMultiQuery = function (a
     });
   }).then(results => {
     assert.equal(results.length, 0, 'query props should be AND\'d');
     done();
   });
 };
 
 exports.testGetAllBookmarks = function (assert, done) {
-  createBookmarkTree().then(() => { 
+  createBookmarkTree().then(() => {
     return send('sdk-places-bookmarks-get-all', {});
   }).then(res => {
     assert.equal(res.length, 8, 'all bookmarks returned');
     done();
-  }, console.error);
+  }, assert.fail);
 };
 
 exports.testGetAllChildren = function (assert, done) {
   createBookmarkTree().then(results => {
     return send('sdk-places-bookmarks-get-children', {
       id: results.filter(({title}) => title === 'mozgroup')[0].id
     });
   }).then(results => {
--- a/addon-sdk/source/test/test-plain-text-console.js
+++ b/addon-sdk/source/test/test-plain-text-console.js
@@ -11,106 +11,106 @@ const { loadSubScript } = Cc['@mozilla.o
 const ADDON_LOG_LEVEL_PREF = "extensions." + id + ".sdk.console.logLevel";
 const SDK_LOG_LEVEL_PREF = "extensions.sdk.console.logLevel";
 
 const HAS_ORIGINAL_ADDON_LOG_LEVEL = prefs.has(ADDON_LOG_LEVEL_PREF);
 const ORIGINAL_ADDON_LOG_LEVEL = prefs.get(ADDON_LOG_LEVEL_PREF);
 const HAS_ORIGINAL_SDK_LOG_LEVEL = prefs.has(SDK_LOG_LEVEL_PREF);
 const ORIGINAL_SDK_LOG_LEVEL = prefs.get(SDK_LOG_LEVEL_PREF);
 
-exports.testPlainTextConsole = function(test) {
-  var prints = [];
+exports.testPlainTextConsole = function(assert) {
+  let prints = [];
   function print(message) {
     prints.push(message);
   }
   function lastPrint() {
-    var last = prints.slice(-1)[0];
+    let last = prints.slice(-1)[0];
     prints = [];
     return last;
   }
 
   prefs.set(SDK_LOG_LEVEL_PREF, "all");
   prefs.reset(ADDON_LOG_LEVEL_PREF);
 
-  var Console = require("sdk/console/plain-text").PlainTextConsole;
-  var con = new Console(print);
+  let Console = require("sdk/console/plain-text").PlainTextConsole;
+  let con = new Console(print);
 
-  test.pass("PlainTextConsole instantiates");
+  assert.ok("PlainTextConsole instantiates");
 
   con.log('testing', 1, [2, 3, 4]);
-  test.assertEqual(lastPrint(), "console.log: " + name + ": testing 1 Array [2,3,4]\n",
+  assert.equal(lastPrint(), "console.log: " + name + ": testing 1 Array [2,3,4]\n",
                    "PlainTextConsole.log() must work.");
 
   con.info('testing', 1, [2, 3, 4]);
-  test.assertEqual(lastPrint(), "console.info: " + name + ": testing 1 Array [2,3,4]\n",
+  assert.equal(lastPrint(), "console.info: " + name + ": testing 1 Array [2,3,4]\n",
                    "PlainTextConsole.info() must work.");
 
   con.warn('testing', 1, [2, 3, 4]);
-  test.assertEqual(lastPrint(), "console.warn: " + name + ": testing 1 Array [2,3,4]\n",
+  assert.equal(lastPrint(), "console.warn: " + name + ": testing 1 Array [2,3,4]\n",
                    "PlainTextConsole.warn() must work.");
 
   con.error('testing', 1, [2, 3, 4]);
-  test.assertEqual(prints[0], "console.error: " + name + ": \n",
+  assert.equal(prints[0], "console.error: " + name + ": \n",
                    "PlainTextConsole.error() must work.");
-  test.assertEqual(prints[1], "  testing\n")
-  test.assertEqual(prints[2], "  1\n")
-  test.assertEqual(prints[3], "Array\n    - 0 = 2\n    - 1 = 3\n    - 2 = 4\n    - length = 3\n");
+  assert.equal(prints[1], "  testing\n")
+  assert.equal(prints[2], "  1\n")
+  assert.equal(prints[3], "Array\n    - 0 = 2\n    - 1 = 3\n    - 2 = 4\n    - length = 3\n");
   prints = [];
 
   con.debug('testing', 1, [2, 3, 4]);
-  test.assertEqual(prints[0], "console.debug: " + name + ": \n",
+  assert.equal(prints[0], "console.debug: " + name + ": \n",
                    "PlainTextConsole.debug() must work.");
-  test.assertEqual(prints[1], "  testing\n")
-  test.assertEqual(prints[2], "  1\n")
-  test.assertEqual(prints[3], "Array\n    - 0 = 2\n    - 1 = 3\n    - 2 = 4\n    - length = 3\n");
+  assert.equal(prints[1], "  testing\n")
+  assert.equal(prints[2], "  1\n")
+  assert.equal(prints[3], "Array\n    - 0 = 2\n    - 1 = 3\n    - 2 = 4\n    - length = 3\n");
   prints = [];
 
   con.log('testing', undefined);
-  test.assertEqual(lastPrint(), "console.log: " + name + ": testing undefined\n",
+  assert.equal(lastPrint(), "console.log: " + name + ": testing undefined\n",
                    "PlainTextConsole.log() must stringify undefined.");
 
   con.log('testing', null);
-  test.assertEqual(lastPrint(), "console.log: " + name + ": testing null\n",
+  assert.equal(lastPrint(), "console.log: " + name + ": testing null\n",
                    "PlainTextConsole.log() must stringify null.");
 
   // TODO: Fix console.jsm to detect custom toString.
   con.log("testing", { toString: function() "obj.toString()" });
-  test.assertEqual(lastPrint(), "console.log: " + name + ": testing {}\n",
+  assert.equal(lastPrint(), "console.log: " + name + ": testing {}\n",
                    "PlainTextConsole.log() doesn't printify custom toString.");
 
   con.log("testing", { toString: function() { throw "fail!"; } });
-  test.assertEqual(lastPrint(), "console.log: " + name + ": testing {}\n",
+  assert.equal(lastPrint(), "console.log: " + name + ": testing {}\n",
                    "PlainTextConsole.log() must stringify custom bad toString.");
 
-  
+
   con.exception(new Error("blah"));
 
-  
-  test.assertEqual(prints[0], "console.error: " + name + ": \n");
+
+  assert.equal(prints[0], "console.error: " + name + ": \n");
   let tbLines = prints[1].split("\n");
-  test.assertEqual(tbLines[0], "  Message: Error: blah");
-  test.assertEqual(tbLines[1], "  Stack:");
-  test.assert(prints[1].indexOf(module.uri + ":84") !== -1);
+  assert.equal(tbLines[0], "  Message: Error: blah");
+  assert.equal(tbLines[1], "  Stack:");
+  assert.ok(prints[1].indexOf(module.uri + ":84") !== -1);
   prints = []
 
   try {
     loadSubScript("invalid-url", {});
-    test.fail("successed in calling loadSubScript with invalid-url");
+    assert.fail("successed in calling loadSubScript with invalid-url");
   }
   catch(e) {
     con.exception(e);
   }
-  test.assertEqual(prints[0], "console.error: " + name + ": \n");
-  test.assertEqual(prints[1], "  Error creating URI (invalid URL scheme?)\n");
+  assert.equal(prints[0], "console.error: " + name + ": \n");
+  assert.equal(prints[1], "  Error creating URI (invalid URL scheme?)\n");
   prints = [];
 
   con.trace();
   let tbLines = prints[0].split("\n");
-  test.assertEqual(tbLines[0], "console.trace: " + name + ": ");
-  test.assert(tbLines[1].indexOf("_ain-text-console.js 105") == 0);
+  assert.equal(tbLines[0], "console.trace: " + name + ": ");
+  assert.ok(tbLines[1].indexOf("_ain-text-console.js 105") == 0);
   prints = [];
 
   // Whether or not console methods should print at the various log levels,
   // structured as a hash of levels, each of which contains a hash of methods,
   // each of whose value is whether or not it should print, i.e.:
   // { [level]: { [method]: [prints?], ... }, ... }.
   let levels = {
     all:   { debug: true,  log: true,  info: true,  warn: true,  error: true  },
@@ -135,40 +135,111 @@ exports.testPlainTextConsole = function(
     for (let method in methods) {
       // We have to reset the log level pref each time we run the test
       // because the test runner relies on the console to print test output,
       // and test results would not get printed to the console for some
       // values of the pref.
       prefs.set(SDK_LOG_LEVEL_PREF, level);
       con[method]("");
       prefs.set(SDK_LOG_LEVEL_PREF, "all");
-      test.assertEqual(prints.join(""), 
+      assert.equal(prints.join(""),
                        (methods[method] ? messages[method] : ""),
                        "at log level '" + level + "', " + method + "() " +
                        (methods[method] ? "prints" : "doesn't print"));
       prints = [];
     }
   }
 
   prefs.set(SDK_LOG_LEVEL_PREF, "off");
   prefs.set(ADDON_LOG_LEVEL_PREF, "all");
   con.debug("");
-  test.assertEqual(prints.join(""), messages["debug"],
+  assert.equal(prints.join(""), messages["debug"],
                    "addon log level 'all' overrides SDK log level 'off'");
   prints = [];
 
   prefs.set(SDK_LOG_LEVEL_PREF, "all");
   prefs.set(ADDON_LOG_LEVEL_PREF, "off");
   con.error("");
   prefs.reset(ADDON_LOG_LEVEL_PREF);
-  test.assertEqual(lastPrint(), null,
+  assert.equal(lastPrint(), null,
                    "addon log level 'off' overrides SDK log level 'all'");
 
+  restorePrefs();
+};
+
+exports.testPlainTextConsoleBoundMethods = function(assert) {
+  let prints = [];
+  function print(message) {
+    prints.push(message);
+  }
+  function lastPrint() {
+    let last = prints.slice(-1)[0];
+    prints = [];
+    return last;
+  }
+
+  prefs.set(SDK_LOG_LEVEL_PREF, "all");
+  prefs.reset(ADDON_LOG_LEVEL_PREF);
+
+  let Console = require("sdk/console/plain-text").PlainTextConsole;
+  let { log, info, warn, error, debug, exception, trace } = new Console(print);
+
+  assert.ok("PlainTextConsole instantiates");
+
+  log('testing', 1, [2, 3, 4]);
+  assert.equal(lastPrint(), "console.log: " + name + ": testing 1 Array [2,3,4]\n",
+                   "PlainTextConsole.log() must work.");
+
+  info('testing', 1, [2, 3, 4]);
+  assert.equal(lastPrint(), "console.info: " + name + ": testing 1 Array [2,3,4]\n",
+                   "PlainTextConsole.info() must work.");
+
+  warn('testing', 1, [2, 3, 4]);
+  assert.equal(lastPrint(), "console.warn: " + name + ": testing 1 Array [2,3,4]\n",
+                   "PlainTextConsole.warn() must work.");
+
+  error('testing', 1, [2, 3, 4]);
+  assert.equal(prints[0], "console.error: " + name + ": \n",
+                   "PlainTextConsole.error() must work.");
+  assert.equal(prints[1], "  testing\n")
+  assert.equal(prints[2], "  1\n")
+  assert.equal(prints[3], "Array\n    - 0 = 2\n    - 1 = 3\n    - 2 = 4\n    - length = 3\n");
+  prints = [];
+
+  debug('testing', 1, [2, 3, 4]);
+  assert.equal(prints[0], "console.debug: " + name + ": \n",
+                   "PlainTextConsole.debug() must work.");
+  assert.equal(prints[1], "  testing\n")
+  assert.equal(prints[2], "  1\n")
+  assert.equal(prints[3], "Array\n    - 0 = 2\n    - 1 = 3\n    - 2 = 4\n    - length = 3\n");
+  prints = [];
+
+  exception(new Error("blah"));
+
+  assert.equal(prints[0], "console.error: " + name + ": \n");
+  let tbLines = prints[1].split("\n");
+  assert.equal(tbLines[0], "  Message: Error: blah");
+  assert.equal(tbLines[1], "  Stack:");
+  assert.ok(prints[1].indexOf(module.uri + ":215") !== -1);
+  prints = []
+
+  trace();
+  let tbLines = prints[0].split("\n");
+  assert.equal(tbLines[0], "console.trace: " + name + ": ");
+  assert.ok(tbLines[1].indexOf("_ain-text-console.js 224") === 0);
+  prints = [];
+
+  restorePrefs();
+};
+
+function restorePrefs() {
   if (HAS_ORIGINAL_ADDON_LOG_LEVEL)
     prefs.set(ADDON_LOG_LEVEL_PREF, ORIGINAL_ADDON_LOG_LEVEL);
   else
     prefs.reset(ADDON_LOG_LEVEL_PREF);
 
   if (HAS_ORIGINAL_SDK_LOG_LEVEL)
     prefs.set(SDK_LOG_LEVEL_PREF, ORIGINAL_SDK_LOG_LEVEL);
   else
     prefs.reset(SDK_LOG_LEVEL_PREF);
-};
+}
+
+require("test").run(exports);
--- a/addon-sdk/source/test/test-promise.js
+++ b/addon-sdk/source/test/test-promise.js
@@ -1,12 +1,11 @@
-/* vim:set ts=2 sw=2 sts=2 expandtab */
-/*jshint asi: true undef: true es5: true node: true devel: true
-         forin: true */
-/*global define: true */
+/* 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';
 
 var core = require('sdk/core/promise'),
     defer = core.defer, resolve = core.resolve, reject = core.reject, all = core.all,
     promised = core.promised;
 
 var { setTimeout } = require('sdk/timers');
--- a/addon-sdk/source/test/test-self.js
+++ b/addon-sdk/source/test/test-self.js
@@ -1,65 +1,65 @@
 /* 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 {Cc, Ci, Cu, Cm, components} = require('chrome');
-Cu.import("resource://gre/modules/AddonManager.jsm", this);
+const { Cc, Ci, Cu, Cm, components } = require("chrome");
 const xulApp = require("sdk/system/xul-app");
+const self = require("sdk/self");
 
-exports.testSelf = function(test) {
-  var self = require("sdk/self");
+const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
 
+exports.testSelf = function(assert) {
   var source = self.data.load("test-content-symbiont.js");
-  test.assert(source.match(/test-content-symbiont/), "self.data.load() works");
+  assert.ok(source.match(/test-content-symbiont/), "self.data.load() works");
 
   // Likewise, we can't assert anything about the full URL, because that
   // depends on self.id . We can only assert that it ends in the right
   // thing.
   var url = self.data.url("test-content-symbiont.js");
-  test.assertEqual(typeof(url), "string", "self.data.url('x') returns string");
-  test.assertEqual(/\/test-content-symbiont\.js$/.test(url), true);
+  assert.equal(typeof(url), "string", "self.data.url('x') returns string");
+  assert.equal(/\/test-content-symbiont\.js$/.test(url), true);
 
   // Make sure 'undefined' is not in url when no string is provided.
   url = self.data.url();
-  test.assertEqual(typeof(url), "string", "self.data.url() returns string");
-  test.assertEqual(/\/undefined$/.test(url), false);
+  assert.equal(typeof(url), "string", "self.data.url() returns string");
+  assert.equal(/\/undefined$/.test(url), false);
 
   // When tests are run on just the api-utils package, self.name is
   // api-utils. When they're run as 'cfx testall', self.name is testpkgs.
-  test.assert(self.name == "addon-sdk", "self.name is addon-sdk");
+  assert.equal(self.name, "addon-sdk", "self.name is addon-sdk");
 
   // loadReason may change here, as we change the way tests addons are installed
   // Bug 854937 fixed loadReason and is now install
   let testLoadReason = xulApp.versionInRange(xulApp.platformVersion,
                                              "23.0a1", "*") ? "install"
                                                             : "startup";
-  test.assertEqual(self.loadReason, testLoadReason,
-                   "self.loadReason is either startup or install on test runs");
+  assert.equal(self.loadReason, testLoadReason,
+               "self.loadReason is either startup or install on test runs");
 
-  test.assertEqual(self.isPrivateBrowsingSupported, false,
-                   'usePrivateBrowsing property is false by default');
+  assert.equal(self.isPrivateBrowsingSupported, false,
+               'usePrivateBrowsing property is false by default');
 };
 
-exports.testSelfID = function(test) {
-  test.waitUntilDone();
-
+exports.testSelfID = function(assert, done) {
   var self = require("sdk/self");
   // We can't assert anything about the ID inside the unit test right now,
   // because the ID we get depends upon how the test was invoked. The idea
   // is that it is supposed to come from the main top-level package's
   // package.json file, from the "id" key.
-  test.assertEqual(typeof(self.id), "string", "self.id is a string");
-  test.assert(self.id.length > 0);
+  assert.equal(typeof(self.id), "string", "self.id is a string");
+  assert.ok(self.id.length > 0);
 
   AddonManager.getAddonByID(self.id, function(addon) {
     if (!addon) {
-      test.fail("did not find addon with self.id");
+      assert.fail("did not find addon with self.id");
     }
     else {
-      test.pass("found addon with self.id");
+      assert.pass("found addon with self.id");
     }
-    test.done();
+
+    done();
   });
 }
+
+require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-simple-storage.js
+++ b/addon-sdk/source/test/test-simple-storage.js
@@ -1,11 +1,9 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et filetype=javascript
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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 file = require("sdk/io/file");
 const prefs = require("sdk/preferences/service");
 
 const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota";
 
--- a/addon-sdk/source/test/test-system-runtime.js
+++ b/addon-sdk/source/test/test-system-runtime.js
@@ -1,13 +1,11 @@
 /* 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/.
- */
-
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 var runtime = require("sdk/system/runtime");
 
 exports["test system runtime"] = function(assert) {
   assert.equal(typeof(runtime.inSafeMode), "boolean",
                "inSafeMode is boolean");
   assert.equal(typeof(runtime.OS), "string",
--- a/addon-sdk/source/test/test-text-streams.js
+++ b/addon-sdk/source/test/test-text-streams.js
@@ -1,11 +1,9 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim:set ts=2 sw=2 sts=2 et filetype=javascript
- * This Source Code Form is subject to the terms of the Mozilla Public
+/* 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 file = require("sdk/io/file");
 const { pathFor } = require("sdk/system");
 const { Loader } = require("sdk/test/loader");
 
 const STREAM_CLOSED_ERROR = "The stream is closed and cannot be used.";
--- a/addon-sdk/source/test/test-traits-core.js
+++ b/addon-sdk/source/test/test-traits-core.js
@@ -1,75 +1,76 @@
 /* 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";
+'use strict';
 
 const ERR_CONFLICT = 'Remaining conflicting property: ',
       ERR_REQUIRED = 'Missing required property: ';
 
-function assertSametrait(test, trait1, trait2) {
+function assertSametrait(assert, trait1, trait2) {
   let names1 = Object.getOwnPropertyNames(trait1),
       names2 = Object.getOwnPropertyNames(trait2);
 
-  test.assertEqual(
+  assert.equal(
     names1.length,
     names2.length,
     'equal traits must have same amount of properties'
   );
 
   for (let i = 0; i < names1.length; i++) {
     let name = names1[i];
-    test.assertNotEqual(
+    assert.notEqual(
       -1,
       names2.indexOf(name),
       'equal traits must contain same named properties: ' + name
     );
-    assertSameDescriptor(test, name, trait1[name], trait2[name]);
+    assertSameDescriptor(assert, name, trait1[name], trait2[name]);
   }
 }
 
-function assertSameDescriptor(test, name, desc1, desc2) {
+function assertSameDescriptor(assert, name, desc1, desc2) {
   if (desc1.conflict || desc2.conflict) {
-    test.assertEqual(
+    assert.equal(
       desc1.conflict,
       desc2.conflict,
       'if one of same descriptors has `conflict` another must have it: '
         + name
     );
-  } else if (desc1.required || desc2.required) {
-    test.assertEqual(
+  }
+  else if (desc1.required || desc2.required) {
+    assert.equal(
       desc1.required,
       desc2.required,
       'if one of same descriptors is has `required` another must have it: '
         + name
     );
-  } else {
-    test.assertEqual(
+  }
+  else {
+    assert.equal(
       desc1.get,
       desc2.get,
       'get must be the same on both descriptors: ' + name
     );
-    test.assertEqual(
+    assert.equal(
       desc1.set,
       desc2.set,
       'set must be the same on both descriptors: ' + name
     );
-    test.assertEqual(
+    assert.equal(
       desc1.value,
       desc2.value,
       'value must be the same on both descriptors: ' + name
     );
-    test.assertEqual(
+    assert.equal(
       desc1.enumerable,
       desc2.enumerable,
       'enumerable must be the same on both descriptors: ' + name
     );
-    test.assertEqual(
+    assert.equal(
       desc1.required,
       desc2.required,
       'value must be the same on both descriptors: ' + name
     );
   }
 }
 
 function Data(value, enumerable, confligurable, writable) {
@@ -118,199 +119,202 @@ function Conflict(name) {
 }
 
 function testMethod() {};
 
 const { trait, compose, resolve, required, override, create } =
   require('sdk/deprecated/traits/core');
 
 
-exports['test:empty trait'] = function(test) {
+exports['test:empty trait'] = function(assert) {
   assertSametrait(
-    test,
+    assert,
     trait({}),
     {}
   );
 };
 
-exports['test:simple trait'] = function(test) {
+exports['test:simple trait'] = function(assert) {
   assertSametrait(
-    test,
+    assert,
     trait({
       a: 0,
       b: testMethod
     }),
     {
       a: Data(0, true, true, true),
       b: Method(testMethod, true, true, true)
     }
   );
 };
 
-exports['test:simple trait with required prop'] = function(test) {
+exports['test:simple trait with required prop'] = function(assert) {
   assertSametrait(
-    test,
+    assert,
     trait({
       a: required,
       b: 1
     }),
     {
       a: Required('a'),
       b: Data(1)
     }
   );
 };
 
-exports['test:ordering of trait properties is irrelevant'] = function(test) {
-  assertSametrait(test,
+exports['test:ordering of trait properties is irrelevant'] = function(assert) {
+  assertSametrait(
+    assert,
     trait({ a: 0, b: 1, c: required }),
     trait({ b: 1, c: required, a: 0 })
   );
 };
 
-exports['test:trait with accessor property'] = function(test) {
+exports['test:trait with accessor property'] = function(assert) {
   let record = { get a() {}, set a(v) {} };
   let get = Object.getOwnPropertyDescriptor(record,'a').get;
   let set = Object.getOwnPropertyDescriptor(record,'a').set;
-  assertSametrait(test,
+  assertSametrait(assert,
     trait(record),
     { a: Accessor(get, set ) }
   );
 };
 
-exports['test:simple composition'] = function(test) {
-  assertSametrait(test,
+exports['test:simple composition'] = function(assert) {
+  assertSametrait(
+    assert,
     compose(
       trait({ a: 0, b: 1 }),
       trait({ c: 2, d: testMethod })
     ),
     {
       a: Data(0),
       b: Data(1),
       c: Data(2),
       d: Method(testMethod)
     }
   );
 };
 
-exports['test:composition with conflict'] = function(test) {
-  assertSametrait(test,
+exports['test:composition with conflict'] = function(assert) {
+  assertSametrait(
+    assert,
     compose(
       trait({ a: 0, b: 1 }),
       trait({ a: 2, c: testMethod })
     ),
     {
       a: Conflict('a'),
       b: Data(1),
       c: Method(testMethod)
     }
   );
 };
 
 exports['test:composition of identical props does not cause conflict'] =
-function(test) {
-  assertSametrait(test,
+function(assert) {
+  assertSametrait(assert,
     compose(
       trait({ a: 0, b: 1 }),
       trait({ a: 0, c: testMethod })
     ),
     {
       a: Data(0),
       b: Data(1),
       c: Method(testMethod) }
   )
 };
 
 exports['test:composition with identical required props'] =
-function(test) {
-  assertSametrait(test,
+function(assert) {
+  assertSametrait(assert,
     compose(
       trait({ a: required, b: 1 }),
       trait({ a: required, c: testMethod })
     ),
     {
       a: Required(),
       b: Data(1),
       c: Method(testMethod)
     }
   );
 };
 
-exports['test:composition satisfying a required prop'] = function (test) {
-  assertSametrait(test,
+exports['test:composition satisfying a required prop'] = function (assert) {
+  assertSametrait(assert,
     compose(
       trait({ a: required, b: 1 }),
       trait({ a: testMethod })
     ),
     {
       a: Method(testMethod),
       b: Data(1)
     }
   );
 };
 
-exports['test:compose is neutral wrt conflicts'] = function (test) {
-  assertSametrait(test,
+exports['test:compose is neutral wrt conflicts'] = function (assert) {
+  assertSametrait(assert,
     compose(
       compose(
         trait({ a: 1 }),
         trait({ a: 2 })
       ),
       trait({ b: 0 })
     ),
     {
       a: Conflict('a'),
       b: Data(0)
     }
   );
 };
 
-exports['test:conflicting prop overrides required prop'] = function (test) {
-  assertSametrait(test,
+exports['test:conflicting prop overrides required prop'] = function (assert) {
+  assertSametrait(assert,
     compose(
       compose(
         trait({ a: 1 }),
         trait({ a: 2 })
       ),
       trait({ a: required })
     ),
     {
       a: Conflict('a')
     }
   );
 };
 
-exports['test:compose is commutative'] = function (test) {
-  assertSametrait(test,
+exports['test:compose is commutative'] = function (assert) {
+  assertSametrait(assert,
     compose(
       trait({ a: 0, b: 1 }),
       trait({ c: 2, d: testMethod })
     ),
     compose(
       trait({ c: 2, d: testMethod }),
       trait({ a: 0, b: 1 })
     )
   );
 };
 
 exports['test:compose is commutative, also for required/conflicting props'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     compose(
       trait({ a: 0, b: 1, c: 3, e: required }),
       trait({ c: 2, d: testMethod })
     ),
     compose(
       trait({ c: 2, d: testMethod }),
       trait({ a: 0, b: 1, c: 3, e: required })
     )
   );
 };
-exports['test:compose is associative'] = function (test) {
-  assertSametrait(test,
+exports['test:compose is associative'] = function (assert) {
+  assertSametrait(assert,
     compose(
       trait({ a: 0, b: 1, c: 3, d: required }),
       compose(
         trait({ c: 3, d: required }),
         trait({ c: 2, d: testMethod, e: 'foo' })
       )
     ),
     compose(
@@ -319,18 +323,18 @@ exports['test:compose is associative'] =
         trait({ c: 3, d: required })
       ),
       trait({ c: 2, d: testMethod, e: 'foo' })
     )
   );
 };
 
 exports['test:diamond import of same prop does not generate conflict'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     compose(
       compose(
         trait({ b: 2 }),
         trait({ a: 1 })
       ),
       compose(
         trait({ c: 3 }),
         trait({ a: 1 })
@@ -342,371 +346,371 @@ function (test) {
       b: Data(2),
       c: Data(3),
       d: Data(4)
     }
   );
 };
 
 exports['test:resolve with empty resolutions has no effect'] =
-function (test) {
-  assertSametrait(test, resolve({}, trait({
+function (assert) {
+  assertSametrait(assert, resolve({}, trait({
     a: 1,
     b: required,
     c: testMethod
   })), {
     a: Data(1),
     b: Required(),
     c: Method(testMethod)
   });
 };
 
-exports['test:resolve: renaming'] = function (test) {
-  assertSametrait(test,
+exports['test:resolve: renaming'] = function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: 'A', c: 'C' },
       trait({ a: 1, b: required, c: testMethod })
     ),
     {
       A: Data(1),
       b: Required(),
       C: Method(testMethod),
       a: Required(),
       c: Required()
     }
   );
 };
 
 exports['test:resolve: renaming to conflicting name causes conflict, order 1']
-= function (test) {
-  assertSametrait(test,
+= function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: 'b'},
       trait({ a: 1, b: 2 })
     ),
     {
       b: Conflict('b'),
       a: Required()
     }
   );
 };
 
 exports['test:resolve: renaming to conflicting name causes conflict, order 2']
-= function (test) {
-  assertSametrait(test,
+= function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: 'b' },
       trait({ b: 2, a: 1 })
     ),
     {
       b: Conflict('b'),
       a: Required()
     }
   );
 };
 
-exports['test:resolve: simple exclusion'] = function (test) {
-  assertSametrait(test,
+exports['test:resolve: simple exclusion'] = function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: undefined },
       trait({ a: 1, b: 2 })
     ),
     {
       a: Required(),
       b: Data(2)
     }
   );
 };
 
-exports['test:resolve: exclusion to "empty" trait'] = function (test) {
-  assertSametrait(test,
+exports['test:resolve: exclusion to "empty" trait'] = function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: undefined, b: undefined },
       trait({ a: 1, b: 2 })
     ),
     {
       a: Required(),
       b: Required()
     }
   );
 };
 
 exports['test:resolve: exclusion and renaming of disjoint props'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: undefined, b: 'c' },
       trait({ a: 1, b: 2 })
     ),
     {
       a: Required(),
       c: Data(2),
       b: Required()
     }
   );
 };
 
 exports['test:resolve: exclusion and renaming of overlapping props'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: undefined, b: 'a' },
       trait({ a: 1, b: 2 })
     ),
     {
       a: Data(2),
       b: Required()
     }
   );
 };
 
 exports['test:resolve: renaming to a common alias causes conflict'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: 'c', b: 'c' },
       trait({ a: 1, b: 2 })
     ),
     {
       c: Conflict('c'),
       a: Required(),
       b: Required()
     }
   );
 };
 
 exports['test:resolve: renaming overrides required target'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { b: 'a' },
       trait({ a: required, b: 2 })
     ),
     {
       a: Data(2),
       b: Required()
     }
   );
 };
 
 exports['test:resolve: renaming required properties has no effect'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { b: 'a' },
       trait({ a: 2, b: required })
     ),
     {
       a: Data(2),
       b: Required()
     }
   );
 };
 
 exports['test:resolve: renaming of non-existent props has no effect'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: 'c', d: 'c' },
       trait({ a: 1, b: 2 })
     ),
     {
       c: Data(1),
       b: Data(2),
       a: Required()
     }
   );
 };
 
 exports['test:resolve: exclusion of non-existent props has no effect'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { b: undefined },
       trait({ a: 1 })
     ),
     {
       a: Data(1)
     }
   );
 };
 
 exports['test:resolve is neutral w.r.t. required properties'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: 'c', b: undefined },
       trait({ a: required, b: required, c: 'foo', d: 1 })
     ),
     {
       a: Required(),
       b: Required(),
       c: Data('foo'),
       d: Data(1)
     }
   );
 };
 
 exports['test:resolve supports swapping of property names, ordering 1'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: 'b', b: 'a' },
       trait({ a: 1, b: 2 })
     ),
     {
       a: Data(2),
       b: Data(1)
     }
   );
 };
 
 exports['test:resolve supports swapping of property names, ordering 2'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { b: 'a', a: 'b' },
       trait({ a: 1, b: 2 })
     ),
     {
       a: Data(2),
       b: Data(1)
     }
   );
 };
 
 exports['test:resolve supports swapping of property names, ordering 3'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { b: 'a', a: 'b' },
       trait({ b: 2, a: 1 })
     ),
     {
       a: Data(2),
       b: Data(1)
     }
   );
 };
 
 exports['test:resolve supports swapping of property names, ordering 4'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     resolve(
       { a: 'b', b: 'a' },
       trait({ b: 2, a: 1 })
     ),
     {
       a: Data(2),
       b: Data(1)
     }
   );
 };
 
-exports['test:override of mutually exclusive traits'] = function (test) {
-  assertSametrait(test,
+exports['test:override of mutually exclusive traits'] = function (assert) {
+  assertSametrait(assert,
     override(
       trait({ a: 1, b: 2 }),
       trait({ c: 3, d: testMethod })
     ),
     {
       a: Data(1),
       b: Data(2),
       c: Data(3),
       d: Method(testMethod)
     }
   );
 };
 
 exports['test:override of mutually exclusive traits is compose'] =
-function (test) {
-  assertSametrait(test,
+function (assert) {
+  assertSametrait(assert,
     override(
       trait({ a: 1, b: 2 }),
       trait({ c: 3, d: testMethod })
     ),
     compose(
       trait({ d: testMethod, c: 3 }),
       trait({ b: 2, a: 1 })
     )
   );
 };
 
-exports['test:override of overlapping traits'] = function (test) {
-  assertSametrait(test,
+exports['test:override of overlapping traits'] = function (assert) {
+  assertSametrait(assert,
     override(
       trait({ a: 1, b: 2 }),
       trait({ a: 3, c: testMethod })
     ),
     {
       a: Data(1),
       b: Data(2),
       c: Method(testMethod)
     }
   );
 };
 
-exports['test:three-way override of overlapping traits'] = function (test) {
-  assertSametrait(test,
+exports['test:three-way override of overlapping traits'] = function (assert) {
+  assertSametrait(assert,
     override(
       trait({ a: 1, b: 2 }),
       trait({ b: 4, c: 3 }),
       trait({ a: 3, c: testMethod, d: 5 })
     ),
     {
       a: Data(1),
       b: Data(2),
       c: Data(3),
       d: Data(5)
     }
   );
 };
 
-exports['test:override replaces required properties'] = function (test) {
-  assertSametrait(test,
+exports['test:override replaces required properties'] = function (assert) {
+  assertSametrait(assert,
     override(
       trait({ a: required, b: 2 }),
       trait({ a: 1, c: testMethod })
     ),
     {
       a: Data(1),
       b: Data(2),
       c: Method(testMethod)
     }
   );
 };
 
-exports['test:override is not commutative'] = function (test) {
-  assertSametrait(test,
+exports['test:override is not commutative'] = function (assert) {
+  assertSametrait(assert,
     override(
       trait({ a: 1, b: 2 }),
       trait({ a: 3, c: 4 })
     ),
     {
       a: Data(1),
       b: Data(2),
       c: Data(4)
     }
   );
 
-  assertSametrait(test,
+  assertSametrait(assert,
     override(
       trait({ a: 3, c: 4 }),
       trait({ a: 1, b: 2 })
     ),
     {
       a: Data(3),
       b: Data(2),
       c: Data(4)
     }
   );
 };
 
-exports['test:override is associative'] = function (test) {
-  assertSametrait(test,
+exports['test:override is associative'] = function (assert) {
+  assertSametrait(assert,
     override(
       override(
         trait({ a: 1, b: 2 }),
         trait({ a: 3, c: 4, d: 5 })
       ),
       trait({ a: 6, c: 7, e: 8 })
     ),
     override(
@@ -714,125 +718,133 @@ exports['test:override is associative'] 
       override(
         trait({ a: 3, c: 4, d: 5 }),
         trait({ a: 6, c: 7, e: 8 })
       )
     )
   );
 };
 
-exports['test:create simple'] = function(test) {
+exports['test:create simple'] = function(assert) {
   let o1 = create(
     Object.prototype,
     trait({ a: 1, b: function() { return this.a; } })
   );
 
-  test.assertEqual(
+  assert.equal(
     Object.prototype,
     Object.getPrototypeOf(o1),
     'o1 prototype'
   );
-  test.assertEqual(1, o1.a, 'o1.a');
-  test.assertEqual(1, o1.b(), 'o1.b()');
-  test.assertEqual(
+  assert.equal(1, o1.a, 'o1.a');
+  assert.equal(1, o1.b(), 'o1.b()');
+  assert.equal(
     2,
     Object.getOwnPropertyNames(o1).length,
     'Object.keys(o1).length === 2'
   );
 };
 
-exports['test:create with Array.prototype'] = function(test) {
+exports['test:create with Array.prototype'] = function(assert) {
   let o2 = create(Array.prototype, trait({}));
-  test.assertEqual(
+  assert.equal(
     Array.prototype,
     Object.getPrototypeOf(o2),
     "o2 prototype"
   );
 };
 
 exports['test:exception for incomplete required properties'] =
-function(test) {
+function(assert) {
   try {
     create(Object.prototype, trait({ foo: required }));
-    test.fail('expected create to complain about missing required props');
-  } catch(e) {
-    test.assertEqual(
+    assert.fail('expected create to complain about missing required props');
+  }
+  catch(e) {
+    assert.equal(
       'Error: Missing required property: foo',
       e.toString(),
       'required prop error'
     );
   }
 };
 
-exports['test:exception for unresolved conflicts'] = function(test) {
+exports['test:exception for unresolved conflicts'] = function(assert) {
   try {
     create({}, compose(trait({ a: 0 }), trait({ a: 1 })));
-    test.fail('expected create to complain about unresolved conflicts');
-  } catch(e) {
-    test.assertEqual(
+    assert.fail('expected create to complain about unresolved conflicts');
+  }
+  catch(e) {
+    assert.equal(
       'Error: Remaining conflicting property: a',
       e.toString(),
       'conflicting prop error'
     );
   }
 };
 
 exports['test:verify that required properties are present but undefined'] =
-function(test) {
+function(assert) {
   try {
     let o4 = Object.create(Object.prototype, trait({ foo: required }));
-    test.assertEqual(true, 'foo' in o4, 'required property present');
+    assert.equal(true, 'foo' in o4, 'required property present');
     try {
       let foo = o4.foo;
-      test.fail('access to required property must throw');
-    } catch(e) {
-      test.assertEqual(
+      assert.fail('access to required property must throw');
+    }
+    catch(e) {
+      assert.equal(
         'Error: Missing required property: foo',
         e.toString(),
         'required prop error'
       )
     }
-  } catch(e) {
-    test.fail('did not expect create to complain about required props');
+  }
+  catch(e) {
+    assert.fail('did not expect create to complain about required props');
   }
 };
 
 exports['test:verify that conflicting properties are present'] =
-function(test) {
+function(assert) {
   try {
     let o5 = Object.create(
       Object.prototype,
       compose(trait({ a: 0 }), trait({ a: 1 }))
     );
-    test.assertEqual(true, 'a' in o5, 'conflicting property present');
+    assert.equal(true, 'a' in o5, 'conflicting property present');
     try {
       let a = o5.a; // accessors or data prop
-      test.fail('expected conflicting prop to cause exception');
-    } catch (e) {
-      test.assertEqual(
+      assert.fail('expected conflicting prop to cause exception');
+    }
+    catch (e) {
+      assert.equal(
         'Error: Remaining conflicting property: a',
         e.toString(),
         'conflicting prop access error'
       );
     }
-  } catch(e) {
-    test.fail('did not expect create to complain about conflicting props');
+  }
+  catch(e) {
+    assert.fail('did not expect create to complain about conflicting props');
   }
 };
 
-exports['test diamond with conflicts'] = function(test) {
+exports['test diamond with conflicts'] = function(assert) {
   function makeT1(x) trait({ m: function() { return x; } })
   function makeT2(x) compose(trait({ t2: 'foo' }), makeT1(x))
   function makeT3(x) compose(trait({ t3: 'bar' }), makeT1(x))
 
   let T4 = compose(makeT2(5), makeT3(5));
   try {
     let o = create(Object.prototype, T4);
-    test.fail('expected diamond prop to cause exception');
-  } catch(e) {
-    test.assertEqual(
+    assert.fail('expected diamond prop to cause exception');
+  }
+  catch(e) {
+    assert.equal(
       'Error: Remaining conflicting property: m',
       e.toString(),
       'diamond prop conflict'
     );
   }
 };
 
+require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-unload.js
+++ b/addon-sdk/source/test/test-unload.js
@@ -1,69 +1,67 @@
-/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ "use strict";
 
 var unload = require("sdk/system/unload");
 var { Loader, LoaderWithHookedConsole } = require("sdk/test/loader");
 
-exports.testUnloading = function(test) {
+exports.testUnloading = function(assert) {
   let { loader, messages } = LoaderWithHookedConsole(module);
   var ul = loader.require("sdk/system/unload");
   var unloadCalled = 0;
   function unload() {
     unloadCalled++;
     throw new Error("error");
   }
   ul.when(unload);
 
   // This should be ignored, as we already registered it
   ul.when(unload);
 
   function unload2() { unloadCalled++; }
   ul.when(unload2);
   loader.unload();
-  test.assertEqual(unloadCalled, 2,
+  assert.equal(unloadCalled, 2,
                    "Unloader functions are called on unload.");
-  test.assertEqual(messages.length, 1,
+  assert.equal(messages.length, 1,
                    "One unload handler threw exception 1/2");
-  test.assertEqual(messages[0].type, "exception",
+  assert.equal(messages[0].type, "exception",
                    "One unload handler threw exception 2/2");
 };
 
-exports.testEnsure = function(test) {
-  test.assertRaises(function() { unload.ensure({}); },
-                    "object has no 'unload' property",
-                    "passing obj with no unload prop should fail");
-  test.assertRaises(function() { unload.ensure({}, "destroy"); },
-                    "object has no 'destroy' property",
-                    "passing obj with no custom unload prop should fail");
+exports.testEnsure = function(assert) {
+  assert.throws(function() { unload.ensure({}); },
+                /object has no 'unload' property/,
+                "passing obj with no unload prop should fail");
+  assert.throws(function() { unload.ensure({}, "destroy"); },
+                /object has no 'destroy' property/,
+                "passing obj with no custom unload prop should fail");
 
   var called = 0;
   var obj = {unload: function() { called++; }};
 
   unload.ensure(obj);
   obj.unload();
-  test.assertEqual(called, 1,
+  assert.equal(called, 1,
                    "unload() should be called");
   obj.unload();
-  test.assertEqual(called, 1,
+  assert.equal(called, 1,
                    "unload() should be called only once");
 };
 
 /**
  * Check that destructors are called only once with Traits.
  * - check that public API is calling the destructor and unregister it,
  * - check that composed traits with multiple ensure calls, leads to only
  * one destructor call.
  */
-exports.testEnsureWithTraits = function(test) {
-
+exports.testEnsureWithTraits = function(assert) {
   let { Trait } = require("sdk/deprecated/traits");
   let loader = Loader(module);
   let ul = loader.require("sdk/system/unload");
 
   let called = 0;
   let composedCalled = 0;
   let composedTrait = Trait.compose({
       constructor: function () {
@@ -74,52 +72,51 @@ exports.testEnsureWithTraits = function(
       },
       unload: function unload() {
         composedCalled++;
       }
     });
   let obj = Trait.compose(
     composedTrait.resolve({
       constructor: "_constructor",
-      unload : "_unload" 
+      unload : "_unload"
     }), {
       constructor: function constructor() {
         // Same thing applies here, we need to pass public interface
         ul.ensure(this._public);
         this._constructor();
       },
       unload: function unload() {
         called++;
         this._unload();
       }
     })();
 
   obj.unload();
-  test.assertEqual(called, 1,
+  assert.equal(called, 1,
                    "unload() should be called");
 
-  test.assertEqual(composedCalled, 1,
+  assert.equal(composedCalled, 1,
                    "composed object unload() should be called");
 
   obj.unload();
-  test.assertEqual(called, 1,
+  assert.equal(called, 1,
                    "unload() should be called only once");
-  test.assertEqual(composedCalled, 1,
+  assert.equal(composedCalled, 1,
                    "composed object unload() should be called only once");
 
   loader.unload();
-  test.assertEqual(called, 1,
+  assert.equal(called, 1,
                    "unload() should be called only once, after addon unload");
-  test.assertEqual(composedCalled, 1,
+  assert.equal(composedCalled, 1,
                    "composed object unload() should be called only once, " +
                    "after addon unload");
 };
 
-exports.testEnsureWithTraitsPrivate = function(test) {
-
+exports.testEnsureWithTraitsPrivate = function(assert) {
   let { Trait } = require("sdk/deprecated/traits");
   let loader = Loader(module);
   let ul = loader.require("sdk/system/unload");
 
   let called = 0;
   let privateObj = null;
   let obj = Trait.compose({
       constructor: function constructor() {
@@ -130,33 +127,35 @@ exports.testEnsureWithTraitsPrivate = fu
       },
       _unload: function unload() {
         called++;
         this._unload();
       }
     })();
 
   loader.unload();
-  test.assertEqual(called, 1,
+  assert.equal(called, 1,
                    "unload() should be called");
 
   privateObj._unload();
-  test.assertEqual(called, 1,
+  assert.equal(called, 1,
                    "_unload() should be called only once, after addon unload");
 };
 
-exports.testReason = function (test) {
+exports.testReason = function (assert) {
   var reason = "Reason doesn't actually have to be anything in particular.";
   var loader = Loader(module);
   var ul = loader.require("sdk/system/unload");
   ul.when(function (rsn) {
-    test.assertEqual(rsn, reason,
+    assert.equal(rsn, reason,
                      "when() reason should be reason given to loader");
   });
   var obj = {
     unload: function (rsn) {
-      test.assertEqual(rsn, reason,
+      assert.equal(rsn, reason,
                        "ensure() reason should be reason given to loader");
     }
   };
   ul.ensure(obj);
   loader.unload(reason);
 };
+
+require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-widget.js
+++ b/addon-sdk/source/test/test-widget.js
@@ -12,359 +12,359 @@ module.metadata = {
 const widgets = require("sdk/widget");
 const { Cc, Ci } = require("chrome");
 const { Loader } = require('sdk/test/loader');
 const url = require("sdk/url");
 const timer = require("sdk/timers");
 const self = require("sdk/self");
 const windowUtils = require("sdk/deprecated/window-utils");
 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
+const { close } = require("sdk/window/helpers");
 
 let jetpackID = "testID";
 try {
   jetpackID = require("sdk/self").id;
 } catch(e) {}
 
 const australis = !!require("sdk/window/utils").getMostRecentBrowserWindow().CustomizableUI;
 
-exports.testConstructor = function(test) {
-  test.waitUntilDone();
-
+exports.testConstructor = function(assert, done) {
   let browserWindow = windowUtils.activeBrowserWindow;
   let doc = browserWindow.document;
   let AddonsMgrListener;
   if (australis) {
     AddonsMgrListener = {
       onInstalling: () => {},
       onInstalled: () => {},
       onUninstalling: () => {},
       onUninstalled: () => {}
     };
-  } else {
+  }
+  else {
     AddonsMgrListener = browserWindow.AddonsMgrListener;
   }
 
   function container() australis ? doc.getElementById("nav-bar") : doc.getElementById("addon-bar");
   function getWidgets() container() ? container().querySelectorAll('[id^="widget\:"]') : [];
   function widgetCount() getWidgets().length;
   let widgetStartCount = widgetCount();
   function widgetNode(index) getWidgets()[index];
 
   // Test basic construct/destroy
   AddonsMgrListener.onInstalling();
   let w = widgets.Widget({ id: "fooID", label: "foo", content: "bar" });
   AddonsMgrListener.onInstalled();
-  test.assertEqual(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction");
+  assert.equal(widgetCount(), widgetStartCount + 1, "panel has correct number of child elements after widget construction");
 
   // test widget height
-  test.assertEqual(widgetNode(0).firstChild.boxObject.height, 16, "widget has correct default height");
+  assert.equal(widgetNode(0).firstChild.boxObject.height, 16, "widget has correct default height");
 
   AddonsMgrListener.onUninstalling();
   w.destroy();
   AddonsMgrListener.onUninstalled();
   w.destroy();
-  test.pass("Multiple destroys do not cause an error");
-  test.assertEqual(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy");
+  assert.pass("Multiple destroys do not cause an error");
+  assert.equal(widgetCount(), widgetStartCount, "panel has correct number of child elements after destroy");
 
   // Test automatic widget destroy on unload
   let loader = Loader(module);
   let widgetsFromLoader = loader.require("sdk/widget");
   let widgetStartCount = widgetCount();
   let w = widgetsFromLoader.Widget({ id: "fooID", label: "foo", content: "bar" });
-  test.assertEqual(widgetCount(), widgetStartCount + 1, "widget has been correctly added");
+  assert.equal(widgetCount(), widgetStartCount + 1, "widget has been correctly added");
   loader.unload();
-  test.assertEqual(widgetCount(), widgetStartCount, "widget has been destroyed on module unload");
+  assert.equal(widgetCount(), widgetStartCount, "widget has been destroyed on module unload");
 
   // Test nothing
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({}),
-    "The widget must have a non-empty label property.",
+    /^The widget must have a non-empty label property\.$/,
     "throws on no properties");
 
   // Test no label
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({content: "foo"}),
-    "The widget must have a non-empty label property.",
+    /^The widget must have a non-empty label property\.$/,
     "throws on no label");
 
   // Test empty label
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({label: "", content: "foo"}),
-    "The widget must have a non-empty label property.",
+    /^The widget must have a non-empty label property\.$/,
     "throws on empty label");
 
   // Test no content or image
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({id: "fooID", label: "foo"}),
-    "No content or contentURL property found. Widgets must have one or the other.",
+    /^No content or contentURL property found\. Widgets must have one or the other\.$/,
     "throws on no content");
 
   // Test empty content, no image
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({id:"fooID", label: "foo", content: ""}),
-    "No content or contentURL property found. Widgets must have one or the other.",
+    /^No content or contentURL property found\. Widgets must have one or the other\.$/,
     "throws on empty content");
 
   // Test empty image, no content
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({id:"fooID", label: "foo", image: ""}),
-    "No content or contentURL property found. Widgets must have one or the other.",
+    /^No content or contentURL property found\. Widgets must have one or the other\.$/,
     "throws on empty content");
 
   // Test empty content, empty image
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({id:"fooID", label: "foo", content: "", image: ""}),
-    "No content or contentURL property found. Widgets must have one or the other.",
+    /^No content or contentURL property found. Widgets must have one or the other\.$/,
     "throws on empty content");
 
   // Test duplicated ID
   let duplicateID = widgets.Widget({id: "foo", label: "foo", content: "bar"});
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({id: "foo", label: "bar", content: "bar"}),
-    /This widget ID is already used:/,
+    /^This widget ID is already used: foo$/,
     "throws on duplicated id");
   duplicateID.destroy();
 
   // Test Bug 652527
-  test.assertRaises(
+  assert.throws(
     function() widgets.Widget({id: "", label: "bar", content: "bar"}),
-    /You have to specify a unique value for the id property of/,
+    /^You have to specify a unique value for the id property of your widget in order for the application to remember its position\./,
     "throws on falsey id");
 
   // Test duplicate label, different ID
   let w1 = widgets.Widget({id: "id1", label: "foo", content: "bar"});
   let w2 = widgets.Widget({id: "id2", label: "foo", content: "bar"});
   w1.destroy();
   w2.destroy();
 
   // Test position restore on create/destroy/create
   // Create 3 ordered widgets
   let w1 = widgets.Widget({id: "first", label:"first", content: "bar"});
   let w2 = widgets.Widget({id: "second", label:"second", content: "bar"});
   let w3 = widgets.Widget({id: "third", label:"third", content: "bar"});
   // Remove the middle widget
-  test.assertEqual(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted");
+  assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is the second widget inserted");
   w2.destroy();
-  test.assertEqual(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one");
+  assert.equal(widgetNode(1).getAttribute("label"), "third", "second widget is removed, so second widget is now the third one");
   w2 = widgets.Widget({id: "second", label:"second", content: "bar"});
-  test.assertEqual(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location");
+  assert.equal(widgetNode(1).getAttribute("label"), "second", "second widget is created again, at the same location");
   // Cleanup this testcase
   AddonsMgrListener.onUninstalling();
   w1.destroy();
   w2.destroy();
   w3.destroy();
   AddonsMgrListener.onUninstalled();
 
   // Test concurrent widget module instances on addon-bar hiding
   if (!australis) {
     let loader = Loader(module);
     let anotherWidgetsInstance = loader.require("sdk/widget");
-    test.assert(container().collapsed, "UI is hidden when no widgets");
+    assert.ok(container().collapsed, "UI is hidden when no widgets");
     AddonsMgrListener.onInstalling();
     let w1 = widgets.Widget({id: "foo", label: "foo", content: "bar"});
     // Ideally we would let AddonsMgrListener display the addon bar
     // But, for now, addon bar is immediatly displayed by sdk code
     // https://bugzilla.mozilla.org/show_bug.cgi?id=627484
-    test.assert(!container().collapsed, "UI is already visible when we just added the widget");
+    assert.ok(!container().collapsed, "UI is already visible when we just added the widget");
     AddonsMgrListener.onInstalled();
-    test.assert(!container().collapsed, "UI become visible when we notify AddonsMgrListener about end of addon installation");
+    assert.ok(!container().collapsed, "UI become visible when we notify AddonsMgrListener about end of addon installation");
     let w2 = anotherWidgetsInstance.Widget({id: "bar", label: "bar", content: "foo"});
-    test.assert(!container().collapsed, "UI still visible when we add a second widget");
+    assert.ok(!container().collapsed, "UI still visible when we add a second widget");
     AddonsMgrListener.onUninstalling();
     w1.destroy();
     AddonsMgrListener.onUninstalled();
-    test.assert(!container().collapsed, "UI still visible when we remove one of two widgets");
+    assert.ok(!container().collapsed, "UI still visible when we remove one of two widgets");
     AddonsMgrListener.onUninstalling();
     w2.destroy();
-    test.assert(!container().collapsed, "UI is still visible when we have removed all widget but still not called onUninstalled");
+    assert.ok(!container().collapsed, "UI is still visible when we have removed all widget but still not called onUninstalled");
     AddonsMgrListener.onUninstalled();
-    test.assert(container().collapsed, "UI is hidden when we have removed all widget and called onUninstalled");
+    assert.ok(container().collapsed, "UI is hidden when we have removed all widget and called onUninstalled");
   }
   // Helper for testing a single widget.
   // Confirms proper addition and content setup.
   function testSingleWidget(widgetOptions) {
     // We have to display which test is being run, because here we do not
     // use the regular test framework but rather a custom one that iterates
     // the `tests` array.
     console.info("executing: " + widgetOptions.id);
 
     let startCount = widgetCount();
     let widget = widgets.Widget(widgetOptions);
     let node = widgetNode(startCount);
-    test.assert(node, "widget node at index");
-    test.assertEqual(node.tagName, "toolbaritem", "widget element is correct");
-    test.assertEqual(widget.width + "px", node.style.minWidth, "widget width is correct");
-    test.assertEqual(widgetCount(), startCount + 1, "container has correct number of child elements");
+    assert.ok(node, "widget node at index");
+    assert.equal(node.tagName, "toolbaritem", "widget element is correct");
+    assert.equal(widget.width + "px", node.style.minWidth, "widget width is correct");
+    assert.equal(widgetCount(), startCount + 1, "container has correct number of child elements");
     let content = node.firstElementChild;
-    test.assert(content, "found content");
-    test.assertMatches(content.tagName, /iframe|image/, "content is iframe or image");
+    assert.ok(content, "found content");
+    assert.ok(/iframe|image/.test(content.tagName), "content is iframe or image");
     return widget;
   }
 
   // Array of widgets to test
   // and a function to test them.
   let tests = [];
   function nextTest() {
-    test.assertEqual(widgetCount(), 0, "widget in last test property cleaned itself up");
+    assert.equal(widgetCount(), 0, "widget in last test property cleaned itself up");
     if (!tests.length)
-      test.done();
+      done();
     else
       timer.setTimeout(tests.shift(), 0);
   }
   function doneTest() nextTest();
 
   // text widget
   tests.push(function testTextWidget() testSingleWidget({
     id: "text",
     label: "text widget",
     content: "oh yeah",
     contentScript: "self.postMessage(document.body.innerHTML);",
     contentScriptWhen: "end",
     onMessage: function (message) {
-      test.assertEqual(this.content, message, "content matches");
+      assert.equal(this.content, message, "content matches");
       this.destroy();
       doneTest();
     }
   }));
 
   // html widget
   tests.push(function testHTMLWidget() testSingleWidget({
     id: "html",
     label: "html widget",
     content: "<div>oh yeah</div>",
     contentScript: "self.postMessage(document.body.innerHTML);",
     contentScriptWhen: "end",
     onMessage: function (message) {
-      test.assertEqual(this.content, message, "content matches");
+      assert.equal(this.content, message, "content matches");
       this.destroy();
       doneTest();
     }
   }));
 
   // image url widget
   tests.push(function testImageURLWidget() testSingleWidget({
     id: "image",
     label: "image url widget",
     contentURL: require("sdk/self").data.url("test.html"),
     contentScript: "self.postMessage({title: document.title, " +
                    "tag: document.body.firstElementChild.tagName, " +
                    "content: document.body.firstElementChild.innerHTML});",
     contentScriptWhen: "end",
     onMessage: function (message) {
-      test.assertEqual(message.title, "foo", "title matches");
-      test.assertEqual(message.tag, "P", "element matches");
-      test.assertEqual(message.content, "bar", "element content matches");
+      assert.equal(message.title, "foo", "title matches");
+      assert.equal(message.tag, "P", "element matches");
+      assert.equal(message.content, "bar", "element content matches");
       this.destroy();
       doneTest();
     }
   }));
 
   // web uri widget
   tests.push(function testWebURIWidget() testSingleWidget({
     id: "web",
     label: "web uri widget",
     contentURL: require("sdk/self").data.url("test.html"),
     contentScript: "self.postMessage({title: document.title, " +
                    "tag: document.body.firstElementChild.tagName, " +
                    "content: document.body.firstElementChild.innerHTML});",
     contentScriptWhen: "end",
     onMessage: function (message) {
-      test.assertEqual(message.title, "foo", "title matches");
-      test.assertEqual(message.tag, "P", "element matches");
-      test.assertEqual(message.content, "bar", "element content matches");
+      assert.equal(message.title, "foo", "title matches");
+      assert.equal(message.tag, "P", "element matches");
+      assert.equal(message.content, "bar", "element content matches");
       this.destroy();
       doneTest();
     }
   }));
 
   // event: onclick + content
   tests.push(function testOnclickEventContent() testSingleWidget({
     id: "click",
     label: "click test widget - content",
     content: "<div id='me'>foo</div>",
     contentScript: "var evt = new MouseEvent('click', {button: 0});" +
                    "document.getElementById('me').dispatchEvent(evt);",
     contentScriptWhen: "end",
     onClick: function() {
-      test.pass("onClick called");
+      assert.pass("onClick called");
       this.destroy();
       doneTest();
     }
   }));
 
   // event: onmouseover + content
   tests.push(function testOnmouseoverEventContent() testSingleWidget({
     id: "mouseover",
     label: "mouseover test widget - content",
     content: "<div id='me'>foo</div>",
     contentScript: "var evt = new MouseEvent('mouseover'); " +
                    "document.getElementById('me').dispatchEvent(evt);",
     contentScriptWhen: "end",
     onMouseover: function() {
-      test.pass("onMouseover called");
+      assert.pass("onMouseover called");
       this.destroy();
       doneTest();
     }
   }));
 
   // event: onmouseout + content
   tests.push(function testOnmouseoutEventContent() testSingleWidget({
     id: "mouseout",
     label: "mouseout test widget - content",
     content: "<div id='me'>foo</div>",
     contentScript: "var evt = new MouseEvent('mouseout');" +
                    "document.getElementById('me').dispatchEvent(evt);",
     contentScriptWhen: "end",
     onMouseout: function() {
-      test.pass("onMouseout called");
+      assert.pass("onMouseout called");
       this.destroy();
       doneTest();
     }
   }));
 
   // event: onclick + image
   tests.push(function testOnclickEventImage() testSingleWidget({
     id: "click",
     label: "click test widget - image",
     contentURL: require("sdk/self").data.url("moz_favicon.ico"),
     contentScript: "var evt = new MouseEvent('click'); " +
                    "document.body.firstElementChild.dispatchEvent(evt);",
     contentScriptWhen: "end",
     onClick: function() {
-      test.pass("onClick called");
+      assert.pass("onClick called");
       this.destroy();
       doneTest();
     }
   }));
 
   // event: onmouseover + image
   tests.push(function testOnmouseoverEventImage() testSingleWidget({
     id: "mouseover",
     label: "mouseover test widget - image",
     contentURL: require("sdk/self").data.url("moz_favicon.ico"),
     contentScript: "var evt = new MouseEvent('mouseover');" +
                    "document.body.firstElementChild.dispatchEvent(evt);",
     contentScriptWhen: "end",
     onMouseover: function() {
-      test.pass("onMouseover called");
+      assert.pass("onMouseover called");
       this.destroy();
       doneTest();
     }
   }));
 
   // event: onmouseout + image
   tests.push(function testOnmouseoutEventImage() testSingleWidget({
     id: "mouseout",
     label: "mouseout test widget - image",
     contentURL: require("sdk/self").data.url("moz_favicon.ico"),
     contentScript: "var evt = new MouseEvent('mouseout'); " +
                    "document.body.firstElementChild.dispatchEvent(evt);",
     contentScriptWhen: "end",
     onMouseout: function() {
-      test.pass("onMouseout called");
+      assert.pass("onMouseout called");
       this.destroy();
       doneTest();
     }
   }));
 
   // test multiple widgets
   tests.push(function testMultipleWidgets() {
     let w1 = widgets.Widget({id: "first", label: "first widget", content: "first content"});
@@ -385,17 +385,17 @@ exports.testConstructor = function(test)
     contentScript: "self.postMessage(1)",
     contentScriptWhen: "ready",
     onMessage: function(message) {
       if (!this.flag) {
         this.content = "<div id='me'>bar</div>";
         this.flag = 1;
       }
       else {
-        test.assertEqual(this.content, "<div id='me'>bar</div>");
+        assert.equal(this.content, "<div id='me'>bar</div>", 'content is as expected');
         this.destroy();
         doneTest();
       }
     }
   }));
 
   // test updating widget contentURL
   let url1 = "data:text/html;charset=utf-8,<body>foodle</body>";
@@ -404,110 +404,110 @@ exports.testConstructor = function(test)
   tests.push(function testUpdatingContentURL() testSingleWidget({
     id: "content",
     label: "content update test widget",
     contentURL: url1,
     contentScript: "self.postMessage(document.location.href);",
     contentScriptWhen: "end",
     onMessage: function(message) {
       if (!this.flag) {
-        test.assertEqual(this.contentURL.toString(), url1);
-        test.assertEqual(message, url1);
+        assert.equal(this.contentURL.toString(), url1);
+        assert.equal(message, url1);
         this.contentURL = url2;
         this.flag = 1;
       }
       else {
-        test.assertEqual(this.contentURL.toString(), url2);
-        test.assertEqual(message, url2);
+        assert.equal(this.contentURL.toString(), url2);
+        assert.equal(message, url2);
         this.destroy();
         doneTest();
       }
     }
   }));
 
   // test tooltip
   tests.push(function testTooltip() testSingleWidget({
     id: "text",
     label: "text widget",
     content: "oh yeah",
     tooltip: "foo",
     contentScript: "self.postMessage(1)",
     contentScriptWhen: "ready",
     onMessage: function(message) {
-      test.assertEqual(this.tooltip, "foo", "tooltip matches");
+      assert.equal(this.tooltip, "foo", "tooltip matches");
       this.destroy();
       doneTest();
     }
   }));
 
   // test tooltip fallback to label
   tests.push(function testTooltipFallback() testSingleWidget({
     id: "fallback",
     label: "fallback",
     content: "oh yeah",
     contentScript: "self.postMessage(1)",
     contentScriptWhen: "ready",
     onMessage: function(message) {
-      test.assertEqual(this.tooltip, this.label, "tooltip fallbacks to label");
+      assert.equal(this.tooltip, this.label, "tooltip fallbacks to label");
       this.destroy();
       doneTest();
     }
   }));
 
   // test updating widget tooltip
   let updated = false;
   tests.push(function testUpdatingTooltip() testSingleWidget({
     id: "tooltip",
     label: "tooltip update test widget",
     tooltip: "foo",
     content: "<div id='me'>foo</div>",
     contentScript: "self.postMessage(1)",
     contentScriptWhen: "ready",
     onMessage: function(message) {
       this.tooltip = "bar";
-      test.assertEqual(this.tooltip, "bar", "tooltip gets updated");
+      assert.equal(this.tooltip, "bar", "tooltip gets updated");
       this.destroy();
       doneTest();
     }
   }));
 
   // test allow attribute
   tests.push(function testDefaultAllow() testSingleWidget({
     id: "allow",
     label: "allow.script attribute",
     content: "<script>document.title = 'ok';</script>",
     contentScript: "self.postMessage(document.title)",
     onMessage: function(message) {
-      test.assertEqual(message, "ok", "scripts are evaluated by default");
+      assert.equal(message, "ok", "scripts are evaluated by default");
       this.destroy();
       doneTest();
     }
   }));
 
   tests.push(function testExplicitAllow() testSingleWidget({
     id: "allow",
     label: "allow.script attribute",
     allow: {script: true},
     content: "<script>document.title = 'ok';</script>",
     contentScript: "self.postMessage(document.title)",
     onMessage: function(message) {
-      test.assertEqual(message, "ok", "scripts are evaluated when we want to");
+      assert.equal(message, "ok", "scripts are evaluated when we want to");
       this.destroy();
       doneTest();
     }
   }));
 
   tests.push(function testExplicitDisallow() testSingleWidget({
     id: "allow",
     label: "allow.script attribute",
     content: "<script>document.title = 'ok';</script>",
     allow: {script: false},
     contentScript: "self.postMessage(document.title)",
     onMessage: function(message) {
-      test.assertNotEqual(message, "ok", "scripts aren't evaluated when " +
+      assert.notEqual(message, "ok", "scripts aren't evaluated when " +
                                          "explicitly blocked it");
       this.destroy();
       doneTest();
     }
   }));
 
   // test multiple windows
   tests.push(function testMultipleWindows() {
@@ -517,30 +517,28 @@ exports.testConstructor = function(test)
       let browserWindow = e.target.defaultView;
       let doc = browserWindow.document;
       function container() australis ? doc.getElementById("nav-bar") : doc.getElementById("addon-bar");
       function widgetCount2() container() ? container().querySelectorAll('[id^="widget\:"]').length : 0;
       let widgetStartCount2 = widgetCount2();
 
       let w1Opts = {id:"first", label: "first widget", content: "first content"};
       let w1 = testSingleWidget(w1Opts);
-      test.assertEqual(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget");
+      assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first widget");
 
       let w2Opts = {id:"second", label: "second widget", content: "second content"};
       let w2 = testSingleWidget(w2Opts);
-      test.assertEqual(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget");
+      assert.equal(widgetCount2(), widgetStartCount2 + 2, "2nd window has correct number of child elements after second widget");
 
       w1.destroy();
-      test.assertEqual(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first destroy");
+      assert.equal(widgetCount2(), widgetStartCount2 + 1, "2nd window has correct number of child elements after first destroy");
       w2.destroy();
-      test.assertEqual(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after second destroy");
+      assert.equal(widgetCount2(), widgetStartCount2, "2nd window has correct number of child elements after second destroy");
 
-      closeBrowserWindow(browserWindow, function() {
-        doneTest();
-      });
+      close(browserWindow).then(doneTest);
     }});
   });
 
   // test window closing
   tests.push(function testWindowClosing() {
     // 1/ Create a new widget
     let w1Opts = {
       id:"first",
@@ -549,117 +547,115 @@ exports.testConstructor = function(test)
       contentScript: "self.port.on('event', function () self.port.emit('event'))"
     };
     let widget = testSingleWidget(w1Opts);
     let windows = require("sdk/windows").browserWindows;
 
     // 2/ Retrieve a WidgetView for the initial browser window
     let acceptDetach = false;
     let mainView = widget.getView(windows.activeWindow);
-    test.assert(mainView, "Got first widget view");
+    assert.ok(mainView, "Got first widget view");
     mainView.on("detach", function () {
       // 8/ End of our test. Accept detach event only when it occurs after
       // widget.destroy()
       if (acceptDetach)
         doneTest();
       else
-        test.fail("View on initial window should not be destroyed");
+        assert.fail("View on initial window should not be destroyed");
     });
     mainView.port.on("event", function () {
       // 7/ Receive event sent during 6/ and cleanup our test
       acceptDetach = true;
       widget.destroy();
     });
 
     // 3/ First: open a new browser window
     windows.open({
       url: "about:blank",
       onOpen: function(window) {
         // 4/ Retrieve a WidgetView for this new window
         let view = widget.getView(window);
-        test.assert(view, "Got second widget view");
+        assert.ok(view, "Got second widget view");
         view.port.on("event", function () {
-          test.fail("We should not receive event on the detach view");
+          assert.fail("We should not receive event on the detach view");
         });
         view.on("detach", function () {
           // The related view is destroyed
           // 6/ Send a custom event
-          test.assertRaises(function () {
+          assert.throws(function () {
               view.port.emit("event");
             },
-            /The widget has been destroyed and can no longer be used./,
+            /^The widget has been destroyed and can no longer be used.$/,
             "emit on a destroyed view should throw");
           widget.port.emit("event");
         });
 
         // 5/ Destroy this window
         window.close();
       }
     });
   });
 
   if (!australis) {
     tests.push(function testAddonBarHide() {
       const tabBrowser = require("sdk/deprecated/tab-browser");
 
       // Hide the addon-bar
       browserWindow.setToolbarVisibility(container(), false);
-      test.assert(container().collapsed,
-                  "1st window starts with an hidden addon-bar");
+      assert.ok(container().collapsed,
+                "1st window starts with an hidden addon-bar");
 
       // Then open a browser window and verify that the addon-bar remains hidden
       tabBrowser.addTab("about:blank", { inNewWindow: true, onLoad: function(e) {
         let browserWindow2 = e.target.defaultView;
         let doc2 = browserWindow2.document;
         function container2() doc2.getElementById("addon-bar");
         function widgetCount2() container2() ? container2().childNodes.length : 0;
         let widgetStartCount2 = widgetCount2();
-        test.assert(container2().collapsed,
-                    "2nd window starts with an hidden addon-bar");
+        assert.ok(container2().collapsed,
+                  "2nd window starts with an hidden addon-bar");
 
         let w1Opts = {id:"first", label: "first widget", content: "first content"};
         let w1 = testSingleWidget(w1Opts);
-        test.assertEqual(widgetCount2(), widgetStartCount2 + 1,
-                         "2nd window has correct number of child elements after" +
-                         "widget creation");
+        assert.equal(widgetCount2(), widgetStartCount2 + 1,
+                     "2nd window has correct number of child elements after" +
+                     "widget creation");
         w1.destroy();
-        test.assertEqual(widgetCount2(), widgetStartCount2,
-                         "2nd window has correct number of child elements after" +
-                         "widget destroy");
+        assert.equal(widgetCount2(), widgetStartCount2,
+                     "2nd window has correct number of child elements after" +
+                     "widget destroy");
 
-        test.assert(container().collapsed, "1st window has an hidden addon-bar");
-        test.assert(container2().collapsed, "2nd window has an hidden addon-bar");
+        assert.ok(container().collapsed, "1st window has an hidden addon-bar");
+        assert.ok(container2().collapsed, "2nd window has an hidden addon-bar");
 
         // Reset addon-bar visibility before exiting this test
         browserWindow.setToolbarVisibility(container(), true);
 
-        closeBrowserWindow(browserWindow2, function() {
-          doneTest();
-        });
+        close(browserWindow2).then(doneTest);
       }});
     });
   }
 
   // test widget.width
   tests.push(function testWidgetWidth() testSingleWidget({
     id: "text",
     label: "test widget.width",
     content: "test width",
     width: 200,
     contentScript: "self.postMessage(1)",
     contentScriptWhen: "ready",
     onMessage: function(message) {
-      test.assertEqual(this.width, 200);
+      assert.equal(this.width, 200, 'width is 200');
 
       let node = widgetNode(0);
-      test.assertEqual(this.width, node.style.minWidth.replace("px", ""));
-      test.assertEqual(this.width, node.firstElementChild.style.width.replace("px", ""));
+      assert.equal(this.width, node.style.minWidth.replace("px", ""));
+      assert.equal(this.width, node.firstElementChild.style.width.replace("px", ""));
       this.width = 300;
-      test.assertEqual(this.width, node.style.minWidth.replace("px", ""));
-      test.assertEqual(this.width, node.firstElementChild.style.width.replace("px", ""));
+      assert.equal(this.width, node.style.minWidth.replace("px", ""));
+      assert.equal(this.width, node.firstElementChild.style.width.replace("px", ""));
 
       this.destroy();
       doneTest();
     }
   }));
 
   // test click handler not respond to right-click
   let clickCount = 0;
@@ -677,218 +673,205 @@ exports.testConstructor = function(test)
                    "evt = new MouseEvent('click', {button: 2});" +
                    "document.getElementById('me').dispatchEvent(evt); " +
                    // Mouseover
                    "evt = new MouseEvent('mouseover');" +
                    "document.getElementById('me').dispatchEvent(evt);",
     contentScriptWhen: "end",
     onClick: function() clickCount++,
     onMouseover: function() {
-      test.assertEqual(clickCount, 1, "only left click was sent to click handler");
+      assert.equal(clickCount, 1, "only left click was sent to click handler");
       this.destroy();
       doneTest();
     }
   }));
 
   // kick off test execution
   doneTest();
 };
 
-exports.testWidgetWithValidPanel = function(test) {
+exports.testWidgetWithValidPanel = function(assert, done) {
   const widgets = require("sdk/widget");
 
   let widget1 = widgets.Widget({
     id: "panel1",
     label: "panel widget 1",
     content: "<div id='me'>foo</div>",
     contentScript: "var evt = new MouseEvent('click', {button: 0});" +
                    "document.body.dispatchEvent(evt);",
     contentScriptWhen: "end",
     panel: require("sdk/panel").Panel({
       contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>",
       onShow: function() {
         let { document } = getMostRecentBrowserWindow();
         let widgetEle = document.getElementById("widget:" + jetpackID + "-" + widget1.id);
         let panelEle = document.getElementById('mainPopupSet').lastChild;
         // See bug https://bugzilla.mozilla.org/show_bug.cgi?id=859592
-        test.assertEqual(panelEle.getAttribute("type"), "arrow", 'the panel is a arrow type');
-        test.assertStrictEqual(panelEle.anchorNode, widgetEle, 'the panel is properly anchored to the widget');
+        assert.equal(panelEle.getAttribute("type"), "arrow", 'the panel is a arrow type');
+        assert.strictEqual(panelEle.anchorNode, widgetEle, 'the panel is properly anchored to the widget');
 
         widget1.destroy();
-        test.pass("panel displayed on click");
-        test.done();
+        assert.pass("panel displayed on click");
+        done();
       }
     })
   });
-  test.waitUntilDone();
 };
 
-exports.testWidgetWithInvalidPanel = function(test) {
+exports.testWidgetWithInvalidPanel = function(assert) {
   const widgets = require("sdk/widget");
-  test.assertRaises(
+  assert.throws(
     function() {
       widgets.Widget({
         id: "panel2",
         label: "panel widget 2",
         panel: {}
       });
     },
-    "The option \"panel\" must be one of the following types: null, undefined, object",
-    "widget.panel must be a Panel object"
-  );
+    /^The option \"panel\" must be one of the following types: null, undefined, object$/,
+    "widget.panel must be a Panel object");
 };
 
-exports.testPanelWidget3 = function testPanelWidget3(test) {
+exports.testPanelWidget3 = function testPanelWidget3(assert, done) {
   const widgets = require("sdk/widget");
   let onClickCalled = false;
   let widget3 = widgets.Widget({
     id: "panel3",
     label: "panel widget 3",
     content: "<div id='me'>foo</div>",
     contentScript: "var evt = new MouseEvent('click', {button: 0});" +
                    "document.body.firstElementChild.dispatchEvent(evt);",
     contentScriptWhen: "end",
     onClick: function() {
       onClickCalled = true;
       this.panel.show();
     },
     panel: require("sdk/panel").Panel({
       contentURL: "data:text/html;charset=utf-8,<body>Look ma, a panel!</body>",
       onShow: function() {
-        test.assert(
+        assert.ok(
           onClickCalled,
-          "onClick called on click for widget with both panel and onClick"
-        );
+          "onClick called on click for widget with both panel and onClick");
         widget3.destroy();
-        test.done();
+        done();
       }
     })
   });
-  test.waitUntilDone();
 };
 
-exports.testWidgetMessaging = function testWidgetMessaging(test) {
-  test.waitUntilDone();
+exports.testWidgetMessaging = function testWidgetMessaging(assert, done) {
   let origMessage = "foo";
   const widgets = require("sdk/widget");
   let widget = widgets.Widget({
     id: "foo",
     label: "foo",
     content: "<bar>baz</bar>",
     contentScriptWhen: "end",
     contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');",
     onMessage: function(message) {
       if (message == "ready")
         widget.postMessage(origMessage);
       else {
-        test.assertEqual(origMessage, message);
+        assert.equal(origMessage, message);
         widget.destroy();
-        test.done();
+        done();
       }
     }
   });
 };
 
-exports.testWidgetViews = function testWidgetViews(test) {
-  test.waitUntilDone();
+exports.testWidgetViews = function testWidgetViews(assert, done) {
   const widgets = require("sdk/widget");
   let widget = widgets.Widget({
     id: "foo",
     label: "foo",
     content: "<bar>baz</bar>",
     contentScriptWhen: "ready",
     contentScript: "self.on('message', function(data) self.postMessage(data)); self.postMessage('ready')",
     onAttach: function(view) {
-      test.pass("WidgetView created");
+      assert.pass("WidgetView created");
       view.on("message", function () {
-        test.pass("Got message in WidgetView");
+        assert.pass("Got message in WidgetView");
         widget.destroy();
       });
       view.on("detach", function () {
-        test.pass("WidgetView destroyed");
-        test.done();
+        assert.pass("WidgetView destroyed");
+        done();
       });
     }
   });
-
 };
 
-exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(test) {
-  test.waitUntilDone();
+exports.testWidgetViewsUIEvents = function testWidgetViewsUIEvents(assert, done) {
   const widgets = require("sdk/widget");
   let view = null;
   let widget = widgets.Widget({
     id: "foo",
     label: "foo",
     content: "<div id='me'>foo</div>",
     contentScript: "var evt = new MouseEvent('click', {button: 0});" +
                    "document.getElementById('me').dispatchEvent(evt);",
     contentScriptWhen: "ready",
     onAttach: function(attachView) {
       view = attachView;
-      test.pass("Got attach event");
+      assert.pass("Got attach event");
     },
     onClick: function (eventView) {
-      test.assertEqual(view, eventView,
+      assert.equal(view, eventView,
                          "event first argument is equal to the WidgetView");
       let view2 = widget.getView(require("sdk/windows").browserWindows.activeWindow);
-      test.assertEqual(view, view2,
+      assert.equal(view, view2,
                          "widget.getView return the same WidgetView");
       widget.destroy();
-      test.done();
+      done();
     }
   });
 };
 
-exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(test) {
-  test.waitUntilDone();
+exports.testWidgetViewsCustomEvents = function testWidgetViewsCustomEvents(assert, done) {
   const widgets = require("sdk/widget");
   let widget = widgets.Widget({
     id: "foo",
     label: "foo",
     content: "<div id='me'>foo</div>",
     contentScript: "self.port.emit('event', 'ok');",
     contentScriptWhen: "ready",
     onAttach: function(view) {
       view.port.on("event", function (data) {
-        test.assertEqual(data, "ok",
+        assert.equal(data, "ok",
                          "event argument is valid on WidgetView");
       });
     },
   });
   widget.port.on("event", function (data) {
-    test.assertEqual(data, "ok",
-                     "event argument is valid on Widget");
+    assert.equal(data, "ok", "event argument is valid on Widget");
     widget.destroy();
-    test.done();
+    done();
   });
 };
 
-exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(test) {
-  test.waitUntilDone();
+exports.testWidgetViewsTooltip = function testWidgetViewsTooltip(assert, done) {
   const widgets = require("sdk/widget");
 
   let widget = new widgets.Widget({
     id: "foo",
     label: "foo",
     content: "foo"
   });
   let view = widget.getView(require("sdk/windows").browserWindows.activeWindow);
   widget.tooltip = null;
-  test.assertEqual(view.tooltip, "foo",
-                   "view tooltip defaults to base widget label");
-  test.assertEqual(widget.tooltip, "foo",
-                   "tooltip defaults to base widget label");
+  assert.equal(view.tooltip, "foo",
+               "view tooltip defaults to base widget label");
+  assert.equal(widget.tooltip, "foo",
+               "tooltip defaults to base widget label");
   widget.destroy();
-  test.done();
+  done();
 };
 
-exports.testWidgetMove = function testWidgetMove(test) {
-  test.waitUntilDone();
-
+exports.testWidgetMove = function testWidgetMove(assert, done) {
   let windowUtils = require("sdk/deprecated/window-utils");
   let widgets = require("sdk/widget");
 
   let browserWindow = windowUtils.activeBrowserWindow;
   let doc = browserWindow.document;
 
   let label = "unique-widget-label";
   let origMessage = "message after node move";
@@ -898,137 +881,128 @@ exports.testWidgetMove = function testWi
     id: "foo",
     label: label,
     content: "<bar>baz</bar>",
     contentScriptWhen: "ready",
     contentScript: "self.on('message', function(data) { self.postMessage(data); }); self.postMessage('ready');",
     onMessage: function(message) {
       if (message == "ready") {
         if (!gotFirstReady) {
-          test.pass("Got first ready event");
+          assert.pass("Got first ready event");
           let widgetNode = doc.querySelector('toolbaritem[label="' + label + '"]');
           let parent = widgetNode.parentNode;
           parent.insertBefore(widgetNode, parent.firstChild);
           gotFirstReady = true;
-        } else {
-          test.pass("Got second ready event");
+        }
+        else {
+          assert.pass("Got second ready event");
           widget.postMessage(origMessage);
         }
       }
       else {
-        test.assertEqual(origMessage, message, "Got message after node move");
+        assert.equal(origMessage, message, "Got message after node move");
         widget.destroy();
-        test.done();
+        done();
       }
     }
   });
 };
 
 /*
 The bug is exhibited when a widget with HTML content has it's content
 changed to new HTML content with a pound in it. Because the src of HTML
 content is converted to a data URI, the underlying iframe doesn't
 consider the content change a navigation change, so doesn't load
 the new content.
 */
-exports.testWidgetWithPound = function testWidgetWithPound(test) {
-  test.waitUntilDone();
-
+exports.testWidgetWithPound = function testWidgetWithPound(assert, done) {
   function getWidgetContent(widget) {
     let windowUtils = require("sdk/deprecated/window-utils");
     let browserWindow = windowUtils.activeBrowserWindow;
     let doc = browserWindow.document;
     let widgetNode = doc.querySelector('toolbaritem[label="' + widget.label + '"]');
-    test.assert(widgetNode, 'found widget node in the front-end');
+    assert.ok(widgetNode, 'found widget node in the front-end');
     return widgetNode.firstChild.contentDocument.body.innerHTML;
   }
 
   let widgets = require("sdk/widget");
   let count = 0;
   let widget = widgets.Widget({
     id: "1",
     label: "foo",
     content: "foo",
     contentScript: "window.addEventListener('load', self.postMessage, false);",
     onMessage: function() {
       count++;
       if (count == 1) {
         widget.content = "foo#";
       }
       else {
-        test.assertEqual(getWidgetContent(widget), "foo#", "content updated to pound?");
+        assert.equal(getWidgetContent(widget), "foo#", "content updated to pound?");
         widget.destroy();
-        test.done();
+        done();
       }
     }
   });
 };
 
-exports.testContentScriptOptionsOption = function(test) {
-  test.waitUntilDone();
-
+exports.testContentScriptOptionsOption = function(assert, done) {
   let widget = require("sdk/widget").Widget({
       id: "fooz",
       label: "fooz",
       content: "fooz",
       contentScript: "self.postMessage( [typeof self.options.d, self.options] );",
       contentScriptWhen: "end",
       contentScriptOptions: {a: true, b: [1,2,3], c: "string", d: function(){ return 'test'}},
       onMessage: function(msg) {
-        test.assertEqual( msg[0], 'undefined', 'functions are stripped from contentScriptOptions' );
-        test.assertEqual( typeof msg[1], 'object', 'object as contentScriptOptions' );
-        test.assertEqual( msg[1].a, true, 'boolean in contentScriptOptions' );
-        test.assertEqual( msg[1].b.join(), '1,2,3', 'array and numbers in contentScriptOptions' );
-        test.assertEqual( msg[1].c, 'string', 'string in contentScriptOptions' );
+        assert.equal( msg[0], 'undefined', 'functions are stripped from contentScriptOptions' );
+        assert.equal( typeof msg[1], 'object', 'object as contentScriptOptions' );
+        assert.equal( msg[1].a, true, 'boolean in contentScriptOptions' );
+        assert.equal( msg[1].b.join(), '1,2,3', 'array and numbers in contentScriptOptions' );
+        assert.equal( msg[1].c, 'string', 'string in contentScriptOptions' );
         widget.destroy();
-        test.done();
+        done();
       }
     });
 };
 
-exports.testOnAttachWithoutContentScript = function(test) {
-  test.waitUntilDone();
-
+exports.testOnAttachWithoutContentScript = function(assert, done) {
   let widget = require("sdk/widget").Widget({
       id: "onAttachNoCS",
       label: "onAttachNoCS",
       content: "onAttachNoCS",
       onAttach: function (view) {
-        test.pass("received attach event");
+        assert.pass("received attach event");
         widget.destroy();
-        test.done();
+        done();
       }
     });
 };
 
-exports.testPostMessageOnAttach = function(test) {
-  test.waitUntilDone();
-
+exports.testPostMessageOnAttach = function(assert, done) {
   let widget = require("sdk/widget").Widget({
       id: "onAttach",
       label: "onAttach",
       content: "onAttach",
       // 1) Send a message immediatly after `attach` event
       onAttach: function (view) {
         view.postMessage("ok");
       },
       // 2) Listen to it and forward it back to the widget
       contentScript: "self.on('message', self.postMessage);",
       // 3) Listen to this forwarded message
       onMessage: function (msg) {
-        test.assertEqual( msg, "ok", "postMessage works on `attach` event");
+        assert.equal( msg, "ok", "postMessage works on `attach` event");
         widget.destroy();
-        test.done();
+        done();
       }
     });
 };
 
-exports.testPostMessageOnLocationChange = function(test) {
-  test.waitUntilDone();
-
+exports.testPostMessageOnLocationChange = function(assert, done) {
   let attachEventCount = 0;
   let messagesCount = 0;
   let widget = require("sdk/widget").Widget({
       id: "onLocationChange",
       label: "onLocationChange",
       content: "onLocationChange",
       contentScript: "new " + function ContentScriptScope() {
         // Emit an event when content script is applied in order to know when
@@ -1036,57 +1010,53 @@ exports.testPostMessageOnLocationChange 
         self.postMessage("ready");
         // And forward any incoming message back to the widget to see if
         // messaging is working on 2nd document
         self.on("message", self.postMessage);
       },
       onMessage: function (msg) {
         messagesCount++;
         if (messagesCount == 1) {
-          test.assertEqual(msg, "ready", "First document is loaded");
+          assert.equal(msg, "ready", "First document is loaded");
           widget.content = "location changed";
         }
         else if (messagesCount == 2) {
-          test.assertEqual(msg, "ready", "Second document is loaded");
+          assert.equal(msg, "ready", "Second document is loaded");
           widget.postMessage("ok");
         }
         else if (messagesCount == 3) {
-          test.assertEqual(msg, "ok",
-                           "We receive the message sent to the 2nd document");
+          assert.equal(msg, "ok",
+                       "We receive the message sent to the 2nd document");
           widget.destroy();
-          test.done();
+          done();
         }
       }
     });
 };
 
-exports.testSVGWidget = function(test) {
-  test.waitUntilDone();
-
+exports.testSVGWidget = function(assert, done) {
   // use of capital SVG here is intended, that was failing..
   let SVG_URL = self.data.url("mofo_logo.SVG");
 
   let widget = require("sdk/widget").Widget({
     id: "mozilla-svg-logo",
     label: "moz foundation logo",
     contentURL: SVG_URL,
     contentScript: "self.postMessage({count: window.document.images.length, src: window.document.images[0].src});",
     onMessage: function(data) {
       widget.destroy();
-      test.assertEqual(data.count, 1, 'only one image');
-      test.assertEqual(data.src, SVG_URL, 'only one image');
-      test.done();
+      assert.equal(data.count, 1, 'only one image');
+      assert.equal(data.src, SVG_URL, 'only one image');
+      done();
     }
   });
 };
 
 if (!australis) {
-  exports.testNavigationBarWidgets = function testNavigationBarWidgets(test) {
-    test.waitUntilDone();
-
+  exports.testNavigationBarWidgets = function testNavigationBarWidgets(assert, done) {
     let w1 = widgets.Widget({id: "1st", label: "1st widget", content: "1"});
     let w2 = widgets.Widget({id: "2nd", label: "2nd widget", content: "2"});
     let w3 = widgets.Widget({id: "3rd", label: "3rd widget", content: "3"});
 
     // First wait for all 3 widgets to be added to the current browser window
     let firstAttachCount = 0;
     function onAttachFirstWindow(widget) {
       if (++firstAttachCount<3)
@@ -1141,43 +1111,30 @@ if (!australis) {
       function onAttach(widget) {
         if (++attachCount < 3)
           return;
         let doc = browserWindow2.document;
         let addonBar = doc.getElementById("addon-bar");
         let searchBox = doc.getElementById("search-container");
 
         // Ensure that 1st is in addon bar
-        test.assertEqual(getWidgetNode(addonBar, 0).getAttribute("label"), w1.label);
+        assert.equal(getWidgetNode(addonBar, 0).getAttribute("label"), w1.label);
         // And that 2nd and 3rd keep their original positions in navigation bar,
         // i.e. right after search box
-        test.assertEqual(searchBox.nextSibling.getAttribute("label"), w2.label);
-        test.assertEqual(searchBox.nextSibling.nextSibling.getAttribute("label"), w3.label);
+        assert.equal(searchBox.nextSibling.getAttribute("label"), w2.label);
+        assert.equal(searchBox.nextSibling.nextSibling.getAttribute("label"), w3.label);
 
         w1.destroy();
         w2.destroy();
         w3.destroy();
 
-        closeBrowserWindow(browserWindow2, function() {
-          test.done();
-        });
+        close(browserWindow2).then(done);
       }
       w1.on("attach", onAttach);
       w2.on("attach", onAttach);
       w3.on("attach", onAttach);
 
       browserWindow2 = openBrowserWindow(browserWindow);
     }
   };
 }
 
-/******************* helpers *********************/
-
-// Helper for calling code at window close
-function closeBrowserWindow(window, callback) {
-  timer.setTimeout(function() {
-    window.addEventListener("unload", function onUnload() {
-      window.removeEventListener("unload", onUnload, false);
-      callback();
-    }, false);
-    window.close();
-  }, 0);
-}
+require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-window-events.js
+++ b/addon-sdk/source/test/test-window-events.js
@@ -16,18 +16,29 @@ const { open, getMostRecentBrowserWindow
 exports["test browser events"] = function(assert, done) {
   let loader = Loader(module);
   let { events } = loader.require("sdk/window/events");
   let { on, off } = loader.require("sdk/event/core");
   let actual = [];
 
   on(events, "data", function handler(e) {
     actual.push(e);
-    if (e.type === "load") window.close();
-    if (e.type === "close") {
+
+    if (e.type === "open") {
+      assert.pass("window open has occured");
+    }
+    else if (e.type === "DOMContentLoaded") {
+      assert.pass("window DOMContentLoaded has occured");
+    }
+    else if (e.type === "load") {
+      assert.pass("window load has occured");
+      window.close();
+    }
+    else if (e.type === "close") {
+      // confirm the ordering of events
       let [ open, ready, load, close ] = actual;
       assert.equal(open.type, "open")
       assert.equal(open.target, window, "window is open")
 
       assert.equal(ready.type, "DOMContentLoaded")
       assert.equal(ready.target, window, "window ready")
 
       assert.equal(load.type, "load")
--- a/addon-sdk/source/test/test-window-loader.js
+++ b/addon-sdk/source/test/test-window-loader.js
@@ -1,12 +1,12 @@
 /* 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";
+'use strict';
 
 // Opening new windows in Fennec causes issues
 module.metadata = {
   engines: {
     'Firefox': '*'
   }
 };
 
@@ -26,101 +26,88 @@ const Loader = Trait.compose(
     },
     window: null,
     _onLoad: null,
     _onUnload: null,
     _tabOptions: []
   }
 );
 
-exports['test compositions with missing required properties'] = function(test) {
-  test.assertRaises(
+exports['test compositions with missing required properties'] = function(assert) {
+  assert.throws(
     function() WindowLoader.compose({})(),
-    'Missing required property: _onLoad',
+    /Missing required property: _onLoad/,
     'should throw missing required property exception'
   );
-  test.assertRaises(
+  assert.throws(
     function() WindowLoader.compose({ _onLoad: null, _tabOptions: null })(),
-    'Missing required property: _onUnload',
+    /Missing required property: _onUnload/,
     'should throw missing required property `_onUnload`'
   );
-  test.assertRaises(
+  assert.throws(
     function() WindowLoader.compose({ _onUnload: null, _tabOptions: null })(),
-    'Missing required property: _onLoad',
+    /Missing required property: _onLoad/,
     'should throw missing required property `_onLoad`'
   );
-  test.assertRaises(
+  assert.throws(
     function() WindowLoader.compose({ _onUnload: null, _onLoad: null })(),
-    'Missing required property: _tabOptions',
+    /Missing required property: _tabOptions/,
     'should throw missing required property `_tabOptions`'
   );
 };
 
-exports['test `load` events'] = function(test) {
-  test.waitUntilDone();
+exports['test `load` events'] = function(assert, done) {
   let onLoadCalled = false;
   Loader({
     onLoad: function(window) {
       onLoadCalled = true;
-      test.assertEqual(
-        window, this._window, 'windows should match'
-      );
-      test.assertEqual(
+      assert.equal(window, this._window, 'windows should match');
+      assert.equal(
         window.document.readyState, 'complete', 'window must be fully loaded'
       );
       window.close();
     },
     onUnload: function(window) {
-      test.assertEqual(
-        window, this._window, 'windows should match'
-      );
-      test.assertEqual(
+      assert.equal(window, this._window, 'windows should match');
+      assert.equal(
         window.document.readyState, 'complete', 'window must be fully loaded'
       );
-      test.assert(onLoadCalled, 'load callback is supposed to be called');
-      test.done();
+      assert.ok(onLoadCalled, 'load callback is supposed to be called');
+      done();
     }
   });
 };
 
-exports['test removeing listeners'] = function(test) {
-  test.waitUntilDone();
+exports['test removeing listeners'] = function(assert, done) {
   Loader({
     onLoad: function(window) {
-      test.assertEqual(
-        window, this._window, 'windows should match'
-      );
+      assert.equal(window, this._window, 'windows should match');
       window.close();
     },
-    onUnload: function(window) {
-      test.done();
-    }
+    onUnload: done
   });
 };
 
-exports['test create loader from opened window'] = function(test) {
-  test.waitUntilDone();
+exports['test create loader from opened window'] = function(assert, done) {
   let onUnloadCalled = false;
   Loader({
     onLoad: function(window) {
-      test.assertEqual(
-        window, this._window, 'windows should match'
-      );
-      test.assertEqual(
-        window.document.readyState, 'complete', 'window must be fully loaded'
-      );
+      assert.equal(window, this._window, 'windows should match');
+      assert.equal(window.document.readyState, 'complete', 'window must be fully loaded');
       Loader({
         window: window,
         onLoad: function(win) {
-          test.assertEqual(win, window, 'windows should match');
+          assert.equal(win, window, 'windows should match');
           window.close();
         },
         onUnload: function(window) {
-          test.assert(onUnloadCalled, 'first handler should be called already');
-          test.done();
+          assert.ok(onUnloadCalled, 'first handler should be called already');
+          done();
         }
       });
     },
     onUnload: function(window) {
       onUnloadCalled = true;
     }
   });
 };
+
+require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-window-observer.js
+++ b/addon-sdk/source/test/test-window-observer.js
@@ -53,9 +53,9 @@ exports["test unload window observer"] =
   function onClose(window) {
     // Ignore non-browser windows & already opened `activeWindow` (unload will
     // emit close on it even though it is not actually closed).
     if (isBrowser(window))
       closed++;
   }
 };
 
-require("test").run(exports);
+require("sdk/test").run(exports);
--- a/addon-sdk/source/test/windows/test-firefox-windows.js
+++ b/addon-sdk/source/test/windows/test-firefox-windows.js
@@ -11,400 +11,403 @@ const { open, close, focus } = require('
 const { browserWindows } = require("sdk/windows");
 const tabs = require("sdk/tabs");
 const winUtils = require("sdk/deprecated/window-utils");
 const { WindowTracker } = winUtils;
 const { isPrivate } = require('sdk/private-browsing');
 const { isWindowPBSupported } = require('sdk/private-browsing/utils');
 
 // TEST: open & close window
-exports.testOpenAndCloseWindow = function(test) {
-  test.waitUntilDone();
-
-  test.assertEqual(browserWindows.length, 1, "Only one window open");
+exports.testOpenAndCloseWindow = function(assert, done) {
+  assert.equal(browserWindows.length, 1, "Only one window open");
+  let title = 'testOpenAndCloseWindow';
 
   browserWindows.open({
-    url: "data:text/html;charset=utf-8,<title>windows API test</title>",
+    url: "data:text/html;charset=utf-8,<title>" + title + "</title>",
     onOpen: function(window) {
-      test.assertEqual(this, browserWindows,
-                       "The 'this' object is the windows object.");
-      test.assertEqual(window.tabs.length, 1, "Only one tab open");
-      test.assertEqual(browserWindows.length, 2, "Two windows open");
-      window.tabs.activeTab.on('ready', function onReady(tab) {
-        tab.removeListener('ready', onReady);
-        test.assert(window.title.indexOf("windows API test") != -1,
-                    "URL correctly loaded");
+      assert.equal(this, browserWindows, "The 'this' object is the windows object.");
+      assert.equal(window.tabs.length, 1, "Only one tab open");
+      assert.equal(browserWindows.length, 2, "Two windows open");
+
+      window.tabs.activeTab.once('ready', function onReady(tab) {
+        assert.pass(RegExp(title).test(window.title), "URL correctly loaded");
         window.close();
       });
     },
     onClose: function(window) {
-      test.assertEqual(window.tabs.length, 0, "Tabs were cleared");
-      test.assertEqual(browserWindows.length, 1, "Only one window open");
-      test.done();
+      assert.equal(window.tabs.length, 0, "Tabs were cleared");
+      assert.equal(browserWindows.length, 1, "Only one window open");
+      done();
     }
   });
 };
 
-exports.testAutomaticDestroy = function(test) {
-  test.waitUntilDone();
-
+exports.testAutomaticDestroy = function(assert, done) {
   let windows = browserWindows;
 
   // Create a second windows instance that we will unload
   let called = false;
   let loader = Loader(module);
   let windows2 = loader.require("sdk/windows").browserWindows;
+
   windows2.on("open", function() {
     called = true;
   });
 
   loader.unload();
 
   // Fire a windows event and check that this unloaded instance is inactive
   windows.open({
     url: "data:text/html;charset=utf-8,foo",
     onOpen: function(window) {
       setTimeout(function () {
-        test.assert(!called,
-          "Unloaded windows instance is destroyed and inactive");
-        window.close(function () {
-          test.done();
-        });
+        assert.ok(!called, "Unloaded windows instance is destroyed and inactive");
+
+        window.close(done);
       });
     }
   });
 };
 
-exports.testWindowTabsObject = function(test) {
-  test.waitUntilDone();
-
-  let count = 0;
-  let window;
+exports.testWindowTabsObject = function(assert, done) {
+  let window, count = 0;
   function runTest() {
     if (++count != 2)
       return;
 
-    test.assertEqual(window.tabs.length, 1, "Only 1 tab open");
-    test.assertEqual(window.tabs.activeTab.title, "tab 1", "Correct active tab");
+    assert.equal(window.tabs.length, 1, "Only 1 tab open");
+    assert.equal(window.tabs.activeTab.title, "tab 1", "Correct active tab");
 
     window.tabs.open({
       url: "data:text/html;charset=utf-8,<title>tab 2</title>",
       inBackground: true,
       onReady: function onReady(newTab) {
-        test.assertEqual(window.tabs.length, 2, "New tab open");
-        test.assertEqual(newTab.title, "tab 2", "Correct new tab title");
-        test.assertEqual(window.tabs.activeTab.title, "tab 1", "Correct active tab");
+        assert.equal(window.tabs.length, 2, "New tab open");
+        assert.equal(newTab.title, "tab 2", "Correct new tab title");
+        assert.equal(window.tabs.activeTab.title, "tab 1", "Correct active tab");
 
         let i = 1;
-        for each (let tab in window.tabs)
-          test.assertEqual(tab.title, "tab " + i++, "Correct title");
+        for (let tab of window.tabs)
+          assert.equal(tab.title, "tab " + i++, "Correct title");
 
         window.close();
       }
     });
   }
+
+  tabs.once("ready", runTest);
+
   browserWindows.open({
     url: "data:text/html;charset=utf-8,<title>tab 1</title>",
     onActivate: function onActivate(win) {
       window = win;
       runTest();
     },
     onClose: function onClose(window) {
-      test.assertEqual(window.tabs.length, 0, "No more tabs on closed window");
-      test.done();
+      assert.equal(window.tabs.length, 0, "No more tabs on closed window");
+      done();
     }
   });
-  tabs.once("ready", runTest);
 };
 
-exports.testOnOpenOnCloseListeners = function(test) {
-  test.waitUntilDone();
+exports.testOnOpenOnCloseListeners = function(assert, done) {
   let windows = browserWindows;
 
-  test.assertEqual(browserWindows.length, 1, "Only one window open");
+  assert.equal(browserWindows.length, 1, "Only one window open");
 
   let received = {
     listener1: false,
     listener2: false,
     listener3: false,
     listener4: false
   }
 
-   function listener1() {
-    test.assertEqual(this, windows, "The 'this' object is the windows object.");
+  function listener1() {
+    assert.equal(this, windows, "The 'this' object is the windows object.");
+
     if (received.listener1)
-      test.fail("Event received twice");
+      assert.fail("Event received twice");
     received.listener1 = true;
   }
 
   function listener2() {
     if (received.listener2)
-      test.fail("Event received twice");
+      assert.fail("Event received twice");
     received.listener2 = true;
   }
 
   function listener3() {
-    test.assertEqual(this, windows, "The 'this' object is the windows object.");
+    assert.equal(this, windows, "The 'this' object is the windows object.");
     if (received.listener3)
-      test.fail("Event received twice");
+      assert.fail("Event received twice");
     received.listener3 = true;
   }
 
   function listener4() {
     if (received.listener4)
-      test.fail("Event received twice");
+      assert.fail("Event received twice");
     received.listener4 = true;
   }
 
   windows.on('open', listener1);
   windows.on('open', listener2);
   windows.on('close', listener3);
   windows.on('close', listener4);
 
-  function verify() {
-    test.assert(received.listener1, "onOpen handler called");
-    test.assert(received.listener2, "onOpen handler called");
-    test.assert(received.listener3, "onClose handler called");
-    test.assert(received.listener4, "onClose handler called");
-
-    windows.removeListener('open', listener1);
-    windows.removeListener('open', listener2);
-    windows.removeListener('close', listener3);
-    windows.removeListener('close', listener4);
-    test.done();
-  }
-
-
   windows.open({
     url: "data:text/html;charset=utf-8,foo",
     onOpen: function(window) {
-      window.close(verify);
+      window.close(function() {
+        assert.ok(received.listener1, "onOpen handler called");
+        assert.ok(received.listener2, "onOpen handler called");
+        assert.ok(received.listener3, "onClose handler called");
+        assert.ok(received.listener4, "onClose handler called");
+
+        windows.removeListener('open', listener1);
+        windows.removeListener('open', listener2);
+        windows.removeListener('close', listener3);
+        windows.removeListener('close', listener4);
+
+        done();
+      });
     }
   });
 };
 
-/*
-Disabled due to all of the Win8 PGO bustage in bug 873007.
-exports.testActiveWindow = function(test) {
+exports.testActiveWindow = function(assert, done) {
   let windows = browserWindows;
 
   // API window objects
   let window2, window3;
 
   // Raw window objects
   let rawWindow2, rawWindow3;
 
-  test.waitUntilDone();
-
   let testSteps = [
     function() {
-      test.assertEqual(windows.length, 3, "Correct number of browser windows");
+      assert.equal(windows.length, 3, "Correct number of browser windows");
+
       let count = 0;
       for (let window in windows)
         count++;
-      test.assertEqual(count, 3, "Correct number of windows returned by iterator");
+      assert.equal(count, 3, "Correct number of windows returned by iterator");
 
-      test.assertEqual(windows.activeWindow.title, window3.title, "Correct active window - 3");
+      assert.equal(windows.activeWindow.title, window3.title, "Correct active window - 3");
 
       continueAfterFocus(rawWindow2);
       rawWindow2.focus();
     },
     function() {
-      nextStep();
-    },
-    function() {
-      test.assertEqual(windows.activeWindow.title, window2.title, "Correct active window - 2");
+      assert.equal(windows.activeWindow.title, window2.title, "Correct active window - 2");
 
       continueAfterFocus(rawWindow2);
       window2.activate();
     },
     function() {
-      test.assertEqual(windows.activeWindow.title, window2.title, "Correct active window - 2");
+      assert.equal(windows.activeWindow.title, window2.title, "Correct active window - 2");
+
       continueAfterFocus(rawWindow3);
       window3.activate();
     },
     function() {
-      test.assertEqual(windows.activeWindow.title, window3.title, "Correct active window - 3");
+      assert.equal(windows.activeWindow.title, window3.title, "Correct active window - 3");
       finishTest();
     }
   ];
 
   let newWindow = null;
   let tracker = new WindowTracker({
     onTrack: function(window) {
       newWindow = window;
     }
   });
 
   windows.open({
     url: "data:text/html;charset=utf-8,<title>window 2</title>",
     onOpen: function(window) {
+      assert.pass('window 2 open');
+
       window.tabs.activeTab.on('ready', function() {
+        assert.pass('window 2 tab activated');
+
         window2 = window;
-        test.assert(newWindow, "A new window was opened");
+        assert.ok(newWindow, "A new window was opened");
         rawWindow2 = newWindow;
         newWindow = null;
-        test.assertEqual(rawWindow2.content.document.title, "window 2", "Got correct raw window 2");
-        test.assertEqual(rawWindow2.document.title, window2.title, "Saw correct title on window 2");
+
+        assert.equal(rawWindow2.content.document.title, "window 2", "Got correct raw window 2");
+        assert.equal(rawWindow2.document.title, window2.title, "Saw correct title on window 2");
 
         windows.open({
           url: "data:text/html;charset=utf-8,<title>window 3</title>",
           onOpen: function(window) {
+            assert.pass('window 3 open');
+
             window.tabs.activeTab.on('ready', function onReady() {
+              assert.pass('window 3 tab activated');
+
               window3 = window;
-              test.assert(newWindow, "A new window was opened");
+              assert.ok(newWindow, "A new window was opened");
               rawWindow3 = newWindow;
               tracker.unload();
-              test.assertEqual(rawWindow3.content.document.title, "window 3", "Got correct raw window 3");
-              test.assertEqual(rawWindow3.document.title, window3.title, "Saw correct title on window 3");
+
+              assert.equal(rawWindow3.content.document.title, "window 3", "Got correct raw window 3");
+              assert.equal(rawWindow3.document.title, window3.title, "Saw correct title on window 3");
+
               continueAfterFocus(rawWindow3);
               rawWindow3.focus();
             });
           }
         });
       });
     }
   });
 
   function nextStep() {
-    if (testSteps.length)
-      testSteps.shift()();
+    if (testSteps.length) {
+      setTimeout(testSteps.shift())
+    }
   }
 
   let continueAfterFocus = function(w) onFocus(w).then(nextStep);
 
   function finishTest() {
-    window3.close(function() {
-      window2.close(function() {
-        test.done();
+    // close unactive window first to avoid unnecessary focus changing
+    window2.close(function() {
+      window3.close(function() {
+        assert.equal(rawWindow2.closed, true, 'window 2 is closed');
+        assert.equal(rawWindow3.closed, true, 'window 3 is closed');
+
+        done();
       });
     });
   }
 };
-*/
 
-exports.testTrackWindows = function(test) {
-  test.waitUntilDone();
-
+exports.testTrackWindows = function(assert, done) {
   let windows = [];
   let actions = [];
 
   let expects = [
     "activate 0", "global activate 0", "deactivate 0", "global deactivate 0",
     "activate 1", "global activate 1", "deactivate 1", "global deactivate 1",
     "activate 2", "global activate 2"
   ];
 
+  function windowsActivation(window) {
+    let index = windows.indexOf(window);
+    // only concerned with windows opened for this test
+    if (index < 0)
+      return;
+
+    assert.equal(actions.join(), expects.slice(0, index*4 + 1).join(), expects[index*4 + 1]);
+    actions.push("global activate " + index)
+  }
+
+  function windowsDeactivation(window) {
+    let index = windows.indexOf(window);
+    // only concerned with windows opened for this test
+    if (index < 0)
+      return;
+
+    assert.equal(actions.join(), expects.slice(0, index*4 + 3).join(), expects[index*4 + 3]);
+    actions.push("global deactivate " + index)
+  }
+
+  // listen to global activate events
+  browserWindows.on("activate", windowsActivation);
+
+  // listen to global deactivate events
+  browserWindows.on("deactivate", windowsDeactivation);
+
+
   function openWindow() {
     windows.push(browserWindows.open({
       url: "data:text/html;charset=utf-8,<i>testTrackWindows</i>",
-
       onActivate: function(window) {
         let index = windows.indexOf(window);
 
-        test.assertEqual(actions.join(), expects.slice(0, index*4).join(), expects[index*4]);
+        assert.equal(actions.join(),
+                     expects.slice(0, index*4).join(),
+                     "expecting " + expects[index*4]);
         actions.push("activate " + index);
 
         if (windows.length < 3) {
           openWindow()
         }
         else {
           (function closeWindows(windows) {
-            if (!windows.length)
-              return test.done();
+            if (!windows.length) {
+              browserWindows.removeListener("activate", windowsActivation);
+              browserWindows.removeListener("deactivate", windowsDeactivation);
+              return done();
+            }
 
             return windows.pop().close(function() {
-              test.pass('window was closed');
+              assert.pass('window was closed');
               closeWindows(windows);
             });
           })(windows)
         }
       },
-
       onDeactivate: function(window) {
         let index = windows.indexOf(window);
 
-        test.assertEqual(actions.join(), expects.slice(0, index*4 + 2).join(), expects[index*4 + 2]);
+        assert.equal(actions.join(),
+                     expects.slice(0, index*4 + 2).join(),
+                     "expecting " + expects[index*4 + 2]);
         actions.push("deactivate " + index)
       }
     }));
   }
-
-  browserWindows.on("activate", function (window) {
-    let index = windows.indexOf(window);
-    // only concerned with windows opened for this test
-    if (index < 0)
-      return;
-
-    test.assertEqual(actions.join(), expects.slice(0, index*4 + 1).join(), expects[index*4 + 1]);
-    actions.push("global activate " + index)
-  })
-
-  browserWindows.on("deactivate", function (window) {
-    let index = windows.indexOf(window);
-    // only concerned with windows opened for this test
-    if (index < 0)
-      return;
-
-    test.assertEqual(actions.join(), expects.slice(0, index*4 + 3).join(), expects[index*4 + 3]);
-    actions.push("global deactivate " + index)
-  })
-
   openWindow();
 }
 
 // test that it is not possible to open a private window by default
-exports.testWindowOpenPrivateDefault = function(test) {
-  test.waitUntilDone();
-
+exports.testWindowOpenPrivateDefault = function(assert, done) {
   browserWindows.open({
     url: 'about:mozilla',
     isPrivate: true,
     onOpen: function(window) {
       let tab = window.tabs[0];
+
       tab.once('ready', function() {
-        test.assertEqual(tab.url, 'about:mozilla', 'opened correct tab');
-        test.assertEqual(isPrivate(tab), false, 'tab is not private');
+        assert.equal(tab.url, 'about:mozilla', 'opened correct tab');
+        assert.equal(isPrivate(tab), false, 'tab is not private');
 
-        window.close(test.done.bind(test));
+        window.close(done);
       });
     }
   });
 }
 
 // test that it is not possible to find a private window in
 // windows module's iterator
-exports.testWindowIteratorPrivateDefault = function(test) {
-  test.waitUntilDone();
-
-  test.assertEqual(browserWindows.length, 1, 'only one window open');
+exports.testWindowIteratorPrivateDefault = function(assert, done) {
+  assert.equal(browserWindows.length, 1, 'only one window open');
 
   open('chrome://browser/content/browser.xul', {
     features: {
       private: true,
       chrome: true
     }
-  }).then(function(window) focus(window).then(function() {
+  }).then(focus).then(function(window) {
     // test that there is a private window opened
-    test.assertEqual(isPrivate(window), isWindowPBSupported, 'there is a private window open');
-    test.assertStrictEqual(window, winUtils.activeWindow);
-    test.assertStrictEqual(window, getMostRecentWindow());
+    assert.equal(isPrivate(window), isWindowPBSupported, 'there is a private window open');
+    assert.strictEqual(window, winUtils.activeWindow);
+    assert.strictEqual(window, getMostRecentWindow());
 
-    test.assert(!isPrivate(browserWindows.activeWindow));
+    assert.ok(!isPrivate(browserWindows.activeWindow));
+
+    assert.equal(browserWindows.length, 1, 'only one window in browserWindows');
+    assert.equal(windows().length, 1, 'only one window in windows()');
 
-    if (isWindowPBSupported) {
-      test.assertEqual(browserWindows.length, 1, 'only one window in browserWindows');
-      test.assertEqual(windows().length, 1, 'only one window in windows()');
-    }
-    else {
-      test.assertEqual(browserWindows.length, 2, 'two windows open');
-      test.assertEqual(windows().length, 2, 'two windows in windows()');
-    }
-    test.assertEqual(windows(null, { includePrivate: true }).length, 2);
+    assert.equal(windows(null, { includePrivate: true }).length, 2);
+
+    // test that all windows in iterator are not private
+    for (let window of browserWindows)
+      assert.ok(!isPrivate(window), 'no window in browserWindows is private');
 
-    for each(let window in browserWindows) {
-      // test that all windows in iterator are not private
-      test.assert(!isPrivate(window), 'no window in browserWindows is private');
-    }
+    close(window).then(done);
+  });
+}
 
-    close(window).then(test.done.bind(test));
-  }));
-}
+require('sdk/test').run(exports);
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -992,16 +992,17 @@ let RemoteDebugger = {
         if ("nsIProfiler" in Ci) {
           DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/profiler.js");
         }
         DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/styleeditor.js");
         DebuggerServer.enableWebappsContentActor = true;
       }
       DebuggerServer.addActors('chrome://browser/content/dbg-browser-actors.js');
       DebuggerServer.addActors("resource://gre/modules/devtools/server/actors/webapps.js");
+      DebuggerServer.registerModule("devtools/server/actors/device");
     }
 
     let port = Services.prefs.getIntPref('devtools.debugger.remote-port') || 6000;
     try {
       DebuggerServer.openListener(port);
     } catch (e) {
       dump('Unable to start debugger server: ' + e + '\n');
     }
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "dbaee540a7d23d271e62e7da80d7db226be8860b", 
+    "revision": "085648d44f2a1ad2c73b0eb4225c6448104e70f5", 
     "repo_path": "/integration/gaia-central"
 }
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/Makefile.in
@@ -0,0 +1,16 @@
+#
+# 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/.
+
+DEPTH		= @DEPTH@
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+include $(topsrcdir)/config/rules.mk
+
+libs::
+	$(NSINSTALL) $(srcdir)/*.js $(FINAL_TARGET)/modules/devtools/app-manager
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/connection-store.js
@@ -0,0 +1,48 @@
+/* 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 ObservableObject = require("devtools/shared/observable-object");
+const {Connection} = require("devtools/client/connection-manager");
+
+const _knownConnectionStores = new WeakMap();
+
+let ConnectionStore;
+
+module.exports = ConnectionStore = function(connection) {
+  // If we already know about this connection,
+  // let's re-use the existing store.
+  if (_knownConnectionStores.has(connection)) {
+    return _knownConnectionStores.get(connection);
+  }
+  _knownConnectionStores.set(connection, this);
+
+  ObservableObject.call(this, {status:null,host:null,port:null});
+
+  this._destroy = this._destroy.bind(this);
+  this._feedStore = this._feedStore.bind(this);
+
+  this._connection = connection;
+  this._connection.once(Connection.Events.DESTROYED, this._destroy);
+  this._connection.on(Connection.Events.STATUS_CHANGED, this._feedStore);
+  this._connection.on(Connection.Events.PORT_CHANGED, this._feedStore);
+  this._connection.on(Connection.Events.HOST_CHANGED, this._feedStore);
+  this._feedStore();
+  return this;
+}
+
+ConnectionStore.prototype = {
+  _destroy: function() {
+    this._connection.off(Connection.Events.STATUS_CHANGED, this._feedStore);
+    this._connection.off(Connection.Events.PORT_CHANGED, this._feedStore);
+    this._connection.off(Connection.Events.HOST_CHANGED, this._feedStore);
+    _knownConnectionStores.delete(this._connection);
+    this._connection = null;
+  },
+
+  _feedStore: function() {
+    this.object.status = this._connection.status;
+    this.object.host = this._connection.host;
+    this.object.port = this._connection.port;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/content/template.js
@@ -0,0 +1,320 @@
+/* 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/. */
+
+/**
+ * Template mechanism based on Object Emitters.
+ *
+ * The data used to expand the templates comes from
+ * a ObjectEmitter object. The templates are automatically
+ * updated as the ObjectEmitter is updated (via the "set"
+ * event). See documentation in observable-object.js.
+ *
+ * Templates are used this way:
+ *
+ * (See examples in browser/devtools/app-manager/content/*.xhtml)
+ *
+ * <div template="{JSON Object}">
+ *
+ * {
+ *  type: "attribute"
+ *  name: name of the attribute
+ *  path: location of the attribute value in the ObjectEmitter
+ * }
+ *
+ * {
+ *  type: "textContent"
+ *  path: location of the textContent value in the ObjectEmitter
+ * }
+ *
+ * {
+ *  type: "localizedContent"
+ *  paths: array of locations of the value of the arguments of the property
+ *  property: l10n property
+ * }
+ *
+ * <div template-loop="{JSON Object}">
+ *
+ * {
+ *  arrayPath: path of the array in the ObjectEmitter to loop from
+ *  childSelector: selector of the element to duplicate in the loop
+ * }
+ *
+ */
+
+const NOT_FOUND_STRING = "n/a";
+
+/**
+ * let t = new Template(root, store, l10nResolver);
+ * t.start();
+ *
+ * @param DOMNode root.
+ *        Node from where templates are expanded.
+ * @param ObjectEmitter store.
+ *        ObjectEmitter object.
+ * @param function (property, args). l10nResolver
+ *        A function that returns localized content.
+ */
+function Template(root, store, l10nResolver) {
+  this._store = store;
+  this._l10n = l10nResolver;
+
+  // Listeners are stored in Maps.
+  // path => Set(node1, node2, ..., nodeN)
+  // For example: "foo.bar.4.name" => Set(div1,div2)
+
+  this._nodeListeners = new Map();
+  this._loopListeners = new Map();
+  this._root = root;
+  this._doc = this._root.ownerDocument;
+
+  this._store.on("set", (event,path,value) => this._storeChanged(path,value));
+}
+
+Template.prototype = {
+  start: function() {
+    this._processTree(this._root);
+  },
+
+  _resolvePath: function(path, defaultValue=null) {
+
+    // From the store, get the value of an object located
+    // at @path.
+    //
+    // For example, if the store is designed as:
+    //
+    // {
+    //   foo: {
+    //     bar: [
+    //       {},
+    //       {},
+    //       {a: 2}
+    //   }
+    // }
+    //
+    // _resolvePath("foo.bar.2.a") will return "2".
+    //
+    // Array indexes are not surrounded by brackets.
+
+    let chunks = path.split(".");
+    let obj = this._store.object;
+    for (let word of chunks) {
+      if ((typeof obj) == "object" &&
+          (word in obj)) {
+        obj = obj[word];
+      } else {
+        return defaultValue;
+      }
+    }
+    return obj;
+  },
+
+  _storeChanged: function(path, value) {
+
+    // The store has changed (a "set" event has been emitted).
+    // We need to invalidate and rebuild the affected elements.
+
+    let strpath = path.join(".");
+    this._invalidate(strpath);
+
+    for (let [registeredPath, set] of this._nodeListeners) {
+      if (strpath != registeredPath &&
+          registeredPath.indexOf(strpath) > -1) {
+        this._invalidate(registeredPath);
+      }
+    }
+  },
+
+  _invalidate: function(path) {
+    // Loops:
+    let set = this._loopListeners.get(path);
+    if (set) {
+      for (let elt of set) {
+        this._processLoop(elt);
+      }
+    }
+
+    // Nodes:
+    set = this._nodeListeners.get(path);
+    if (set) {
+      for (let elt of set) {
+        this._processNode(elt);
+      }
+    }
+  },
+
+  _registerNode: function(path, element) {
+
+    // We map a node to a path.
+    // If the value behind this path is updated,
+    // we get notified from the ObjectEmitter,
+    // and then we know which objects to update.
+
+    if (!this._nodeListeners.has(path)) {
+      this._nodeListeners.set(path, new Set());
+    }
+    let set = this._nodeListeners.get(path);
+    set.add(element);
+  },
+
+  _unregisterNodes: function(nodes) {
+    for (let [registeredPath, set] of this._nodeListeners) {
+      for (let e of nodes) {
+        set.delete(e);
+      }
+      if (set.size == 0) {
+        this._nodeListeners.delete(registeredPath);
+      }
+    }
+  },
+
+  _registerLoop: function(path, element) {
+    if (!this._loopListeners.has(path)) {
+      this._loopListeners.set(path, new Set());
+    }
+    let set = this._loopListeners.get(path);
+    set.add(element);
+  },
+
+  _processNode: function(element, rootPath="") {
+    // The actual magic.
+    // The element has a template attribute.
+    // The value is supposed to be a JSON string.
+    // rootPath is the prefex to the path used by
+    // these elements (if children of template-loop);
+
+    let e = element;
+    let str = e.getAttribute("template");
+
+    if (rootPath) {
+      // We will prefix paths with this rootPath.
+      // It needs to end with a dot.
+      rootPath = rootPath + ".";
+    }
+
+    try {
+      let json = JSON.parse(str);
+      // Sanity check
+      if (!("type" in json)) {
+        throw new Error("missing property");
+      }
+      if (json.rootPath) {
+        // If node has been generated through a loop, we stored
+        // previously its rootPath.
+        rootPath = json.rootPath;
+      }
+
+      // paths is an array that will store all the paths we needed
+      // to expand the node. We will then, via _registerNode, link
+      // this element to these paths.
+
+      let paths = [];
+
+      switch (json.type) {
+        case "attribute": {
+          if (!("name" in json) ||
+              !("path" in json)) {
+            throw new Error("missing property");
+          }
+          e.setAttribute(json.name, this._resolvePath(rootPath + json.path, NOT_FOUND_STRING));
+          paths.push(rootPath + json.path);
+          break;
+        }
+        case "textContent": {
+          if (!("path" in json)) {
+            throw new Error("missing property");
+          }
+          e.textContent = this._resolvePath(rootPath + json.path, NOT_FOUND_STRING);
+          paths.push(rootPath + json.path);
+          break;
+        }
+        case "localizedContent": {
+          if (!("property" in json) ||
+              !("paths" in json)) {
+            throw new Error("missing property");
+          }
+          let params = json.paths.map((p) => {
+            paths.push(rootPath + p);
+            let str = this._resolvePath(rootPath + p, NOT_FOUND_STRING);
+            return str;
+          });
+          e.textContent = this._l10n(json.property, params);
+          break;
+        }
+      }
+      if (rootPath) {
+        // We save the rootPath if any.
+        json.rootPath = rootPath;
+        e.setAttribute("template", JSON.stringify(json));
+      }
+      if (paths.length > 0) {
+        for (let path of paths) {
+          this._registerNode(path, e);
+        }
+      }
+    } catch(exception) {
+      console.error("Invalid template: " + e.outerHTML + " (" + exception + ")");
+    }
+  },
+
+  _processLoop: function(element, rootPath="") {
+    // The element has a template-loop attribute.
+    // The related path must be an array. We go
+    // through the array, and build one child per
+    // item. The template for this child is pointed
+    // by the childSelector property.
+    try {
+      let e = element;
+      let template, count;
+      let str = e.getAttribute("template-loop");
+      let json = JSON.parse(str);
+      if (!("arrayPath" in json)     ||
+          !("childSelector" in json)) {
+        throw new Error("missing property");
+      }
+      if (rootPath) {
+        json.arrayPath = rootPath + "." + json.arrayPath;
+      }
+      let templateParent = this._doc.querySelector(json.childSelector);
+      if (!templateParent) {
+        throw new Error("can't find child");
+      }
+      template = this._doc.createElement("div");
+      template.innerHTML = templateParent.innerHTML;
+      template = template.firstElementChild;
+      let array = this._resolvePath(json.arrayPath, []);
+      if (!Array.isArray(array)) {
+        console.error("referenced array is not an array");
+      }
+      count = array.length;
+
+      let fragment = this._doc.createDocumentFragment();
+      for (let i = 0; i < count; i++) {
+        let node = template.cloneNode(true);
+        this._processTree(node, json.arrayPath + "." + i);
+        fragment.appendChild(node);
+      }
+      this._registerLoop(json.arrayPath, e);
+      this._registerLoop(json.arrayPath + ".length", e);
+      this._unregisterNodes(e.querySelectorAll("[template]"));
+      e.innerHTML = "";
+      e.appendChild(fragment);
+    } catch(exception) {
+      console.error("Invalid template: " + e.outerHTML + " (" + exception + ")");
+    }
+  },
+
+  _processTree: function(parent, rootPath="") {
+    let loops = parent.querySelectorAll(":not(template) [template-loop]");
+    let nodes = parent.querySelectorAll(":not(template) [template]");
+    for (let e of loops) {
+      this._processLoop(e, rootPath);
+    }
+    for (let e of nodes) {
+      this._processNode(e, rootPath);
+    }
+    if (parent.hasAttribute("template")) {
+      this._processNode(parent, rootPath);
+    }
+  },
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/device-store.js
@@ -0,0 +1,94 @@
+/* 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 ObservableObject = require("devtools/shared/observable-object");
+const {getDeviceFront} = require("devtools/server/actors/device");
+const {Connection} = require("devtools/client/connection-manager");
+
+const {Cu} = require("chrome");
+
+const _knownDeviceStores = new WeakMap();
+
+let DeviceStore;
+
+module.exports = DeviceStore = function(connection) {
+  // If we already know about this connection,
+  // let's re-use the existing store.
+  if (_knownDeviceStores.has(connection)) {
+    return _knownDeviceStores.get(connection);
+  }
+
+  _knownDeviceStores.set(connection, this);
+
+  ObservableObject.call(this, {});
+
+  this._resetStore();
+
+  this._destroy = this._destroy.bind(this);
+  this._onStatusChanged = this._onStatusChanged.bind(this);
+
+  this._connection = connection;
+  this._connection.once(Connection.Events.DESTROYED, this._destroy);
+  this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
+  this._onStatusChanged();
+  return this;
+}
+
+DeviceStore.prototype = {
+  _destroy: function() {
+    this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
+    _knownDeviceStores.delete(this._connection);
+    this._connection = null;
+  },
+
+  _resetStore: function() {
+    this.object.description = {};
+    this.object.permissions = [];
+  },
+
+  _onStatusChanged: function() {
+    if (this._connection.status == Connection.Status.CONNECTED) {
+      this._listTabs();
+    } else {
+      this._resetStore();
+    }
+  },
+
+  _listTabs: function() {
+    this._connection.client.listTabs((resp) => {
+      this._deviceFront = getDeviceFront(this._connection.client, resp);
+      this._feedStore();
+    });
+  },
+
+  _feedStore: function() {
+    this._getDeviceDescription();
+    this._getDevicePermissionsTable();
+  },
+
+  _getDeviceDescription: function() {
+    return this._deviceFront.getDescription()
+    .then(json => {
+      json.dpi = Math.ceil(json.dpi);
+      this.object.description = json;
+    });
+  },
+
+  _getDevicePermissionsTable: function() {
+    return this._deviceFront.getRawPermissionsTable()
+    .then(json => {
+      let permissionsTable = json.rawPermissionsTable;
+      let permissionsArray = [];
+      for (let name in permissionsTable) {
+        permissionsArray.push({
+          name: name,
+          app: permissionsTable[name].app,
+          privileged: permissionsTable[name].privileged,
+          certified: permissionsTable[name].certified,
+        });
+      }
+      this.object.permissions = permissionsArray;
+    });
+  },
+}
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/moz.build
@@ -0,0 +1,7 @@
+# -*- 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/.
+
+TEST_DIRS += ['test']
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/test/Makefile.in
@@ -0,0 +1,19 @@
+# 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/.
+
+DEPTH     = @DEPTH@
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+relativesrcdir  = @relativesrcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MOCHITEST_CHROME_FILES = \
+		test_template.html \
+		test_connection_store.html \
+		test_device_store.html \
+		$(NULL)
+
+include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/test/moz.build
@@ -0,0 +1,6 @@
+# -*- 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/.
+
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/test/test_connection_store.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+
+<!--
+Bug 901519 - [app manager] data store for connections
+-->
+
+<html>
+
+  <head>
+    <meta charset="utf8">
+    <title></title>
+
+    <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  </head>
+
+  <body>
+
+    <div id="root">
+      <span id="status" template='{"type":"textContent","path":"status"}'></span>
+      <span id="host" template='{"type":"textContent","path":"host"}'></span>
+      <span id="port" template='{"type":"textContent","path":"port"}'></span>
+    </div>
+
+    <script type="application/javascript;version=1.8" src="chrome://browser/content/devtools/app-manager/template.js"></script>
+    <script type="application/javascript;version=1.8">
+      const Cu = Components.utils;
+      Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
+      DebuggerServer.init(function () { return true; });
+      DebuggerServer.addBrowserActors();
+
+      window.onload = function() {
+        SimpleTest.waitForExplicitFinish();
+
+        Cu.import("resource://gre/modules/Services.jsm");
+        Cu.import("resource:///modules/devtools/gDevTools.jsm");
+
+        const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+        const {require} = devtools;
+
+        const {ConnectionManager} = require("devtools/client/connection-manager");
+        const ConnectionStore = require("devtools/app-manager/connection-store");
+
+        let connection = ConnectionManager.createConnection();
+        let store = new ConnectionStore(connection);
+
+        let root = document.querySelector("#root");
+        let status = root.querySelector("#status");
+        let host = root.querySelector("#host");
+        let port = root.querySelector("#port");
+        let template = new Template(root, store, () => {});
+        template.start();
+
+        connection.host = "foobar";
+        connection.port = 42;
+
+        is(host.textContent, "foobar", "host updated");
+        is(port.textContent, 42, "port updated");
+
+        let been_through_connecting = false;
+        let been_through_connected = false;
+        let been_through_disconnected = false;
+
+        is(status.textContent, "disconnected", "status updated (diconnected)");
+
+        connection.once("connecting", (e) => {
+          SimpleTest.executeSoon(() => {
+            been_through_connecting = true;
+            is(status.textContent, "connecting", "status updated (connecting)");
+          })
+        });
+
+        connection.once("connected", (e) => {
+          SimpleTest.executeSoon(() => {
+            been_through_connected = true;
+            is(status.textContent, "connected", "status updated (connected)");
+            connection.disconnect();
+          })
+        });
+
+        connection.once("disconnected", (e) => {
+          SimpleTest.executeSoon(() => {
+            been_through_disconnected = true;
+            is(status.textContent, "disconnected", "status updated (disconnected)");
+            connection.destroy();
+            finishup();
+          })
+        });
+
+        function finishup() {
+          ok(been_through_connecting &&
+            been_through_connected &&
+            been_through_disconnected, "All updates happened");
+          DebuggerServer.destroy();
+          SimpleTest.finish();
+        }
+
+        connection.host = null; // force pipe
+        connection.port = null;
+
+        connection.connect();
+      }
+
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/test/test_device_store.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+
+<!--
+Bug 901520 - [app manager] data store for device
+-->
+
+<html>
+
+  <head>
+    <meta charset="utf8">
+    <title></title>
+
+    <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  </head>
+
+  <body>
+
+    <script type="application/javascript;version=1.8" src="chrome://browser/content/devtools/app-manager/template.js"></script>
+    <script type="application/javascript;version=1.8">
+      const Cu = Components.utils;
+      Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
+      DebuggerServer.init(function () { return true; });
+      DebuggerServer.addBrowserActors();
+
+      function compare(o1, o2, msg) {
+        is(JSON.stringify(o1), JSON.stringify(o2), msg);
+      }
+
+      window.onload = function() {
+        SimpleTest.waitForExplicitFinish();
+
+        Cu.import("resource://gre/modules/Services.jsm");
+        Cu.import("resource:///modules/devtools/gDevTools.jsm");
+
+
+        const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+        const {require} = devtools;
+
+        const {ConnectionManager} = require("devtools/client/connection-manager");
+        const DeviceStore = require("devtools/app-manager/device-store");
+
+        let {getDeviceFront} = devtools.require("devtools/server/actors/device");
+
+        let connection = ConnectionManager.createConnection();
+        let store = new DeviceStore(connection);
+
+        connection.once("connected", function() {
+          store.on("set", function check(event, path, value) {
+            if (path.join(".") != "description") return;
+            store.off("set", check);
+            info("Connected");
+            connection.client.listTabs((resp) => {
+              info("List tabs response");
+              let deviceFront = getDeviceFront(connection.client, resp);
+              deviceFront.getDescription().then(json => {
+                info("getDescription response: " + JSON.stringify(json));
+                json.dpi = Math.ceil(json.dpi);
+                for (let key in json) {
+                  compare(json[key], store.object.description[key], "description." + key + " is valid");
+                  compare(json[key], value[key], "description." + key + " is valid");
+                }
+                connection.disconnect();
+              }).then(null, (error) => ok(false, "Error:" + error));
+            });
+          });
+        });
+
+        connection.once("disconnected", function() {
+          compare(store.object, {description:{},permissions:[]}, "empty store after disconnect")
+          connection.destroy();
+          DebuggerServer.destroy();
+          SimpleTest.finish();
+        });
+
+        compare(store.object, {description:{},permissions:[]}, "empty store before disconnect")
+
+        connection.connect();
+
+      }
+
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/test/test_template.html
@@ -0,0 +1,239 @@
+<!DOCTYPE html>
+
+<html>
+
+  <head>
+    <meta charset="utf8">
+    <title></title>
+
+    <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  </head>
+
+  <div id="root">
+    <span template='{"type":"textContent","path":"title"}'></span>
+    <span template='{"type":"attribute","name":"title","path":"title"}'></span>
+    <span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'></span>
+    <div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template"}'></div>
+  </div>
+
+  <div id="ref0">
+    <span template='{"type":"textContent","path":"title"}'>ttt</span>
+    <span title="ttt" template='{"type":"attribute","name":"title","path":"title"}'></span>
+    <span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:foo_l10n/bar_l10n</span>
+    <div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template"}'>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0."}'>xx0</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1."}'>xx1</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1."}'>b</span>
+      </div>
+    </div>
+  </div>
+
+
+  <div id="ref1">
+    <span template='{"type":"textContent","path":"title"}'>xxx</span>
+    <span title="xxx" template='{"type":"attribute","name":"title","path":"title"}'></span>
+    <span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:foo2_l10n/bar_l10n</span>
+    <div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template"}'>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0."}'>xx0</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1."}'>xx1</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1."}'>b</span>
+      </div>
+    </div>
+  </div>
+
+  <div id="ref2">
+    <span template='{"type":"textContent","path":"title"}'>xxx</span>
+    <span title="xxx" template='{"type":"attribute","name":"title","path":"title"}'></span>
+    <span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:yyy/zzz</span>
+    <div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template"}'>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0."}'>xx0</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1."}'>xx1</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1."}'>b</span>
+      </div>
+    </div>
+  </div>
+
+  <div id="ref3">
+    <span template='{"type":"textContent","path":"title"}'>xxx</span>
+    <span title="xxx" template='{"type":"attribute","name":"title","path":"title"}'></span>
+    <span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:yyy/zzz</span>
+    <div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template"}'>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0."}'>xx0</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1."}'>xx1</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.2."}'>xx2</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.2."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.2."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.3."}'>xx3</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.3."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.3."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.4."}'>xx4</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.4."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.4."}'>b</span>
+      </div>
+    </div>
+  </div>
+
+  <div id="ref4">
+    <span template='{"type":"textContent","path":"title"}'>xxx</span>
+    <span title="xxx" template='{"type":"attribute","name":"title","path":"title"}'></span>
+    <span template='{"type":"localizedContent","paths":["foo2.foo_l10n","foo2.bar_l10n"],"property":"foo2"}'>foo2:yyy/zzz</span>
+    <div template-loop='{"arrayPath":"foo1.bar1","childSelector":"#template"}'>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.0."}'>xx0</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.0."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.0."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.1."}'>xx1</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.1."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.1."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.2."}'>xx2</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.2."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.2."}'>b</span>
+      </div>
+      <div>
+        <span template='{"type":"textContent","path":"idx","rootPath":"foo1.bar1.3."}'>xx3</span>
+        <span template='{"type":"textContent","path":"a","rootPath":"foo1.bar1.3."}'>a</span>
+        <span template='{"type":"textContent","path":"b","rootPath":"foo1.bar1.3."}'>b</span>
+      </div>
+    </div>
+  </div>
+
+
+
+  <template id="template">
+    <div>
+      <span template='{"type":"textContent","path":"idx"}'></span>
+      <span template='{"type":"textContent","path":"a"}'></span>
+      <span template='{"type":"textContent","path":"b"}'></span>
+    </div>
+  </template>
+
+  <script type="application/javascript;version=1.8" src="chrome://browser/content/devtools/app-manager/template.js"></script>
+  <script type="application/javascript;version=1.8">
+    SimpleTest.waitForExplicitFinish();
+
+    const Cu = Components.utils;
+    Cu.import("resource:///modules/devtools/gDevTools.jsm");
+    const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+    const {require} = devtools;
+    const ObservableObject = require("devtools/shared/observable-object");
+
+    let data = {
+      title: "ttt",
+      foo1: {
+        bar1: [
+          {idx: "xx0", a: "a", b: "b"},
+          {idx: "xx1", a: "a", b: "b"},
+        ],
+      },
+      foo2: {
+        foo_l10n: "foo_l10n",
+        bar_l10n: "bar_l10n"
+      },
+    };
+
+    let store = new ObservableObject(data);
+
+    let changes = [
+      {
+        exec: function() {},
+        reference: document.querySelector("#ref0")
+      },
+      {
+        exec: function() {
+          store.object.title = "xxx";
+          store.object.foo2.foo_l10n = "foo2_l10n";
+        },
+        reference: document.querySelector("#ref1")
+      },
+      {
+        exec: function() {
+          store.object.foo2 = {
+            foo_l10n: "yyy",
+            bar_l10n: "zzz",
+          }
+        },
+        reference: document.querySelector("#ref2")
+      },
+      {
+        exec: function() {
+          let items = [];
+          for (let i = 2; i < 5; i++) {
+            items.push({idx: "xx" + i, a: "a", b: "b"});
+          }
+
+          store.object.foo1.bar1 = store.object.foo1.bar1.concat(items);
+        },
+        reference: document.querySelector("#ref3")
+      },
+      {
+        exec: function() {
+          store.object.foo1.bar1.pop();
+        },
+        reference: document.querySelector("#ref4")
+      },
+    ];
+
+    function compare(node1, node2) {
+      let text1 = node1.innerHTML;
+      let text2 = node2.innerHTML;
+      text1 = text1.replace(/\n/g,"");
+      text2 = text2.replace(/\n/g,"");
+      text1 = text1.replace(/\s+/g,"");
+      text2 = text2.replace(/\s+/g,"");
+      return text1 == text2;
+    }
+
+
+    let root = document.querySelector("#root");
+
+    let t = new Template(root, store, (prop, args) => {
+      return prop + ":" + args.join("/");
+    });
+
+    t.start();
+
+    for (let i = 0; i < changes.length; i++) {
+      let change = changes[i];
+      change.exec();
+      ok(compare(change.reference, root), "Content " + i + " looks good.");
+    }
+  SimpleTest.finish();
+
+  </script>
+</html>
new file mode 100644
--- /dev/null
+++ b/browser/devtools/app-manager/webapps-store.js
@@ -0,0 +1,207 @@
+/* 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 ObservableObject = require("devtools/shared/observable-object");
+const promise = require("sdk/core/promise");
+const {Connection} = require("devtools/client/connection-manager");
+
+const {Cu} = require("chrome");
+const dbgClient = Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
+dbgClient.UnsolicitedNotifications.appOpen = "appOpen";
+dbgClient.UnsolicitedNotifications.appClose = "appClose"
+
+const _knownWebappsStores = new WeakMap();
+
+let WebappsStore;
+
+module.exports = WebappsStore = function(connection) {
+  // If we already know about this connection,
+  // let's re-use the existing store.
+  if (_knownWebappsStores.has(connection)) {
+    return _knownWebappsStores.get(connection);
+  }
+
+  _knownWebappsStores.set(connection, this);
+
+  ObservableObject.call(this, {});
+
+  this._resetStore();
+
+  this._destroy = this._destroy.bind(this);
+  this._onStatusChanged = this._onStatusChanged.bind(this);
+
+  this._connection = connection;
+  this._connection.once(Connection.Events.DESTROYED, this._destroy);
+  this._connection.on(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
+  this._onStatusChanged();
+  return this;
+}
+
+WebappsStore.prototype = {
+  _destroy: function() {
+    this._connection.off(Connection.Events.STATUS_CHANGED, this._onStatusChanged);
+    _knownWebappsStores.delete(this._connection);
+    this._connection = null;
+  },
+
+  _resetStore: function() {
+    this.object.all = []; // list of app objects
+    this.object.running = []; // list of manifests
+  },
+
+  _getAppFromManifest: function(manifest) {
+    for (let app of this.object.all) {
+      if (app.manifestURL == manifest) {
+        return app;
+      }
+    }
+    return null;
+  },
+
+  _onStatusChanged: function() {
+    if (this._connection.status == Connection.Status.CONNECTED) {
+      this._listTabs();
+    } else {
+      this._resetStore();
+    }
+  },
+
+  _listTabs: function() {
+    this._connection.client.listTabs((resp) => {
+      this._webAppsActor = resp.webappsActor;
+      this._feedStore();
+    });
+  },
+
+  _feedStore: function(deviceFront, webAppsActor) {
+    this._listenToApps();
+    this._getAllApps()
+    .then(this._getRunningApps.bind(this))
+    .then(this._getAppsIcons.bind(this))
+  },
+
+  _listenToApps: function() {
+    let deferred = promise.defer();
+    let client = this._connection.client;
+
+    let request = {
+      to: this._webAppsActor,
+      type: "watchApps"
+    };
+
+    client.request(request, (res) => {
+      if (res.error) {
+        return deferred.reject(res.error);
+      }
+
+      client.addListener("appOpen", (type, { manifestURL }) => {
+        this._onAppOpen(manifestURL);
+      });
+
+      client.addListener("appClose", (type, { manifestURL }) => {
+        this._onAppClose(manifestURL);
+      });
+
+      return deferred.resolve();
+    })
+    return deferred.promise;
+  },
+
+  _getAllApps: function() {
+    let deferred = promise.defer();
+    let request = {
+      to: this._webAppsActor,
+      type: "getAll"
+    };
+
+    this._connection.client.request(request, (res) => {
+      if (res.error) {
+        return deferred.reject(res.error);
+      }
+      let apps = res.apps;
+      for (let a of apps) {
+        a.running = false;
+      }
+      this.object.all = apps;
+      return deferred.resolve();
+    });
+    return deferred.promise;
+  },
+
+  _getRunningApps: function() {
+    let deferred = promise.defer();
+    let request = {
+      to: this._webAppsActor,
+      type: "listRunningApps"
+    };
+
+    this._connection.client.request(request, (res) => {
+      if (res.error) {
+        return deferred.reject(res.error);
+      }
+
+      let manifests = res.apps;
+      this.object.running = manifests;
+
+      for (let m of manifests) {
+        let a = this._getAppFromManifest(m);
+        if (a) {
+          a.running = true;
+        } else {
+          return deferred.reject("Unexpected manifest: " + m);
+        }
+      }
+
+      return deferred.resolve();
+    });
+    return deferred.promise;
+  },
+
+  _getAppsIcons: function() {
+    let deferred = promise.defer();
+    let allApps = this.object.all;
+
+    let request = {
+      to: this._webAppsActor,
+      type: "getIconAsDataURL"
+    };
+
+    let client = this._connection.client;
+
+    let idx = 0;
+    (function getIcon() {
+      if (idx == allApps.length) {
+        return deferred.resolve();
+      }
+      let a = allApps[idx++];
+      request.manifestURL = a.manifestURL;
+      return client.request(request, (res) => {
+        if (res.url) {
+          a.iconURL = res.url;
+        }
+        getIcon();
+      });
+    })();
+
+    return deferred.promise;
+  },
+
+  _onAppOpen: function(manifest) {
+    let a = this._getAppFromManifest(manifest);
+    a.running = true;
+    let running = this.object.running;
+    if (running.indexOf(manifest) < 0) {
+      this.object.running.push(manifest);
+    }
+  },
+
+  _onAppClose: function(manifest) {
+    let a = this._getAppFromManifest(manifest);
+    a.running = false;
+    let running = this.object.running;
+    this.object.running = running.filter((m) => {
+      return m != manifest;
+    });
+  },
+}
--- a/browser/devtools/jar.mn
+++ b/browser/devtools/jar.mn
@@ -60,8 +60,9 @@ browser.jar:
     content/browser/devtools/framework/toolbox-options.js              (framework/toolbox-options.js)
 *   content/browser/devtools/framework/toolbox.xul                     (framework/toolbox.xul)
     content/browser/devtools/framework/toolbox.css                     (framework/toolbox.css)
     content/browser/devtools/inspector/inspector.xul                   (inspector/inspector.xul)
     content/browser/devtools/inspector/inspector.css                   (inspector/inspector.css)
     content/browser/devtools/connect.xhtml                             (framework/connect/connect.xhtml)
     content/browser/devtools/connect.css                               (framework/connect/connect.css)
     content/browser/devtools/connect.js                                (framework/connect/connect.js)
+    content/browser/devtools/app-manager/template.js                   (app-manager/content/template.js)
--- a/browser/devtools/moz.build
+++ b/browser/devtools/moz.build
@@ -17,10 +17,10 @@ DIRS += [
     'debugger',
     'netmonitor',
     'layoutview',
     'shared',
     'responsivedesign',
     'framework',
     'profiler',
     'fontinspector',
-
+    'app-manager',
 ]
--- a/browser/devtools/shared/observable-object.js
+++ b/browser/devtools/shared/observable-object.js
@@ -1,9 +1,9 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
+/* 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/. */
 
 /**
  * ObservableObject
  *
  * An observable object is a JSON-like object that throws
  * events when its direct properties or properties of any
@@ -23,31 +23,34 @@
  *   let emitter = new ObservableObject({ x: { y: [10] } });
  *   emitter.on("set", console.log);
  *   emitter.on("get", console.log);
  *   let obj = emitter.object;
  *   obj.x.y[0] = 50;
  *
  */
 
+"use strict";
+
 const EventEmitter = require("devtools/shared/event-emitter");
 
 function ObservableObject(object = {}) {
+  EventEmitter.decorate(this);
   let handler = new Handler(this);
   this.object = new Proxy(object, handler);
   handler._wrappers.set(this.object, object);
   handler._paths.set(object, []);
 }
 
-exports.ObservableObject = ObservableObject;
+module.exports = ObservableObject;
 
-ObservableObject.prototype = new EventEmitter();
-
-function isObject(value) {
-  return Object(value) === value;
+function isObject(x) {
+  if (typeof x === "object")
+    return x !== null;
+  return typeof x === "function";
 }
 
 function Handler(emitter) {
   this._emitter = emitter;
   this._wrappers = new WeakMap();
   this._paths = new WeakMap();
 }
 
@@ -66,17 +69,17 @@ Handler.prototype = {
       value = wrapper;
     }
     return [value, path];
   },
   unwrap: function(target, key, value) {
     if (!isObject(value) || !this._wrappers.has(value)) {
       return [value, this._paths.get(target).concat(key)];
     }
-    return [this._wrappers.get(value), this._paths.get(value)];
+    return [this._wrappers.get(value), this._paths.get(target).concat(key)];
   },
   get: function(target, key) {
     let value = target[key];
     let [wrapped, path] = this.wrap(target, key, value);
     this._emitter.emit("get", path, value);
     return wrapped;
   },
   set: function(target, key, value) {
--- a/browser/devtools/shared/test/browser_observableobject.js
+++ b/browser/devtools/shared/test/browser_observableobject.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   let tmp = {};
   Cu.import("resource://gre/modules/devtools/Loader.jsm", tmp);
-  let {ObservableObject} = tmp.devtools.require("devtools/shared/observable-object");
+  let ObservableObject = tmp.devtools.require("devtools/shared/observable-object");
 
   let rawObject = {};
   let oe = new ObservableObject(rawObject);
 
   function str(o) {
     return JSON.stringify(o);
   }
 
@@ -35,30 +35,32 @@ function test() {
     {type: "set", path: "bar", value: {}},
     {type: "set", path: "foo", value: [{a:42}]},
     {type: "get", path: "foo", value: [{a:42}]},
     {type: "get", path: "foo.0", value: {a:42}},
     {type: "get", path: "foo.0.a", value: 42},
     {type: "get", path: "foo", value: [{a:42}]},
     {type: "get", path: "foo.0", value: {a:42}},
     {type: "set", path: "foo.0.a", value: 2},
+    {type: "get", path: "foo", value: [{a:2}]},
+    {type: "get", path: "bar", value: {}},
+    {type: "set", path: "foo.1", value: {}},
   ];
 
   function callback(event, path, value) {
     oe.off("get", callback);
+    ok(event, "event defined");
+    ok(path, "path defined");
     let e = expected[index];
     is(event, e.type, "[" + index + "] Right event received");
     is(path.join("."), e.path, "[" + index + "] Path valid");
     is(str(value), str(e.value), "[" + index + "] Value valid");
     index++;
     areObjectsSynced();
     oe.on("get", callback);
-    if (index == expected.length) {
-      finish();
-    }
   }
 
   oe.on("set", callback);
   oe.on("get", callback);
 
   oe.object.foo = 4;
   oe.object.foo;
   Object.getOwnPropertyDescriptor(oe.object, "foo")
@@ -67,9 +69,14 @@ function test() {
   oe.object.bar = {};
   oe.object.bar;
   oe.object.bar.a = [1,2,3,4];
   Object.defineProperty(oe.object.bar, "mop", {value:1});
   oe.object.bar = {};
   oe.object.foo = [{a:42}];
   oe.object.foo[0].a;
   oe.object.foo[0].a = 2;
+  oe.object.foo[1] = oe.object.bar;
+
+  is(index, expected.length, "Event count is right");
+
+  finish();
 }
--- a/browser/devtools/styleeditor/StyleEditorDebuggee.jsm
+++ b/browser/devtools/styleeditor/StyleEditorDebuggee.jsm
@@ -90,22 +90,27 @@ StyleEditorDebuggee.prototype = {
     return null;
   },
 
   /**
    * Clear stylesheets and state.
    */
   clear: function() {
     this.baseURI = null;
+    this.clearStyleSheets();
+  },
 
+  /**
+   * Clear stylesheets.
+   */
+  clearStyleSheets: function() {
     for (let stylesheet of this.styleSheets) {
       stylesheet.destroy();
     }
     this.styleSheets = [];
-
     this.emit("stylesheets-cleared");
   },
 
   /**
    * Called when target is created or has navigated.
    * Clear previous sheets and request new document's
    */
   _onNewDocument: function() {
@@ -132,16 +137,19 @@ StyleEditorDebuggee.prototype = {
    * all the stylesheets available on load.
    *
    * @param  {string} type
    *         Event type
    * @param  {object} request
    *         Object with 'styleSheets' array of actor forms
    */
   _onDocumentLoad: function(type, request) {
+    if (this.styleSheets.length > 0) {
+      this.clearStyleSheets();
+    }
     let sheets = [];
     for (let form of request.styleSheets) {
       let sheet = this._addStyleSheet(form);
       sheets.push(sheet);
     }
     this.emit("document-load", sheets);
   },
 
--- a/browser/devtools/styleeditor/test/Makefile.in
+++ b/browser/devtools/styleeditor/test/Makefile.in
@@ -21,16 +21,17 @@ MOCHITEST_BROWSER_FILES := \
                  browser_styleeditor_loading.js \
                  browser_styleeditor_new.js \
                  browser_styleeditor_pretty.js \
                  browser_styleeditor_private_perwindowpb.js \
                  browser_styleeditor_sv_keynav.js \
                  browser_styleeditor_sv_resize.js \
                  browser_styleeditor_bug_740541_iframes.js \
                  browser_styleeditor_bug_851132_middle_click.js \
+                 browser_styleeditor_bug_870339.js \
                  browser_styleeditor_nostyle.js \
                  browser_styleeditor_reload.js \
                  head.js \
                  four.html \
                  head.js \
                  import.css \
                  import.html \
                  import2.css \
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleeditor/test/browser_styleeditor_bug_870339.js
@@ -0,0 +1,46 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function test()
+{
+  const SIMPLE = TEST_BASE_HTTP + "simple.css";
+  const DOCUMENT_WITH_ONE_STYLESHEET = "data:text/html;charset=UTF-8," +
+          encodeURIComponent(
+            ["<!DOCTYPE html>",
+             "<html>",
+             " <head>",
+             "  <title>Bug 870339</title>",
+             '  <link rel="stylesheet" type="text/css" href="'+SIMPLE+'">',
+             " </head>",
+             " <body>",
+             " </body>",
+             "</html>"
+            ].join("\n"));
+
+  waitForExplicitFinish();
+  addTabAndOpenStyleEditor(function (aPanel) {
+    let debuggee = aPanel._debuggee;
+
+    // Spam the _onNewDocument callback multiple times before the
+    // StyleEditorActor has a chance to respond to the first one.
+    const SPAM_COUNT = 2;
+    for (let i=0; i<SPAM_COUNT; ++i) {
+      debuggee._onNewDocument();
+    }
+
+    // Wait for the StyleEditorActor to respond to each "newDocument"
+    // message.
+    let loadCount = 0;
+    debuggee.on("document-load", function () {
+      ++loadCount;
+      if (loadCount == SPAM_COUNT) {
+        // No matter how large SPAM_COUNT is, the number of style
+        // sheets should never be more than the number of style sheets
+        // in the document.
+        is(debuggee.styleSheets.length, 1, "correct style sheet count");
+        finish();
+      }
+    });
+  });
+  content.location = DOCUMENT_WITH_ONE_STYLESHEET;
+}
--- a/browser/metro/components/HelperAppDialog.js
+++ b/browser/metro/components/HelperAppDialog.js
@@ -36,18 +36,20 @@ HelperAppLauncherDialog.prototype = {
       this._showDownloadInfobar(aLauncher);
     }
   },
 
   _getDownloadSize: function dv__getDownloadSize (aSize) {
     let displaySize = DownloadUtils.convertByteUnits(aSize);
     if (displaySize[0] > 0) // [0] is size, [1] is units
       return displaySize.join("");
-    else
-      return Strings.browser.GetStringFromName("downloadsUnknownSize");
+    else {
+      let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
+      return browserBundle.GetStringFromName("downloadsUnknownSize");
+    }
   },
 
   _getChromeWindow: function (aWindow) {
       let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIWebNavigation)
                             .QueryInterface(Ci.nsIDocShellTreeItem)
                             .rootTreeItem
                             .QueryInterface(Ci.nsIInterfaceRequestor)
--- a/browser/metro/theme/defines.inc
+++ b/browser/metro/theme/defines.inc
@@ -14,17 +14,20 @@
 %define selected_color #FF8000
 
 %define urlbar_border_color #BFC6CC
 %define urlbar_edit_height 36px
 
 %define toolbar_vertical_spacing 5px
 %define toolbar_horizontal_spacing 20px
 %define toolbar_snapped_horizontal_spacing 10px
-%define toolbar_height 68px
+
+% XXX Per UX mockups, this should be 68px, but we need to make this
+% one pixel higher to reduce button clipping until bug 905453 is resolved
+%define toolbar_height 69px
 %define labelled_toolbar_height 90px
 %define tabs_height 178px
 %define findbar_height 54px
 
 %define progress_height 5px
 
 %define metro_orange #FF8000
 
--- a/build/mobile/robocop/Actions.java.in
+++ b/build/mobile/robocop/Actions.java.in
@@ -78,12 +78,19 @@ public interface Actions {
      * @param key The special key to send
      */
     void sendSpecialKey(SpecialKey key);
     void sendKeyCode(int keyCode);
 
     void drag(int startingX, int endingX, int startingY, int endingY);
 
     /**
+     * This is the implementation of clickLongOnScreen from Robotium 4.0 since this sometimes fails for Robotium 3.6
+     * TODO : Remove this when Robotium is updated
+     */
+
+    void clickLongOnScreen(float x, float y);
+
+    /**
      * Run a sql query on the specified database
      */
     public Cursor querySql(String dbPath, String sql);
 }
--- a/build/mobile/robocop/FennecNativeActions.java.in
+++ b/build/mobile/robocop/FennecNativeActions.java.in
@@ -17,17 +17,19 @@ import java.util.ArrayList;
 import android.app.Activity;
 import android.app.Instrumentation;
 import android.content.Context;
 import android.database.Cursor;
 import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
+import android.view.MotionEvent;
 import android.view.View;
+import android.view.ViewConfiguration;
 
 import com.jayway.android.robotium.solo.Solo;
 
 import static @ANDROID_PACKAGE_NAME@.FennecNativeDriver.LogLevel;
 
 public class FennecNativeActions implements Actions {
     private Solo mSolo;
     private Instrumentation mInstr;
@@ -453,16 +455,51 @@ public class FennecNativeActions impleme
     public void sendKeys(String input) {
         mInstr.sendStringSync(input);
     }
 
     public void drag(int startingX, int endingX, int startingY, int endingY) {
         mSolo.drag(startingX, endingX, startingY, endingY, 10);
     }
 
+     /**
+     * This is the implementation of clickLongOnScreen from Robotium 4.0 since this sometimes fails for Robotium 3.6
+     * TODO : Remove this when Robotium is updated
+     */
+
+    public void clickLongOnScreen(float x, float y) {
+    	boolean successfull = false;
+        int retry = 0;
+        long downTime = SystemClock.uptimeMillis();
+        long eventTime = SystemClock.uptimeMillis();
+        MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
+
+        while(!successfull && retry < 10) {
+            try{
+                mInstr.sendPointerSync(event);
+                successfull = true;
+            }catch(SecurityException e){
+                FennecNativeDriver.log(LogLevel.ERROR, e);
+                retry++;
+            }
+        }
+
+        mAsserter.ok(successfull, "Trying to click on long on screen at (" + x + "," + y + ")", "Was able to click long on screen");
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_MOVE, x + 1.0f, y + 1.0f, 0);
+        mInstr.sendPointerSync(event);
+        mSolo.sleep(((int)(ViewConfiguration.getLongPressTimeout() * 2.5f)));
+
+        eventTime = SystemClock.uptimeMillis();
+        event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
+        mInstr.sendPointerSync(event);
+        mSolo.sleep(500);
+    }
+
     public Cursor querySql(String dbPath, String sql) {
         try {
             return (Cursor)mQuerySql.invoke(mRobocopApi, dbPath, sql);
         } catch(InvocationTargetException ex) {
             Log.e(LOGTAG, "Error invoking method", ex);
         } catch(IllegalAccessException ex) {
             Log.e(LOGTAG, "Error using field", ex);
         }
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -772,8 +772,11 @@ pref("media.useAudioChannelService", fal
 // Turn on the CSP 1.0 parser for Content Security Policy headers
 pref("security.csp.speccompliant", true);
 
 // Enable hardware-accelerated Skia canvas
 pref("gfx.canvas.azure.backends", "skia");
 pref("gfx.canvas.azure.accelerated", true);
 
 pref("general.useragent.override.youtube.com", "Android; Tablet;#Android; Mobile;");
+
+// When true, phone number linkification is enabled.
+pref("browser.ui.linkify.phone", false);
--- a/mobile/android/base/ActivityHandlerHelper.java
+++ b/mobile/android/base/ActivityHandlerHelper.java
@@ -31,17 +31,16 @@ import java.util.concurrent.TimeUnit;
 
 public class ActivityHandlerHelper implements GeckoEventListener {
     private static final String LOGTAG = "GeckoActivityHandlerHelper";
 
     private final ConcurrentLinkedQueue<String> mFilePickerResult;
 
     private final ActivityResultHandlerMap mActivityResultHandlerMap;
     private final FilePickerResultHandlerSync mFilePickerResultHandlerSync;
-    private final AwesomebarResultHandler mAwesomebarResultHandler;
     private final CameraImageResultHandler mCameraImageResultHandler;
     private final CameraVideoResultHandler mCameraVideoResultHandler;
 
     public interface FileResultHandler {
         public void gotFile(String filename);
     }
 
     @SuppressWarnings("serial")
@@ -53,17 +52,16 @@ public class ActivityHandlerHelper imple
                     GeckoAppShell.sendEventToGecko(GeckoEvent.createNoOpEvent());
                     return true;
                 }
                 return false;
             }
         };
         mActivityResultHandlerMap = new ActivityResultHandlerMap();
         mFilePickerResultHandlerSync = new FilePickerResultHandlerSync(mFilePickerResult);
-        mAwesomebarResultHandler = new AwesomebarResultHandler();
         mCameraImageResultHandler = new CameraImageResultHandler(mFilePickerResult);
         mCameraVideoResultHandler = new CameraVideoResultHandler(mFilePickerResult);
         GeckoAppShell.getEventDispatcher().registerEventListener("FilePicker:Show", this);
     }
 
     @Override
     public void handleMessage(String event, final JSONObject message) {
         if (event.equals("FilePicker:Show")) {
@@ -86,20 +84,16 @@ public class ActivityHandlerHelper imple
                     }
                     GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
                         "FilePicker:Result", message.toString()));
                 }
             });
         }
     }
 
-    public int makeRequestCodeForAwesomebar() {
-        return mActivityResultHandlerMap.put(mAwesomebarResultHandler);
-    }
-
     public int makeRequestCode(ActivityResultHandler aHandler) {
         return mActivityResultHandlerMap.put(aHandler);
     }
 
     public void startIntentForActivity (Activity activity, Intent intent, ActivityResultHandler activityResultHandler) {
         activity.startActivityForResult(intent, mActivityResultHandlerMap.put(activityResultHandler));
     }
 
--- a/mobile/android/base/AndroidManifest.xml.in
+++ b/mobile/android/base/AndroidManifest.xml.in
@@ -225,21 +225,16 @@
         <activity android:name="org.mozilla.gecko.VideoPlayer"
                   android:configChanges="keyboard|keyboardHidden|mcc|mnc|orientation"
                   android:theme="@android:style/Theme.NoTitleBar">
             <intent-filter>
                 <action android:name="org.mozilla.gecko.PLAY_VIDEO" />
             </intent-filter>
         </activity>
 
-        <activity android:name="org.mozilla.gecko.AwesomeBar"
-                  android:theme="@style/Gecko.AwesomeBar"
-                  android:configChanges="orientation|screenSize"
-                  android:windowSoftInputMode="stateUnspecified|adjustResize"/>
-
         <activity android:name="org.mozilla.gecko.GeckoPreferences"
                   android:theme="@style/Gecko.Preferences"
                   android:label="@string/settings_title"
                   android:configChanges="orientation|screenSize"
                   android:excludeFromRecents="true"/>
 
         <provider android:name="org.mozilla.gecko.db.BrowserProvider"
                   android:authorities="@ANDROID_PACKAGE_NAME@.db.browser"
--- a/mobile/android/base/AnimatedHeightLayout.java
+++ b/mobile/android/base/AnimatedHeightLayout.java
@@ -12,18 +12,22 @@ import android.view.animation.Animation;
 import android.view.animation.DecelerateInterpolator;
 import android.widget.RelativeLayout;
 
 public class AnimatedHeightLayout extends RelativeLayout {
     private static final String LOGTAG = "GeckoAnimatedHeightLayout";
     private static final int ANIMATION_DURATION = 100;
     private boolean mAnimating = false;
 
+    public AnimatedHeightLayout(Context context) {
+        super(context, null);
+    }
+
     public AnimatedHeightLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
+        super(context, attrs, 0);
     }
 
     public AnimatedHeightLayout(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/AutocompleteHandler.java
@@ -0,0 +1,10 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko;
+
+public interface AutocompleteHandler {
+    void onAutocomplete(String res);
+}
deleted file mode 100644
--- a/mobile/android/base/AwesomeBar.java
+++ /dev/null
@@ -1,730 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * 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/. */
-
-package org.mozilla.gecko;
-
-import org.mozilla.gecko.db.BrowserContract.Combined;
-import org.mozilla.gecko.db.BrowserDB;
-import org.mozilla.gecko.gfx.BitmapUtils;
-import org.mozilla.gecko.health.BrowserHealthRecorder;
-import org.mozilla.gecko.util.GamepadUtils;
-import org.mozilla.gecko.util.StringUtils;
-import org.mozilla.gecko.util.ThreadUtils;
-import org.mozilla.gecko.util.UiAsyncTask;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.Intent;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.Editable;
-import android.text.InputType;
-import android.text.Spanned;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.MenuInflater;
-import android.view.View;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.TabWidget;
-import android.widget.Toast;
-
-import org.json.JSONObject;
-
-import java.net.URLEncoder;
-
-interface AutocompleteHandler {
-    void onAutocomplete(String res);
-}
-
-public class AwesomeBar extends GeckoActivity
-                        implements AutocompleteHandler,
-                                   TextWatcher {
-    private static final String LOGTAG = "GeckoAwesomeBar";
-
-    public static final String URL_KEY = "url";
-    public static final String TAB_KEY = "tab";
-    public static final String CURRENT_URL_KEY = "currenturl";
-    public static final String TARGET_KEY = "target";
-    public static final String SEARCH_KEY = "search";
-    public static final String TITLE_KEY = "title";
-    public static final String USER_ENTERED_KEY = "user_entered";
-    public static final String READING_LIST_KEY = "reading_list";
-    public static enum Target { NEW_TAB, CURRENT_TAB, PICK_SITE };
-
-    private String mTarget;
-    private AwesomeBarTabs mAwesomeTabs;
-    private CustomEditText mText;
-    private ImageButton mGoButton;
-    private ContextMenuSubject mContextMenuSubject;
-    private boolean mDelayRestartInput;
-    // The previous autocomplete result returned to us
-    private String mAutoCompleteResult = "";
-    // The user typed part of the autocomplete result
-    private String mAutoCompletePrefix = null;
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        LayoutInflater.from(this).setFactory(this);
-
-        super.onCreate(savedInstanceState);
-
-        Log.d(LOGTAG, "creating awesomebar");
-
-        setContentView(R.layout.awesomebar);
-
-        mGoButton = (ImageButton) findViewById(R.id.awesomebar_button);
-        mText = (CustomEditText) findViewById(R.id.awesomebar_text);
-
-        TabWidget tabWidget = (TabWidget) findViewById(android.R.id.tabs);
-        tabWidget.setDividerDrawable(null);
-
-        mAwesomeTabs = (AwesomeBarTabs) findViewById(R.id.awesomebar_tabs);
-        mAwesomeTabs.setOnUrlOpenListener(new AwesomeBarTabs.OnUrlOpenListener() {
-            @Override
-            public void onUrlOpen(String url, String title) {
-                openUrlAndFinish(url, title, false);
-            }
-
-            @Override
-            public void onSearch(SearchEngine engine, String text) {
-                Intent resultIntent = new Intent();
-                resultIntent.putExtra(URL_KEY, text);
-                resultIntent.putExtra(TARGET_KEY, mTarget);
-                resultIntent.putExtra(SEARCH_KEY, engine.name);
-                recordSearch(engine.identifier, "barsuggest");
-                finishWithResult(resultIntent);
-            }
-
-            @Override
-            public void onEditSuggestion(final String text) {
-                ThreadUtils.postToUiThread(new Runnable() {
-                    @Override
-                    public void run() {
-                        mText.setText(text);
-                        mText.setSelection(mText.getText().length());
-                        mText.requestFocus();
-                    }
-                });
-            }
-
-            @Override
-            public void onSwitchToTab(final int tabId) {
-                Intent resultIntent = new Intent();
-                resultIntent.putExtra(TAB_KEY, Integer.toString(tabId));
-                finishWithResult(resultIntent);
-            }
-        });
-
-        mGoButton.setOnClickListener(new Button.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                openUserEnteredAndFinish(mText.getText().toString());
-            }
-        });
-
-        Intent intent = getIntent();
-        String currentUrl = intent.getStringExtra(CURRENT_URL_KEY);
-        if (currentUrl != null) {
-            mText.setText(currentUrl);
-            mText.selectAll();
-        }
-
-        mTarget = intent.getStringExtra(TARGET_KEY);
-        if (mTarget.equals(Target.CURRENT_TAB.name())) {
-            Tab tab = Tabs.getInstance().getSelectedTab();
-            if (tab != null && tab.isPrivate()) {
-                BrowserToolbarBackground mAddressBarBg = (BrowserToolbarBackground) findViewById(R.id.address_bar_bg);
-                mAddressBarBg.setPrivateMode(true);
-
-                ShapedButton mTabs = (ShapedButton) findViewById(R.id.dummy_tab);
-                if (mTabs != null)
-                    mTabs.setPrivateMode(true);
-
-                mText.setPrivateMode(true);
-            }
-        }
-        mAwesomeTabs.setTarget(mTarget);
-
-        mText.setOnKeyPreImeListener(new CustomEditText.OnKeyPreImeListener() {
-            @Override
-            public boolean onKeyPreIme(View v, int keyCode, KeyEvent event) {
-                // We only want to process one event per tap
-                if (event.getAction() != KeyEvent.ACTION_DOWN)
-                    return false;
-
-                if (keyCode == KeyEvent.KEYCODE_ENTER) {
-                    // If the AwesomeBar has a composition string, don't submit the text yet.
-                    // ENTER is needed to commit the composition string.
-                    Editable content = mText.getText();
-                    if (!hasCompositionString(content)) {
-                        openUserEnteredAndFinish(content.toString());
-                        return true;
-                    }
-                }
-
-                // If input method is in fullscreen mode, we want to dismiss
-                // it instead of closing awesomebar straight away.
-                InputMethodManager imm =
-                        (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
-                if (keyCode == KeyEvent.KEYCODE_BACK && !imm.isFullscreenMode()) {
-                    return handleBackKey();
-                }
-
-                return false;
-            }
-        });
-
-        mText.addTextChangedListener(this);
-
-        mText.setOnKeyListener(new View.OnKeyListener() {
-            @Override
-            public boolean onKey(View v, int keyCode, KeyEvent event) {
-                if (keyCode == KeyEvent.KEYCODE_ENTER) {
-                    if (event.getAction() != KeyEvent.ACTION_DOWN)
-                        return true;
-
-                    openUserEnteredAndFinish(mText.getText().toString());
-                    return true;
-                } else if (GamepadUtils.isBackKey(event)) {
-                    return handleBackKey();
-                } else {
-                    return false;
-                }
-            }
-        });
-
-        mText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                if (v == null || hasFocus) {
-                    return;
-                }
-
-                InputMethodManager imm = (InputMethodManager)
-                    getSystemService(Context.INPUT_METHOD_SERVICE);
-                try {
-                    imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
-                } catch (NullPointerException e) {
-                    Log.e(LOGTAG, "InputMethodManagerService, why are you throwing"
-                                  + " a NullPointerException? See bug 782096", e);
-                }
-            }
-        });
-
-        boolean showReadingList = intent.getBooleanExtra(READING_LIST_KEY, false);
-        if (showReadingList) {
-            BookmarksTab bookmarksTab = mAwesomeTabs.getBookmarksTab();
-            bookmarksTab.setShowReadingList(true);
-            mAwesomeTabs.setCurrentItemByTag(bookmarksTab.getTag());
-        }
-    }
-
-    private boolean handleBackKey() {
-        // Let mAwesomeTabs try to handle the back press, since we may be in a
-        // bookmarks sub-folder.
-        if (mAwesomeTabs.onBackPressed())
-            return true;
-
-        // If mAwesomeTabs.onBackPressed() returned false, we didn't move up
-        // a folder level, so just exit the activity.
-        cancelAndFinish();
-        return true;
-    }
-
-    @Override
-    public void onConfigurationChanged(Configuration newConfiguration) {
-        super.onConfigurationChanged(newConfiguration);
-    }
-
-    @Override
-    public boolean onSearchRequested() {
-        cancelAndFinish();
-        return true;
-    }
-
-    private void updateGoButton(String text) {
-        if (text.length() == 0) {
-            mGoButton.setVisibility(View.GONE);
-            return;
-        }
-
-        mGoButton.setVisibility(View.VISIBLE);
-
-        int imageResource = R.drawable.ic_awesomebar_go;
-        String contentDescription = getString(R.string.go);
-        int imeAction = EditorInfo.IME_ACTION_GO;
-
-        int actionBits = mText.getImeOptions() & EditorInfo.IME_MASK_ACTION;
-        if (StringUtils.isSearchQuery(text, actionBits == EditorInfo.IME_ACTION_SEARCH)) {
-            imageResource = R.drawable.ic_awesomebar_search;
-            contentDescription = getString(R.string.search);
-            imeAction = EditorInfo.IME_ACTION_SEARCH;
-        }
-
-        InputMethodManager imm = InputMethods.getInputMethodManager(mText.getContext());
-        if (imm == null) {
-            return;
-        }
-        boolean restartInput = false;
-        if (actionBits != imeAction) {
-            int optionBits = mText.getImeOptions() & ~EditorInfo.IME_MASK_ACTION;
-            mText.setImeOptions(optionBits | imeAction);
-
-            mDelayRestartInput = (imeAction == EditorInfo.IME_ACTION_GO) &&
-                                 (InputMethods.shouldDelayAwesomebarUpdate(mText.getContext()));
-            if (!mDelayRestartInput) {
-                restartInput = true;
-            }
-        } else if (mDelayRestartInput) {
-            // Only call delayed restartInput when actionBits == imeAction
-            // so if there are two restarts in a row, the first restarts will
-            // be discarded and the second restart will be properly delayed
-            mDelayRestartInput = false;
-            restartInput = true;
-        }
-        if (restartInput) {
-            updateKeyboardInputType();
-            imm.restartInput(mText);
-            mGoButton.setImageResource(imageResource);
-            mGoButton.setContentDescription(contentDescription);
-        }
-    }
-
-    private void updateKeyboardInputType() {
-        // If the user enters a space, then we know they are entering search terms, not a URL.
-        // We can then switch to text mode so,
-        // 1) the IME auto-inserts spaces between words
-        // 2) the IME doesn't reset input keyboard to Latin keyboard.
-        String text = mText.getText().toString();
-        int currentInputType = mText.getInputType();
-        int newInputType = StringUtils.isSearchQuery(text, false)
-                           ? (currentInputType & ~InputType.TYPE_TEXT_VARIATION_URI) // Text mode
-                           : (currentInputType | InputType.TYPE_TEXT_VARIATION_URI); // URL mode
-        if (newInputType != currentInputType) {
-            mText.setRawInputType(newInputType);
-        }
-    }
-
-    private void cancelAndFinish() {
-        setResult(Activity.RESULT_CANCELED);
-        finish();
-        overridePendingTransition(R.anim.awesomebar_hold_still, R.anim.awesomebar_fade_out);
-    }
-
-    private void finishWithResult(Intent intent) {
-        setResult(Activity.RESULT_OK, intent);
-        finish();
-        overridePendingTransition(R.anim.awesomebar_hold_still, R.anim.awesomebar_fade_out);
-    }
-
-    private void openUrlAndFinish(String url) {
-        openUrlAndFinish(url, null, false);
-    }
-
-    private void openUrlAndFinish(String url, String title, boolean userEntered) {
-        Intent resultIntent = new Intent();
-        resultIntent.putExtra(URL_KEY, url);
-        if (title != null && !TextUtils.isEmpty(title))
-            resultIntent.putExtra(TITLE_KEY, title);
-        if (userEntered)
-            resultIntent.putExtra(USER_ENTERED_KEY, userEntered);
-        resultIntent.putExtra(TARGET_KEY, mTarget);
-        finishWithResult(resultIntent);
-    }
-
-    /**
-     * Record in Health Report that a search has occurred.
-     *
-     * @param identifier
-     *        a search identifier, such as "partnername". Can be null.
-     * @param where
-     *        where the search was initialized; one of the values in
-     *        {@link BrowserHealthRecorder#SEARCH_LOCATIONS}.
-     */
-    private static void recordSearch(String identifier, String where) {
-        Log.i(LOGTAG, "Recording search: " + identifier + ", " + where);
-        try {
-            JSONObject message = new JSONObject();
-            message.put("type", BrowserHealthRecorder.EVENT_SEARCH);
-            message.put("location", where);
-            message.put("identifier", identifier);
-            GeckoAppShell.getEventDispatcher().dispatchEvent(message);
-        } catch (Exception e) {
-            Log.w(LOGTAG, "Error recording search.", e);
-        }
-    }
-
-    private void openUserEnteredAndFinish(final String url) {
-        final int index = url.indexOf(' ');
-
-        // Check for a keyword if the URL looks like a search query
-        if (!StringUtils.isSearchQuery(url, true)) {
-            openUrlAndFinish(url, "", true);
-            return;
-        }
-        ThreadUtils.postToBackgroundThread(new Runnable() {
-            @Override
-            public void run() {
-                final String keyword;
-                final String keywordSearch;
-
-                if (index == -1) {
-                    keyword = url;
-                    keywordSearch = "";
-                } else {
-                    keyword = url.substring(0, index);
-                    keywordSearch = url.substring(index + 1);
-                }
-
-                final String keywordUrl = BrowserDB.getUrlForKeyword(getContentResolver(), keyword);
-                final String searchUrl = (keywordUrl != null)
-                                       ? keywordUrl.replace("%s", URLEncoder.encode(keywordSearch))
-                                       : url;
-                if (keywordUrl != null) {
-                    recordSearch(null, "barkeyword");
-                }
-                openUrlAndFinish(searchUrl, "", true);
-            }
-        });
-    }
-
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        // Galaxy Note sends key events for the stylus that are outside of the
-        // valid keyCode range (see bug 758427)
-        if (keyCode > KeyEvent.getMaxKeyCode())
-            return true;
-
-        // This method is called only if the key event was not handled
-        // by any of the views, which usually means the edit box lost focus
-        if (keyCode == KeyEvent.KEYCODE_BACK ||
-            keyCode == KeyEvent.KEYCODE_MENU ||
-            keyCode == KeyEvent.KEYCODE_DPAD_UP ||
-            keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
-            keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
-            keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
-            keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
-            keyCode == KeyEvent.KEYCODE_DEL ||
-            keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
-            keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
-            GamepadUtils.isActionKey(event)) {
-            return super.onKeyDown(keyCode, event);
-        } else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
-             mText.setText("");
-             mText.requestFocus();
-             return true;
-        } else {
-            int prevSelStart = mText.getSelectionStart();
-            int prevSelEnd = mText.getSelectionEnd();
-
-            // Manually dispatch the key event to the AwesomeBar. If selection changed as
-            // a result of the key event, then give focus back to mText
-            mText.dispatchKeyEvent(event);
-
-            int curSelStart = mText.getSelectionStart();
-            int curSelEnd = mText.getSelectionEnd();
-            if (prevSelStart != curSelStart || prevSelEnd != curSelEnd) {
-                mText.requestFocusFromTouch();
-                // Restore the selection, which gets lost due to the focus switch
-                mText.setSelection(curSelStart, curSelEnd);
-            }
-            return true;
-        }
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        if (mText != null && mText.getText() != null) {
-            updateGoButton(mText.getText().toString());
-            if (mDelayRestartInput) {
-                // call updateGoButton again to force a restartInput call
-                updateGoButton(mText.getText().toString());
-            }
-        }
-
-        // Invlidate the cached value that keeps track of whether or
-        // not desktop bookmarks exist
-        BrowserDB.invalidateCachedState();
-    }
-
-    @Override
-    public void onDestroy() {
-        super.onDestroy();
-        mAwesomeTabs.destroy();
-    }
-
-    @Override
-    public void onBackPressed() {
-        // Let mAwesomeTabs try to handle the back press, since we may be in a
-        // bookmarks sub-folder.
-        if (mAwesomeTabs.onBackPressed())
-            return;
-
-        // Otherwise, just exit the awesome screen
-        cancelAndFinish();
-    }
-
-    static public class ContextMenuSubject {
-        public int id;
-        public String url;
-        public byte[] favicon;
-        public String title;
-        public String keyword;
-        public int display;
-
-        public ContextMenuSubject(int id, String url, byte[] favicon, String title, String keyword) {
-            this(id, url, favicon, title, keyword, Combined.DISPLAY_NORMAL);
-        }
-
-        public ContextMenuSubject(int id, String url, byte[] favicon, String title, String keyword, int display) {
-            this.id = id;
-            this.url = url;
-            this.favicon = favicon;
-            this.title = title;
-            this.keyword = keyword;
-            this.display = display;
-        }
-    };
-
-    @Override
-    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
-        super.onCreateContextMenu(menu, view, menuInfo);
-        AwesomeBarTab tab = mAwesomeTabs.getAwesomeBarTabForView(view);
-        mContextMenuSubject = tab.getSubject(menu, view, menuInfo);
-    }
-
-    @Override
-    public boolean onContextItemSelected(MenuItem item) {
-        if (mContextMenuSubject == null)
-            return false;
-
-        final int id = mContextMenuSubject.id;
-        final String url = mContextMenuSubject.url;
-        final byte[] b = mContextMenuSubject.favicon;
-        final String title = mContextMenuSubject.title;
-        final String keyword = mContextMenuSubject.keyword;
-        final int display = mContextMenuSubject.display;
-
-        final int itemId = item.getItemId();
-        if (itemId == R.id.open_private_tab || itemId == R.id.open_new_tab) {
-            if (url == null) {
-                Log.e(LOGTAG, "Can't open in new tab because URL is null");
-            }
-
-            String newTabUrl = url;
-            if (display == Combined.DISPLAY_READER)
-                newTabUrl = ReaderModeUtils.getAboutReaderForUrl(url, true);
-
-            int flags = Tabs.LOADURL_NEW_TAB;
-            if (item.getItemId() == R.id.open_private_tab)
-                flags |= Tabs.LOADURL_PRIVATE;
-
-            Tabs.getInstance().loadUrl(newTabUrl, flags);
-            Toast.makeText(this, R.string.new_tab_opened, Toast.LENGTH_SHORT).show();
-
-            return true;
-        }
-
-        if (itemId == R.id.open_in_reader) {
-            if (url == null) {
-                Log.e(LOGTAG, "Can't open in reader mode because URL is null");
-            } else {
-                openUrlAndFinish(ReaderModeUtils.getAboutReaderForUrl(url, true));
-            }
-            return true;
-        }
-
-        if (itemId == R.id.edit_bookmark) {
-            new EditBookmarkDialog(this).show(id, title, url, keyword);
-            return true;
-        }
-
-        if (itemId == R.id.remove_bookmark) {
-            (new UiAsyncTask<Void, Void, Integer>(ThreadUtils.getBackgroundHandler()) {
-                private boolean mInReadingList;
-
-                @Override
-                public void onPreExecute() {
-                    mInReadingList = mAwesomeTabs.isInReadingList();
-                }
-
-                @Override
-                public Integer doInBackground(Void... params) {
-                    BrowserDB.removeBookmark(getContentResolver(), id);
-                    Integer count = mInReadingList ?
-                        BrowserDB.getReadingListCount(getContentResolver()) : 0;
-
-                    return count;
-                }
-
-                @Override
-                public void onPostExecute(Integer aCount) {
-                    int messageId = R.string.bookmark_removed;
-                    if (mInReadingList) {
-                        messageId = R.string.reading_list_removed;
-
-                        GeckoEvent e = GeckoEvent.createBroadcastEvent("Reader:Remove", url);
-                        GeckoAppShell.sendEventToGecko(e);
-
-                        // Delete from Awesomebar context menu can alter reading list bookmark count
-                        e = GeckoEvent.createBroadcastEvent("Reader:ListCountUpdated", Integer.toString(aCount));
-                        GeckoAppShell.sendEventToGecko(e);
-                    }
-
-                    Toast.makeText(AwesomeBar.this, messageId, Toast.LENGTH_SHORT).show();
-                }
-            }).execute();
-
-            return true;
-        }
-
-        if (itemId == R.id.remove_history) {
-            (new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
-                @Override
-                public Void doInBackground(Void... params) {
-                    BrowserDB.removeHistoryEntry(getContentResolver(), id);
-                    return null;
-                }
-
-                @Override
-                public void onPostExecute(Void result) {
-                    Toast.makeText(AwesomeBar.this, R.string.history_removed, Toast.LENGTH_SHORT).show();
-                }
-            }).execute();
-
-            return true;
-        }
-
-        if (itemId == R.id.add_to_launcher) {
-            if (url == null) {
-                Log.e(LOGTAG, "Can't add to home screen because URL is null");
-            } else {
-                Bitmap bitmap = null;
-                if (b != null) {
-                    bitmap = BitmapUtils.decodeByteArray(b);
-                }
-
-                String shortcutTitle = TextUtils.isEmpty(title) ? url.replaceAll("^([a-z]+://)?(www\\.)?", "") : title;
-                GeckoAppShell.createShortcut(shortcutTitle, url, bitmap, "");
-            }
-
-            return true;
-        }
-
-        if (itemId == R.id.share) {
-            if (url == null) {
-                Log.e(LOGTAG, "Can't share because URL is null");
-            } else {
-                GeckoAppShell.openUriExternal(url, "text/plain", "", "",
-                                              Intent.ACTION_SEND, title);
-            }
-
-            return true;
-        }
-
-        return super.onContextItemSelected(item);
-    }
-
-    public static String getReaderForUrl(String url) {
-        // FIXME: still need to define the final way to open items from
-        // reading list. For now, we're using an about:reader page.
-        return "about:reader?url=" + Uri.encode(url) + "&readingList=1";
-    }
-
-    private static boolean hasCompositionString(Editable content) {
-        Object[] spans = content.getSpans(0, content.length(), Object.class);
-        if (spans != null) {
-            for (Object span : spans) {
-                if ((content.getSpanFlags(span) & Spanned.SPAN_COMPOSING) != 0) {
-                    // Found composition string.
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    // return early if we're backspacing through the string, or have no autocomplete results
-    public void onAutocomplete(final String result) {
-        final String text = mText.getText().toString();
-
-        if (result == null) {
-            mAutoCompleteResult = "";
-            return;
-        }
-
-        if (!result.startsWith(text) || text.equals(result)) {
-            return;
-        }
-
-        mAutoCompleteResult = result;
-        mText.getText().append(result.substring(text.length()));
-        mText.setSelection(text.length(), result.length());
-    }
-
-    @Override
-    public void afterTextChanged(final Editable s) {
-        final String text = s.toString();
-        boolean useHandler = false;
-        boolean reuseAutocomplete = false;
-        if (!hasCompositionString(s) && !StringUtils.isSearchQuery(text, false)) {
-            useHandler = true;
-
-            // If you're hitting backspace (the string is getting smaller
-            // or is unchanged), don't autocomplete.
-            if (mAutoCompletePrefix != null && (mAutoCompletePrefix.length() >= text.length())) {
-                useHandler = false;
-            } else if (mAutoCompleteResult != null && mAutoCompleteResult.startsWith(text)) {
-                // If this text already matches our autocomplete text, autocomplete likely
-                // won't change. Just reuse the old autocomplete value.
-                useHandler = false;
-                reuseAutocomplete = true;
-            }
-        }
-
-        // If this is the autocomplete text being set, don't run the filter.
-        if (TextUtils.isEmpty(mAutoCompleteResult) || !mAutoCompleteResult.equals(text)) {
-            mAwesomeTabs.filter(text, useHandler ? this : null);
-            mAutoCompletePrefix = text;
-
-            if (reuseAutocomplete) {
-                onAutocomplete(mAutoCompleteResult);
-            }
-        }
-
-        // If the AwesomeBar has a composition string, don't call updateGoButton().
-        // That method resets IME and composition state will be broken.
-        if (!hasCompositionString(s) ||
-            InputMethods.isGestureKeyboard(mText.getContext())) {
-            updateGoButton(text);
-        }
-    }
-
-    @Override
-    public void beforeTextChanged(CharSequence s, int start, int count,
-                                  int after) {
-        // do nothing
-    }
-
-    @Override
-    public void onTextChanged(CharSequence s, int start, int before,
-                              int count) {
-        // do nothing
-    }
-}
deleted file mode 100644
--- a/mobile/android/base/AwesomeBarTabs.java
+++ /dev/null
@@ -1,381 +0,0 @@
-/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * 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/. */
-
-package org.mozilla.gecko;
-
-import android.content.Context;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.support.v4.view.PagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TabHost;
-import android.widget.TabWidget;
-
-public class AwesomeBarTabs extends TabHost
-                            implements LightweightTheme.OnChangeListener { 
-    private static final String LOGTAG = "GeckoAwesomeBarTabs";
-
-    private Context mContext;
-    private GeckoActivity mActivity;
-
-    private boolean mInflated;
-    private LayoutInflater mInflater;
-    private OnUrlOpenListener mUrlOpenListener;
-    private View.OnTouchListener mListTouchListener;
-    private boolean mSearching = false;
-    private String mTarget;
-    private ViewPager mViewPager;
-    private AwesomePagerAdapter mPagerAdapter;
-
-    private AwesomeBarTab mTabs[];
-
-    public interface OnUrlOpenListener {
-        public void onUrlOpen(String url, String title);
-        public void onSearch(SearchEngine engine, String text);
-        public void onEditSuggestion(String suggestion);
-        public void onSwitchToTab(final int tabId);
-    }
-
-    private class AwesomePagerAdapter extends PagerAdapter {
-        public AwesomePagerAdapter() {
-            super();
-        }
-
-        @Override
-        public Object instantiateItem(ViewGroup group, int index) {
-            AwesomeBarTab tab = mTabs[index];
-            group.addView(tab.getView());
-            return tab;
-        }
-
-        @Override
-        public void destroyItem(ViewGroup group, int index, Object obj) {
-            AwesomeBarTab tab = (AwesomeBarTab)obj;
-            group.removeView(tab.getView());
-        }
-
-        @Override
-        public int getCount() {
-            if (mSearching)
-                return 1;
-            return mTabs.length;
-        }
-
-        @Override
-        public boolean isViewFromObject(View view, Object object) {
-            return getAwesomeBarTabForView(view) == object;
-        }
-    }
-
-    private AwesomeBarTab getCurrentAwesomeBarTab() {
-        int index = mViewPager.getCurrentItem();
-        return mTabs[index];
-    }
-
-    public AwesomeBarTab getAwesomeBarTabForView(View view) {
-        String tag = (String)view.getTag();
-        return getAwesomeBarTabForTag(tag);
-    }
-
-    public AwesomeBarTab getAwesomeBarTabForTag(String tag) {
-        for (AwesomeBarTab tab : mTabs) {
-            if (tag.equals(tab.getTag())) {
-                return tab;
-            }
-        }
-        return null;
-    }
-
-    public boolean onBackPressed() {
-        AwesomeBarTab tab = getCurrentAwesomeBarTab();
-        if (tab == null)
-             return false;
-        return tab.onBackPressed();
-    }
-
-    public AwesomeBarTabs(Context context, AttributeSet attrs) {
-        super(context, attrs);
-
-        Log.d(LOGTAG, "Creating AwesomeBarTabs");
-
-        mContext = context;
-        mActivity = (GeckoActivity) context;
-
-        mInflated = false;
-        mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-
-        // HACK: Without this, the onFinishInflate is called twice
-        // This issue is due to a bug when Android inflates a layout with a
-        // parent. Fixed in Honeycomb
-        if (mInflated)
-            return;
-
-        mInflated = true;
-
-        // This should be called before adding any tabs
-        // to the TabHost.
-        setup();
-
-        mListTouchListener = new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View view, MotionEvent event) {
-                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-                    // take focus away from awesome bar to hide the keyboard
-                    requestFocus();
-                }
-                return false;
-            }
-        };
-
-        mTabs = new AwesomeBarTab[] {
-            new AllPagesTab(mContext),
-            new BookmarksTab(mContext),
-            new HistoryTab(mContext)
-        };
-
-        final TabWidget tabWidget = (TabWidget) findViewById(android.R.id.tabs);
-        // hide the strip since we aren't using the TabHost...
-        tabWidget.setStripEnabled(false);
-
-        mViewPager = (ViewPager) findViewById(R.id.tabviewpager);
-        mPagerAdapter = new AwesomePagerAdapter();
-        mViewPager.setAdapter(mPagerAdapter);
-
-        mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
-            @Override
-            public void onPageScrollStateChanged(int state) { }
-            @Override
-            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
-            @Override
-            public void onPageSelected(int position) {
-                tabWidget.setCurrentTab(position);
-                styleSelectedTab();
-                // take focus away from awesome bar to hide the keyboard
-                requestFocus();
-             }
-         });
-
-        for (int i = 0; i < mTabs.length; i++) {
-            mTabs[i].setListTouchListener(mListTouchListener);
-            addAwesomeTab(mTabs[i].getTag(),
-                          mTabs[i].getTitleStringId(),
-                          i);
-        }
-
-        // Initialize "All Pages" list with no filter
-        filter("", null);
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mActivity.getLightweightTheme().addListener(this);
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mActivity.getLightweightTheme().removeListener(this);
-    }
-
-    @Override
-    public void onLightweightThemeChanged() {
-        styleSelectedTab();
-    }
-
-    @Override<