Merge m-c to cedar
authorJames Graham <james@hoppipolla.co.uk>
Fri, 05 Jun 2015 14:55:01 +0100
changeset 326812 25b7b298c3f340651cacdfb28e596076c29d22fa
parent 326811 4275bf6a483448ae9d46bb8b17cfb956dde0ac20 (current diff)
parent 270214 920ded6a1f77189943310aa1fda0f38a20e5f824 (diff)
child 326813 0283d11943916b865db83d22c014e397e6fc588a
push id10169
push userdminor@mozilla.com
push dateThu, 28 Jan 2016 13:10:48 +0000
milestone41.0a1
Merge m-c to cedar
CLOBBER
addon-sdk/source/lib/sdk/deprecated/memory.js
addon-sdk/source/lib/sdk/util/bond.js
addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/main.js
addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/manifest-overload.json
addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/package.json
addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js
addon-sdk/source/test/addons/require/memory.js
addon-sdk/source/test/test-bond.js
addon-sdk/source/test/test-memory.js
browser/devtools/performance/test/browser_profiler_categories.js
browser/devtools/performance/test/browser_profiler_content-check.js
browser/devtools/performance/test/browser_waterfall-collapse.js
dom/mobileconnection/tests/marionette/test_call_barring_get_option.js
dom/push/PushService.jsm
intl/uconv/ucvcn/gbkuniq2b.uf
intl/unicharutil/tests/UnicharSelfTest.cpp
layout/base/nsRefreshDriver.cpp
layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-001-ref.xht
layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-001.xht
layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-002-ref.xht
layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-002.xht
layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-003-ref.xht
layout/reftests/w3c-css/submitted/ui3/box-sizing-padding-box-003.xht
mobile/android/base/resources/layout/doorhanger_button.xml
security/manager/ssl/tests/mochitest/bugs/chrome.ini
security/manager/ssl/tests/mochitest/bugs/test_bug644006.html
security/manager/ssl/tests/unit/test_certificate_usages.js
security/manager/ssl/tests/unit/test_certificate_usages/ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-1-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-1-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-1-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-1-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-2-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-2-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-2-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-2-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-3-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-3-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-3-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-3-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-4-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-4-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-4-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-4-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-5-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-5-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-5-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-5-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-6-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-6-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-6-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-6-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-7-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-7-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-7-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-7-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-8-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-8-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-8-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-8-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-9-ca-1.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-9-ca-2.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-9-ca-3.der
security/manager/ssl/tests/unit/test_certificate_usages/ee-9-ca-4.der
security/manager/ssl/tests/unit/test_certificate_usages/generate.pl
testing/docker/desktop-build/configs/disable_sendchange.py
testing/mozharness/mozharness.json
testing/web-platform/harness/wptrunner/browsers/b2g.py
testing/web-platform/harness/wptrunner/browsers/chrome.py
testing/web-platform/harness/wptrunner/browsers/firefox.py
testing/web-platform/harness/wptrunner/browsers/servo.py
testing/web-platform/harness/wptrunner/testloader.py
testing/web-platform/harness/wptrunner/wptcommandline.py
testing/web-platform/harness/wptrunner/wptrunner.py
testing/web-platform/harness/wptrunner/wpttest.py
testing/web-platform/meta/MANIFEST.json
testing/web-platform/meta/XMLHttpRequest/interfaces.html.ini
testing/web-platform/meta/ambient-light/idlharness.html.ini
testing/web-platform/meta/animation-timing/idlharness.html.ini
testing/web-platform/meta/eventsource/eventsource-constructor-document-domain.htm.ini
testing/web-platform/meta/navigation-timing/test_navigation_type_reload.html.ini
testing/web-platform/meta/proximity/idlharness.html.ini
testing/web-platform/meta/service-workers/stub-3.1-service-worker-obj.html.ini
testing/web-platform/meta/service-workers/stub-3.1.1-service-worker-scope.html.ini
testing/web-platform/meta/service-workers/stub-3.1.2-service-worker-url.html.ini
testing/web-platform/meta/service-workers/stub-3.1.3-service-worker-state.html.ini
testing/web-platform/meta/service-workers/stub-3.1.4-service-worker-on-state-change.html.ini
testing/web-platform/meta/service-workers/stub-3.2-navigator-service-worker.html.ini
testing/web-platform/meta/service-workers/stub-3.2.1-navigator-service-worker-installing.html.ini
testing/web-platform/meta/service-workers/stub-3.2.10-navigator-service-worker-oncontrollerchange.html.ini
testing/web-platform/meta/service-workers/stub-3.2.11-navigator-service-worker-onreloadpage.html.ini
testing/web-platform/meta/service-workers/stub-3.2.12-navigator-service-worker-onerror.html.ini
testing/web-platform/meta/service-workers/stub-3.2.2-navigator-service-worker-waiting.html.ini
testing/web-platform/meta/service-workers/stub-3.2.3-navigator-service-worker-active.html.ini
testing/web-platform/meta/service-workers/stub-3.2.4-navigator-service-worker-controller.html.ini
testing/web-platform/meta/service-workers/stub-3.2.5-navigator-service-worker-ready.html.ini
testing/web-platform/meta/service-workers/stub-3.2.6-navigator-service-worker-getAll.html.ini
testing/web-platform/meta/service-workers/stub-3.2.7-navigator-service-worker-register.html.ini
testing/web-platform/meta/service-workers/stub-3.2.8-navigator-service-worker-unregister.html.ini
testing/web-platform/meta/service-workers/stub-3.2.9-navigator-service-worker-onupdatefound.html.ini
testing/web-platform/meta/service-workers/stub-4.1-service-worker-global-scope.html.ini
testing/web-platform/meta/service-workers/stub-4.1.1-service-worker-global-scope-caches.html.ini
testing/web-platform/meta/service-workers/stub-4.1.2-service-worker-global-scope-clients.html.ini
testing/web-platform/meta/service-workers/stub-4.1.3-service-worker-global-scope-scope.html.ini
testing/web-platform/meta/service-workers/stub-4.1.4-service-worker-global-scope-fetch.html.ini
testing/web-platform/meta/service-workers/stub-4.1.5-service-worker-global-scope-update.html.ini
testing/web-platform/meta/service-workers/stub-4.1.6-service-worker-global-scope-unregister.html.ini
testing/web-platform/meta/service-workers/stub-4.1.7-service-worker-global-scope-onmessage.html.ini
testing/web-platform/meta/service-workers/stub-4.2-client.html.ini
testing/web-platform/meta/service-workers/stub-4.3-service-worker-clients.html.ini
testing/web-platform/meta/service-workers/stub-4.3.1-get-serviced-method.html.ini
testing/web-platform/meta/service-workers/stub-4.3.2-reloadall-method.html.ini
testing/web-platform/meta/service-workers/stub-4.4-request-objects.html.ini
testing/web-platform/meta/service-workers/stub-4.5-response-objects.html.ini
testing/web-platform/meta/service-workers/stub-4.5.2-response.html.ini
testing/web-platform/meta/service-workers/stub-4.5.4-opaque-response.html.ini
testing/web-platform/meta/service-workers/stub-4.6-cache-objects.html.ini
testing/web-platform/meta/service-workers/stub-4.6.1-cache-lifetimes.html.ini
testing/web-platform/meta/service-workers/stub-4.6.2-cache.html.ini
testing/web-platform/meta/service-workers/stub-4.6.3-cache-storage.html.ini
testing/web-platform/meta/service-workers/stub-4.7.1-install-phase-event.html.ini
testing/web-platform/meta/service-workers/stub-4.7.1.1-wait-until-method.html.ini
testing/web-platform/meta/service-workers/stub-4.7.2-install-event.html.ini
testing/web-platform/meta/service-workers/stub-4.7.2.1-install-event-section.html.ini
testing/web-platform/meta/service-workers/stub-4.7.2.2-replace-method.html.ini
testing/web-platform/meta/service-workers/stub-4.7.3-activate-event.html.ini
testing/web-platform/meta/service-workers/stub-4.7.4.1-fetch-event-section.html.ini
testing/web-platform/meta/service-workers/stub-4.7.4.2-respond-with-method.html.ini
testing/web-platform/meta/service-workers/stub-4.7.4.3-default-method.html.ini
testing/web-platform/meta/service-workers/stub-4.7.4.4-is-reload-attribute.html.ini
testing/web-platform/meta/service-workers/stub-5.1-origin-relativity.html.ini
testing/web-platform/meta/service-workers/stub-5.2-cross-origin-resources.html.ini
testing/web-platform/meta/url/a-element.xhtml.ini
testing/web-platform/tests/battery-status/prime.js
testing/web-platform/tests/eventsource/eventsource-request-cancellation.htm
testing/web-platform/tests/referrer-policy/README.html
testing/web-platform/tests/referrer-policy/no-referrer-policy/no-referrer-policy.html
testing/web-platform/tests/referrer-policy/no-referrer-policy/no-referrer-policy.subresource.py
testing/web-platform/tests/referrer-policy/no-referrer-policy/no-referrer-policy.subresource.template.html
testing/web-platform/tests/subresource-integrity/loads-scripts-with-base64-encoded-sha-digests.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-correct-content-type.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-improper-integrity-uri-scheme.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-incorrect-content-type.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-matching-digest.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-non-matching-digest.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-unhyphenated-digest-name.js
testing/web-platform/tests/subresource-integrity/loads-scripts-with-weak-digest-algorithms.js
toolkit/components/passwordmgr/test/chrome.ini
toolkit/components/passwordmgr/test/test_bug_221634.html
toolkit/components/passwordmgr/test/test_bug_242956.html
toolkit/components/passwordmgr/test/test_bug_360493_1.html
toolkit/components/passwordmgr/test/test_bug_360493_2.html
toolkit/components/passwordmgr/test/test_bug_391514.html
toolkit/components/passwordmgr/test/test_bug_427033.html
toolkit/components/passwordmgr/test/test_bug_444968.html
toolkit/components/passwordmgr/test/test_bug_654348.html
toolkit/devtools/server/tests/unit/test_promise_actor_list_promises.js
toolkit/mozapps/update/tests/chrome/chrome.ini
toolkit/mozapps/update/tests/unit_base_updater/marAppInUseFallbackStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileInUseFallbackStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marFileLockedFallbackStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailureComplete_win.js
toolkit/mozapps/update/tests/unit_base_updater/marRMRFDirFileInUseFallbackStageFailurePartial_win.js
toolkit/mozapps/update/tests/unit_service_updater/marAppInUseFallbackStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseFallbackStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileInUseFallbackStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFallbackStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marFileLockedFallbackStageFailurePartialSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseFallbackStageFailureCompleteSvc_win.js
toolkit/mozapps/update/tests/unit_service_updater/marRMRFDirFileInUseFallbackStageFailurePartialSvc_win.js
xpcom/base/VisualEventTracer.cpp
xpcom/base/VisualEventTracer.h
xpcom/base/nsIVisualEventTracer.idl
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1166031 - NSS update hit needs-clobber bustage.
+Bug 1165422 - Updated the Android SDK versions
--- a/addon-sdk/moz.build
+++ b/addon-sdk/moz.build
@@ -24,17 +24,16 @@ EXTRA_JS_MODULES.sdk.system += [
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != "gonk":
     EXTRA_JS_MODULES.commonjs.method.test += [
         'source/lib/method/test/browser.js',
         'source/lib/method/test/common.js',
     ]
 
     EXTRA_JS_MODULES.commonjs.sdk.deprecated += [
         'source/lib/sdk/deprecated/api-utils.js',
-        'source/lib/sdk/deprecated/memory.js',
         'source/lib/sdk/deprecated/sync-worker.js',
         'source/lib/sdk/deprecated/unit-test-finder.js',
         'source/lib/sdk/deprecated/unit-test.js',
         'source/lib/sdk/deprecated/window-utils.js',
     ]
 
     EXTRA_JS_MODULES.commonjs.sdk.frame += [
         'source/lib/sdk/frame/hidden-frame.js',
@@ -253,16 +252,20 @@ EXTRA_JS_MODULES.commonjs.sdk.content +=
     'source/lib/sdk/content/sandbox.js',
     'source/lib/sdk/content/tab-events.js',
     'source/lib/sdk/content/thumbnail.js',
     'source/lib/sdk/content/utils.js',
     'source/lib/sdk/content/worker-child.js',
     'source/lib/sdk/content/worker.js',
 ]
 
+EXTRA_JS_MODULES.commonjs.sdk.content.sandbox += [
+    'source/lib/sdk/content/sandbox/events.js',
+]
+
 EXTRA_JS_MODULES.commonjs.sdk['context-menu'] += [
     'source/lib/sdk/context-menu/context.js',
     'source/lib/sdk/context-menu/core.js',
     'source/lib/sdk/context-menu/readers.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.core += [
     'source/lib/sdk/core/disposable.js',
@@ -448,17 +451,16 @@ EXTRA_JS_MODULES.commonjs.sdk.uri += [
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.url += [
     'source/lib/sdk/url/utils.js',
 ]
 
 EXTRA_JS_MODULES.commonjs.sdk.util += [
     'source/lib/sdk/util/array.js',
-    'source/lib/sdk/util/bond.js',
     'source/lib/sdk/util/collection.js',
     'source/lib/sdk/util/contract.js',
     'source/lib/sdk/util/deprecate.js',
     'source/lib/sdk/util/dispatcher.js',
     'source/lib/sdk/util/list.js',
     'source/lib/sdk/util/match-pattern.js',
     'source/lib/sdk/util/object.js',
     'source/lib/sdk/util/rules.js',
--- a/addon-sdk/source/.travis.yml
+++ b/addon-sdk/source/.travis.yml
@@ -1,12 +1,12 @@
 sudo: false
 language: node_js
 node_js:
-  - "0.10"
+  - "0.12"
 
 env:
   - JPM_FX_DEBUG=0
   - JPM_FX_DEBUG=1
 
 notifications:
   irc: "irc.mozilla.org#jetpack"
 
--- a/addon-sdk/source/bin/jpm-test.js
+++ b/addon-sdk/source/bin/jpm-test.js
@@ -12,22 +12,23 @@ var mocha = new Mocha({
 });
 
 var isDebug = require("./node-scripts/utils").isDebug;
 
 exports.run = function(type) {
   return new Promise(function(resolve) {
     type = type || "";
     [
-      (!isDebug && /^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"),
-      (!isDebug && /^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"),
-      (/^(examples)?$/.test(type)) && require.resolve("../bin/node-scripts/test.examples"),
+      (!isDebug && /^(firefox-bin)?$/.test(type)) && require.resolve("../bin/node-scripts/test.firefox-bin"),
       (!isDebug && /^(docs)?$/.test(type)) && require.resolve("../bin/node-scripts/test.docs"),
       (!isDebug && /^(ini)?$/.test(type)) && require.resolve("../bin/node-scripts/test.ini"),
-    ].sort().forEach(function(filepath) {
+      (/^(examples)?$/.test(type)) && require.resolve("../bin/node-scripts/test.examples"),
+      (!isDebug && /^(addons)?$/.test(type)) && require.resolve("../bin/node-scripts/test.addons"),
+      (!isDebug && /^(modules)?$/.test(type)) && require.resolve("../bin/node-scripts/test.modules"),
+    ].forEach(function(filepath) {
       filepath && mocha.addFile(filepath);
     })
 
     mocha.run(function(failures) {
       resolve(failures);
     });
   });
 }
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/bin/node-scripts/test.firefox-bin.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+var fs = require("fs");
+var Promise = require("promise");
+var chai = require("chai");
+var expect = chai.expect;
+var normalizeBinary = require("fx-runner/lib/utils").normalizeBinary;
+
+//var firefox_binary = process.env["JPM_FIREFOX_BINARY"] || normalizeBinary("nightly");
+
+describe("Checking Firefox binary", function () {
+
+  it("using matching fx-runner version with jpm", function () {
+    var sdkPackageJSON = require("../../package.json");
+    var jpmPackageINI = require("jpm/package.json");
+    expect(sdkPackageJSON.devDependencies["fx-runner"]).to.be.equal(jpmPackageINI.dependencies["fx-runner"]);
+  });
+
+  it("exists", function (done) {
+    var useEnvVar = new Promise(function(resolve) {
+      resolve(process.env["JPM_FIREFOX_BINARY"]);
+    });
+
+    var firefox_binary = process.env["JPM_FIREFOX_BINARY"] ? useEnvVar : normalizeBinary("nightly");
+    firefox_binary.then(function(path) {
+      expect(path).to.be.ok;
+      fs.exists(path, function (exists) {
+        expect(exists).to.be.ok;
+        done();
+      });
+    })
+  });
+
+});
--- a/addon-sdk/source/bin/node-scripts/test.ini.js
+++ b/addon-sdk/source/bin/node-scripts/test.ini.js
@@ -6,34 +6,63 @@
 var fs = require("fs");
 var path = require("path");
 var Promise = require("promise");
 var chai = require("chai");
 var expect = chai.expect;
 var ini = require("./update-ini");
 
 var addonINI = path.resolve("./test/addons/jetpack-addon.ini");
+var packageINI = path.resolve("./test/jetpack-package.ini");
 
 describe("Checking ini files", function () {
 
   it("Check test/addons/jetpack-addon.ini", function (done) {
 
     fs.readFile(addonINI, function (err, data) {
       if (err) {
         throw err;
       }
-      var text = data.toString();
+      // filter comments
+      var text = data.toString().split("\n").filter(function(line) {
+        return !/^\s*#/.test(line);
+      }).join("\n");
       var expected = "";
 
       ini.makeAddonIniContent()
       .then(function(contents) {
         expected = contents;
 
         setTimeout(function end() {
-          expect(expected.trim()).to.be.equal(text.trim());
+          expect(text.trim()).to.be.equal(expected.trim());
+          done();
+        });
+      });
+    });
+
+  });
+
+  it("Check test/jetpack-package.ini", function (done) {
+
+    fs.readFile(packageINI, function (err, data) {
+      if (err) {
+        throw err;
+      }
+      // filter comments
+      var text = data.toString().split("\n").filter(function(line) {
+        return !/^\s*#/.test(line);
+      }).join("\n");
+      var expected = "";
+
+      ini.makePackageIniContent()
+      .then(function(contents) {
+        expected = contents;
+
+        setTimeout(function end() {
+          expect(text.trim()).to.be.equal(expected.trim());
           done();
         });
       });
     });
 
   });
 
 });
--- a/addon-sdk/source/bin/node-scripts/update-ini.js
+++ b/addon-sdk/source/bin/node-scripts/update-ini.js
@@ -6,16 +6,25 @@
 var path = require("path");
 var cp = require("child_process");
 var fs = require("fs");
 var Promise = require("promise");
 var parser = require("ini-parser");
 
 var addonINI = path.resolve("./test/addons/jetpack-addon.ini");
 var addonsDir = path.resolve("./test/addons/");
+var packageINI = path.resolve("./test/jetpack-package.ini");
+var packageDir = path.resolve("./test/");
+var packageIgnorables = [ "addons", "preferences" ];
+var packageSupportFiles = [
+  "fixtures.js",
+  "pagemod-test-helpers.js",
+  "test-context-menu.html",
+  "util.js"
+]
 
 function updateAddonINI() {
   return new Promise(function(resolve) {
     console.log("Start updating " + addonINI);
 
     makeAddonIniContent().
     then(function(contents) {
       fs.writeFileSync(addonINI, contents, { encoding: "utf8" });
@@ -27,32 +36,107 @@ function updateAddonINI() {
 exports.updateAddonINI = updateAddonINI;
 
 function makeAddonIniContent() {
   return new Promise(function(resolve) {
     var data = parser.parse(fs.readFileSync(addonINI, { encoding: "utf8" }).toString());
     var result = {};
 
     fs.readdir(addonsDir, function(err, files) {
+      // get a list of folders
       var folders = files.filter(function(file) {
         return fs.statSync(path.resolve(addonsDir, file)).isDirectory();
       }).sort();
 
+      // copy any related data from the existing ini
       folders.forEach(function(folder) {
         var oldData = data[folder + ".xpi"];
         result[folder] = oldData ? oldData : {};
       });
 
-      // build ini file
+      // build a new ini file
       var contents = [];
       Object.keys(result).sort().forEach(function(key) {
         contents.push("[" + key + ".xpi]");
         Object.keys(result[key]).forEach(function(dataKey) {
           contents.push(dataKey + " = " + result[key][dataKey]);
         });
       });
       contents = contents.join("\n") + "\n";
 
       return resolve(contents);
     });
   });
 }
 exports.makeAddonIniContent = makeAddonIniContent;
+
+function makePackageIniContent() {
+  return new Promise(function(resolve) {
+    var data = parser.parse(fs.readFileSync(packageINI, { encoding: "utf8" }).toString());
+    var result = {};
+
+    fs.readdir(packageDir, function(err, files) {
+      // get a list of folders
+      var folders = files.filter(function(file) {
+        var ignore = (packageIgnorables.indexOf(file) >= 0);
+        var isDir = fs.statSync(path.resolve(packageDir, file)).isDirectory();
+        return (isDir && !ignore);
+      }).sort();
+
+      // get a list of "test-"" files
+      var files = files.filter(function(file) {
+        var ignore = !/^test\-.*\.js$/i.test(file);
+        var isDir = fs.statSync(path.resolve(packageDir, file)).isDirectory();
+        return (!isDir && !ignore);
+      }).sort();
+
+      // get a list of the support files
+      var support_files = packageSupportFiles.map(function(file) {
+        return "  " + file;
+      });
+      folders.forEach(function(folder) {
+        support_files.push("  " + folder + "/**");
+      });
+      support_files = support_files.sort();
+
+      // copy any related data from the existing ini
+      files.forEach(function(file) {
+        var oldData = data[file];
+        result[file] = oldData ? oldData : {};
+      });
+
+      // build a new ini file
+      var contents = [
+        "[DEFAULT]",
+        "support-files ="
+      ];
+      support_files.forEach(function(support_file) {
+        contents.push(support_file);
+      });
+      contents.push("");
+
+      Object.keys(result).sort().forEach(function(key) {
+        contents.push("[" + key + "]");
+        Object.keys(result[key]).forEach(function(dataKey) {
+          contents.push(dataKey + " = " + result[key][dataKey]);
+        });
+      });
+      contents = contents.join("\n") + "\n";
+
+      return resolve(contents);
+    });
+  });
+}
+exports.makePackageIniContent = makePackageIniContent;
+
+function updatePackageINI() {
+  return new Promise(function(resolve) {
+    console.log("Start updating " + packageINI);
+
+    makeAddonIniContent().
+    then(function(contents) {
+      fs.writeFileSync(packageINI, contents, { encoding: "utf8" });
+      console.log("Done updating " + packageINI);
+      resolve();
+    });
+  })
+}
+exports.updatePackageINI = updatePackageINI;
--- a/addon-sdk/source/bin/node-scripts/utils.js
+++ b/addon-sdk/source/bin/node-scripts/utils.js
@@ -60,16 +60,19 @@ function run (cmd, options, p) {
       }
       output.push(data);
       return null;
     });
 
     if (p) {
       proc.stdout.pipe(p.stdout);
     }
+    else if (!isDebug) {
+      proc.stdout.pipe(DEFAULT_PROCESS.stdout);
+    }
     else {
       proc.stdout.on("data", function (data) {
         data = (data || "") + "";
         if (/TEST-/.test(data)) {
           DEFAULT_PROCESS.stdout.write(data.replace(/[\s\n]+$/, "") + "\n");
         }
       });
     }
--- a/addon-sdk/source/gulpfile.js
+++ b/addon-sdk/source/gulpfile.js
@@ -23,22 +23,22 @@ gulp.task('test:examples', function(done
   require("./bin/jpm-test").run("examples").catch(console.error).then(done);
 });
 
 gulp.task('test:modules', function(done) {
   require("./bin/jpm-test").run("modules").catch(console.error).then(done);
 });
 
 gulp.task('test:ini', function(done) {
-  test("ini").catch(console.error).then(done);
+  require("./bin/jpm-test").run("ini").catch(console.error).then(done);
+});
+
+gulp.task('test:firefox-bin', function(done) {
+  require("./bin/jpm-test").run("firefox-bin").catch(console.error).then(done);
 });
 
 gulp.task('patch:clean', function(done) {
   patch.clean().catch(console.error).then(done);
 });
 
 gulp.task('patch:apply', function(done) {
   patch.apply().catch(console.error).then(done);
 });
-
-gulp.task('update:ini', function(done) {
-  ini.updateAddonINI().catch(console.error).then(done);
-});
--- a/addon-sdk/source/lib/sdk/console/plain-text.js
+++ b/addon-sdk/source/lib/sdk/console/plain-text.js
@@ -42,17 +42,17 @@ let branch = Cc["@mozilla.org/preference
              getService(Ci.nsIPrefService).
              getBranch(null);
 branch.addObserver(ADDON_LOG_LEVEL_PREF, logLevelObserver, true);
 branch.addObserver(SDK_LOG_LEVEL_PREF, logLevelObserver, true);
 
 function PlainTextConsole(print, innerID) {
 
   let consoleOptions = {
-    prefix: self.name + ": ",
+    prefix: self.name,
     maxLogLevel: logLevel,
     dump: print,
     innerID: innerID,
     consoleID: "addon/" + self.id
   };
   let console = new ConsoleAPI(consoleOptions);
 
   // As we freeze the console object, we can't modify this property afterward
--- a/addon-sdk/source/lib/sdk/console/traceback.js
+++ b/addon-sdk/source/lib/sdk/console/traceback.js
@@ -1,24 +1,21 @@
 /* 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"
 };
 
-const { Cc, Ci, components } = require("chrome");
+const { Ci, components } = require("chrome");
 const { parseStack, sourceURI } = require("toolkit/loader");
 const { readURISync } = require("../net/url");
 
-exports.sourceURI = sourceURI
-
 function safeGetFileLine(path, line) {
   try {
     var scheme = require("../url").URL(path).scheme;
     // TODO: There should be an easier, more accurate way to figure out
     // what's the case here.
     if (!(scheme == "http" || scheme == "https"))
       return readURISync(path).split("\n")[line - 1];
   } catch (e) {}
--- a/addon-sdk/source/lib/sdk/content/sandbox.js
+++ b/addon-sdk/source/lib/sdk/content/sandbox.js
@@ -5,28 +5,28 @@
 
 module.metadata = {
   'stability': 'unstable'
 };
 
 const { Class } = require('../core/heritage');
 const { EventTarget } = require('../event/target');
 const { on, off, emit } = require('../event/core');
+const { events } = require('./sandbox/events');
 const { requiresAddonGlobal } = require('./utils');
 const { delay: async } = require('../lang/functional');
 const { Ci, Cu, Cc } = require('chrome');
 const timer = require('../timers');
 const { URL } = require('../url');
 const { sandbox, evaluate, load } = require('../loader/sandbox');
 const { merge } = require('../util/object');
 const { getTabForContentWindow } = require('../tabs/utils');
 const { getInnerId } = require('../window/utils');
 const { PlainTextConsole } = require('../console/plain-text');
-const { data } = require('../self');
-const { isChildLoader } = require('../remote/core');
+const { data } = require('../self');const { isChildLoader } = require('../remote/core');
 // WeakMap of sandboxes so we can access private values
 const sandboxes = new WeakMap();
 
 /* Trick the linker in order to ensure shipping these files in the XPI.
   require('./content-worker.js');
   Then, retrieve URL of these files in the XPI:
 */
 let prefix = module.uri.split('sandbox.js')[0];
@@ -161,16 +161,17 @@ const WorkerSandbox = Class({
     let top = window.top === window ? content : content.top;
     let parent = window.parent === window ? content : content.parent;
     merge(content, {
       // We need 'this === window === top' to be true in toplevel scope:
       get window() content,
       get top() top,
       get parent() parent
     });
+
     // Use the Greasemonkey naming convention to provide access to the
     // unwrapped window object so the content script can access document
     // JavaScript values.
     // NOTE: this functionality is experimental and may change or go away
     // at any time!
     //
     // Note that because waivers aren't propagated between origins, we
     // need the unsafeWindow getter to live in the sandbox.
@@ -256,28 +257,34 @@ const WorkerSandbox = Class({
       };
 
       Object.defineProperties(con, properties);
       Cu.makeObjectPropsNormal(con);
 
       win.console = con;
     };
 
+    emit(events, "content-script-before-inserted", {
+      window: window,
+      worker: worker
+    });
+
     // The order of `contentScriptFile` and `contentScript` evaluation is
     // intentional, so programs can load libraries like jQuery from script URLs
     // and use them in scripts.
     let contentScriptFile = ('contentScriptFile' in worker)
           ? worker.contentScriptFile
           : null,
         contentScript = ('contentScript' in worker)
           ? worker.contentScript
           : null;
 
     if (contentScriptFile)
       importScripts.apply(null, [this].concat(contentScriptFile));
+
     if (contentScript) {
       evaluateIn(
         this,
         Array.isArray(contentScript) ? contentScript.join(';\n') : contentScript
       );
     }
   },
   destroy: function destroy(reason) {
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/lib/sdk/content/sandbox/events.js
@@ -0,0 +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";
+
+module.metadata = {
+  "stability": "experimental"
+};
+
+const events = {};
+exports.events = events;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/deprecated/memory.js
+++ /dev/null
@@ -1,129 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-"use strict";
-
-module.metadata = {
-  "stability": "deprecated"
-};
-
-const { Cc, Ci, Cu, components } = require("chrome");
-const { when: unload } = require("../system/unload")
-
-var trackedObjects = {};
-const Compacter = {
-  notify: function() {
-    var newTrackedObjects = {};
-
-    for (let name in trackedObjects) {
-      let oldBin = trackedObjects[name];
-      let newBin = [];
-      let strongRefs = [];
-
-      for (let i = 0, l = oldBin.length; i < l; i++) {
-        let strongRef = oldBin[i].weakref.get();
-
-        if (strongRef && strongRefs.indexOf(strongRef) == -1) {
-          strongRefs.push(strongRef);
-          newBin.push(oldBin[i]);
-        }
-      }
-
-      if (newBin.length)
-        newTrackedObjects[name] = newBin;
-    }
-
-    trackedObjects = newTrackedObjects;
-  }
-};
-
-var timer = Cc["@mozilla.org/timer;1"]
-            .createInstance(Ci.nsITimer);
-timer.initWithCallback(Compacter,
-                       5000,
-                       Ci.nsITimer.TYPE_REPEATING_SLACK);
-
-function track(object, bin, stackFrameNumber) {
-  var frame = components.stack.caller;
-  var weakref = Cu.getWeakReference(object);
-
-  if (!bin && 'constructor' in object)
-    bin = object.constructor.name;
-  if (bin == "Object")
-    bin = frame.name;
-  if (!bin)
-    bin = "generic";
-  if (!(bin in trackedObjects))
-    trackedObjects[bin] = [];
-
-  if (stackFrameNumber > 0)
-    for (var i = 0; i < stackFrameNumber; i++)
-      frame = frame.caller;
-
-  trackedObjects[bin].push({weakref: weakref,
-                            created: new Date(),
-                            filename: frame.filename,
-                            lineNo: frame.lineNumber,
-                            bin: bin});
-}
-exports.track = track;
-
-var getBins = exports.getBins = function getBins() {
-  var names = [];
-  for (let name in trackedObjects)
-    names.push(name);
-  return names;
-};
-
-function getObjects(bin) {
-  var results = [];
-
-  function getLiveObjectsInBin(bin) {
-    for (let i = 0, l = bin.length; i < l; i++) {
-      let object = bin[i].weakref.get();
-
-      if (object) {
-        results.push(bin[i]);
-      }
-    }
-  }
-
-  if (bin) {
-    if (bin in trackedObjects)
-      getLiveObjectsInBin(trackedObjects[bin]);
-  }
-  else {
-    for (let name in trackedObjects)
-      getLiveObjectsInBin(trackedObjects[name]);
-  }
-
-  return results;
-}
-exports.getObjects = getObjects;
-
-function gc() {
-  // Components.utils.forceGC() doesn't currently perform
-  // cycle collection, which means that e.g. DOM elements
-  // won't be collected by it. Fortunately, there are
-  // other ways...
-  var test_utils = Cc["@mozilla.org/appshell/appShellService;1"]
-               .getService(Ci.nsIAppShellService)
-               .hiddenDOMWindow
-               .QueryInterface(Ci.nsIInterfaceRequestor)
-               .getInterface(Ci.nsIDOMWindowUtils);
-  test_utils.garbageCollect();
-  // Clean metadata for dead objects
-  Compacter.notify();
-  // Not sure why, but sometimes it appears that we don't get
-  // them all with just one CC, so let's do it again.
-  test_utils.garbageCollect();
-};
-exports.gc = gc;
-
-unload(_ => {
-  trackedObjects = {};
-  if (timer) {
-    timer.cancel();
-    timer = null;
-  }
-});
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test-finder.js
@@ -3,17 +3,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 module.metadata = {
   "stability": "deprecated"
 };
 
 const file = require("../io/file");
-const memory = require('./memory');
 const { Loader } = require("../test/loader");
 
 const { isNative } = require('@loader/options');
 
 const cuddlefish = isNative ? require("toolkit/loader") : require("../loader/cuddlefish");
 
 const { defer, resolve } = require("../core/promise");
 const { getAddon } = require("../addon/installer");
@@ -127,17 +126,16 @@ const makeFilters = function makeFilters
   };
 }
 exports.makeFilters = makeFilters;
 
 let loader = Loader(module);
 const NOT_TESTS = ['setup', 'teardown'];
 
 var TestFinder = exports.TestFinder = function TestFinder(options) {
-  memory.track(this);
   this.filter = options.filter;
   this.testInProcess = options.testInProcess === false ? false : true;
   this.testOutOfProcess = options.testOutOfProcess === true ? true : false;
 };
 
 TestFinder.prototype = {
   findTests: function findTests() {
     let { fileFilter, testFilter } = makeFilters({ filter: this.filter });
--- a/addon-sdk/source/lib/sdk/deprecated/unit-test.js
+++ b/addon-sdk/source/lib/sdk/deprecated/unit-test.js
@@ -2,17 +2,16 @@
  * 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"
 };
 
-const memory = require("./memory");
 const timer = require("../timers");
 const cfxArgs = require("../test/options");
 const { getTabs, closeTab, getURI, getTabId, getSelectedTab } = require("../tabs/utils");
 const { windows, isBrowser, getMostRecentBrowserWindow } = require("../window/utils");
 const { defer, all, Debugging: PromiseDebugging, resolve } = require("../core/promise");
 const { getInnerId } = require("../window/utils");
 const { cleanUI } = require("../test/utils");
 
@@ -42,17 +41,16 @@ const TestRunner = function TestRunner(o
 
   // remember the id's for the open window and tab
   let window = getMostRecentBrowserWindow();
   runnerWindows.set(this, getInnerId(window));
   runnerTabs.set(this, getTabId(getSelectedTab(window)));
 
   this.fs = options.fs;
   this.console = options.console || console;
-  memory.track(this);
   this.passed = 0;
   this.failed = 0;
   this.testRunSummary = [];
   this.expectFailNesting = 0;
   this.done = TestRunner.prototype.done.bind(this);
 };
 
 TestRunner.prototype = {
@@ -278,50 +276,56 @@ TestRunner.prototype = {
   },
 
   done: function done() {
     if (this.isDone) {
       return resolve();
     }
 
     this.isDone = true;
+    this.pass("This test is done.");
+
     if (this.test.teardown) {
       this.test.teardown(this);
     }
+
     if (this.waitTimeout !== null) {
       timer.clearTimeout(this.waitTimeout);
       this.waitTimeout = null;
     }
+
     // Do not leave any callback set when calling to `waitUntil`
     this.waitUntilCallback = null;
     if (this.test.passed == 0 && this.test.failed == 0) {
       this._logTestFailed("empty test");
+
       if ("testMessage" in this.console) {
         this.console.testMessage(false, false, this.test.name, "Empty test");
       }
       else {
         this.console.error("fail:", "Empty test")
       }
+
       this.failed++;
       this.test.failed++;
     }
 
     let wins = windows(null, { includePrivate: true });
-    let winPromises = wins.map(win =>  {
-      let { promise, resolve } = defer();
-      if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) {
-        resolve()
-      }
-      else {
-        win.addEventListener("DOMContentLoaded", function onLoad() {
-          win.removeEventListener("DOMContentLoaded", onLoad, false);
-          resolve();
-        }, false);
-      }
-      return promise;
+    let winPromises = wins.map(win => {
+      return new Promise(resolve => {
+        if (["interactive", "complete"].indexOf(win.document.readyState) >= 0) {
+          resolve()
+        }
+        else {
+          win.addEventListener("DOMContentLoaded", function onLoad() {
+            win.removeEventListener("DOMContentLoaded", onLoad, false);
+            resolve();
+          }, false);
+        }
+      });
     });
 
     PromiseDebugging.flushUncaughtErrors();
     PromiseDebugging.removeUncaughtErrorObserver(this._uncaughtErrorObserver);
 
 
     return all(winPromises).then(() => {
       let browserWins = wins.filter(isBrowser);
@@ -353,19 +357,27 @@ TestRunner.prototype = {
             console.log(win.location + " - " + tabs.map(getURI).join(", "));
           }
           else {
             console.log(win.location);
           }
         }
       }
 
-      return null;
+      return failure;
     }).
-    then(cleanUI).
+    then(failure => {
+      if (!failure) {
+        this.pass("There was a clean UI.");
+        return null;
+      }
+      return cleanUI().then(() => {
+        this.pass("There is a clean UI.");
+      });
+    }).
     then(() => {
       this.testRunSummary.push({
         name: this.test.name,
         passed: this.test.passed,
         failed: this.test.failed,
         errors: [error for (error in this.test.errors)].join(", ")
       });
 
--- a/addon-sdk/source/lib/sdk/io/text-streams.js
+++ b/addon-sdk/source/lib/sdk/io/text-streams.js
@@ -1,46 +1,41 @@
 /* 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"
 };
 
-const {Cc,Ci,Cu,components} = require("chrome");
-var NetUtil = {};
-Cu.import("resource://gre/modules/NetUtil.jsm", NetUtil);
-NetUtil = NetUtil.NetUtil;
+const { Cc, Ci, Cu, components } = require("chrome");
+const { ensure } = require("../system/unload");
+const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 
 // NetUtil.asyncCopy() uses this buffer length, and since we call it, for best
 // performance we use it, too.
 const BUFFER_BYTE_LEN = 0x8000;
 const PR_UINT32_MAX = 0xffffffff;
 const DEFAULT_CHARSET = "UTF-8";
 
-exports.TextReader = TextReader;
-exports.TextWriter = TextWriter;
 
 /**
  * An input stream that reads text from a backing stream using a given text
  * encoding.
  *
  * @param inputStream
  *        The stream is backed by this nsIInputStream.  It must already be
  *        opened.
  * @param charset
  *        Text in inputStream is expected to be in this character encoding.  If
  *        not given, "UTF-8" is assumed.  See nsICharsetConverterManager.idl for
  *        documentation on how to determine other valid values for this.
  */
 function TextReader(inputStream, charset) {
-  const self = this;
   charset = checkCharset(charset);
 
   let stream = Cc["@mozilla.org/intl/converter-input-stream;1"].
                createInstance(Ci.nsIConverterInputStream);
   stream.init(inputStream, charset, BUFFER_BYTE_LEN,
               Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER);
 
   let manager = new StreamManager(this, stream);
@@ -84,31 +79,31 @@ function TextReader(inputStream, charset
       chunkRead = stream.readString(toRead, chunk);
       str += chunk.value;
       totalRead += chunkRead;
     }
 
     return str;
   };
 }
+exports.TextReader = TextReader;
 
 /**
  * A buffered output stream that writes text to a backing stream using a given
  * text encoding.
  *
  * @param outputStream
  *        The stream is backed by this nsIOutputStream.  It must already be
  *        opened.
  * @param charset
  *        Text will be written to outputStream using this character encoding.
  *        If not given, "UTF-8" is assumed.  See nsICharsetConverterManager.idl
  *        for documentation on how to determine other valid values for this.
  */
 function TextWriter(outputStream, charset) {
-  const self = this;
   charset = checkCharset(charset);
 
   let stream = outputStream;
 
   // Buffer outputStream if it's not already.
   let ioUtils = Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
   if (!ioUtils.outputStreamIsBuffered(outputStream)) {
     stream = Cc["@mozilla.org/network/buffered-output-stream;1"].
@@ -164,64 +159,62 @@ function TextWriter(outputStream, charse
    * @param callback
    *        An optional function.  If given, it's called as callback(error) when
    *        the write completes.  error is an Error object or undefined if there
    *        was no error.  Inside callback, |this| is the stream object.
    */
   this.writeAsync = function TextWriter_writeAsync(str, callback) {
     manager.ensureOpened();
     let istream = uconv.convertToInputStream(str);
-    NetUtil.asyncCopy(istream, stream, function (result) {
+    NetUtil.asyncCopy(istream, stream, (result) => {
         let err = components.isSuccessCode(result) ? undefined :
         new Error("An error occured while writing to the stream: " + result);
       if (err)
         console.error(err);
 
       // asyncCopy() closes its output (and input) stream.
       manager.opened = false;
 
       if (typeof(callback) === "function") {
         try {
-          callback.call(self, err);
+          callback.call(this, err);
         }
         catch (exc) {
           console.exception(exc);
         }
       }
     });
   };
 }
+exports.TextWriter = TextWriter;
 
 // This manages the lifetime of stream, a TextReader or TextWriter.  It defines
 // closed and close() on stream and registers an unload listener that closes
 // rawStream if it's still opened.  It also provides ensureOpened(), which
 // throws an exception if the stream is closed.
 function StreamManager(stream, rawStream) {
-  const self = this;
   this.rawStream = rawStream;
   this.opened = true;
 
   /**
    * True iff the stream is closed.
    */
-  stream.__defineGetter__("closed", function stream_closed() {
-    return !self.opened;
-  });
+  stream.__defineGetter__("closed", () => !this.opened);
 
   /**
    * Closes both the stream and its backing stream.  If the stream is already
    * closed, an exception is thrown.  For TextWriters, this first flushes the
    * backing stream's buffer.
    */
-  stream.close = function stream_close() {
-    self.ensureOpened();
-    self.unload();
+  stream.close = () => {
+    this.ensureOpened();
+    this.unload();
   };
 
-  require("../system/unload").ensure(this);
+  ensure(this);
 }
 
 StreamManager.prototype = {
   ensureOpened: function StreamManager_ensureOpened() {
     if (!this.opened)
       throw new Error("The stream is closed and cannot be used.");
   },
   unload: function StreamManager_unload() {
--- a/addon-sdk/source/lib/sdk/places/host/host-query.js
+++ b/addon-sdk/source/lib/sdk/places/host/host-query.js
@@ -1,24 +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";
 
 module.metadata = {
   "stability": "experimental",
   "engines": {
     "Firefox": "*",
     "SeaMonkey": "*"
   }
 };
 
 const { Cc, Ci } = require('chrome');
-const { defer, all, resolve } = require('../../core/promise');
+const { all } = require('../../core/promise');
 const { safeMerge, omit } = require('../../util/object');
 const historyService = Cc['@mozilla.org/browser/nav-history-service;1']
                      .getService(Ci.nsINavHistoryService);
 const bookmarksService = Cc['@mozilla.org/browser/nav-bookmarks-service;1']
                          .getService(Ci.nsINavBookmarksService);
 const { request, response } = require('../../addon/host');
 const { newURI } = require('../../url/utils');
 const { send } = require('../../addon/events');
@@ -40,23 +39,21 @@ const MANUAL_QUERY_PROPERTIES = [
   'uri', 'folder', 'tags', 'url', 'folder'
 ];
 
 const PLACES_PROPERTIES = [
   'uri', 'title', 'accessCount', 'time'
 ];
 
 function execute (queries, options) {
-  let deferred = defer();
-  let root = historyService
-    .executeQueries(queries, queries.length, options).root;
-
-  let items = collect([], root);
-  deferred.resolve(items);
-  return deferred.promise;
+  return new Promise(resolve => {
+    let root = historyService
+        .executeQueries(queries, queries.length, options).root;
+    resolve(collect([], root));
+  });
 }
 
 function collect (acc, node) {
   node.containerOpen = true;
   for (let i = 0; i < node.childCount; i++) {
     let child = node.getChild(i);
     acc.push(child);
     if (child.type === child.RESULT_TYPE_FOLDER) {
@@ -64,50 +61,45 @@ function collect (acc, node) {
       collect(acc, container);
     }
   }
   node.containerOpen = false;
   return acc;
 }
 
 function query (queries, options) {
-  queries = queries || [];
-  options = options || {}; 
-  let deferred = defer();
-  let optionsObj, queryObjs;
+  return new Promise((resolve, reject) => {
+    queries = queries || [];
+    options = options || {};
+    let optionsObj, queryObjs;
 
-  try {
     optionsObj = historyService.getNewQueryOptions();
     queryObjs = [].concat(queries).map(createQuery);
     if (!queryObjs.length) {
       queryObjs = [historyService.getNewQuery()];
     }
     safeMerge(optionsObj, options);
-  } catch (e) {
-    deferred.reject(e);
-    return deferred.promise;
-  }
 
-  /*
-   * Currently `places:` queries are not supported
-   */
-  optionsObj.excludeQueries = true;
+    /*
+     * Currently `places:` queries are not supported
+     */
+    optionsObj.excludeQueries = true;
 
-  execute(queryObjs, optionsObj).then(function (results) {
-    if (optionsObj.queryType === 0) {
-      return results.map(normalize);
-    } else if (optionsObj.queryType === 1) {
-      // Formats query results into more standard
-      // data structures for returning
-      return all(results.map(({itemId}) =>
-        send('sdk-places-bookmarks-get', { id: itemId })));
-    }
-  }).then(deferred.resolve, deferred.reject);
-  
-  return deferred.promise;
+    execute(queryObjs, optionsObj).then((results) => {
+      if (optionsObj.queryType === 0) {
+        return results.map(normalize);
+      }
+      else if (optionsObj.queryType === 1) {
+        // Formats query results into more standard
+        // data structures for returning
+        return all(results.map(({itemId}) =>
+          send('sdk-places-bookmarks-get', { id: itemId })));
+      }
+    }).then(resolve, reject);
+  });
 }
 exports.query = query;
 
 function createQuery (query) {
   query = query || {};
   let queryObj = historyService.getNewQuery();
 
   safeMerge(queryObj, omit(query, MANUAL_QUERY_PROPERTIES));
@@ -135,27 +127,28 @@ function queryReceiver (message) {
   }, reason => {
     resData.error = reason;
     respond(resData);
   });
 }
 
 /*
  * Converts a nsINavHistoryResultNode into a plain object
- * 
+ *
  * https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryResultNode
  */
 function normalize (historyObj) {
   return PLACES_PROPERTIES.reduce((obj, prop) => {
     if (prop === 'uri')
       obj.url = historyObj.uri;
     else if (prop === 'time') {
       // Cast from microseconds to milliseconds
       obj.time = Math.floor(historyObj.time / 1000)
-    } else if (prop === 'accessCount')
+    }
+    else if (prop === 'accessCount')
       obj.visitCount = historyObj[prop];
     else
       obj[prop] = historyObj[prop];
     return obj;
   }, {});
 }
 
 /*
--- a/addon-sdk/source/lib/sdk/places/utils.js
+++ b/addon-sdk/source/lib/sdk/places/utils.js
@@ -46,24 +46,24 @@ let TreeNode = Class({
   walk: method(walk),
   toString: function () '[object TreeNode]'
 });
 exports.TreeNode = TreeNode;
 
 /*
  * Descends down from `node` applying `fn` to each in order.
  * `fn` can return values or promises -- if promise returned,
- * children are not processed until resolved. `fn` is passed 
+ * children are not processed until resolved. `fn` is passed
  * one argument, the current node, `curr`.
  */
 function walk (curr, fn) {
   return promised(fn)(curr).then(val => {
     return all(curr.children.map(child => walk(child, fn)));
   });
-} 
+}
 
 /*
  * Descends from the TreeNode `node`, returning
  * the node with value `value` if found or `null`
  * otherwise
  */
 function get (node, value) {
   if (node.value === value) return node;
@@ -117,17 +117,17 @@ function isRootGroup (id) {
     bmsrv.unfiledBookmarksFolder
   ].indexOf(id);
 }
 exports.isRootGroup = isRootGroup;
 
 /*
  * Merges appropriate options into query based off of url
  * 4 scenarios:
- * 
+ *
  * 'moz.com' // domain: moz.com, domainIsHost: true
  *    --> 'http://moz.com', 'http://moz.com/thunderbird'
  * '*.moz.com' // domain: moz.com, domainIsHost: false
  *    --> 'http://moz.com', 'http://moz.com/index', 'http://ff.moz.com/test'
  * 'http://moz.com' // url: http://moz.com/, urlIsPrefix: false
  *    --> 'http://moz.com/'
  * 'http://moz.com/*' // url: http://moz.com/, urlIsPrefix: true
  *    --> 'http://moz.com/', 'http://moz.com/thunderbird'
@@ -172,34 +172,34 @@ exports.promisedEmitter = promisedEmitte
 
 
 // https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsINavHistoryQueryOptions
 function createQuery (type, query) {
   query = query || {};
   let qObj = {
     searchTerms: query.query
   };
-     
+
   urlQueryParser(qObj, query.url);
-  
+
   // 0 === history
   if (type === 0) {
     // PRTime used by query is in microseconds, not milliseconds
     qObj.beginTime = (query.from || 0) * 1000;
     qObj.endTime = (query.to || new Date()) * 1000;
 
     // Set reference time to Epoch
     qObj.beginTimeReference = 0;
     qObj.endTimeReference = 0;
   }
   // 1 === bookmarks
   else if (type === 1) {
     qObj.tags = query.tags;
     qObj.folder = query.group && query.group.id;
-  } 
+  }
   // 2 === unified (not implemented on platform)
   else if (type === 2) {
 
   }
 
   return qObj;
 }
 exports.createQuery = createQuery;
--- a/addon-sdk/source/lib/sdk/test/harness.js
+++ b/addon-sdk/source/lib/sdk/test/harness.js
@@ -10,17 +10,16 @@ module.metadata = {
 const { Cc, Ci, Cu } = require("chrome");
 const { Loader } = require('./loader');
 const { serializeStack, parseStack  } = require("toolkit/loader");
 const { setTimeout } = require('../timers');
 const { PlainTextConsole } = require("../console/plain-text");
 const { when: unload } = require("../system/unload");
 const { format, fromException }  = require("../console/traceback");
 const system = require("../system");
-const memory = require('../deprecated/memory');
 const { gc: gcPromise } = require('./memory');
 const { defer } = require('../core/promise');
 const { extend } = require('../core/heritage');
 
 // Trick manifest builder to make it think we need these modules ?
 const unit = require("../deprecated/unit-test");
 const test = require("../../test");
 const url = require("../url");
@@ -145,29 +144,24 @@ function dictDiff(last, curr) {
   return diff;
 }
 
 function reportMemoryUsage() {
   if (!profileMemory) {
     return emptyPromise();
   }
 
-  return gcPromise().then((function () {
+  return gcPromise().then((() => {
     var mgr = Cc["@mozilla.org/memory-reporter-manager;1"]
               .getService(Ci.nsIMemoryReporterManager);
     let count = 0;
     function logReporter(process, path, kind, units, amount, description) {
       print(((++count == 1) ? "\n" : "") + description + ": " + amount + "\n");
     }
     mgr.getReportsForThisProcess(logReporter, null, /* anonymize = */ false);
-
-    var weakrefs = [info.weakref.get()
-                    for (info of memory.getObjects())];
-    weakrefs = [weakref for (weakref of weakrefs) if (weakref)];
-    print("Tracked memory objects in testing sandbox: " + weakrefs.length + "\n");
   }));
 }
 
 var gWeakrefInfo;
 
 function checkMemory() {
   return gcPromise().then(_ => {
     let leaks = getPotentialLeaks();
@@ -211,26 +205,16 @@ function showResults() {
 
   resolve();
   return promise;
 }
 
 function cleanup() {
   let coverObject = {};
   try {
-    for (let name in loader.modules)
-      memory.track(loader.modules[name],
-                           "module global scope: " + name);
-      memory.track(loader, "Cuddlefish Loader");
-
-    if (profileMemory) {
-      gWeakrefInfo = [{ weakref: info.weakref, bin: info.bin }
-                      for (info of memory.getObjects())];
-    }
-
     loader.unload();
 
     if (loader.globals.console.errorsLogged && !results.failed) {
       results.failed++;
       console.error("warnings and/or errors were logged.");
     }
 
     if (consoleListener.errorsLogged && !results.failed) {
@@ -246,17 +230,17 @@ function cleanup() {
       coverObject = loader.globals.global['__$coverObject'] || {};
     }
 
     consoleListener.errorsLogged = 0;
     loader = null;
 
     consoleListener.unregister();
 
-    memory.gc();
+    Cu.forceGC();
   }
   catch (e) {
     results.failed++;
     console.error("unload.send() threw an exception.");
     console.exception(e);
   };
 
   setTimeout(require("./options").checkMemory ? checkMemory : showResults, 1);
@@ -273,17 +257,17 @@ function cleanup() {
     let outfh = file.open(out,'w');
     outfh.write(JSON.stringify(coverObject,null,2));
     outfh.flush();
     outfh.close();
   }
 }
 
 function getPotentialLeaks() {
-  memory.gc();
+  Cu.forceGC();
 
   // Things we can assume are part of the platform and so aren't leaks
   let GOOD_BASE_URLS = [
     "chrome://",
     "resource:///",
     "resource://app/",
     "resource://gre/",
     "resource://gre-resources/",
--- a/addon-sdk/source/lib/sdk/test/memory.js
+++ b/addon-sdk/source/lib/sdk/test/memory.js
@@ -1,20 +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 { Cu } = require("chrome");
-const memory = require('../deprecated/memory');
-const { defer } = require('../core/promise');
 
 function gc() {
-  let { promise, resolve } = defer();
-
-  Cu.forceGC();
-  memory.gc();
-
-  Cu.schedulePreciseGC(_ => resolve());
-
-  return promise;
+  return new Promise(resolve => Cu.schedulePreciseGC(resolve));
 }
 exports.gc = gc;
deleted file mode 100644
--- a/addon-sdk/source/lib/sdk/util/bond.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";
-
-module.metadata = {
-  "stability": "experimental"
-};
-
-const makeDescriptor = (name, method) => ({
-  get() {
-    if (!Object.hasOwnProperty.call(this, name)) {
-      Object.defineProperty(this, name, {value: method.bind(this)});
-      return this[name];
-    } else {
-      return method;
-    }
-  }
-});
-
-const Bond = function(methods) {
-  let descriptor = {};
-  let members = [...Object.getOwnPropertyNames(methods),
-                 ...Object.getOwnPropertySymbols(methods)];
-
-  for (let name of members) {
-    let method = methods[name];
-    if (typeof(method) !== "function") {
-      throw new TypeError(`Property named "${name}" passed to Bond must be a function`);
-    }
-    descriptor[name] = makeDescriptor(name, method);
-  }
-
-  return Object.create(Bond.prototype, descriptor);
-}
-exports.Bond = Bond;
--- a/addon-sdk/source/lib/sdk/zip/utils.js
+++ b/addon-sdk/source/lib/sdk/zip/utils.js
@@ -1,22 +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/. */
-'use strict';
+"use strict";
 
-const { Cc, Ci, Cu } = require("chrome");
-const { defer } = require("../core/promise");
+const { Cc, Ci } = require("chrome");
 
-const getZipReader = function getZipReader(aFile) {
-  let { promise, resolve, reject } = defer();
-  let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
-                      createInstance(Ci.nsIZipReader);
-  try {
+function getZipReader(aFile) {
+  return new Promise(resolve => {
+    let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].
+                        createInstance(Ci.nsIZipReader);
     zipReader.open(aFile);
-  }
-  catch(e){
-    reject(e);
-  }
-  resolve(zipReader);
-  return promise;
+    resolve(zipReader);
+  });
 };
 exports.getZipReader = getZipReader;
--- a/addon-sdk/source/mapping.json
+++ b/addon-sdk/source/mapping.json
@@ -8,17 +8,16 @@
   "functional": "sdk/core/functional",
   "l10n/core": "sdk/l10n/json/core",
   "l10n/html": "sdk/l10n/html",
   "l10n/loader": "sdk/l10n/loader",
   "l10n/locale": "sdk/l10n/locale",
   "l10n/prefs": "sdk/l10n/prefs",
   "list": "sdk/util/list",
   "loader": "sdk/loader/loader",
-  "memory": "sdk/deprecated/memory",
   "namespace": "sdk/core/namespace",
   "preferences-service": "sdk/preferences/service",
   "promise": "sdk/core/promise",
   "system": "sdk/system",
   "system/events": "sdk/system/events",
   "tabs/tab": "sdk/tabs/tab",
   "tabs/utils": "sdk/tabs/utils",
   "timer": "sdk/timers",
--- a/addon-sdk/source/package.json
+++ b/addon-sdk/source/package.json
@@ -17,16 +17,17 @@
   },
   "version": "0.1.18",
   "main": "./lib/index.js",
   "loader": "lib/sdk/loader/cuddlefish.js",
   "devDependencies": {
     "async": "0.9.0",
     "chai": "2.1.1",
     "fs-extra": "0.18.2",
+    "fx-runner": "0.0.7",
     "glob": "4.4.2",
     "gulp": "3.8.11",
     "ini-parser": "0.0.2",
     "jpm": "0.0.29",
     "lodash": "3.3.1",
     "mocha": "2.1.0",
     "patch-editor": "0.0.1",
     "promise": "6.1.0",
--- a/addon-sdk/source/python-lib/cuddlefish/__init__.py
+++ b/addon-sdk/source/python-lib/cuddlefish/__init__.py
@@ -231,20 +231,16 @@ parser_groups = (
                                        action="store_true",
                                        default=False,
                                        cmds=['test', 'testpkgs', 'testaddons',
                                              'testall'])),
         (("", "--output-file",), dict(dest="output_file",
                                       help="Where to put the finished .xpi",
                                       default=None,
                                       cmds=['xpi'])),
-        (("", "--manifest-overload",), dict(dest="manifest_overload",
-                                      help="JSON file to overload package.json properties",
-                                      default=None,
-                                      cmds=['xpi'])),
         (("", "--abort-on-missing-module",), dict(dest="abort_on_missing",
                                       help="Abort if required module is missing",
                                       action="store_true",
                                       default=False,
                                       cmds=['test', 'run', 'xpi', 'testpkgs'])),
         (("", "--no-connections",), dict(dest="no_connections",
                                       help="disable/enable remote connections (on for cfx run only by default)",
                                       type="choice",
@@ -656,20 +652,16 @@ def run(arguments=sys.argv[1:], target_c
         if not os.path.exists(os.path.join(options.pkgdir, 'package.json')):
             print >>sys.stderr, ("cannot find 'package.json' in"
                                  " %s." % options.pkgdir)
             sys.exit(1)
 
         target_cfg_json = os.path.join(options.pkgdir, 'package.json')
         target_cfg = packaging.get_config_in_dir(options.pkgdir)
 
-    if options.manifest_overload:
-        for k, v in packaging.load_json_file(options.manifest_overload).items():
-            target_cfg[k] = v
-
     # At this point, we're either building an XPI or running Jetpack code in
     # a Mozilla application (which includes running tests).
 
     use_main = False
     inherited_options = ['verbose', 'enable_e10s', 'parseable', 'check_memory',
                          'no_quit', 'abort_on_missing']
     enforce_timeouts = False
 
deleted file mode 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/main.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { Cc, Ci } = require("chrome");
-
-exports.main = function(options, callbacks) {
-  // Close Firefox window. Firefox should quit.
-  require("sdk/deprecated/window-utils").activeBrowserWindow.close();
-
-  // But not on Mac where it stay alive! We have to request application quit.
-  if (require("sdk/system/runtime").OS == "Darwin") {
-    let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'].
-                     getService(Ci.nsIAppStartup);
-    appStartup.quit(appStartup.eAttemptQuit);
-  }
-}
deleted file mode 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/manifest-overload.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  "version": "1.0-nightly"
-}
deleted file mode 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
-  "id": "simplest-test",
-  "directories": {
-    "lib": "."
-  }
-}
deleted file mode 100644
--- a/addon-sdk/source/python-lib/cuddlefish/tests/addons/simplest-test/tests/test-minimal.js
+++ /dev/null
@@ -1,7 +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/. */
-
-exports.minimalTest = function(test) {
-  test.assert(true);
-};
--- a/addon-sdk/source/python-lib/cuddlefish/tests/test_init.py
+++ b/addon-sdk/source/python-lib/cuddlefish/tests/test_init.py
@@ -177,45 +177,16 @@ class TestCfxQuits(unittest.TestCase):
     # implements our own
     def assertIn(self, member, container):
         """Just like self.assertTrue(a in b), but with a nicer default message."""
         if member not in container:
             standardMsg = '"%s" not found in "%s"' % (member,
                                                   container)
             self.fail(standardMsg)
 
-    def test_cfx_run(self):
-        addon_path = os.path.join(tests_path,
-                                  "addons", "simplest-test")
-        rc, out, err = self.run_cfx(addon_path, ["run"])
-        self.assertEqual(rc, 0)
-        self.assertIn("Program terminated successfully.", err)
-
-    def test_cfx_test(self):
-        addon_path = os.path.join(tests_path, "addons", "simplest-test")
-        rc, out, err = self.run_cfx(addon_path, ["test"])
-        self.assertEqual(rc, 0)
-        self.assertIn("1 of 1 tests passed.", err)
-        self.assertIn("Program terminated successfully.", err)
-
-    def test_cfx_xpi(self):
-        addon_path = os.path.join(tests_path,
-                                  "addons", "simplest-test")
-        rc, out, err = self.run_cfx(addon_path, \
-          ["xpi", "--manifest-overload", "manifest-overload.json"])
-        self.assertEqual(rc, 0)
-        # Ensure that the addon version from our manifest overload is used
-        # in install.rdf
-        xpi_path = os.path.join(addon_path, "simplest-test.xpi")
-        xpi = zipfile.ZipFile(xpi_path, "r")
-        manifest = xpi.read("install.rdf")
-        self.assertIn("<em:version>1.0-nightly</em:version>", manifest)
-        xpi.close()
-        os.remove(xpi_path)
-
     def test_cfx_init(self):
         # Create an empty test directory
         addon_path = os.path.abspath(os.path.join(".test_tmp", "test-cfx-init"))
         if os.path.isdir(addon_path):
             shutil.rmtree(addon_path)
         os.makedirs(addon_path)
 
         # Fake a call to cfx init
@@ -227,14 +198,14 @@ class TestCfxQuits(unittest.TestCase):
         out, err = out.getvalue(), err.getvalue()
         self.assertEqual(rc["result"], 0)
         self.assertTrue("Have fun!" in out)
         self.assertEqual(err,"")
 
         # run cfx test
         rc, out, err = self.run_cfx(addon_path, ["test"])
         self.assertEqual(rc, 0)
-        self.assertIn("2 of 2 tests passed.", err)
+        self.assertIn("6 of 6 tests passed.", err)
         self.assertIn("Program terminated successfully.", err)
 
 
 if __name__ == "__main__":
     unittest.main()
--- a/addon-sdk/source/test/addons/chrome/data/panel.js
+++ b/addon-sdk/source/test/addons/chrome/data/panel.js
@@ -1,8 +1,10 @@
 /* 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';
 
 self.port.on('echo', _ => {
   self.port.emit('echo', '');
 });
+
+self.port.emit('start', '');
--- a/addon-sdk/source/test/addons/chrome/main.js
+++ b/addon-sdk/source/test/addons/chrome/main.js
@@ -62,28 +62,36 @@ exports.testChromeLocale = function(asse
                'locales ja-JP folder was copied correctly');
 
   let enStringBundle = Services.strings.createBundle(enLocalePath);
   assert.equal(enStringBundle.GetStringFromName('test'),
                'Test',
                'locales en-US folder was copied correctly');
 }
 
-exports.testChromeInPanel = function(assert, done) {
+exports.testChromeInPanel = function*(assert) {
   let panel = Panel({
     contentURL: 'chrome://test/content/panel.html',
-    contentScriptWhen: 'start',
+    contentScriptWhen: 'end',
     contentScriptFile: data.url('panel.js')
   });
-  panel.once('show', _ => {
-    assert.pass('panel shown');
-    panel.port.once('echo', _ => {
-      assert.pass('got echo');
-      panel.destroy();
-      assert.pass('panel is destroyed');
-      done();
-    });
+
+  yield new Promise(resolve => panel.port.once('start', resolve));
+  assert.pass('start was emitted');
+
+  yield new Promise(resolve => {
+    panel.once('show', resolve);
+    panel.show();
+  });
+  assert.pass('panel shown');
+
+  yield new Promise(resolve => {
+    panel.port.once('echo', resolve);
     panel.port.emit('echo');
   });
-  panel.show();
+
+  assert.pass('got echo');
+
+  panel.destroy();
+  assert.pass('panel is destroyed');
 }
 
 require('sdk/test/runner').runTestsFromModule(module);
--- a/addon-sdk/source/test/addons/layout-change/lib/test-cuddlefish-loader.js
+++ b/addon-sdk/source/test/addons/layout-change/lib/test-cuddlefish-loader.js
@@ -142,19 +142,16 @@ exports["test compatibility"] = function
                require("sdk/tabs/utils"), "sdk/tabs/utils -> tabs/utils");
 
   assert.equal(require("dom/events"),
                require("sdk/dom/events"), "sdk/dom/events -> dom/events");
 
   assert.equal(require("tabs/tab.js"),
                require("sdk/tabs/tab"), "sdk/tabs/tab -> tabs/tab.js");
 
-  assert.equal(require("memory"),
-               require("sdk/deprecated/memory"), "sdk/deprecated/memory -> memory");
-
   assert.equal(require("environment"),
                require("sdk/system/environment"), "sdk/system/environment -> environment");
 
   if (app.is("Firefox")) {
     // This module fails on fennec because of favicon xpcom component
     // being not implemented on it.
     assert.equal(require("utils/data"),
                  require("sdk/io/data"), "sdk/io/data -> utils/data");
--- a/addon-sdk/source/test/addons/places/lib/places-helper.js
+++ b/addon-sdk/source/test/addons/places/lib/places-helper.js
@@ -28,23 +28,16 @@ const {
 
 function invalidResolve (assert) {
   return function (e) {
     assert.fail('Resolve state should not be called: ' + e);
   };
 }
 exports.invalidResolve = invalidResolve;
 
-function invalidReject (assert) {
-  return function (e) {
-    assert.fail('Reject state should not be called: ' + e);
-  };
-}
-exports.invalidReject = invalidReject;
-
 // Removes all children of group
 function clearBookmarks (group) {
   group
    ? bmsrv.removeFolderChildren(group.id)
    : clearAllBookmarks();
 }
 
 function clearAllBookmarks () {
--- a/addon-sdk/source/test/addons/places/lib/test-places-bookmarks.js
+++ b/addon-sdk/source/test/addons/places/lib/test-places-bookmarks.js
@@ -19,17 +19,17 @@ const { defer, all, resolve } = require(
 const { before, after } = require('sdk/test/utils');
 
 const {
   Bookmark, Group, Separator,
   save, search, remove,
   MENU, TOOLBAR, UNSORTED
 } = require('sdk/places/bookmarks');
 const {
-  invalidResolve, invalidReject, createTree,
+  invalidResolve, createTree,
   compareWithHost, createBookmark, createBookmarkItem,
   createBookmarkTree, addVisits, resetPlaces
 } = require('./places-helper');
 const { promisedEmitter } = require('sdk/places/utils');
 const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
                     getService(Ci.nsINavBookmarksService);
 const tagsrv = Cc['@mozilla.org/browser/tagging-service;1'].
                     getService(Ci.nsITaggingService);
@@ -364,38 +364,37 @@ exports.testPromisedSave = function (ass
     return saveP(first);
   }).then(() => {
     assert.equal(bmsrv.getItemIndex(first.id), 2, 'properly moved bookmark');
     assert.equal(bmsrv.getItemIndex(second.id), 0, 'other bookmarks adjusted');
     assert.equal(bmsrv.getItemIndex(third.id), 1, 'other bookmarks adjusted');
   }).then(done).catch(assert.fail);
 };
 
-exports.testPromisedErrorSave = function (assert, done) {
+exports.testPromisedErrorSave = function*(assert) {
   let bookmarks = [
     { title: 'moz1', url: 'http://moz1.com', type: 'bookmark'},
     { title: 'moz2', url: 'invalidurl', type: 'bookmark'},
     { title: 'moz3', url: 'http://moz3.com', type: 'bookmark'}
   ];
 
-  saveP(bookmarks).then(invalidResolve, reason => {
+  yield saveP(bookmarks).then(() => {
+    assert.fail("should not resolve");
+  }, reason => {
     assert.ok(
       /The `url` property must be a valid URL/.test(reason),
       'Error event called with correct reason');
+  });
 
-    bookmarks[1].url = 'http://moz2.com';
-    return saveP(bookmarks);
-  }).
-  then(res => searchP({ query: 'moz' })).
-  then(res => {
-    assert.equal(res.length, 3, 'all 3 should be saved upon retry');
-    res.map(item => assert.ok(/moz\d\.com/.test(item.url), 'correct item'));
-    done();
-  }, invalidReject).
-  catch(assert.fail);
+  bookmarks[1].url = 'http://moz2.com';
+  yield saveP(bookmarks);
+
+  let res = yield searchP({ query: 'moz' });
+  assert.equal(res.length, 3, 'all 3 should be saved upon retry');
+  res.map(item => assert.ok(/moz\d\.com/.test(item.url), 'correct item'));
 };
 
 exports.testMovingChildren = function (assert, done) {
   let topFolder = Group({ title: 'top', group: MENU });
   let midFolder = Group({ title: 'middle', group: topFolder });
   let bookmarks = [
     Bookmark({ title: 'moz1', url: 'http://moz1.com', group: midFolder}),
     Bookmark({ title: 'moz2', url: 'http://moz2.com', group: midFolder}),
@@ -687,71 +686,73 @@ exports.testSearchTags = function (asser
 
 /*
  * Tests 4 scenarios
  * '*.mozilla.com'
  * 'mozilla.com'
  * 'http://mozilla.com/'
  * 'http://mozilla.com/*'
  */
-exports.testSearchURL = function (assert, done) {
-  createBookmarkTree().then(() => {
-    return searchP({ url: 'mozilla.org' });
-  }).then(data => {
-    assert.equal(data.length, 2, 'only URLs with host domain');
-    assert.equal(data[0].url, 'http://mozilla.org/');
-    assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
-    return searchP({ url: '*.mozilla.org' });
-  }).then(data => {
-    assert.equal(data.length, 3, 'returns domain and when host is other than domain');
-    assert.equal(data[0].url, 'http://mozilla.org/');
-    assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
-    assert.equal(data[2].url, 'http://developer.mozilla.org/en-US/');
-    return searchP({ url: 'http://mozilla.org' });
-  }).then(data => {
-    assert.equal(data.length, 1, 'only exact URL match');
-    assert.equal(data[0].url, 'http://mozilla.org/');
-    return searchP({ url: 'http://mozilla.org/*' });
-  }).then(data => {
-    assert.equal(data.length, 2, 'only URLs that begin with query');
-    assert.equal(data[0].url, 'http://mozilla.org/');
-    assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
-    return searchP([{ url: 'mozilla.org' }, { url: 'component.fm' }]);
-  }).then(data => {
-    assert.equal(data.length, 3, 'returns URLs that match EITHER query');
-    assert.equal(data[0].url, 'http://mozilla.org/');
-    assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
-    assert.equal(data[2].url, 'http://component.fm/');
-  }).then(done).catch(assert.fail);
+exports.testSearchURLForBookmarks = function*(assert) {
+  yield createBookmarkTree()
+  let data = yield searchP({ url: 'mozilla.org' });
+
+  assert.equal(data.length, 2, 'only URLs with host domain');
+  assert.equal(data[0].url, 'http://mozilla.org/');
+  assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
+
+  data = yield searchP({ url: '*.mozilla.org' });
+
+  assert.equal(data.length, 3, 'returns domain and when host is other than domain');
+  assert.equal(data[0].url, 'http://mozilla.org/');
+  assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
+  assert.equal(data[2].url, 'http://developer.mozilla.org/en-US/');
+
+  data = yield searchP({ url: 'http://mozilla.org' });
+
+  assert.equal(data.length, 1, 'only exact URL match');
+  assert.equal(data[0].url, 'http://mozilla.org/');
+
+  data = yield searchP({ url: 'http://mozilla.org/*' });
+
+  assert.equal(data.length, 2, 'only URLs that begin with query');
+  assert.equal(data[0].url, 'http://mozilla.org/');
+  assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
+
+  data = yield searchP([{ url: 'mozilla.org' }, { url: 'component.fm' }]);
+
+  assert.equal(data.length, 3, 'returns URLs that match EITHER query');
+  assert.equal(data[0].url, 'http://mozilla.org/');
+  assert.equal(data[1].url, 'http://mozilla.org/thunderbird/');
+  assert.equal(data[2].url, 'http://component.fm/');
 };
 
 /*
  * Searches url, title, tags
  */
-exports.testSearchQuery = function (assert, done) {
-  createBookmarkTree().then(() => {
-    return searchP({ query: 'thunder' });
-  }).then(data => {
-    assert.equal(data.length, 3);
-    assert.equal(data[0].title, 'mozilla.com', 'query matches tag, url, or title');
-    assert.equal(data[1].title, 'mozilla.org', 'query matches tag, url, or title');
-    assert.equal(data[2].title, 'thunderbird', 'query matches tag, url, or title');
-    return searchP([{ query: 'rust' }, { query: 'component' }]);
-  }).then(data => {
-    // rust OR component
-    assert.equal(data.length, 3);
-    assert.equal(data[0].title, 'mozilla.com', 'query matches tag, url, or title');
-    assert.equal(data[1].title, 'mozilla.org', 'query matches tag, url, or title');
-    assert.equal(data[2].title, 'web audio components', 'query matches tag, url, or title');
-    return searchP([{ query: 'moz', tags: ['javascript']}]);
-  }).then(data => {
-    assert.equal(data.length, 1);
-    assert.equal(data[0].title, 'mdn',
-      'only one item matches moz query AND has a javascript tag');
-  }).then(done).catch(assert.fail);
+exports.testSearchQueryForBookmarks = function*(assert) {
+  yield createBookmarkTree();
+
+  let data = yield searchP({ query: 'thunder' });
+  assert.equal(data.length, 3);
+  assert.equal(data[0].title, 'mozilla.com', 'query matches tag, url, or title');
+  assert.equal(data[1].title, 'mozilla.org', 'query matches tag, url, or title');
+  assert.equal(data[2].title, 'thunderbird', 'query matches tag, url, or title');
+
+  data = yield searchP([{ query: 'rust' }, { query: 'component' }]);
+  // rust OR component
+  assert.equal(data.length, 3);
+  assert.equal(data[0].title, 'mozilla.com', 'query matches tag, url, or title');
+  assert.equal(data[1].title, 'mozilla.org', 'query matches tag, url, or title');
+  assert.equal(data[2].title, 'web audio components', 'query matches tag, url, or title');
+
+  data = yield searchP([{ query: 'moz', tags: ['javascript']}]);
+  assert.equal(data.length, 1);
+  assert.equal(data[0].title, 'mdn',
+    'only one item matches moz query AND has a javascript tag');
 };
 
 /*
  * Test caching on bulk calls.
  * Each construction of a bookmark item snapshot results in
  * the recursive lookup of parent groups up to the root groups --
  * ensure that the appropriate instances equal each other, and no duplicate
  * fetches are called
@@ -822,17 +823,17 @@ exports.testSearchCount = function (asse
         if (n > max) n = max;
         assert.equal(results.length, n,
           'count ' + n + ' returns ' + n + ' results');
       });
     };
   }
 };
 
-exports.testSearchSort = function (assert, done) {
+exports.testSearchSortForBookmarks = 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,'')}))
--- a/addon-sdk/source/test/addons/places/lib/test-places-events.js
+++ b/addon-sdk/source/test/addons/places/lib/test-places-events.js
@@ -22,17 +22,17 @@ const { release, platform } = require('n
 
 const isOSX10_6 = (() => {
   let vString = release();
   return vString && /darwin/.test(platform()) && /10\.6/.test(vString);
 })();
 
 const { search } = require('sdk/places/history');
 const {
-  invalidResolve, invalidReject, createTree, createBookmark,
+  invalidResolve, createTree, createBookmark,
   compareWithHost, addVisits, resetPlaces, createBookmarkItem,
   removeVisits, historyBatch
 } = require('./places-helper');
 const { save, MENU, UNSORTED } = require('sdk/places/bookmarks');
 const { promisedEmitter } = require('sdk/places/utils');
 
 exports['test bookmark-item-added'] = function (assert, done) {
   events.on('data', function handler ({type, data}) {
--- a/addon-sdk/source/test/addons/places/lib/test-places-history.js
+++ b/addon-sdk/source/test/addons/places/lib/test-places-history.js
@@ -14,82 +14,80 @@ const { defer, all } = require('sdk/core
 const { has } = require('sdk/util/array');
 const { setTimeout } = require('sdk/timers');
 const { before, after } = require('sdk/test/utils');
 const { set } = require('sdk/preferences/service');
 const {
   search
 } = require('sdk/places/history');
 const {
-  invalidResolve, invalidReject, createTree,
+  invalidResolve, createTree,
   compareWithHost, addVisits, resetPlaces
 } = require('./places-helper');
 const { promisedEmitter } = require('sdk/places/utils');
 
-exports.testEmptyQuery = function (assert, done) {
+exports.testEmptyQuery = function*(assert) {
   let within = toBeWithin();
-  addVisits([
+  yield addVisits([
     'http://simplequery-1.com', 'http://simplequery-2.com'
-  ]).then(searchP).then(results => {
-    assert.equal(results.length, 2, 'Correct number of entries returned');
-    assert.equal(results[0].url, 'http://simplequery-1.com/',
-      'matches url');
-    assert.equal(results[1].url, 'http://simplequery-2.com/',
-      'matches url');
-    assert.equal(results[0].title, 'Test visit for ' + results[0].url,
-      'title matches');
-    assert.equal(results[1].title, 'Test visit for ' + results[1].url,
-      'title matches');
-    assert.equal(results[0].visitCount, 1, 'matches access');
-    assert.equal(results[1].visitCount, 1, 'matches access');
-    assert.ok(within(results[0].time), 'accurate access time');
-    assert.ok(within(results[1].time), 'accurate access time');
-    assert.equal(Object.keys(results[0]).length, 4,
-      'no addition exposed properties on history result');
-    done();
-  }, invalidReject);
+  ]);
+
+  let results = yield searchP();
+  assert.equal(results.length, 2, 'Correct number of entries returned');
+  assert.equal(results[0].url, 'http://simplequery-1.com/',
+    'matches url');
+  assert.equal(results[1].url, 'http://simplequery-2.com/',
+    'matches url');
+  assert.equal(results[0].title, 'Test visit for ' + results[0].url,
+    'title matches');
+  assert.equal(results[1].title, 'Test visit for ' + results[1].url,
+    'title matches');
+  assert.equal(results[0].visitCount, 1, 'matches access');
+  assert.equal(results[1].visitCount, 1, 'matches access');
+  assert.ok(within(results[0].time), 'accurate access time');
+  assert.ok(within(results[1].time), 'accurate access time');
+  assert.equal(Object.keys(results[0]).length, 4,
+    'no addition exposed properties on history result');
 };
 
-exports.testVisitCount = function (assert, done) {
-  addVisits([
+exports.testVisitCount = function*(assert) {
+  yield addVisits([
     'http://simplequery-1.com', 'http://simplequery-1.com',
     'http://simplequery-1.com', 'http://simplequery-1.com'
-  ]).then(searchP).then(results => {
-    assert.equal(results.length, 1, 'Correct number of entries returned');
-    assert.equal(results[0].url, 'http://simplequery-1.com/', 'correct url');
-    assert.equal(results[0].visitCount, 4, 'matches access count');
-    done();
-  }, invalidReject);
+  ]);
+  let results = yield searchP();
+  assert.equal(results.length, 1, 'Correct number of entries returned');
+  assert.equal(results[0].url, 'http://simplequery-1.com/', 'correct url');
+  assert.equal(results[0].visitCount, 4, 'matches access count');
 };
 
 /*
  * Tests 4 scenarios
  * '*.mozilla.org'
  * 'mozilla.org'
  * 'http://mozilla.org/'
  * 'http://mozilla.org/*'
  */
-exports.testSearchURL = function (assert, done) {
-  addVisits([
+exports.testSearchURLForHistory = function*(assert) {
+  yield addVisits([
     'http://developer.mozilla.org', 'http://mozilla.org',
     'http://mozilla.org/index', 'https://mozilla.org'
-  ]).then(() => searchP({ url: '*.mozilla.org' }))
-  .then(results => {
-    assert.equal(results.length, 4, 'returns all entries');
-    return searchP({ url: 'mozilla.org' });
-  }).then(results => {
-    assert.equal(results.length, 3, 'returns entries where mozilla.org is host');
-    return searchP({ url: 'http://mozilla.org/' });
-  }).then(results => {
-    assert.equal(results.length, 1, 'should just be an exact match');
-    return searchP({ url: 'http://mozilla.org/*' });
-  }).then(results => {
-    assert.equal(results.length, 2, 'should match anything starting with substring');
-    done();
-  });
+  ]);
+
+  let results = yield searchP({ url: 'http://mozilla.org/' });
+  assert.equal(results.length, 1, 'should just be an exact match');
+
+  results = yield searchP({ url: '*.mozilla.org' });
+  assert.equal(results.length, 4, 'returns all entries');
+
+  results = yield searchP({ url: 'mozilla.org' });
+  assert.equal(results.length, 3, 'returns entries where mozilla.org is host');
+
+  results = yield searchP({ url: 'http://mozilla.org/*' });
+  assert.equal(results.length, 2, 'should match anything starting with substring');
 };
 
 // Disabling due to intermittent Bug 892619
 // TODO solve this
 /*
 exports.testSearchTimeRange = function (assert, done) {
   let firstTime, secondTime;
   addVisits([
@@ -119,33 +117,31 @@ exports.testSearchTimeRange = function (
     assert.equal(results.length, 2, 'should return only last entries');
     results.map(item => {
       assert.ok(/newvisit/.test(item.url), 'correct entry');
     });
     done();
   });
 };
 */
-exports.testSearchQuery = function (assert, done) {
-  addVisits([
+exports.testSearchQueryForHistory = function*(assert) {
+  yield addVisits([
     'http://mozilla.com', 'http://webaud.io', 'http://mozilla.com/webfwd'
-  ]).then(() => {
-    return searchP({ query: 'moz' });
-  }).then(results => {
-    assert.equal(results.length, 2, 'should return urls that match substring');
-    results.map(({url}) => {
-      assert.ok(/moz/.test(url), 'correct item');
-    });
-    return searchP([{ query: 'webfwd' }, { query: 'aud.io' }]);
-  }).then(results => {
-    assert.equal(results.length, 2, 'should OR separate queries');
-    results.map(({url}) => {
-      assert.ok(/webfwd|aud\.io/.test(url), 'correct item');
-    });
-    done();
+  ]);
+
+  let results = yield searchP({ query: 'moz' });
+  assert.equal(results.length, 2, 'should return urls that match substring');
+  results.map(({url}) => {
+    assert.ok(/moz/.test(url), 'correct item');
+  });
+
+  results = yield searchP([{ query: 'webfwd' }, { query: 'aud.io' }]);
+  assert.equal(results.length, 2, 'should OR separate queries');
+  results.map(({url}) => {
+    assert.ok(/webfwd|aud\.io/.test(url), 'correct item');
   });
 };
 
 /*
  * Query Options
  */
 
 exports.testSearchCount = function (assert, done) {
@@ -163,61 +159,60 @@ exports.testSearchCount = function (asse
       return searchP({}, { count: n }).then(results => {
         assert.equal(results.length, n,
           'count ' + n + ' returns ' + n + ' results');
       });
     };
   }
 };
 
-exports.testSearchSort = function (assert, done) {
-  let places = [
-    'http://mozilla.com/', 'http://webaud.io/', 'http://mozilla.com/webfwd/',
-    'http://developer.mozilla.com/', 'http://bandcamp.com/'
-  ];
-  addVisits(places).then(() => {
-    return searchP({}, { sort: 'title' });
-  }).then(results => {
-    checkOrder(results, [4,3,0,2,1]);
-    return searchP({}, { sort: 'title', descending: true });
-  }).then(results => {
-    checkOrder(results, [1,2,0,3,4]);
-    return searchP({}, { sort: 'url' });
-  }).then(results => {
-    checkOrder(results, [4,3,0,2,1]);
-    return searchP({}, { sort: 'url', descending: true });
-  }).then(results => {
-    checkOrder(results, [1,2,0,3,4]);
-    return addVisits('http://mozilla.com') // for visit conut
-      .then(() => addVisits('http://github.com')); // for checking date
-  }).then(() => {
-    return 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');
-    return searchP({}, { sort: 'date' });
-  }).then(results => {
-    assert.equal(results[5].url, 'http://github.com/',
-      'latest visited should be first');
-    return searchP({}, { sort: 'date', descending: true });
-  }).then(results => {
-    assert.equal(results[0].url, 'http://github.com/',
-      'latest visited should be at the end');
-  }).then(done);
-
+exports.testSearchSortForHistory = function*(assert) {
   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, places[nums[i]], 'successful order');
     }
   }
+
+  let places = [
+    'http://mozilla.com/', 'http://webaud.io/', 'http://mozilla.com/webfwd/',
+    'http://developer.mozilla.com/', 'http://bandcamp.com/'
+  ];
+  yield addVisits(places);
+
+  let results = yield searchP({}, { sort: 'title' });
+  checkOrder(results, [4,3,0,2,1]);
+
+  results = yield searchP({}, { sort: 'title', descending: true });
+  checkOrder(results, [1,2,0,3,4]);
+
+  results = yield searchP({}, { sort: 'url' });
+  checkOrder(results, [4,3,0,2,1]);
+
+  results = yield searchP({}, { sort: 'url', descending: true });
+  checkOrder(results, [1,2,0,3,4]);
+
+  yield addVisits('http://mozilla.com'); // for visit conut
+  yield addVisits('http://github.com'); // for checking date
+
+  results = yield searchP({}, { sort: 'visitCount' });
+  assert.equal(results[5].url, 'http://mozilla.com/',
+    'last entry is the highest visit count');
+
+  results = yield  searchP({}, { sort: 'visitCount', descending: true });
+  assert.equal(results[0].url, 'http://mozilla.com/',
+    'first entry is the highest visit count');
+
+  results = yield  searchP({}, { sort: 'date' });
+  assert.equal(results[5].url, 'http://github.com/',
+    'latest visited should be first');
+
+  results = yield  searchP({}, { sort: 'date', descending: true });
+  assert.equal(results[0].url, 'http://github.com/',
+    'latest visited should be at the end');
 };
 
 exports.testEmitters = function (assert, done) {
   let urls = [
     'http://mozilla.com/', 'http://webaud.io/', 'http://mozilla.com/webfwd/',
     'http://developer.mozilla.com/', 'http://bandcamp.com/'
   ];
   addVisits(urls).then(() => {
--- a/addon-sdk/source/test/addons/places/lib/test-places-host.js
+++ b/addon-sdk/source/test/addons/places/lib/test-places-host.js
@@ -16,49 +16,47 @@ const { newURI } = require('sdk/url/util
 const { send } = require('sdk/addon/events');
 const { set } = require('sdk/preferences/service');
 const { before, after } = require('sdk/test/utils');
 
 require('sdk/places/host/host-bookmarks');
 require('sdk/places/host/host-tags');
 require('sdk/places/host/host-query');
 const {
-  invalidResolve, invalidReject, createTree,
+  invalidResolve, createTree,
   compareWithHost, createBookmark, createBookmarkTree, resetPlaces
 } = require('./places-helper');
 
 const bmsrv = Cc['@mozilla.org/browser/nav-bookmarks-service;1'].
                     getService(Ci.nsINavBookmarksService);
 const hsrv = Cc['@mozilla.org/browser/nav-history-service;1'].
               getService(Ci.nsINavHistoryService);
 const tagsrv = Cc['@mozilla.org/browser/tagging-service;1'].
               getService(Ci.nsITaggingService);
 
-exports.testBookmarksCreate = function (assert, done) {
+exports.testBookmarksCreate = function*(assert) {
   let items = [{
     title: 'my title',
     url: 'http://test-places-host.com/testBookmarksCreate/',
     tags: ['some', 'tags', 'yeah'],
     type: 'bookmark'
   }, {
     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) {
+  yield all(items.map((item) => {
+    return send('sdk-places-bookmarks-create', item).then((data) => {
       compareWithHost(assert, data);
-    }, invalidReject(assert));
-  })).then(function () {
-    done();
-  }, invalidReject(assert));
+    });
+  }));
 };
 
 exports.testBookmarksCreateFail = function (assert, done) {
   let items = [{
     title: 'my title',
     url: 'not-a-url',
     type: 'bookmark'
   }, {
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/addons/require/list.js
@@ -0,0 +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/. */
+"use strict";
+
+exports.local = true;
--- a/addon-sdk/source/test/addons/require/main.js
+++ b/addon-sdk/source/test/addons/require/main.js
@@ -1,20 +1,20 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 var { isNative } = require("@loader/options");
 
 exports["test local vs sdk module"] = function (assert) {
-  assert.notEqual(require("memory"),
-                  require("sdk/deprecated/memory"),
+  assert.notEqual(require("list"),
+                  require("sdk/util/list"),
                   "Local module takes the priority over sdk modules");
-  assert.ok(require("memory").local,
+  assert.ok(require("list").local,
             "this module is really the local one");
 }
 
 if (!isNative) {
   exports["test 3rd party vs sdk module"] = function (assert) {
     // We are testing with a 3rd party package called `tabs` with 3 modules
     // main, page-mod and third-party
 
deleted file mode 100644
--- a/addon-sdk/source/test/addons/require/memory.js
+++ /dev/null
@@ -1,5 +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/. */
-
-exports.local = true;
--- a/addon-sdk/source/test/fixtures/index.html
+++ b/addon-sdk/source/test/fixtures/index.html
@@ -4,10 +4,15 @@
 
 <html>
   <head>
     <meta charset="UTF-8">
     <title>Add-on Page</title>
   </head>
   <body>
     <p>This is an add-on page test!</p>
+    <script>
+    function getTestURL() {
+      return window.document.documentURI + "";
+    }
+    </script>
   </body>
 </html>
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/fixtures/test-addon-extras-window.html
@@ -0,0 +1,21 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Worker test</title>
+</head>
+<body>
+  <p id="paragraph">Lorem ipsum dolor sit amet.</p>
+  <script>
+    if ("addon" in window) {
+      var count = 1;
+      addon.port.on("get-result", () => {
+        addon.port.emit("result" + count++, extras.test().getTestURL())
+      });
+    }
+  </script>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/fixtures/test-addon-extras.html
@@ -0,0 +1,31 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<html>
+<head>
+    <meta charset="UTF-8">
+    <title>Worker test</title>
+</head>
+<body>
+  <p id="paragraph">Lorem ipsum dolor sit amet.</p>
+  <script>
+    if ("addon" in window) {
+      var count = 1;
+      addon.port.on("get-result", () => {
+        console.log("get-result recieved");
+        addon.port.emit("result" + count++, extras && extras.test())
+      });
+    }
+
+    window.addEventListener("message", function getMessage({ data }) {
+      if (data.name == "start") {
+        window.postMessage({
+          name: "extras",
+          result: window.extras === undefined
+        }, '*');
+      }
+    }, false);
+  </script>
+</body>
+</html>
--- a/addon-sdk/source/test/fixtures/test.html
+++ b/addon-sdk/source/test/fixtures/test.html
@@ -4,10 +4,15 @@
 
 <html>
   <head>
     <meta charset="UTF-8">
     <title>foo</title>
   </head>
   <body>
     <p>bar</p>
+    <script>
+    function getTestURL() {
+      return window.document.documentURI + "";
+    }
+    </script>
   </body>
 </html>
--- a/addon-sdk/source/test/jetpack-package.ini
+++ b/addon-sdk/source/test/jetpack-package.ini
@@ -1,44 +1,44 @@
 [DEFAULT]
 support-files =
   buffers/**
   commonjs-test-adapter/**
   context-menu/**
   event/**
+  fixtures.js
   fixtures/**
   framescript-manager/**
   framescript-util/**
+  lib/**
   loader/**
-  lib/**
   modules/**
+  pagemod-test-helpers.js
   path/**
   private-browsing/**
   querystring/**
   sidebar/**
   tabs/**
+  test-context-menu.html
   traits/**
+  util.js
   windows/**
   zip/**
-  fixtures.js
-  pagemod-test-helpers.js
-  test-context-menu.html
-  util.js
 
 [test-addon-bootstrap.js]
+[test-addon-extras.js]
 [test-addon-installer.js]
 [test-addon-window.js]
 [test-api-utils.js]
 [test-array.js]
 [test-base64.js]
 [test-bootstrap.js]
 [test-browser-events.js]
 [test-buffer.js]
 [test-byte-streams.js]
-[test-bond.js]
 [test-child_process.js]
 [test-chrome.js]
 [test-clipboard.js]
 [test-collection.js]
 [test-commonjs-test-adapter.js]
 [test-content-events.js]
 [test-content-script.js]
 [test-content-sync-worker.js]
@@ -67,29 +67,30 @@ skip-if = true
 [test-functional.js]
 [test-globals.js]
 [test-heritage.js]
 [test-hidden-frame.js]
 [test-host-events.js]
 [test-hotkeys.js]
 [test-httpd.js]
 [test-indexed-db.js]
+[test-jetpack-id.js]
 [test-keyboard-observer.js]
 [test-keyboard-utils.js]
-[test-lang-type.js]
 [test-l10n-locale.js]
 [test-l10n-plural-rules.js]
+[test-lang-type.js]
 [test-libxul.js]
 [test-list.js]
 [test-loader.js]
 [test-match-pattern.js]
-[test-memory.js]
 [test-method.js]
 [test-module.js]
 [test-modules.js]
+[test-mozilla-toolkit-versioning.js]
 [test-mpl2-license-header.js]
 skip-if = true
 [test-namespace.js]
 [test-native-loader.js]
 [test-native-options.js]
 [test-net-url.js]
 [test-node-os.js]
 [test-notifications.js]
@@ -111,16 +112,17 @@ skip-if = true
 [test-request.js]
 [test-require.js]
 [test-rules.js]
 [test-sandbox.js]
 [test-selection.js]
 [test-self.js]
 [test-sequence.js]
 [test-set-exports.js]
+[test-shared-require.js]
 [test-simple-prefs.js]
 [test-simple-storage.js]
 [test-system-events.js]
 [test-system-input-output.js]
 [test-system-runtime.js]
 [test-system-startup.js]
 [test-system.js]
 [test-tab-events.js]
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/loader/user-global.js
@@ -0,0 +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";
+
+// Test module to check presense of user defined globals.
+// Related to bug 827792.
+
+exports.getCom = function() {
+  return com;
+};
--- a/addon-sdk/source/test/private-browsing/windows.js
+++ b/addon-sdk/source/test/private-browsing/windows.js
@@ -6,16 +6,17 @@
 const { onFocus, openDialog, open } = require('sdk/window/utils');
 const { open: openPromise, close, focus, promise } = require('sdk/window/helpers');
 const { isPrivate } = require('sdk/private-browsing');
 const { getMode } = require('sdk/private-browsing/utils');
 const { browserWindows: windows } = require('sdk/windows');
 const { defer } = require('sdk/core/promise');
 const tabs = require('sdk/tabs');
 const { getMostRecentBrowserWindow } = require('sdk/window/utils');
+const { cleanUI } = require("sdk/test/utils");
 
 // test openDialog() from window/utils with private option
 // test isActive state in pwpb case
 // test isPrivate on ChromeWindow
 exports.testPerWindowPrivateBrowsingGetter = function*(assert) {
   let win = openDialog({ private: true });
 
   yield promise(win, 'DOMContentLoaded');
@@ -37,25 +38,28 @@ exports.testPerWindowPrivateBrowsingGett
   });
 
   yield promise(win, 'DOMContentLoaded');
   assert.equal(getMode(win), true, 'Newly opened window is in PB mode');
   assert.ok(isPrivate(win), 'isPrivate(window) is true');
   yield close(win)
 }
 
-exports.testIsPrivateOnWindowOpen = function(assert, done) {
-  windows.open({
-    isPrivate: true,
-    onOpen: function(window) {
-      assert.equal(isPrivate(window), false, 'isPrivate for a window is true when it should be');
-      assert.equal(isPrivate(window.tabs[0]), false, 'isPrivate for a tab is false when it should be');
-      window.close(done);
-    }
+exports.testIsPrivateOnWindowOpen = function*(assert) {
+  let window = yield new Promise(resolve => {
+    windows.open({
+      isPrivate: true,
+      onOpen: resolve
+    });
   });
+
+  assert.equal(isPrivate(window), false, 'isPrivate for a window is true when it should be');
+  assert.equal(isPrivate(window.tabs[0]), false, 'isPrivate for a tab is false when it should be');
+
+  yield cleanUI();
 }
 
 exports.testIsPrivateOnWindowOpenFromPrivate = function(assert, done) {
     // open a private window
     openPromise(null, {
       features: {
         private: true,
         chrome: true,
--- a/addon-sdk/source/test/tabs/test-firefox-tabs.js
+++ b/addon-sdk/source/test/tabs/test-firefox-tabs.js
@@ -13,16 +13,17 @@ const { getOwnerWindow } = require('sdk/
 const { windows, onFocus, getMostRecentBrowserWindow } = require('sdk/window/utils');
 const { open, focus, close } = require('sdk/window/helpers');
 const tabs = require('sdk/tabs');
 const { browserWindows } = require('sdk/windows');
 const { set: setPref } = require("sdk/preferences/service");
 const DEPRECATE_PREF = "devtools.errorconsole.deprecation_warnings";
 const fixtures = require("../fixtures");
 const { base64jpeg } = fixtures;
+const { cleanUI, after } = require("sdk/test/utils");
 
 // Bug 682681 - tab.title should never be empty
 exports.testBug682681_aboutURI = function(assert, done) {
   let url = 'chrome://browser/locale/tabbrowser.properties';
   let stringBundle = Cc["@mozilla.org/intl/stringbundle;1"].
                         getService(Ci.nsIStringBundleService).
                         createBundle(url);
   let emptyTabTitle = stringBundle.GetStringFromName('tabs.emptyTabTitle');
@@ -367,41 +368,38 @@ exports.testTabMove = function(assert, d
         tab.index = 0;
         assert.equal(tab.index, 0, "tab index after move matches");
         close(window).then(done).then(null, assert.fail);
       }
     });
   }).then(null, assert.fail);
 };
 
-exports.testIgnoreClosing = function(assert, done) {
-  let originalWindow = viewFor(browserWindows.activeWindow);
-  openBrowserWindow(function(window, browser) {
-    onFocus(window).then(() => {
-      let url = "data:text/html;charset=utf-8,foobar";
+exports.testIgnoreClosing = function*(assert) {
+  let url = "data:text/html;charset=utf-8,foobar";
+  let originalWindow = getMostRecentBrowserWindow();
 
-      assert.equal(tabs.length, 2, "should be two windows open each with one tab");
+  let window = yield open().then(focus);
 
-      tabs.on('ready', function onReady(tab) {
-        tabs.removeListener('ready', onReady);
+  assert.equal(tabs.length, 2, "should be two windows open each with one tab");
 
-        let win = tab.window;
-        assert.equal(win.tabs.length, 2, "should be two tabs in the new window");
-        assert.equal(tabs.length, 3, "should be three tabs in total");
+  yield new Promise(resolve => {
+    tabs.once("ready", (tab) => {
+      let win = tab.window;
+      assert.equal(win.tabs.length, 2, "should be two tabs in the new window");
+      assert.equal(tabs.length, 3, "should be three tabs in total");
 
-        tab.close(function() {
-          assert.equal(win.tabs.length, 1, "should be one tab in the new window");
-          assert.equal(tabs.length, 2, "should be two tabs in total");
+      tab.close(() => {
+        assert.equal(win.tabs.length, 1, "should be one tab in the new window");
+        assert.equal(tabs.length, 2, "should be two tabs in total");
+        resolve();
+      });
+    });
 
-          close(window).then(onFocus(originalWindow)).then(done).then(null, assert.fail);
-        });
-      });
-
-      tabs.open(url);
-    });
+    tabs.open(url);
   });
 };
 
 // TEST: open tab with default options
 exports.testOpen = function(assert, done) {
   let url = "data:text/html;charset=utf-8,default";
   tabs.open({
     url: url,
@@ -532,42 +530,48 @@ exports.testTabsEvent_onOpen = function(
       close(window).then(done).then(null, assert.fail);
     });
 
     tabs.open(url);
   }).then(null, assert.fail);
 };
 
 // TEST: onClose event handler
-exports.testTabsEvent_onClose = function(assert, done) {
-  open().then(focus).then(window => {
-    let url = "data:text/html;charset=utf-8,onclose";
-    let eventCount = 0;
+exports.testTabsEvent_onClose = function*(assert) {
+  let window = yield open().then(focus);
+  let url = "data:text/html;charset=utf-8,onclose";
+  let eventCount = 0;
 
-    // add listener via property assignment
-    function listener1(tab) {
-      eventCount++;
-    }
-    tabs.on('close', listener1);
+  // add listener via property assignment
+  function listener1(tab) {
+    eventCount++;
+  }
+  tabs.on("close", listener1);
 
+  yield new Promise(resolve => {
     // add listener via collection add
-    tabs.on('close', function listener2(tab) {
+    tabs.on("close", function listener2(tab) {
       assert.equal(++eventCount, 2, "both listeners notified");
-      tabs.removeListener('close', listener1);
-      tabs.removeListener('close', listener2);
-      close(window).then(done).then(null, assert.fail);
+      tabs.removeListener("close", listener2);
+      resolve();
     });
 
     tabs.on('ready', function onReady(tab) {
       tabs.removeListener('ready', onReady);
       tab.close();
     });
 
     tabs.open(url);
-  }).then(null, assert.fail);
+  });
+
+  tabs.removeListener("close", listener1);
+  assert.pass("done test!");
+
+  yield close(window);
+  assert.pass("window was closed!");
 };
 
 // TEST: onClose event handler when a window is closed
 exports.testTabsEvent_onCloseWindow = function(assert, done) {
   let closeCount = 0;
   let individualCloseCount = 0;
 
   open().then(focus).then(window => {
@@ -666,42 +670,48 @@ exports.testTabsEvent_onActivate = funct
       close(window).then(done).then(null, assert.fail);
     });
 
     tabs.open(url);
   }).then(null, assert.fail);
 };
 
 // onDeactivate event handler
-exports.testTabsEvent_onDeactivate = function(assert, done) {
-  open().then(focus).then(window => {
-    let url = "data:text/html;charset=utf-8,ondeactivate";
-    let eventCount = 0;
+exports.testTabsEvent_onDeactivate = function*(assert) {
+  let window = yield open().then(focus);
+
+  let url = "data:text/html;charset=utf-8,ondeactivate";
+  let eventCount = 0;
 
-    // add listener via property assignment
-    function listener1(tab) {
-      eventCount++;
-    };
-    tabs.on('deactivate', listener1);
+  // add listener via property assignment
+  function listener1(tab) {
+    eventCount++;
+    assert.pass("listener1 was called " + eventCount);
+  };
+  tabs.on('deactivate', listener1);
 
+  yield new Promise(resolve => {
     // add listener via collection add
     tabs.on('deactivate', function listener2(tab) {
       assert.equal(++eventCount, 2, "both listeners notified");
-      tabs.removeListener('deactivate', listener1);
       tabs.removeListener('deactivate', listener2);
-      close(window).then(done).then(null, assert.fail);
+      resolve();
     });
 
     tabs.on('open', function onOpen(tab) {
+      assert.pass("tab opened");
       tabs.removeListener('open', onOpen);
       tabs.open("data:text/html;charset=utf-8,foo");
     });
 
     tabs.open(url);
-  }).then(null, assert.fail);
+  });
+
+  tabs.removeListener('deactivate', listener1);
+  assert.pass("listeners were removed");
 };
 
 // pinning
 exports.testTabsEvent_pinning = function(assert, done) {
   open().then(focus).then(window => {
     let url = "data:text/html;charset=utf-8,1";
 
     tabs.on('open', function onOpen(tab) {
@@ -721,39 +731,46 @@ exports.testTabsEvent_pinning = function
       close(window).then(done).then(null, assert.fail);
     });
 
     tabs.open(url);
   }).then(null, assert.fail);
 };
 
 // TEST: per-tab event handlers
-exports.testPerTabEvents = function(assert, done) {
-  open().then(focus).then(window => {
-    let eventCount = 0;
+exports.testPerTabEvents = function*(assert) {
+  let window = yield open().then(focus);
+  let eventCount = 0;
 
+  let tab = yield new Promise(resolve => {
     tabs.open({
       url: "data:text/html;charset=utf-8,foo",
-      onOpen: function(tab) {
+      onOpen: (tab) => {
+        assert.pass("the tab was opened");
+
         // add listener via property assignment
         function listener1() {
           eventCount++;
         };
         tab.on('ready', listener1);
 
         // add listener via collection add
         tab.on('ready', function listener2() {
-          assert.equal(eventCount, 1, "both listeners notified");
+          assert.equal(eventCount, 1, "listener1 called before listener2");
           tab.removeListener('ready', listener1);
           tab.removeListener('ready', listener2);
-          close(window).then(done).then(null, assert.fail);
+          assert.pass("removed listeners");
+          eventCount++;
+          resolve();
         });
       }
     });
-  }).then(null, assert.fail);
+  });
+
+  assert.equal(eventCount, 2, "both listeners were notified.");
 };
 
 exports.testAttachOnOpen = function (assert, done) {
   // Take care that attach has to be called on tab ready and not on tab open.
   open().then(focus).then(window => {
     tabs.open({
       url: "data:text/html;charset=utf-8,foobar",
       onOpen: function (tab) {
@@ -1198,16 +1215,20 @@ exports.testTabDestroy = function(assert
           tab.activate();
         });
       }));
       myFirstTab.activate();
     })
   })
 };
 
+after(exports, function*(name, assert) {
+  yield cleanUI();
+});
+
 /******************* helpers *********************/
 
 // Utility function to open a new browser window.
 function openBrowserWindow(callback, url) {
   let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
            getService(Ci.nsIWindowWatcher);
   let urlString = Cc["@mozilla.org/supports-string;1"].
                   createInstance(Ci.nsISupportsString);
new file mode 100644
--- /dev/null
+++ b/addon-sdk/source/test/test-addon-extras.js
@@ -0,0 +1,171 @@
+/* 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 { Ci, Cu, Cc, components } = require("chrome");
+const self = require("sdk/self");
+const { before, after } = require("sdk/test/utils");
+const fixtures = require("./fixtures");
+const { Loader } = require("sdk/test/loader");
+const { merge } = require("sdk/util/object");
+
+exports["test changing result from addon extras in panel"] = function(assert, done) {
+  let loader = Loader(module, null, null, {
+    modules: {
+      "sdk/self": merge({}, self, {
+        data: merge({}, self.data, {url: fixtures.url})
+      })
+    }
+  });
+
+  const { Panel } = loader.require("sdk/panel");
+  const { events } = loader.require("sdk/content/sandbox/events");
+  const { on } = loader.require("sdk/event/core");
+  const { isAddonContent } = loader.require("sdk/content/utils");
+
+  var result = 1;
+  var extrasVal = {
+    test: function() {
+      return result;
+    }
+  };
+
+  on(events, "content-script-before-inserted", ({ window, worker }) => {
+    assert.pass("content-script-before-inserted");
+
+    if (isAddonContent({ contentURL: window.location.href })) {
+      let extraStuff = Cu.cloneInto(extrasVal, window, {
+        cloneFunctions: true
+      });
+      getUnsafeWindow(window).extras = extraStuff;
+
+      assert.pass("content-script-before-inserted done!");
+    }
+  });
+
+  let panel = Panel({
+    contentURL: "./test-addon-extras.html"
+  });
+
+  panel.port.once("result1", (result) => {
+    assert.equal(result, 1, "result is a number");
+    result = true;
+    panel.port.emit("get-result");
+  });
+
+  panel.port.once("result2", (result) => {
+    assert.equal(result, true, "result is a boolean");
+    loader.unload();
+    done();
+  });
+
+  panel.port.emit("get-result");
+}
+
+exports["test window result from addon extras in panel"] = function*(assert) {
+  let loader = Loader(module, null, null, {
+    modules: {
+      "sdk/self": merge({}, self, {
+        data: merge({}, self.data, {url: fixtures.url})
+      })
+    }
+  });
+
+  const { Panel } = loader.require('sdk/panel');
+  const { Page } = loader.require('sdk/page-worker');
+  const { getActiveView } = loader.require("sdk/view/core");
+  const { getDocShell } = loader.require('sdk/frame/utils');
+  const { events } = loader.require("sdk/content/sandbox/events");
+  const { on } = loader.require("sdk/event/core");
+  const { isAddonContent } = loader.require("sdk/content/utils");
+
+  // make a page worker and wait for it to load
+  var page = yield new Promise(resolve => {
+    assert.pass("Creating the background page");
+
+    let page = Page({
+      contentURL: "./test.html",
+      contentScriptWhen: "end",
+      contentScript: "self.port.emit('end', unsafeWindow.getTestURL() + '')"
+    });
+
+    page.port.once("end", (url) => {
+      assert.equal(url, fixtures.url("./test.html"), "url is correct");
+      resolve(page);
+    });
+  });
+  assert.pass("Created the background page");
+
+  var extrasVal = {
+    test: function() {
+      assert.pass("start test function");
+      let frame = getActiveView(page);
+      let window = getUnsafeWindow(frame.contentWindow);
+      assert.equal(typeof window.getTestURL, "function", "window.getTestURL is a function");
+      return window;
+    }
+  };
+
+  on(events, "content-script-before-inserted", ({ window, worker }) => {
+    let url = window.location.href;
+    assert.pass("content-script-before-inserted " + url);
+
+    if (isAddonContent({ contentURL: url })) {
+      let extraStuff = Cu.cloneInto(extrasVal, window, {
+        cloneFunctions: true
+      });
+      getUnsafeWindow(window).extras = extraStuff;
+
+      assert.pass("content-script-before-inserted done!");
+    }
+  });
+
+  let panel = Panel({
+    contentURL: "./test-addon-extras-window.html"
+  });
+
+
+  yield new Promise(resolve => {
+    panel.port.once("result1", (result) => {
+      assert.equal(result, fixtures.url("./test.html"), "result1 is a window");
+      resolve();
+    });
+
+    assert.pass("emit get-result");
+    panel.port.emit("get-result");
+  });
+
+  page.destroy();
+
+
+  page = yield new Promise(resolve => {
+    let page = Page({
+      contentURL: "./index.html",
+      contentScriptWhen: "end",
+      contentScript: "self.port.emit('end')"
+    });
+    page.port.once("end", () => resolve(page));
+  });
+
+
+  yield new Promise(resolve => {
+    panel.port.once("result2", (result) => {
+      assert.equal(result, fixtures.url("./index.html"), "result2 is a window");
+      resolve();
+    });
+
+    assert.pass("emit get-result");
+    panel.port.emit("get-result");
+  });
+
+  loader.unload();
+}
+
+
+
+function getUnsafeWindow (win) {
+  return win.wrappedJSObject || win;
+}
+
+require("sdk/test").run(exports);
deleted file mode 100644
--- a/addon-sdk/source/test/test-bond.js
+++ /dev/null
@@ -1,169 +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 { Bond } = require("sdk/util/bond");
-const { Class } = require("sdk/core/heritage");
-
-exports["test bonds on constructors"] = assert => {
-  const MyClass = function(name) {
-    this.name = name;
-  }
-  MyClass.prototype = Bond({
-    hello() {
-      return `Hello my name is ${this.name}`
-    }
-  })
-  Object.assign(MyClass.prototype, {
-    constructor: MyClass,
-    readName() {
-      return this.name
-    }
-  });
-
-  const i1 = new MyClass("James Bond");
-
-  assert.equal(i1.hello(), "Hello my name is James Bond");
-  assert.equal(i1.hello.call({name: "Hack"}), "Hello my name is James Bond");
-  assert.equal(i1.readName(), "James Bond");
-  assert.equal(i1.readName.call({name: "Hack"}), "Hack");
-
-  const hello = i1.hello
-  assert.equal(hello(), "Hello my name is James Bond");
-};
-
-exports["test subclassing"] = assert => {
-  const MyClass = function(name) {
-    this.name = name;
-  }
-  MyClass.prototype = Bond({
-    hello() {
-      return `Hello my name is ${this.name}`
-    }
-  });
-
-  const i1 = new MyClass("James Bond");
-
-  assert.equal(i1.hello(), "Hello my name is James Bond");
-  assert.equal(i1.hello.call({name: "Hack"}), "Hello my name is James Bond");
-  const i1Hello = i1.hello
-  assert.equal(i1Hello(), "Hello my name is James Bond");
-
-  const MySubClass = function(...args) {
-    MyClass.call(this, ...args)
-  }
-  MySubClass.prototype = Object.create(MyClass.prototype)
-
-  const i2 = new MySubClass("Your father");
-
-  assert.equal(i2.hello(), "Hello my name is Your father");
-  assert.equal(i2.hello.call({name: "Hack"}), "Hello my name is Your father");
-  const i2Hello = i2.hello
-  assert.equal(i2Hello(), "Hello my name is Your father");
-};
-
-exports["test access on prototype"] = assert => {
-  const MyClass = function(name) {
-    this.name = name;
-  }
-  MyClass.prototype = Bond({
-    hello() {
-      return `Hello my name is ${this.name}`
-    }
-  });
-
-  assert.equal(MyClass.prototype.hello(), "Hello my name is undefined");
-  assert.ok(Object.getOwnPropertyDescriptor(MyClass.prototype, "hello").get,
-            "hello is still a getter");
-  assert.equal(MyClass.prototype.hello.call({name: "this"}),
-               "Hello my name is this",
-               "passing `this` on prototype methods work");
-
-  const i1 = new MyClass("James Bond");
-  assert.equal(i1.hello(), "Hello my name is James Bond");
-
-  assert.ok(!Object.getOwnPropertyDescriptor(i1, "hello").get,
-            "hello is not a getter on instance");
-
-  assert.equal(i1.hello.call({name: "Hack"}), "Hello my name is James Bond");
-  const i1Hello = i1.hello
-  assert.equal(i1Hello(), "Hello my name is James Bond");
-};
-
-
-exports["test bonds with Class"] = assert => {
-  const MyClass = Class({
-    extends: Bond({
-      hello() {
-        return `Hello my name is ${this.name}`
-      }
-    }),
-    initialize(name) {
-      this.name = name;
-    }
-  });
-
-  const i1 = new MyClass("James Bond");
-
-  assert.equal(i1.hello(), "Hello my name is James Bond");
-  assert.equal(i1.hello.call({name: "Hack"}), "Hello my name is James Bond");
-
-  const hello = i1.hello
-  assert.equal(hello(), "Hello my name is James Bond");
-};
-
-
-exports["test with mixin"] = assert => {
-  const MyClass = Class({
-    implements: [
-      Bond({
-        hello() {
-          return `Hello my name is ${this.name}`
-        }
-      })
-    ],
-    initialize(name) {
-      this.name = name;
-    }
-  });
-
-  const i1 = new MyClass("James Bond");
-
-  assert.equal(i1.hello(), "Hello my name is James Bond");
-  assert.equal(i1.hello.call({name: "Hack"}), "Hello my name is James Bond");
-
-  const hello = i1.hello
-  assert.equal(hello(), "Hello my name is James Bond");
-
-  const MyComposedClass = Class({
-    implements: [
-      MyClass,
-      Bond({
-        bye() {
-          return `Bye ${this.name}`
-        }
-      })
-    ],
-    initialize(name) {
-      this.name = name;
-    }
-  });
-
-  const i2 = new MyComposedClass("Major Tom");
-
-  assert.equal(i2.hello(), "Hello my name is Major Tom");
-  assert.equal(i2.hello.call({name: "Hack"}), "Hello my name is Major Tom");
-
-  const i2Hello = i2.hello
-  assert.equal(i2Hello(), "Hello my name is Major Tom");
-
-  assert.equal(i2.bye(), "Bye Major Tom");
-  assert.equal(i2.bye.call({name: "Hack"}), "Bye Major Tom");
-
-  const i2Bye = i2.bye
-  assert.equal(i2Bye(), "Bye Major Tom");
-};
-
-
-require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-file.js
+++ b/addon-sdk/source/test/test-file.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 { pathFor } = require('sdk/system');
 const file = require("sdk/io/file");
 const url = require("sdk/url");
 
 const byteStreams = require("sdk/io/byte-streams");
 const textStreams = require("sdk/io/text-streams");
--- a/addon-sdk/source/test/test-loader.js
+++ b/addon-sdk/source/test/test-loader.js
@@ -519,9 +519,27 @@ exports['test lazy globals'] = function 
   let loader = Loader({ paths: { '': uri }, modules: modules});
   assert.ok(!gotFoo, "foo hasn't been accessed during loader instanciation");
   let program = main(loader, 'main');
   assert.ok(!gotFoo, "foo hasn't been accessed during module loading");
   assert.equal(program.useFoo(), foo, "foo mock works");
   assert.ok(gotFoo, "foo has been accessed only when we first try to use it");
 };
 
+exports['test user global'] = function(assert) {
+  // Test case for bug 827792
+  let com = {};
+  let loader = require('toolkit/loader');
+  let loadOptions = require('@loader/options');
+  let options = loader.override(loadOptions,
+                                {globals: loader.override(loadOptions.globals,
+                                                          {com: com,
+                                                           console: console,
+                                                           dump: dump})});
+  let subloader = loader.Loader(options);
+  let userRequire = loader.Require(subloader, module);
+  let userModule = userRequire("./loader/user-global");
+
+  assert.equal(userModule.getCom(), com,
+               "user module returns expected `com` global");
+};
+
 require('sdk/test').run(exports);
deleted file mode 100644
--- a/addon-sdk/source/test/test-memory.js
+++ /dev/null
@@ -1,22 +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 memory = require("sdk/deprecated/memory");
-const { gc } = require("sdk/test/memory");
-
-exports.testMemory = function(assert) {
-  var obj = {};
-  memory.track(obj, "testMemory.testObj");
-
-  var objs = memory.getObjects("testMemory.testObj");
-  assert.equal(objs[0].weakref.get(), obj);
-  obj = null;
-
-  gc().then(function() {
-    assert.equal(objs[0].weakref.get(), null);
-  });
-};
-
-require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-mpl2-license-header.js
+++ b/addon-sdk/source/test/test-mpl2-license-header.js
@@ -5,16 +5,18 @@
 "use strict";
 
 const { Cc, Ci, Cu } = require("chrome");
 const options = require('@loader/options');
 const { id } = require("sdk/self");
 const { getAddonByID } = require("sdk/addon/manager");
 const { mapcat, map, filter, fromEnumerator } = require("sdk/util/sequence");
 const { readURISync } = require('sdk/net/url');
+const { Request } = require('sdk/request');
+const { defer } = require("sdk/core/promise");
 
 const ios = Cc['@mozilla.org/network/io-service;1'].
               getService(Ci.nsIIOService);
 
 const MIT_LICENSE_HEADER = [];
 
 const MPL2_LICENSE_TEST = new RegExp([
   "^\\/\\* This Source Code Form is subject to the terms of the Mozilla Public",
@@ -52,36 +54,52 @@ const getEntries = directory => mapcat(e
     return getEntries(entry);
   }
   else if (isTestFile(entry)) {
     return [ entry ];
   }
   return [];
 }, filter(() => true, getDirectoryEntries(directory)));
 
+function readURL(url) {
+  let { promise, resolve } = defer();
+
+  Request({
+    url: url,
+    overrideMimeType: "text/plain",
+    onComplete: (response) => resolve(response.text)
+  }).get();
+
+  return promise;
+}
 
 exports["test MPL2 license header"] = function*(assert) {
   let addon = yield getAddonByID(id);
   let xpiURI = addon.getResourceURI();
   let rootURL = xpiURI.spec;
+  assert.ok(rootURL, rootURL);
   let files = [...getEntries(xpiURI.QueryInterface(Ci.nsIFileURL).file)];
 
   assert.ok(files.length > 1, files.length + " files found.");
   let failures = [];
   let success = 0;
 
-  files.forEach(file => {
+  for (let i = 0, len = files.length; i < len; i++) {
+    let file = files[i];
+    assert.ok(file.path, "Trying " + file.path);
+
     const URI = ios.newFileURI(file);
+
     let leafName = URI.spec.replace(rootURL, "");
-    let contents = readURISync(URI);
 
+    let contents = yield readURL(URI.spec);
     if (!MPL2_LICENSE_TEST.test(contents)) {
       failures.push(leafName);
     }
-  });
+  }
 
   assert.equal(1, failures.length, "we expect one failure");
   assert.ok(/test-mpl2-license-header\.js$/.test(failures[0]), "the only failure is this file");
   failures.shift();
   assert.equal("", failures.join(",\n"), failures.length + " files found missing the required mpl 2 header");
 }
 
 require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-unit-test.js
+++ b/addon-sdk/source/test/test-unit-test.js
@@ -118,36 +118,37 @@ exports.testWaitUntilTimeoutInCallback =
   test.waitUntilDone();
 
   let expected = [];
   let message = 0;
   if (require("sdk/test/options").parseable) {
     expected.push(["print", "TEST-START | wait4ever\n"]);
     expected.push(["error", "fail:", "Timed out (after: START)"]);
     expected.push(["error", "test assertion never became true:\n", "assertion failed, value is false\n"]);
-    expected.push(["print", "TEST-END | wait4ever\n"]);
   }
   else {
     expected.push(["info",  "executing 'wait4ever'"]);
     expected.push(["error", "fail:", "Timed out (after: START)"]);
     expected.push(["error", "test assertion never became true:\n", "assertion failed, value is false\n"]);
   }
 
   function checkExpected(name, args) {
-    if (expected.length == 0 || expected[0][0] != name) {
-      test.fail("Saw an unexpected console." + name + "() call " + args);
+    var index = message;
+    if (message++ >= expected.length) {
       return;
     }
 
-    message++;
-    let expectedArgs = expected.shift().slice(1);
-    for (let i = 0; i < expectedArgs.length; i++)
+    let expectedArgs = expected[index].slice(1);
+    for (let i = 0; i < expectedArgs.length; i++) {
       test.assertEqual(args[i], expectedArgs[i], "Should have seen the right message in argument " + i + " of message " + message);
-    if (expected.length == 0)
+    }
+
+    if (message >= expected.length) {
       test.done();
+    }
   }
 
   let runner = new (require("sdk/deprecated/unit-test").TestRunner)({
     console: {
       error: function() {
         checkExpected("error", Array.slice(arguments));
       },
       info: function () {
--- a/addon-sdk/source/test/test-weak-set.js
+++ b/addon-sdk/source/test/test-weak-set.js
@@ -1,123 +1,86 @@
 /* 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 { Cu } = require('chrome');
-const { Loader } = require('sdk/test/loader');
-const { gc } = require("sdk/test/memory");
-
-exports['test adding item'] = function*(assert) {
-  let loader = Loader(module);
-  let { add, remove, has, clear, iterator } = loader.require('sdk/lang/weak-set');
+"use strict";
 
-  let items = {};
-  let item = {};
-
-  add(items, item);
+const { Cu } = require("chrome");
+const memory = require("sdk/test/memory");
+const { add, remove, has, clear, iterator } = require("sdk/lang/weak-set");
+const { setInterval, clearInterval } = require("sdk/timers");
 
-  yield gc();
-
-  assert.ok(has(items, item), 'the item is in the weak set');
-
-  loader.unload();
-};
+function gc(assert) {
+  let wait = 1;
+  let interval = setInterval(function() {
+    assert.pass("waited " + (wait++ * 0.250) + "secs for gc()..");
+  }, 250);
 
-exports['test remove item'] = function*(assert) {
-  let loader = Loader(module);
-  let { add, remove, has, clear, iterator } = loader.require('sdk/lang/weak-set');
-
-  let items = {};
-  let item = {};
-
-  add(items, item);
-
-  remove(items, item);
+  return memory.gc().then(() => {
+    assert.pass("gc completed!");
+    clearInterval(interval);
+  });
+}
 
-  yield gc();
-
-  assert.ok(!has(items, item), 'the item is not in weak set');
+exports['test add/remove/iterate/clear item'] = function*(assert) {
+  let addItems = {};
+  let removeItems = {};
+  let iterateItems = {};
+  let clearItems = {};
+  let nonReferencedItems = {};
 
-  loader.unload();
-};
-
-exports['test iterate'] = function*(assert) {
-  let loader = Loader(module);
-  let { add, remove, has, clear, iterator } = loader.require('sdk/lang/weak-set');
-
-  let items = {};
+  let item = {};
   let addedItems = [{}, {}];
 
-  add(items, addedItems[0]);
-  add(items, addedItems[1]);
-  add(items, addedItems[0]); // weak set shouldn't add this twice
+  assert.pass("adding things to items");
+  add(addItems, item);
+  add(removeItems, item);
+  add(iterateItems, addedItems[0]);
+  add(iterateItems, addedItems[1]);
+  add(iterateItems, addedItems[0]); // weak set shouldn't add this twice
+  add(clearItems, addedItems[0]);
+  add(clearItems, addedItems[1]);
+  add(nonReferencedItems, {});
 
-  yield gc();
+  assert.pass("removing things from removeItems");
+  remove(removeItems, item);
+
+  assert.pass("clear things from clearItems");
+  clear(clearItems);
+
+  assert.pass("starting gc..");
+  yield gc(assert);
   let count = 0;
 
-  for (let item of iterator(items)) {
-    assert.equal(item, addedItems[count],
-      'item in the expected order');
+  assert.equal(has(addItems, item), true, 'the addItems is in the weak set');
+  assert.equal(has(removeItems, item), false, 'the removeItems is not in weak set');
 
+  assert.pass("iterating iterateItems..");
+  for (let item of iterator(iterateItems)) {
+    assert.equal(item, addedItems[count], "item in the expected order");
     count++;
   }
 
   assert.equal(count, 2, 'items in the expected number');
-  loader.unload();
-};
 
-exports['test clear'] = function*(assert) {
-  let loader = Loader(module);
-  let { add, remove, has, clear, iterator } = loader.require('sdk/lang/weak-set');
-
-  let items = {};
-  let addedItems = [{}, {}];
-
-  add(items, addedItems[0]);
-  add(items, addedItems[1]);
-
-  clear(items)
-
-  yield gc();
-  let count = 0;
-
-  for (let item of iterator(items)) {
-    assert.fail('the loop should not be executed');
+  assert.pass("iterating clearItems..");
+  for (let item of iterator(clearItems)) {
+    assert.fail("the loop should not be executed");
+    count++
   }
 
-  assert.equal(count, 0, 'no items in the weak set');
-  loader.unload();
-};
-
-exports['test adding item without reference'] = function*(assert) {
-  let loader = Loader(module);
-  let { add, remove, has, clear, iterator } = loader.require('sdk/lang/weak-set');
-
-  let items = {};
-
-  add(items, {});
-
-  yield gc();
-  let count = 0;
-
-  for (let item of iterator(items)) {
-    assert.fail('the loop should not be executed');
+  for (let item of iterator(nonReferencedItems)) {
+    assert.fail("the loop should not be executed");
+    count++
   }
 
-  assert.equal(count, 0, 'no items in the weak set');
-
-  loader.unload();
+  assert.equal(count, 2, 'items in the expected number');
 };
 
 exports['test adding non object or null item'] = function(assert) {
-  let loader = Loader(module);
-  let { add, remove, has, clear, iterator } = loader.require('sdk/lang/weak-set');
-
   let items = {};
 
   assert.throws(() => {
     add(items, 'foo');
   },
   /^\w+ is not a non-null object/,
   'only non-null object are allowed');
 
@@ -142,19 +105,16 @@ exports['test adding non object or null 
   assert.throws(() => {
     add(items, true);
   },
   /^\w+ is not a non-null object/,
   'only non-null object are allowed');
 };
 
 exports['test adding to non object or null item'] = function(assert) {
-  let loader = Loader(module);
-  let { add, remove, has, clear, iterator } = loader.require('sdk/lang/weak-set');
-
   let item = {};
 
   assert.throws(() => {
     add('foo', item);
   },
   /^\w+ is not a non-null object/,
   'only non-null object are allowed');
 
@@ -178,9 +138,9 @@ exports['test adding to non object or nu
 
   assert.throws(() => {
     add(true, item);
   },
   /^\w+ is not a non-null object/,
   'only non-null object are allowed');
 };
 
-require('sdk/test').run(exports);
+require("sdk/test").run(exports);
--- a/addon-sdk/source/test/test-windows-common.js
+++ b/addon-sdk/source/test/test-windows-common.js
@@ -5,16 +5,17 @@
 
 const { Loader } = require('sdk/test/loader');
 const { browserWindows } = require('sdk/windows');
 const { isFocused } = require('sdk/window/utils');
 const { viewFor } = require('sdk/view/core');
 const { modelFor } = require('sdk/model/core');
 const { Ci } = require("chrome");
 const { isBrowser, getWindowTitle } = require("sdk/window/utils");
+const { after, cleanUI } = require("sdk/test/utils");
 
 // TEST: browserWindows Iterator
 exports.testBrowserWindowsIterator = function(assert) {
   let activeWindowCount = 0;
   let windows = [];
   let i = 0;
   for (let window of browserWindows) {
     if (window === browserWindows.activeWindow)
@@ -60,30 +61,28 @@ exports.testWindowActivateMethod_simple 
 
   assert.equal(browserWindows.activeWindow, window,
                'Active window is active after window.activate() call');
   assert.equal(window.tabs.activeTab, tab,
                'Active tab is active after window.activate() call');
 };
 
 
-exports["test getView(window)"] = function(assert, done) {
-  browserWindows.once("open", window => {
-    const view = viewFor(window);
-
-    assert.ok(view instanceof Ci.nsIDOMWindow, "view is a window");
-    assert.ok(isBrowser(view), "view is a browser window");
-    assert.equal(getWindowTitle(view), window.title,
-                 "window has a right title");
-
-    window.close(done);
+exports["test getView(window)"] = function*(assert) {
+  let window = yield new Promise(resolve => {
+    browserWindows.once("open", resolve);
+    browserWindows.open({ url: "data:text/html;charset=utf-8,<title>yo</title>" });
   });
 
+  const view = viewFor(window);
 
-  browserWindows.open({ url: "data:text/html;charset=utf-8,<title>yo</title>" });
+  assert.ok(view instanceof Ci.nsIDOMWindow, "view is a window");
+  assert.ok(isBrowser(view), "view is a browser window");
+  assert.equal(getWindowTitle(view), window.title,
+               "window has a right title");
 };
 
 
 exports["test modelFor(window)"] = function(assert, done) {
   browserWindows.once("open", window => {
     const view = viewFor(window);
 
     assert.ok(view instanceof Ci.nsIDOMWindow, "view is a window");
@@ -92,9 +91,14 @@ exports["test modelFor(window)"] = funct
 
     window.close(done);
   });
 
 
   browserWindows.open({ url: "data:text/html;charset=utf-8,<title>yo</title>" });
 };
 
+after(exports, function*(name, assert) {
+  assert.pass("cleaning the ui.");
+  yield cleanUI();
+});
+
 require('sdk/test').run(exports);
--- a/addon-sdk/source/test/test-xul-app.js
+++ b/addon-sdk/source/test/test-xul-app.js
@@ -1,44 +1,45 @@
 /* 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 xulApp = require("sdk/system/xul-app");
 
-exports["test xulapp"] = function(assert) {
+exports["test xulapp"] = function (assert) {
   assert.equal(typeof(xulApp.ID), "string",
                    "ID is a string");
   assert.equal(typeof(xulApp.name), "string",
                    "name is a string");
   assert.equal(typeof(xulApp.version), "string",
                    "version is a string");
   assert.equal(typeof(xulApp.platformVersion), "string",
                    "platformVersion is a string");
 
-  assert.throws(function() { xulApp.is("blargy"); },
-                    /Unkown Mozilla Application: blargy/,
-                    "is() throws error on bad app name");
-  assert.throws(function() { xulApp.isOneOf(["blargy"]); },
-                    /Unkown Mozilla Application: blargy/,
-                    "isOneOf() throws error on bad app name");
+  assert.throws(() => xulApp.is("blargy"),
+      /Unkown Mozilla Application: blargy/,
+      "is() throws error on bad app name");
+
+  assert.throws(() => xulApp.isOneOf(["blargy"]),
+      /Unkown Mozilla Application: blargy/,
+      "isOneOf() throws error on bad app name");
 
   function testSupport(name) {
     var item = xulApp.is(name);
     assert.ok(item === true || item === false,
-                "is('" + name + "') is true or false.");
+                  "is('" + name + "') is true or false.");
   }
 
   var apps = ["Firefox", "Mozilla", "SeaMonkey", "Fennec", "Thunderbird"];
 
   apps.forEach(testSupport);
 
-  assert.ok(xulApp.isOneOf(apps) == true ||
-              xulApp.isOneOf(apps) == false,
-              "isOneOf() returns true or false.");
+  assert.ok(xulApp.isOneOf(apps) == true || xulApp.isOneOf(apps) == false,
+                "isOneOf() returns true or false.");
 
   assert.equal(xulApp.versionInRange(xulApp.platformVersion, "1.9", "*"),
                    true, "platformVersion in range [1.9, *)");
   assert.equal(xulApp.versionInRange("3.6.4", "3.6.4", "3.6.*"),
                    true, "3.6.4 in [3.6.4, 3.6.*)");
   assert.equal(xulApp.versionInRange("1.9.3", "1.9.2", "1.9.3"),
                    false, "1.9.3 not in [1.9.2, 1.9.3)");
 };
--- a/addon-sdk/source/test/windows/test-firefox-windows.js
+++ b/addon-sdk/source/test/windows/test-firefox-windows.js
@@ -322,17 +322,16 @@ exports.testTrackWindows = function(asse
   }
 
   // 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);
 
         // Guard against windows that have already been removed.
         // See bug 874502 comment 32.
@@ -345,18 +344,20 @@ exports.testTrackWindows = function(asse
         actions.push("activate " + index);
 
         if (windows.length < 3) {
           openWindow()
         }
         else {
           (function closeWindows(windows) {
             if (!windows.length) {
+              assert.pass('the last window was closed');
               browserWindows.removeListener("activate", windowsActivation);
               browserWindows.removeListener("deactivate", windowsDeactivation);
+              assert.pass('removed listeners');
               return done();
             }
 
             return windows.pop().close(function() {
               assert.pass('window was closed');
               closeWindows(windows);
             });
           })(windows)
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -327,16 +327,17 @@ pref("media.eme.apiVisible", true);
 // The default number of decoded video frames that are enqueued in
 // MediaDecoderReader's mVideoQueue.
 pref("media.video-queue.default-size", 3);
 
 // optimize images' memory usage
 pref("image.downscale-during-decode.enabled", true);
 pref("image.decode-only-on-draw.enabled", false);
 pref("image.mem.allow_locking_in_content_processes", true);
+pref("image.decode.retry-on-alloc-failure", true);
 // Limit the surface cache to 1/8 of main memory or 128MB, whichever is smaller.
 // Almost everything that was factored into 'max_decoded_image_kb' is now stored
 // in the surface cache.  1/8 of main memory is 32MB on a 256MB device, which is
 // about the same as the old 'max_decoded_image_kb'.
 pref("image.mem.surfacecache.max_size_kb", 131072);  // 128MB
 pref("image.mem.surfacecache.size_factor", 8);  // 1/8 of main memory
 pref("image.mem.surfacecache.discard_factor", 2);  // Discard 1/2 of the surface cache at a time.
 pref("image.mem.surfacecache.min_expiration_ms", 86400000); // 24h, we rely on the out of memory hook
--- a/b2g/components/ProcessGlobal.js
+++ b/b2g/components/ProcessGlobal.js
@@ -58,16 +58,28 @@ function ConsoleMessage(aMsg, aLevel) {
       this.logLevel = Ci.nsIConsoleMessage.info;
       break;
     default:
       this.logLevel = Ci.nsIConsoleMessage.debug;
       break;
   }
 }
 
+function toggleUnrestrictedDevtools(unrestricted) {
+  Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps",
+    !unrestricted);
+  Services.prefs.setBoolPref("dom.apps.developer_mode", unrestricted);
+  // TODO: Remove once bug 1125916 is fixed.
+  Services.prefs.setBoolPref("network.disable.ipc.security", unrestricted);
+  Services.prefs.setBoolPref("dom.webcomponents.enabled", unrestricted);
+  let lock = settings.createLock();
+  lock.set("developer.menu.enabled", unrestricted, null);
+  lock.set("devtools.unrestricted", unrestricted, null);
+}
+
 ConsoleMessage.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIConsoleMessage]),
   toString: function() { return this.msg; }
 };
 
 const gFactoryResetFile = "__post_reset_cmd__";
 
 function ProcessGlobal() {}
@@ -94,27 +106,27 @@ ProcessGlobal.prototype = {
   },
 
   processCommandsFile: function(text) {
     log("processCommandsFile " + text);
     let lines = text.split("\n");
     lines.forEach((line) => {
       log(line);
       let params = line.split(" ");
-      if (params[0] == "wipe") {
-        this.wipeDir(params[1]);
-      } else if (params[0] == "root") {
-        log("unrestrict devtools");
-        Services.prefs.setBoolPref("devtools.debugger.forbid-certified-apps", false);
-        Services.prefs.setBoolPref("dom.apps.developer_mode", true);
-        // TODO: Remove once bug 1125916 is fixed.
-        Services.prefs.setBoolPref("network.disable.ipc.security", true);
-        Services.prefs.setBoolPref("dom.webcomponents.enabled", true);
-        let lock = settings.createLock();
-        lock.set("developer.menu.enabled", true, null);
+      switch (params[0]) {
+        case "root":
+          log("unrestrict devtools");
+          toggleUnrestrictedDevtools(true);
+          break;
+        case "wipe":
+          this.wipeDir(params[1]);
+        case "normal":
+          log("restrict devtools");
+          toggleUnrestrictedDevtools(false);
+          break;
       }
     });
   },
 
   cleanupAfterFactoryReset: function() {
     log("cleanupAfterWipe start");
 
     Cu.import("resource://gre/modules/osfile.jsm");
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
@@ -105,17 +105,17 @@
   <project name="platform/libcore" path="libcore" revision="baf7d8068dd501cfa338d3a8b1b87216d6ce0571"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="50c4430e32849530ced32680fd6ee98963b3f7ac"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="23404f05422c6bf3c39573325a4f4909167671b4"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
   <project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
   <project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="42fa2a0f14f965970a4b629a176bbd2666edf017"/>
   <project name="platform/external/curl" path="external/curl" revision="e68addd988448959ea8157c5de637346b4180c33"/>
   <project name="platform/external/icu4c" path="external/icu4c" revision="d3ec7428eb276db43b7ed0544e09344a6014806c"/>
   <project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="76c4bf4bc430a1b8317f2f21ef735867733e50cc"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
@@ -110,17 +110,17 @@
   <project name="platform/libcore" path="libcore" revision="e195beab082c09217318fc19250caeaf4c1bd800"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="feeb36c2bd4adfe285f98f5de92e0f3771b2c115"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="23404f05422c6bf3c39573325a4f4909167671b4"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="cfcef469537869947abb9aa1d656774cc2678d4c"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
   <project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
   <project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
   <project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="fe12a9e2268da653d1cd4c39ec89a42211d22f25"/>
   <!--original fetch url was http://sprdsource.spreadtrum.com:8085/b2g/android-->
   <remote fetch="https://git.mozilla.org/external/sprd-aosp" name="sprd-aosp"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,21 +14,21 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
-  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="22664edc4c73e5fe8f5095ff1d5549db78a2bc10"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="218a5637399d023f4326e12c8a486dad95403b6c"/>
+  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="10b3daf0093db94c64e78a72ac43a93b68976087"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
@@ -112,17 +112,17 @@
   <project name="platform/libnativehelper" path="libnativehelper" revision="4792069e90385889b0638e97ae62c67cdf274e22"/>
   <project name="platform/ndk" path="ndk" revision="7666b97bbaf1d645cdd6b4430a367b7a2bb53369"/>
   <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="f6ab40b3257abc07741188fd173ac392575cc8d2"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="e52099755d0bd3a579130eefe8e58066cc6c0cb6"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="02c32feb2fe97037be0ac4dace3a6a5025ac895d"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
@@ -110,31 +110,31 @@
   <project name="platform/libcore" path="libcore" revision="9877ade9617bb0db6e59aa2a54719a9bc92600f3"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="46c96ace65eb1ccab05bf15b9bf8e53e443039af"/>
   <project name="platform/ndk" path="ndk" revision="cb5519af32ae7b4a9c334913a612462ecd04c5d0"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="23404f05422c6bf3c39573325a4f4909167671b4"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="6aa61f8557a22039a30b42b7f283996381fd625d"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="b562b01c93de9578d5db537b6a602a38e1aaa0ce"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="387f03e815f57d536dd922706db1622bddba8d81"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
   <project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
   <project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
   <project name="platform/system/netd" path="system/netd" revision="36704b0da24debcab8090156568ac236315036bb"/>
   <project name="platform/system/security" path="system/security" revision="583374f69f531ba68fc3dcbff1f74893d2a96406"/>
   <project name="platform/system/vold" path="system/vold" revision="d4455b8cf361f8353e8aebac15ffd64b4aedd2b9"/>
   <project name="platform/external/icu4c" path="external/icu4c" remote="aosp" revision="b4c6379528887dc25ca9991a535a8d92a61ad6b6"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="f3cedd7fd9b1649aa5107d466be9078bb7602af6"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="9395eb5aa885cf6d305a202de6e9694a58a89717"/>
   <default remote="caf" revision="refs/tags/android-4.4.2_r1" sync-j="4"/>
   <!-- Emulator specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="72ffdf71c68a96309212eb13d63560d66db14c9e"/>
   <project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="f390788a00706c06e5248edfd8d27b365387e84a"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d2f58dbee70cba71bd3fad8cdd0fee620d10cf92"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c4d9746e5f1a3a2e6cb53d59d5d721e9888cd2e1"/>
   <project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="f37bd545063039e30a92f2550ae78c0e6e4e2d08"/>
   <project name="platform_external_wpa_supplicant_8" path="external/wpa_supplicant_8" remote="b2g" revision="0c6a6547cd1fd302fa2b0f6e375654df36bf0ec4"/>
-  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="42f61f665e7a9857da8cd14b455e15bae98e6b44"/>
+  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="de4bfffbbc2aabe5b5eca485e459da75e49097e2"/>
   <project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d82e00fb6380b4f6cea7a96213913ee9eb441239"/>
   <project name="platform/development" path="development" revision="5968ff4e13e0d696ad8d972281fc27ae5a12829b"/>
   <project name="android-sdk" path="sdk" remote="b2g" revision="0951179277915335251c5e11d242e4e1a8c2236f"/>
   <project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
 </manifest>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
   <!-- Stock Android things -->
   <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" revision="8af5ff6f5dced9eb5a8127459df6c75d24342204"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="30915518fa7ea07166efedc191a4f40aef516fe7"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" revision="96eee58e3389fb05a835310d6a06a6ba4486097a"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" revision="7c8a46698171aa2e0be09edb43d15a6acf832770"/>
   <project groups="pdk,linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" revision="24b2038be8a636fd4a5d21f0abae1e466b07bcf7"/>
@@ -122,17 +122,17 @@
   <project name="platform/libcore" path="libcore" revision="bdec7d684c083760bef7bc4ba2429cceccaaf7d0"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="27bcc086236cedd31c056303e255c6d0ea3d4a50"/>
   <project name="platform/ndk" path="ndk" revision="42e85f81cc6c74af145056ee80b06e520cccb9a7"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="f105a2d852c988fb1aa16a1e758ca7f93dd54fe9"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="1d080491f26dfdfd76d5bbc3e6b40c660e8565af"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="2c0d193349c55337e37196a7f2d5cef37753ed3e"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="61a10cbd19d6b7fc052a8cb92dfa1b37b93754f3"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="9e892a67a01671f312c76b0880dedaa6ba478148"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
   <project name="platform/system/extras" path="system/extras" revision="47fa016e2248b80aebd5928402c7409f8e0ca64e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
   <project name="platform/system/media" path="system/media" revision="70bfebc66d9c6a4c614a8c7efde90e8e7e1d8641"/>
   <project name="platform/system/netd" path="system/netd" revision="d113f0ceefa9ce29eb3c86e2d23c7417a70b4048"/>
   <project name="platform/system/security" path="system/security" revision="94e1617f6f2bc2286d005e79cffa6bf0721b06b3"/>
   <project name="platform/system/vold" path="system/vold" revision="c065e301e38ea0c241164e2a373e1ecefbeaf2ec"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="e372b6a77f71c8f9fbbf6f8adbfa7bf8ef45dc60"/>
   <project name="platform_frameworks_base" path="frameworks/base" remote="b2g" revision="04e26ebdc36ca83f4ee3e9e2082b3fcf04c5b971"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,21 +14,21 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="173b3104bfcbd23fc9dccd4b0035fc49aae3d444">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
-  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="22664edc4c73e5fe8f5095ff1d5549db78a2bc10"/>
-  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="218a5637399d023f4326e12c8a486dad95403b6c"/>
+  <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="aac9cc4bb94cf720baf8f7ee419b4d76ac86b1ac"/>
+  <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="10b3daf0093db94c64e78a72ac43a93b68976087"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="apitrace" path="external/apitrace" remote="apitrace" revision="34ea6163f9f0e0122fb0bb03607eccdca31ced7a"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
@@ -104,17 +104,17 @@
   <project name="platform/libcore" path="libcore" revision="baf7d8068dd501cfa338d3a8b1b87216d6ce0571"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="50c4430e32849530ced32680fd6ee98963b3f7ac"/>
   <project name="platform/ndk" path="ndk" revision="e58ef003be4306bb53a8c11331146f39e4eab31f"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="23404f05422c6bf3c39573325a4f4909167671b4"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="c792f0bd9fff7aea2887c60bbb3a9bbdb534ffa3"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="6a1bb59af65b6485b1090522f66fac95c3f9e22c"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="69d524e80cdf3981006627c65ac85f3a871238a3"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
   <project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
   <project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
   <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
   <project name="platform/system/vold" path="system/vold" revision="42fa2a0f14f965970a4b629a176bbd2666edf017"/>
   <project name="platform/external/curl" path="external/curl" revision="e68addd988448959ea8157c5de637346b4180c33"/>
   <project name="platform/external/icu4c" path="external/icu4c" revision="d3ec7428eb276db43b7ed0544e09344a6014806c"/>
   <project name="platform/hardware/libhardware_legacy" path="hardware/libhardware_legacy" revision="76c4bf4bc430a1b8317f2f21ef735867733e50cc"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "6d477a7884273886605049b20f60af5c1583a150", 
+        "git_revision": "ae4ef3f63b921fa46c20d9d4feb271713fb014ba", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "c7beef2b034d2308a85e8c866395c78245bc554f", 
+    "revision": "d9730e79977fe0a3416596d1ec9e942ed6dc15a9", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4efd19d199ae52656604f794c5a77518400220fd">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
@@ -112,17 +112,17 @@
   <project name="platform/libnativehelper" path="libnativehelper" revision="4792069e90385889b0638e97ae62c67cdf274e22"/>
   <project name="platform/ndk" path="ndk" revision="7666b97bbaf1d645cdd6b4430a367b7a2bb53369"/>
   <project name="platform/prebuilts/misc" path="prebuilts/misc" revision="f6ab40b3257abc07741188fd173ac392575cc8d2"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="e52099755d0bd3a579130eefe8e58066cc6c0cb6"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="02c32feb2fe97037be0ac4dace3a6a5025ac895d"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="842e33e43a55ea44833b9e23e4d180fa17c843af"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5db24726f0f42124304195a6bdea129039eeeaeb"/>
   <project name="platform/system/bluetooth" path="system/bluetooth" revision="930ae098543881f47eac054677726ee4b998b2f8"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
   <project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
   <project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
   <project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
   <project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
   <project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
   <project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
   <default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="6d477a7884273886605049b20f60af5c1583a150"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="ae4ef3f63b921fa46c20d9d4feb271713fb014ba"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="fffc68521ebb1501d6b015c6d1c4a17a04fdb2e2"/>
+  <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5deaf27fd266316f27e68206cc3be0e6f47ded54"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="4a697ec692aa762eb8cdb7812f5a051c5870020f"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="5c487ecd9afbcea1d507b9e4dfd09b3a8787fa65"/>
   <!-- Stock Android things -->
   <project groups="pdk,linux" name="platform/prebuilts/clang/linux-x86/host/3.5" path="prebuilts/clang/linux-x86/host/3.5" revision="ffc05a232799fe8fcb3e47b7440b52b1fb4244c0"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" path="prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.8" revision="337e0ef5e40f02a1ae59b90db0548976c70a7226"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.8" revision="8af5ff6f5dced9eb5a8127459df6c75d24342204"/>
   <project groups="pdk,linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.8" revision="30915518fa7ea07166efedc191a4f40aef516fe7"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.6" revision="96eee58e3389fb05a835310d6a06a6ba4486097a"/>
   <project groups="pdk,linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.11-4.8" revision="7c8a46698171aa2e0be09edb43d15a6acf832770"/>
   <project groups="pdk,linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" path="prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.8" revision="24b2038be8a636fd4a5d21f0abae1e466b07bcf7"/>
@@ -122,17 +122,17 @@
   <project name="platform/libcore" path="libcore" revision="bdec7d684c083760bef7bc4ba2429cceccaaf7d0"/>
   <project name="platform/libnativehelper" path="libnativehelper" revision="27bcc086236cedd31c056303e255c6d0ea3d4a50"/>
   <project name="platform/ndk" path="ndk" revision="42e85f81cc6c74af145056ee80b06e520cccb9a7"/>
   <project name="platform_prebuilts_misc" path="prebuilts/misc" remote="b2g" revision="f105a2d852c988fb1aa16a1e758ca7f93dd54fe9"/>
   <project name="platform/prebuilts/ndk" path="prebuilts/ndk" revision="1d080491f26dfdfd76d5bbc3e6b40c660e8565af"/>
   <project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="2c0d193349c55337e37196a7f2d5cef37753ed3e"/>
   <project name="platform/prebuilts/sdk" path="prebuilts/sdk" revision="61a10cbd19d6b7fc052a8cb92dfa1b37b93754f3"/>
   <project name="platform/prebuilts/tools" path="prebuilts/tools" revision="9e892a67a01671f312c76b0880dedaa6ba478148"/>
-  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="4132c66e4bc78e119eb1cf34b6cf77db8e714e9a"/>
+  <project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9afc4e0e3e883f3a22a5eb94470d50f4b1cfe5c5"/>
   <project name="platform/system/extras" path="system/extras" revision="47fa016e2248b80aebd5928402c7409f8e0ca64e"/>
   <project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3c5405863d2002f665ef2b901abb3853c420129b"/>
   <project name="platform/system/media" path="system/media" revision="70bfebc66d9c6a4c614a8c7efde90e8e7e1d8641"/>
   <project name="platform/system/netd" path="system/netd" revision="d113f0ceefa9ce29eb3c86e2d23c7417a70b4048"/>
   <project name="platform/system/security" path="system/security" revision="94e1617f6f2bc2286d005e79cffa6bf0721b06b3"/>
   <project name="platform/system/vold" path="system/vold" revision="c065e301e38ea0c241164e2a373e1ecefbeaf2ec"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="e372b6a77f71c8f9fbbf6f8adbfa7bf8ef45dc60"/>
   <project name="platform_frameworks_base" path="frameworks/base" remote="b2g" revision="04e26ebdc36ca83f4ee3e9e2082b3fcf04c5b971"/>
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -20,21 +20,28 @@ MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/bran
 MOZ_SAFE_BROWSING=1
 MOZ_SERVICES_COMMON=1
 MOZ_SERVICES_METRICS=1
 MOZ_CAPTIVEDETECT=1
 
 MOZ_WEBSMS_BACKEND=1
 MOZ_NO_SMART_CARDS=1
 MOZ_APP_STATIC_INI=1
-NSS_NO_LIBPKIX=1
 NSS_DISABLE_DBM=1
 MOZ_NO_EV_CERTS=1
 MOZ_DISABLE_EXPORT_JS=1
 
+# Bug 1171082 - Broken on Windows B2G Desktop
+if test "$OS_TARGET" != "WINNT"; then
+MOZ_WEBSPEECH=1
+MOZ_WEBSPEECH_MODELS=1
+MOZ_WEBSPEECH_POCKETSPHINX=1
+MOZ_WEBSPEECH_TEST_BACKEND=1
+fi # !WINNT
+
 if test "$OS_TARGET" = "Android"; then
 MOZ_CAPTURE=1
 MOZ_RAW=1
 MOZ_AUDIO_CHANNEL_MANAGER=1
 fi
 
 # use custom widget for html:select
 MOZ_USE_NATIVE_POPUP_WINDOWS=1
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -130,16 +130,19 @@
 #endif
 @RESPATH@/blocklist.xml
 @RESPATH@/ua-update.json
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
 @RESPATH@/run-mozilla.sh
 #endif
 #endif
+#ifdef MOZ_WEBSPEECH_MODELS
+@BINPATH@/models/
+#endif
 
 ; [Components]
 @RESPATH@/components/components.manifest
 @RESPATH@/components/alerts.xpt
 #ifdef ACCESSIBILITY
 #ifdef XP_WIN32
 @BINPATH@/AccessibleMarshal.dll
 #endif
@@ -276,16 +279,17 @@
 @RESPATH@/components/necko_about.xpt
 @RESPATH@/components/necko_cache.xpt
 @RESPATH@/components/necko_cache2.xpt
 @RESPATH@/components/necko_cookie.xpt
 @RESPATH@/components/necko_dns.xpt
 @RESPATH@/components/necko_file.xpt
 @RESPATH@/components/necko_ftp.xpt
 @RESPATH@/components/necko_http.xpt
+@RESPATH@/components/necko_mdns.xpt
 @RESPATH@/components/necko_res.xpt
 @RESPATH@/components/necko_socket.xpt
 @RESPATH@/components/necko_strconv.xpt
 @RESPATH@/components/necko_viewsource.xpt
 @RESPATH@/components/necko_websocket.xpt
 @RESPATH@/components/necko_wifi.xpt
 @RESPATH@/components/necko_wyciwyg.xpt
 #ifdef MOZ_RTSP
--- a/browser/app/moz.build
+++ b/browser/app/moz.build
@@ -55,16 +55,19 @@ if CONFIG['_MSC_VER']:
     # Always enter a Windows program through wmain, whether or not we're
     # a console application.
     WIN32_EXE_LDFLAGS += ['-ENTRY:wmainCRTStartup']
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     RCINCLUDE = 'splash.rc'
     DEFINES['MOZ_PHOENIX'] = True
 
+for cdm in CONFIG['MOZ_EME_MODULES']:
+    DEFINES['MOZ_%s_EME' % cdm.upper()] = True
+
 # Control the default heap size.
 # This is the heap returned by GetProcessHeap().
 # As we use the CRT heap, the default size is too large and wastes VM.
 #
 # The default heap size is 1MB on Win32.
 # The heap will grow if need be.
 #
 # Set it to 256k.  See bug 127069.
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -173,19 +173,17 @@ pref("app.update.mode", 1);
 pref("app.update.silent", false);
 
 // If set to true, the hamburger button will show badges for update events.
 #ifndef RELEASE_BUILD
 pref("app.update.badge", true);
 #else
 pref("app.update.badge", false);
 #endif
-// Give the user x seconds to reboot before showing a badge on the hamburger
-// button. default=4 days
-pref("app.update.badgeWaitTime", 345600);
+// app.update.badgeWaitTime is in branding section
 
 // If set to true, the Update Service will apply updates in the background
 // when it finishes downloading them.
 pref("app.update.staging.enabled", true);
 
 // Update service URL:
 pref("app.update.url", "https://aus4.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml");
 // app.update.url.manual is in branding section
@@ -1744,23 +1742,19 @@ pref("loop.fxa_oauth.profile", "");
 pref("loop.support_url", "https://support.mozilla.org/kb/group-conversations-firefox-hello-webrtc");
 pref("loop.contacts.gravatars.show", false);
 pref("loop.contacts.gravatars.promo", true);
 pref("loop.browserSharing.showInfoBar", true);
 pref("loop.contextInConversations.enabled", true);
 
 pref("social.sidebar.unload_timeout_ms", 10000);
 
-// activation from inside of share panel is possible if activationPanelEnabled
+// Activation from inside of share panel is possible if activationPanelEnabled
 // is true. Pref'd off for release while usage testing is done through beta.
-#ifdef EARLY_BETA_OR_EARLIER
 pref("social.share.activationPanelEnabled", true);
-#else
-pref("social.share.activationPanelEnabled", false);
-#endif
 pref("social.shareDirectory", "https://activations.cdn.mozilla.net/sharePanel.html");
 
 pref("dom.identity.enabled", false);
 
 // Block insecure active content on https pages
 pref("security.mixed_content.block_active_content", true);
 
 // 1 = allow MITM for certificate pinning checks.
@@ -1838,30 +1832,32 @@ pref("identity.fxaccounts.migrateToDevEd
 #ifdef MOZ_WIDGET_GTK
 pref("ui.key.menuAccessKeyFocuses", true);
 #endif
 
 // Encrypted media extensions.
 pref("media.eme.enabled", true);
 pref("media.eme.apiVisible", true);
 
-#ifdef XP_WIN
+#ifdef MOZ_ADOBE_EME
+pref("browser.eme.ui.enabled", true);
 pref("media.gmp-eme-adobe.enabled", true);
-pref("browser.eme.ui.enabled", true);
 #endif
 
 // Play with different values of the decay time and get telemetry,
 // 0 means to randomize (and persist) the experiment value in users' profiles,
 // -1 means no experiment is run and we use the preferred value for frecency (6h)
 pref("browser.cache.frecency_experiment", 0);
 
 pref("browser.translation.detectLanguage", false);
 pref("browser.translation.neverForLanguages", "");
 // Show the translation UI bits, like the info bar, notification icon and preferences.
 pref("browser.translation.ui.show", false);
+// Allows to define the translation engine. Bing is default, Yandex may optionally switched on.
+pref("browser.translation.engine", "bing");
 
 // Telemetry settings.
 // Determines if Telemetry pings can be archived locally.
 pref("toolkit.telemetry.archive.enabled", true);
 
 // Telemetry experiments settings.
 pref("experiments.enabled", true);
 pref("experiments.manifest.fetchIntervalSeconds", 86400);
--- a/browser/base/content/abouthealthreport/abouthealth.js
+++ b/browser/base/content/abouthealthreport/abouthealth.js
@@ -44,28 +44,73 @@ let healthReportWrapper = {
       };
       healthReportWrapper.injectData("prefs", prefs);
     }
     catch (ex) {
       healthReportWrapper.reportFailure(healthReportWrapper.ERROR_PREFS_FAILED);
     }
   },
 
+  sendTelemetryPingList: function () {
+    console.log("AboutHealthReport: Collecting Telemetry ping list.");
+    MozSelfSupport.getTelemetryPingList().then((list) => {
+      console.log("AboutHealthReport: Sending Telemetry ping list.");
+      this.injectData("telemetry-ping-list", list);
+    }).catch((ex) => {
+      console.log("AboutHealthReport: Collecting ping list failed: " + ex);
+    });
+  },
+
+  sendTelemetryPingData: function (pingId) {
+    console.log("AboutHealthReport: Collecting Telemetry ping data.");
+    MozSelfSupport.getTelemetryPing(pingId).then((ping) => {
+      console.log("AboutHealthReport: Sending Telemetry ping data.");
+      this.injectData("telemetry-ping-data", {
+        id: pingId,
+        pingData: ping,
+      });
+    }).catch((ex) => {
+      console.log("AboutHealthReport: Loading ping data failed: " + ex);
+      this.injectData("telemetry-ping-data", {
+        id: pingId,
+        error: "error-generic",
+      });
+    });
+  },
+
+  sendCurrentEnvironment: function () {
+    console.log("AboutHealthReport: Sending Telemetry environment data.");
+    MozSelfSupport.getCurrentTelemetryEnvironment().then((environment) => {
+      this.injectData("telemetry-current-environment-data", environment);
+    }).catch((ex) => {
+      console.log("AboutHealthReport: Collecting current environment data failed: " + ex);
+    });
+  },
+
+  sendCurrentPingData: function () {
+    console.log("AboutHealthReport: Sending current Telemetry ping data.");
+    MozSelfSupport.getCurrentTelemetrySubsessionPing().then((ping) => {
+      this.injectData("telemetry-current-ping-data", ping);
+    }).catch((ex) => {
+      console.log("AboutHealthReport: Collecting current ping data failed: " + ex);
+    });
+  },
+
   refreshPayload: function () {
     MozSelfSupport.getHealthReportPayload().then(this.updatePayload,
                                                  this.handlePayloadFailure);
   },
 
   updatePayload: function (payload) {
     healthReportWrapper.injectData("payload", JSON.stringify(payload));
   },
 
   injectData: function (type, content) {
     let report = this._getReportURI();
-    
+
     // file URIs can't be used for targetOrigin, so we use "*" for this special case
     // in all other cases, pass in the URL to the report so we properly restrict the message dispatch
     let reportUrl = report.scheme == "file" ? "*" : report.spec;
 
     let data = {
       type: type,
       content: content
     }
@@ -83,16 +128,28 @@ let healthReportWrapper = {
         this.setDataSubmission(true);
         break;
       case "RequestCurrentPrefs":
         this.updatePrefState();
         break;
       case "RequestCurrentPayload":
         this.refreshPayload();
         break;
+      case "RequestTelemetryPingList":
+        this.sendTelemetryPingList();
+        break;
+      case "RequestTelemetryPingData":
+        this.sendTelemetryPingData(evt.detail.id);
+        break;
+      case "RequestCurrentEnvironment":
+        this.sendCurrentEnvironment();
+        break;
+      case "RequestCurrentPingData":
+        this.sendCurrentPingData();
+        break;
       default:
         Cu.reportError("Unexpected remote command received: " + evt.detail.command + ". Ignoring command.");
         break;
     }
   },
 
   initRemotePage: function () {
     let iframe = document.getElementById("remote-report").contentDocument;
--- a/browser/base/content/abouthome/aboutHome.xhtml
+++ b/browser/base/content/abouthome/aboutHome.xhtml
@@ -59,17 +59,17 @@
       </div>
     </div>
     <div class="spacer"/>
 
     <div id="launcher">
       <button class="launchButton" id="downloads">&abouthome.downloadsButton.label;</button>
       <button class="launchButton" id="bookmarks">&abouthome.bookmarksButton.label;</button>
       <button class="launchButton" id="history">&abouthome.historyButton.label;</button>
-      <button class="launchButton" id="apps">&abouthome.appsButton.label;</button>
+      <button class="launchButton" id="apps">&abouthome.appsButton2.label;</button>
       <button class="launchButton" id="addons">&abouthome.addonsButton.label;</button>
       <button class="launchButton" id="sync">&abouthome.syncButton.label;</button>
 #ifdef XP_WIN
       <button class="launchButton" id="settings">&abouthome.preferencesButtonWin.label;</button>
 #else
       <button class="launchButton" id="settings">&abouthome.preferencesButtonUnix.label;</button>
 #endif
       <div id="restorePreviousSessionSeparator"/>
--- a/browser/base/content/browser-fullScreen.js
+++ b/browser/base/content/browser-fullScreen.js
@@ -166,19 +166,17 @@ var FullScreen = {
     // Exit DOM full-screen mode upon open, close, or change tab.
     gBrowser.tabContainer.addEventListener("TabOpen", this.exitDomFullScreen);
     gBrowser.tabContainer.addEventListener("TabClose", this.exitDomFullScreen);
     gBrowser.tabContainer.addEventListener("TabSelect", this.exitDomFullScreen);
 
     // Add listener to detect when the fullscreen window is re-focused.
     // If a fullscreen window loses focus, we show a warning when the
     // fullscreen window is refocused.
-    if (!this.useLionFullScreen) {
-      window.addEventListener("activate", this);
-    }
+    window.addEventListener("activate", this);
 
     // Cancel any "hide the toolbar" animation which is in progress, and make
     // the toolbar hide immediately.
     this.hideNavToolbox(true);
     this._fullScrToggler.hidden = true;
   },
 
   cleanup: function () {
@@ -190,18 +188,17 @@ var FullScreen = {
     }
   },
 
   cleanupDomFullscreen: function () {
     this.cancelWarning();
     gBrowser.tabContainer.removeEventListener("TabOpen", this.exitDomFullScreen);
     gBrowser.tabContainer.removeEventListener("TabClose", this.exitDomFullScreen);
     gBrowser.tabContainer.removeEventListener("TabSelect", this.exitDomFullScreen);
-    if (!this.useLionFullScreen)
-      window.removeEventListener("activate", this);
+    window.removeEventListener("activate", this);
 
     document.documentElement.removeAttribute("inDOMFullscreen");
     this.showNavToolbox();
     // If we are still in fullscreen mode, re-hide
     // the toolbox with animation.
     if (window.fullScreen) {
       this._shouldAnimate = true;
       this.hideNavToolbox();
--- a/browser/base/content/browser-fxaccounts.js
+++ b/browser/base/content/browser-fxaccounts.js
@@ -26,16 +26,17 @@ let gFxAccounts = {
   get topics() {
     // Do all this dance to lazy-load FxAccountsCommon.
     delete this.topics;
     return this.topics = [
       "weave:service:ready",
       "weave:service:sync:start",
       "weave:service:login:error",
       "weave:service:setup-complete",
+      "weave:ui:login:error",
       "fxa-migration:state-changed",
       this.FxAccountsCommon.ONVERIFIED_NOTIFICATION,
       this.FxAccountsCommon.ONLOGOUT_NOTIFICATION,
       "weave:notification:removed",
     ];
   },
 
   get button() {
@@ -239,18 +240,20 @@ let gFxAccounts = {
     let doUpdate = userData => {
       // Reset the button to its original state.
       this.button.setAttribute("label", defaultLabel);
       this.button.removeAttribute("tooltiptext");
       this.button.removeAttribute("fxastatus");
 
       if (!this._inCustomizationMode) {
         if (this.loginFailed) {
+          let tooltipDescription = this.strings.formatStringFromName("reconnectDescription", [userData.email], 1);
           this.button.setAttribute("fxastatus", "error");
           this.button.setAttribute("label", errorLabel);
+          this.button.setAttribute("tooltiptext", tooltipDescription);
         } else if (userData) {
           this.button.setAttribute("fxastatus", "signedin");
           this.button.setAttribute("label", userData.email);
           this.button.setAttribute("tooltiptext", userData.email);
         }
       }
     }
     fxAccounts.getSignedInUser().then(userData => {
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -24,17 +24,17 @@
                           command="cmd_newNavigator"/>
                 <menuitem id="menu_newPrivateWindow"
                           label="&newPrivateWindow.label;"
                           accesskey="&newPrivateWindow.accesskey;"
                           command="Tools:PrivateBrowsing"
                           key="key_privatebrowsing"/>
 #ifdef E10S_TESTING_ONLY
                 <menuitem id="menu_newNonRemoteWindow"
-                          label="New Non-e10s Window"
+                          label="&newNonRemoteWindow.label;"
                           hidden="true"
                           command="Tools:NonRemoteWindow"/>
 #endif
 #ifdef MAC_NON_BROWSER_WINDOW
                 <menuitem id="menu_openLocation"
                           label="&openLocationCmd.label;"
                           command="Browser:OpenLocation"
                           key="focusURLBar"/>
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -299,19 +299,22 @@ SocialActivationListener = {
           SocialSidebar.show(provider.origin);
         }
         if (provider.shareURL) {
           // Ensure that the share button is somewhere usable.
           // SocialShare.shareButton may return null if it is in the menu-panel
           // and has never been visible, so we check the widget directly. If
           // there is no area for the widget we move it into the toolbar.
           let widget = CustomizableUI.getWidget("social-share-button");
-          if (!widget.areaType) {
+          // If the panel is already open, we can be sure that the provider can
+          // already be accessed, possibly anchored to another toolbar button.
+          // In that case we don't move the widget.
+          if (!widget.areaType && SocialShare.panel.state != "open") {
             CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
-            // ensure correct state
+            // Ensure correct state.
             SocialUI.onCustomizeEnd(window);
           }
 
           // make this new provider the selected provider. If the panel hasn't
           // been opened, we need to make the frame first.
           SocialShare._createFrame();
           SocialShare.iframe.setAttribute('src', 'data:text/plain;charset=utf8,');
           SocialShare.iframe.setAttribute('origin', provider.origin);
@@ -468,16 +471,19 @@ SocialShare = {
   },
 
   // Share panel may be attached to the overflow or menu button depending on
   // customization, we need to manage open state of the anchor.
   get anchor() {
     let widget = CustomizableUI.getWidget("social-share-button");
     return widget.forWindow(window).anchor;
   },
+  // Holds the anchor node in use whilst the panel is open, because it may vary.
+  _currentAnchor: null,
+
   get panel() {
     return document.getElementById("social-share-panel");
   },
 
   get iframe() {
     // panel.firstChild is our toolbar hbox, panel.lastChild is the iframe
     // container hbox used for an interstitial "loading" graphic
     return this.panel.lastChild.firstChild;
@@ -573,36 +579,37 @@ SocialShare = {
     return widget.forWindow(window).node;
   },
 
   _onclick: function() {
     Services.telemetry.getHistogramById("SOCIAL_PANEL_CLICKS").add(0);
   },
 
   onShowing: function() {
-    this.anchor.setAttribute("open", "true");
+    (this._currentAnchor || this.anchor).setAttribute("open", "true");
     this.iframe.addEventListener("click", this._onclick, true);
   },
 
   onHidden: function() {
-    this.anchor.removeAttribute("open");
+    (this._currentAnchor || this.anchor).removeAttribute("open");
+    this._currentAnchor = null;
     this.iframe.removeEventListener("click", this._onclick, true);
     this.iframe.setAttribute("src", "data:text/plain;charset=utf8,");
     // make sure that the frame is unloaded after it is hidden
     this.iframe.docShell.createAboutBlankContentViewer(null);
     this.currentShare = null;
     // share panel use is over, purge any history
     if (this.iframe.sessionHistory) {
       let purge = this.iframe.sessionHistory.count;
       if (purge > 0)
         this.iframe.sessionHistory.PurgeHistory(purge);
     }
   },
 
-  sharePage: function(providerOrigin, graphData, target) {
+  sharePage: function(providerOrigin, graphData, target, anchor) {
     // if providerOrigin is undefined, we use the last-used provider, or the
     // current/default provider.  The provider selection in the share panel
     // will call sharePage with an origin for us to switch to.
     this._createFrame();
     let iframe = this.iframe;
 
     // graphData is an optional param that either defines the full set of data
     // to be shared, or partial data about the current page. It is set by a call
@@ -625,40 +632,40 @@ SocialShare = {
         messageManager.removeMessageListener("PageMetadata:PageDataResult", _dataFn);
         let pageData = msg.json;
         if (graphData) {
           // overwrite data retreived from page with data given to us as a param
           for (let p in graphData) {
             pageData[p] = graphData[p];
           }
         }
-        this.sharePage(providerOrigin, pageData, target);
+        this.sharePage(providerOrigin, pageData, target, anchor);
       });
       gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetPageData");
       return;
     }
     // if this is a share of a selected item, get any microdata
     if (!pageData.microdata && target) {
       messageManager.addMessageListener("PageMetadata:MicrodataResult", _dataFn = (msg) => {
         messageManager.removeMessageListener("PageMetadata:MicrodataResult", _dataFn);
         pageData.microdata = msg.data;
-        this.sharePage(providerOrigin, pageData, target);
+        this.sharePage(providerOrigin, pageData, target, anchor);
       });
       gBrowser.selectedBrowser.messageManager.sendAsyncMessage("PageMetadata:GetMicrodata", null, { target });
       return;
     }
     this.currentShare = pageData;
 
     let provider;
     if (providerOrigin)
       provider = Social._getProviderFromOrigin(providerOrigin);
     else
       provider = this.getSelectedProvider();
     if (!provider || !provider.shareURL) {
-      this.showDirectory();
+      this.showDirectory(anchor);
       return;
     }
     // check the menu button
     let hbox = document.getElementById("social-share-provider-buttons");
     let btn = hbox.querySelector("[origin='" + provider.origin + "']");
     if (btn)
       btn.checked = true;
 
@@ -708,20 +715,20 @@ SocialShare = {
       if (purge > 0)
         iframe.sessionHistory.PurgeHistory(purge);
     }
 
     // always ensure that origin belongs to the endpoint
     let uri = Services.io.newURI(shareEndpoint, null, null);
     iframe.setAttribute("origin", provider.origin);
     iframe.setAttribute("src", shareEndpoint);
-    this._openPanel();
+    this._openPanel(anchor);
   },
 
-  showDirectory: function() {
+  showDirectory: function(anchor) {
     this._createFrame();
     let iframe = this.iframe;
     if (iframe.getAttribute("src") == "about:providerdirectory")
       return;
     iframe.removeAttribute("origin");
     iframe.parentNode.setAttribute("loading", "true");
     iframe.addEventListener("DOMContentLoaded", function _dcl(e) {
       iframe.removeEventListener("DOMContentLoaded", _dcl, true);
@@ -735,21 +742,22 @@ SocialShare = {
       SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
 
       iframe.addEventListener("unload", function panelBrowserOnload(e) {
         iframe.removeEventListener("unload", panelBrowserOnload, true);
         SocialShare._dynamicResizer.stop();
       }, true);
     }, true);
     iframe.setAttribute("src", "about:providerdirectory");
-    this._openPanel();
+    this._openPanel(anchor);
   },
 
-  _openPanel: function() {
-    let anchor = document.getAnonymousElementByAttribute(this.anchor, "class", "toolbarbutton-icon");
+  _openPanel: function(anchor) {
+    this._currentAnchor = anchor || this.anchor;
+    anchor = document.getAnonymousElementByAttribute(this._currentAnchor, "class", "toolbarbutton-icon");
     this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
     Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
   }
 };
 
 SocialSidebar = {
   _openStartTime: 0,
 
--- a/browser/base/content/browser-syncui.js
+++ b/browser/base/content/browser-syncui.js
@@ -222,16 +222,17 @@ let gSyncUI = {
     this.clearError(title);
   },
 
   onSetupComplete: function SUI_onSetupComplete() {
     this.onLoginFinish();
   },
 
   onLoginError: function SUI_onLoginError() {
+    this.log.debug("onLoginError: login=${login}, sync=${sync}", Weave.Status);
     // Note: This is used for *both* Sync and ReadingList login errors.
     // if login fails, any other notifications are essentially moot
     Weave.Notifications.removeAll();
 
     // if we haven't set up the client, don't show errors
     if (this._needsSetup()) {
       this.updateUI();
       return;
@@ -457,16 +458,24 @@ let gSyncUI = {
     // Clear out sync failures on a successful sync
     this.clearError(title);
   },
 
   // Return true if the reading-list is in a "prolonged" error state. That
   // engine doesn't impose what that means, so calculate it here. For
   // consistency, we just use the sync prefs.
   isProlongedReadingListError() {
+    // If the readinglist scheduler is disabled we don't treat it as prolonged.
+    let enabled = false;
+    try {
+      enabled = Services.prefs.getBoolPref("readinglist.scheduler.enabled");
+    } catch (_) {}
+    if (!enabled) {
+      return false;
+    }
     let lastSync, threshold, prolonged;
     try {
       lastSync = new Date(Services.prefs.getCharPref("readinglist.scheduler.lastSync"));
       threshold = new Date(Date.now() - Services.prefs.getIntPref("services.sync.errorhandler.networkFailureReportTimeout") * 1000);
       prolonged = lastSync <= threshold;
     } catch (ex) {
       // no pref, assume not prolonged.
       prolonged = false;
@@ -515,17 +524,17 @@ let gSyncUI = {
     let notification =
       new Weave.Notification(title, description, null, priority, buttons);
     Weave.Notifications.replaceTitle(notification);
 
     this.updateUI();
   },
 
   onSyncError: function SUI_onSyncError() {
-    this.log.debug("onSyncError");
+    this.log.debug("onSyncError: login=${login}, sync=${sync}", Weave.Status);
     let title = this._stringBundle.GetStringFromName("error.sync.title");
 
     if (Weave.Status.login != Weave.LOGIN_SUCCEEDED) {
       this.onLoginError();
       return;
     }
 
     let description;
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -631,32 +631,16 @@ window[chromehidden~="toolbar"] toolbar:
 #historySwipeAnimationCurrentPage {
   background-image: -moz-element(#historySwipeAnimationCurrentPageSnapshot);
 }
 
 #historySwipeAnimationNextPage {
   background-image: -moz-element(#historySwipeAnimationNextPageSnapshot);
 }
 
-/* Identity UI */
-#identity-popup-content-box:not(.chromeUI) > #identity-popup-brandName,
-#identity-popup-content-box:not(.chromeUI) > #identity-popup-chromeLabel,
-#identity-popup-content-box.chromeUI > .identity-popup-label:not(#identity-popup-brandName):not(#identity-popup-chromeLabel),
-#identity-popup-content-box.chromeUI > .identity-popup-description,
-#identity-popup.chromeUI > #identity-popup-button-container,
-#identity-popup-content-box.unknownIdentity > #identity-popup-connectedToLabel ,
-#identity-popup-content-box.unknownIdentity > #identity-popup-runByLabel ,
-#identity-popup-content-box.unknownIdentity > #identity-popup-content-host ,
-#identity-popup-content-box.unknownIdentity > #identity-popup-content-owner ,
-#identity-popup-content-box.verifiedIdentity > #identity-popup-connectedToLabel2 ,
-#identity-popup-content-box.verifiedDomain > #identity-popup-connectedToLabel2 ,
-#identity-popup-content-box.verifiedDomain > #identity-popup-runByLabel {
-  display: none;
-}
-
 /*  Full Screen UI */
 
 #fullscr-toggler {
   height: 1px;
   background: black;
 }
 
 #full-screen-warning-container {
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -981,17 +981,16 @@ var gBrowserInit = {
     DevEdition.init();
     AboutPrivateBrowsingListener.init();
 
     let mm = window.getGroupMessageManager("browsers");
     mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
     mm.loadFrameScript("chrome://browser/content/content.js", true);
     mm.loadFrameScript("chrome://browser/content/content-UITour.js", true);
     mm.loadFrameScript("chrome://global/content/manifestMessages.js", true);
-    mm.loadFrameScript("chrome://global/content/viewSource-content.js", true);
 
     window.messageManager.addMessageListener("Browser:LoadURI", RedirectLoad);
 
     // initialize observers and listeners
     // and give C++ access to gBrowser
     XULBrowserWindow.init();
     window.QueryInterface(Ci.nsIInterfaceRequestor)
           .getInterface(nsIWebNavigation)
@@ -6681,24 +6680,16 @@ var gIdentityHandler = {
     this._identityIconLabel = document.getElementById("identity-icon-label");
     this._identityIconCountryLabel = document.getElementById("identity-icon-country-label");
     this._identityIcon = document.getElementById("page-proxy-favicon");
     this._permissionsContainer = document.getElementById("identity-popup-permissions");
     this._permissionList = document.getElementById("identity-popup-permission-list");
   },
 
   /**
-   * Handler for commands on the help button in the "identity-popup" panel.
-   */
-  handleHelpCommand : function(event) {
-    openHelpLink("secure-connection");
-    this._identityPopup.hidePopup();
-  },
-
-  /**
    * Handler for mouseclicks on the "More Information" button in the
    * "identity-popup" panel.
    */
   handleMoreInfoClick : function(event) {
     displaySecurityInfo();
     event.stopPropagation();
     this._identityPopup.hidePopup();
   },
@@ -7046,18 +7037,16 @@ var gIdentityHandler = {
       self._identityBox.removeAttribute("open");
     }, false);
 
     // Now open the popup, anchored off the primary chrome element
     this._identityPopup.openPopup(this._identityIcon, "bottomcenter topleft");
   },
 
   onPopupShown : function(event) {
-    document.getElementById('identity-popup-more-info-button').focus();
-
     this._identityPopup.addEventListener("blur", this, true);
     this._identityPopup.addEventListener("popuphidden", this);
   },
 
   onDragStart: function (event) {
     if (gURLBar.getAttribute("pageproxystate") != "valid")
       return;
 
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -4,16 +4,17 @@
 #
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 <?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/content/places/places.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
+<?xml-stylesheet href="chrome://browser/skin/controlcenter/panel.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/customizableui/panelUIOverlay.css" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
 <?xml-stylesheet href="chrome://browser/skin/browser-lightweightTheme.css" type="text/css"?>
 
 <?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/baseMenuOverlay.xul"?>
 <?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
 
@@ -401,77 +402,16 @@
                               gContextMenu.hiding();
                               gContextMenu = null;
                               updateEditUIVisibility();">
 #include browser-context.inc
     </menupopup>
 
     <menupopup id="placesContext"/>
 
-    <!-- Popup for site identity information -->
-    <panel id="identity-popup"
-           type="arrow"
-           hidden="true"
-           noautofocus="true"
-           onpopupshown="if (event.target == this)
-                           gIdentityHandler.onPopupShown(event);"
-           orient="vertical"
-           level="top">
-      <hbox id="identity-popup-container" align="top">
-        <image id="identity-popup-icon"/>
-        <vbox id="identity-popup-content-box">
-          <label id="identity-popup-brandName"
-                 class="identity-popup-label"
-                 value="&brandFullName;"/>
-          <label id="identity-popup-chromeLabel"
-                 class="identity-popup-label"/>
-          <label id="identity-popup-connectedToLabel"
-                 class="identity-popup-label"
-                 value="&identity.connectedTo;"/>
-          <label id="identity-popup-connectedToLabel2"
-                 class="identity-popup-label"
-                 value="&identity.unverifiedsite2;"/>
-          <description id="identity-popup-content-host"
-                       class="identity-popup-description"/>
-          <label id="identity-popup-runByLabel"
-                 class="identity-popup-label"
-                 value="&identity.runBy;"/>
-          <description id="identity-popup-content-owner"
-                       class="identity-popup-description"/>
-          <description id="identity-popup-content-supplemental"
-                       class="identity-popup-description"/>
-          <description id="identity-popup-content-verifier"
-                       class="identity-popup-description"/>
-          <hbox id="identity-popup-encryption" flex="1">
-            <vbox>
-              <image id="identity-popup-encryption-icon"/>
-            </vbox>
-            <description id="identity-popup-encryption-label" flex="1"
-                         class="identity-popup-description"/>
-          </hbox>
-          <vbox id="identity-popup-permissions">
-            <separator class="thin"/>
-            <label class="identity-popup-label header"
-                   value="&identity.permissions;"/>
-            <vbox id="identity-popup-permission-list" class="indent"/>
-          </vbox>
-        </vbox>
-      </hbox>
-      <!-- Footer button to open security page info -->
-      <hbox id="identity-popup-button-container" align="center">
-        <button id="identity-popup-help-icon"
-               oncommand="gIdentityHandler.handleHelpCommand(event);"
-               tooltiptext="&identity.help.tooltip;"/>
-        <spacer flex="1"/>
-        <button id="identity-popup-more-info-button"
-                label="&identity.moreInfoLinkText;"
-                oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
-      </hbox>
-    </panel>
-
     <panel id="ctrlTab-panel" class="KUI-panel" hidden="true" norestorefocus="true" level="top">
       <hbox>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
         <button class="ctrlTab-preview" flex="1"/>
@@ -544,16 +484,17 @@
     <tooltip id="share-button-tooltip" onpopupshowing="SocialShare.createTooltip(event);">
       <label class="tooltip-label"/>
       <label class="tooltip-label"/>
     </tooltip>
 
 #include popup-notifications.inc
 
 #include ../../components/customizableui/content/panelUI.inc.xul
+#include ../../components/controlcenter/content/panel.inc.xul
 
     <hbox id="downloads-animation-container" mousethrough="always">
       <vbox id="downloads-notification-anchor">
         <vbox id="downloads-indicator-notification"/>
       </vbox>
     </hbox>
 
     <hbox id="bookmarked-notification-container" mousethrough="always">
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1503,16 +1503,23 @@
             aBrowser.destroy();
 
             // Change the "remote" attribute.
             let parent = aBrowser.parentNode;
             parent.removeChild(aBrowser);
             aBrowser.setAttribute("remote", aShouldBeRemote ? "true" : "false");
             parent.appendChild(aBrowser);
 
+            // Switching a browser's remoteness will create a new frameLoader.
+            // As frameLoaders start out with an active docShell we have to
+            // deactivate it if this is not the selected tab's browser or the
+            // browser window is minimized.
+            aBrowser.docShellIsActive = (aBrowser == this.selectedBrowser &&
+                                         window.windowState != window.STATE_MINIMIZED);
+
             // Restore the progress listener.
             aBrowser.webProgress.addProgressListener(filter, Ci.nsIWebProgress.NOTIFY_ALL);
 
             if (aShouldBeRemote) {
               // Switching the browser to be remote will connect to a new child
               // process so the browser can no longer be considered to be
               // crashed.
               tab.removeAttribute("crashed");
--- a/browser/base/content/test/general/browser.ini
+++ b/browser/base/content/test/general/browser.ini
@@ -59,16 +59,17 @@ support-files =
   file_bug970276_favicon2.ico
   file_dom_notifications.html
   file_double_close_tab.html
   file_favicon_change.html
   file_favicon_change_not_in_document.html
   file_fullscreen-window-open.html
   get_user_media.html
   head.js
+  healthreport_pingData.js
   healthreport_testRemoteCommands.html
   moz.png
   navigating_window_with_download.html
   offlineQuotaNotification.cacheManifest
   offlineQuotaNotification.html
   page_style_sample.html
   parsingTestHelpers.jsm
   pinning_headers.sjs
--- a/browser/base/content/test/general/browser_aboutHealthReport.js
+++ b/browser/base/content/test/general/browser_aboutHealthReport.js
@@ -2,38 +2,80 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/Promise.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
 
+const CHROME_BASE = "chrome://mochitests/content/browser/browser/base/content/test/general/";
+const HTTPS_BASE = "https://example.com/browser/browser/base/content/test/general/";
+
+const TELEMETRY_LOG_PREF = "toolkit.telemetry.log.level";
+const telemetryOriginalLogPref = Preferences.get(TELEMETRY_LOG_PREF, null);
+
 registerCleanupFunction(function() {
   // Ensure we don't pollute prefs for next tests.
+  if (telemetryOriginalLogPref) {
+    Preferences.set(TELEMETRY_LOG_PREF, telemetryOriginalLogPref);
+  } else {
+    Preferences.reset(TELEMETRY_LOG_PREF);
+  }
+
   try {
     Services.prefs.clearUserPref("datareporting.healthreport.about.reportUrl");
     let policy = Cc["@mozilla.org/datareporting/service;1"]
                  .getService(Ci.nsISupports)
                  .wrappedJSObject
                  .policy;
-        policy.recordHealthReportUploadEnabled(true,
+    policy.recordHealthReportUploadEnabled(true,
                                            "Resetting after tests.");
   } catch (ex) {}
 });
 
+function fakeTelemetryNow(...args) {
+  let date = new Date(...args);
+  let scope = {};
+  const modules = [
+    Cu.import("resource://gre/modules/TelemetrySession.jsm", scope),
+    Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", scope),
+    Cu.import("resource://gre/modules/TelemetryController.jsm", scope),
+  ];
+
+  for (let m of modules) {
+    m.Policy.now = () => new Date(date);
+  }
+
+  return date;
+}
+
+function setupPingArchive() {
+  let scope = {};
+  Cu.import("resource://gre/modules/TelemetryController.jsm", scope);
+  Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader)
+    .loadSubScript(CHROME_BASE + "healthreport_pingData.js", scope);
+
+  for (let p of scope.TEST_PINGS) {
+    fakeTelemetryNow(p.date);
+    p.id = yield scope.TelemetryController.submitExternalPing(p.type, p.payload);
+  }
+}
+
 let gTests = [
 
 {
   desc: "Test the remote commands",
-  setup: function ()
+  setup: Task.async(function*()
   {
-    Services.prefs.setCharPref("datareporting.healthreport.about.reportUrl",
-                               "https://example.com/browser/browser/base/content/test/general/healthreport_testRemoteCommands.html");
-  },
+    Preferences.set(TELEMETRY_LOG_PREF, "Trace");
+    yield setupPingArchive();
+    Preferences.set("datareporting.healthreport.about.reportUrl",
+                    HTTPS_BASE + "healthreport_testRemoteCommands.html");
+  }),
   run: function (iframe)
   {
     let deferred = Promise.defer();
 
     let policy = Cc["@mozilla.org/datareporting/service;1"]
                  .getService(Ci.nsISupports)
                  .wrappedJSObject
                  .policy;
@@ -56,30 +98,29 @@ let gTests = [
     } catch(e) {
       ok(false, "Failed to get all commands");
       deferred.reject();
     }
     return deferred.promise;
   }
 },
 
-
 ]; // gTests
 
 function test()
 {
   waitForExplicitFinish();
 
   // xxxmpc leaving this here until we resolve bug 854038 and bug 854060
   requestLongerTimeout(10);
 
   Task.spawn(function () {
     for (let test of gTests) {
       info(test.desc);
-      test.setup();
+      yield test.setup();
 
       let iframe = yield promiseNewTabLoadEvent("about:healthreport");
 
       yield test.run(iframe);
 
       gBrowser.removeCurrentTab();
     }
 
@@ -100,9 +141,8 @@ function promiseNewTabLoadEvent(aUrl, aE
           return;
         }
         iframe.removeEventListener("load", frameLoad, false);
         deferred.resolve(iframe);
       }, false);
     }, true);
   return deferred.promise;
 }
-
--- a/browser/base/content/test/general/browser_syncui.js
+++ b/browser/base/content/test/general/browser_syncui.js
@@ -32,16 +32,33 @@ add_task(function* prepare() {
   // mock out the "_needsSetup()" function so we don't short-circuit.
   let oldNeedsSetup = window.gSyncUI._needsSetup;
   window.gSyncUI._needsSetup = () => false;
   registerCleanupFunction(() => {
     window.gSyncUI._needsSetup = oldNeedsSetup;
   });
 });
 
+add_task(function* testNotProlongedRLErrorWhenDisabled() {
+  // Here we arrange for the (dead?) readinglist scheduler to have a last-synced
+  // date of long ago and the RL scheduler is disabled.
+  // gSyncUI.isProlongedReadingListError() should return false.
+  // Pretend the reading-list is in the "prolonged error" state.
+  let longAgo = new Date(Date.now() - 100 * 24 * 60 * 60 * 1000); // 100 days ago.
+  Services.prefs.setCharPref("readinglist.scheduler.lastSync", longAgo.toString());
+
+  // It's prolonged while it's enabled.
+  Services.prefs.setBoolPref("readinglist.scheduler.enabled", true);
+  Assert.equal(gSyncUI.isProlongedReadingListError(), true);
+
+  // But false when disabled.
+  Services.prefs.setBoolPref("readinglist.scheduler.enabled", false);
+  Assert.equal(gSyncUI.isProlongedReadingListError(), false);
+});
+
 add_task(function* testProlongedSyncError() {
   let promiseNotificationAdded = promiseObserver("weave:notification:added");
   Assert.equal(Notifications.notifications.length, 0, "start with no notifications");
 
   // Pretend we are in the "prolonged error" state.
   Weave.Status.sync = Weave.PROLONGED_SYNC_FAILURE;
   Weave.Status.login = Weave.LOGIN_SUCCEEDED;
   Services.obs.notifyObservers(null, "weave:ui:sync:error", null);
@@ -55,16 +72,17 @@ add_task(function* testProlongedSyncErro
   let promiseNotificationRemoved = promiseObserver("weave:notification:removed");
   Weave.Status.sync = Weave.STATUS_OK;
   Services.obs.notifyObservers(null, "weave:ui:sync:finish", null);
   yield promiseNotificationRemoved;
   Assert.equal(Notifications.notifications.length, 0, "no notifications left");
 });
 
 add_task(function* testProlongedRLError() {
+  Services.prefs.setBoolPref("readinglist.scheduler.enabled", true);
   let promiseNotificationAdded = promiseObserver("weave:notification:added");
   Assert.equal(Notifications.notifications.length, 0, "start with no notifications");
 
   // Pretend the reading-list is in the "prolonged error" state.
   let longAgo = new Date(Date.now() - 100 * 24 * 60 * 60 * 1000); // 100 days ago.
   Services.prefs.setCharPref("readinglist.scheduler.lastSync", longAgo.toString());
   getInternalScheduler().state = ReadingListScheduler.STATE_ERROR_OTHER;
   Services.obs.notifyObservers(null, "readinglist:sync:start", null);
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/general/healthreport_pingData.js
@@ -0,0 +1,17 @@
+const TEST_PINGS = [
+  {
+    type: "test-telemetryArchive-1",
+    payload: { foo: "bar" },
+    date: new Date(2010, 1, 1, 10, 0, 0),
+  },
+  {
+    type: "test-telemetryArchive-2",
+    payload: { x: { y: "z"} },
+    date: new Date(2010, 1, 1, 11, 0, 0),
+  },
+  {
+    type: "test-telemetryArchive-3",
+    payload: { moo: "meh" },
+    date: new Date(2010, 1, 1, 12, 0, 0),
+  },
+];
--- a/browser/base/content/test/general/healthreport_testRemoteCommands.html
+++ b/browser/base/content/test/general/healthreport_testRemoteCommands.html
@@ -1,13 +1,15 @@
 <html>
   <head>
     <meta charset="utf-8">
-
-<script>
+<script type="application/javascript;version=1.7"
+            src="healthreport_pingData.js">
+</script>
+<script type="application/javascript;version=1.7">
 
 function init() {
   window.addEventListener("message", function process(e) {
     // The init function of abouthealth.js schedules an initial payload event,
     // which will be sent after the payload data has been collected. This extra
     // event can cause unexpected successes/failures in this test, so we wait
     // for the extra event to arrive here before progressing with the actual
     // test.
@@ -29,16 +31,90 @@ function validatePayload(payload) {
 
   // xxxmpc - this is some pretty low-bar validation, but we have plenty of tests of that API elsewhere
   if (!payload.thisPingDate)
     return false;
 
   return true;
 }
 
+function isArray(arg) {
+  return Object.prototype.toString.call(arg) === '[object Array]';
+}
+
+function writeDiagnostic(text) {
+  let node = document.createTextNode(text);
+  let br = document.createElement("br");
+  document.body.appendChild(node);
+  document.body.appendChild(br);
+}
+
+function validateCurrentTelemetryEnvironment(data) {
+  // Simple check for now: check that the received object has the expected
+  // top-level properties.
+  const expectedKeys = ["profile", "settings", "system", "build", "partner", "addons"];
+  return expectedKeys.every(key => (key in data));
+}
+
+function validateCurrentTelemetryPingData(ping) {
+  // Simple check for now: check that the received object has the expected
+  // top-level properties and that the type and reason match.
+  const expectedKeys = ["environment", "clientId", "payload", "application",
+                        "version", "type", "id"];
+  return expectedKeys.every(key => (key in ping)) &&
+         (ping.type == "main") &&
+         ("info" in ping.payload) &&
+         ("reason" in ping.payload.info) &&
+         (ping.payload.info.reason == "gather-subsession-payload");
+}
+
+function validateTelemetryPingList(list) {
+  if (!isArray(list)) {
+    console.log("Telemetry ping list is not an array.");
+    return false;
+  }
+
+  if (list.length != TEST_PINGS.length) {
+    console.log("Telemetry ping length is not correct.");
+    return false;
+  }
+
+  let valid = true;
+  for (let i=0; i<list.length; ++i) {
+    let received = list[i];
+    let expected = TEST_PINGS[i];
+    if (received.type != expected.type ||
+        received.timestampCreated != expected.date.getTime()) {
+      writeDiagnostic("Telemetry ping " + i + " does not match.");
+      writeDiagnostic("Expected: " + JSON.stringify(expected));
+      writeDiagnostic("Received: " + JSON.stringify(received));
+      valid = false;
+    } else {
+      writeDiagnostic("Telemetry ping " + i + " matches.");
+    }
+  }
+
+  return true;
+}
+
+function validateTelemetryPingData(expected, received) {
+  const receivedDate = new Date(received.creationDate);
+  if (received.id != expected.id ||
+      received.type != expected.type ||
+      receivedDate.getTime() != expected.date.getTime()) {
+    writeDiagnostic("Telemetry ping data for " + expected.id + " doesn't match.");
+    writeDiagnostic("Expected: " + JSON.stringify(expected));
+    writeDiagnostic("Received: " + JSON.stringify(received));
+    return false;
+  }
+
+  writeDiagnostic("Telemetry ping data for " + expected.id + " matched.");
+  return true;
+}
+
 var tests = [
 {
   info: "Checking initial value is enabled",
   event: "RequestCurrentPrefs",
   payloadType: "prefs",
   validateResponse: function(payload) {
     return checkSubmissionValue(payload, true);
   },
@@ -86,16 +162,60 @@ var tests = [
 {
   info: "Verifying we can get a payload after re-enabling",
   event: "RequestCurrentPayload",
   payloadType: "payload",
   validateResponse: function(payload) {
     return validatePayload(payload);
   },
 },
+{
+  info: "Verifying that we can get the current Telemetry environment data",
+  event: "RequestCurrentEnvironment",
+  payloadType: "telemetry-current-environment-data",
+  validateResponse: function(payload) {
+    return validateCurrentTelemetryEnvironment(payload);
+  },
+},
+{
+  info: "Verifying that we can get the current Telemetry ping data",
+  event: "RequestCurrentPingData",
+  payloadType: "telemetry-current-ping-data",
+  validateResponse: function(payload) {
+    return validateCurrentTelemetryPingData(payload);
+  },
+},
+{
+  info: "Verifying that we get the proper Telemetry ping list",
+  event: "RequestTelemetryPingList",
+  payloadType: "telemetry-ping-list",
+  validateResponse: function(payload) {
+    // Validate the ping list
+    if (!validateTelemetryPingList(payload)) {
+      return false;
+    }
+
+    // Now that we received the ping ids, set up additional test tasks
+    // that check loading the individual pings.
+    for (let i=0; i<TEST_PINGS.length; ++i) {
+      TEST_PINGS[i].id = payload[i].id;
+      tests.push({
+        info: "Verifying that we can get the proper Telemetry ping data #" + (i + 1),
+        event: "RequestTelemetryPingData",
+        eventData: { id: TEST_PINGS[i].id },
+        payloadType: "telemetry-ping-data",
+        validateResponse: function(payload) {
+          return validateTelemetryPingData(TEST_PINGS[i], payload.pingData);
+        },
+      });
+    }
+
+    return true;
+  },
+},
 ];
 
 var currentTest = -1;
 function doTest(evt) {
   if (evt) {
     if (currentTest < 0 || !evt.data.content)
       return; // not yet testing
 
@@ -107,35 +227,41 @@ function doTest(evt) {
     var pass = false;
     try {
       pass = test.validateResponse(evt.data.content)
     } catch (e) {}
     reportResult(test.info, pass, error);
   }
   // start the next test if there are any left
   if (tests[++currentTest])
-    sendToBrowser(tests[currentTest].event);
+    sendToBrowser(tests[currentTest].event, tests[currentTest].eventData);
   else
     reportFinished();
 }
 
 function reportResult(info, pass, error) {
   var data = {type: "testResult", info: info, pass: pass, error: error};
   var event = new CustomEvent("FirefoxHealthReportTestResponse", {detail: {data: data}, bubbles: true});
   document.dispatchEvent(event);
 }
 
 function reportFinished(cmd) {
   var data = {type: "testsComplete", count: tests.length};
   var event = new CustomEvent("FirefoxHealthReportTestResponse", {detail: {data: data}, bubbles: true});
   document.dispatchEvent(event);
 }
 
-function sendToBrowser(type) {
-  var event = new CustomEvent("RemoteHealthReportCommand", {detail: {command: type}, bubbles: true});
+function sendToBrowser(type, eventData) {
+  eventData = eventData || {};
+  let detail = {command: type};
+  for (let key of Object.keys(eventData)) {
+    detail[key] = eventData[key];
+  }
+
+  var event = new CustomEvent("RemoteHealthReportCommand", {detail: detail, bubbles: true});
   document.dispatchEvent(event);
 }
 
 </script>
   </head>
   <body onload="init()">
   </body>
 </html>
--- a/browser/branding/aurora/pref/firefox-branding.js
+++ b/browser/branding/aurora/pref/firefox-branding.js
@@ -21,11 +21,15 @@ pref("app.update.url.manual", "https://w
 // supplied in the "An update is available" page of the update wizard. 
 pref("app.update.url.details", "https://www.mozilla.org/firefox/aurora/");
 
 // The number of days a binary is permitted to be old
 // without checking for an update.  This assumes that
 // app.update.checkInstallTime is true.
 pref("app.update.checkInstallTime.days", 2);
 
+// Give the user x seconds to reboot before showing a badge on the hamburger
+// button. default=4 days
+pref("app.update.badgeWaitTime", 345600);
+
 // Number of usages of the web console or scratchpad.
 // If this is less than 5, then pasting code into the web console or scratchpad is disabled
-pref("devtools.selfxss.count", 5);
\ No newline at end of file
+pref("devtools.selfxss.count", 5);
--- a/browser/branding/nightly/pref/firefox-branding.js
+++ b/browser/branding/nightly/pref/firefox-branding.js
@@ -19,11 +19,15 @@ pref("app.update.url.manual", "https://n
 // supplied in the "An update is available" page of the update wizard. 
 pref("app.update.url.details", "https://nightly.mozilla.org");
 
 // The number of days a binary is permitted to be old
 // without checking for an update.  This assumes that
 // app.update.checkInstallTime is true.
 pref("app.update.checkInstallTime.days", 2);
 
+// Give the user x seconds to reboot before showing a badge on the hamburger
+// button. default=immediately
+pref("app.update.badgeWaitTime", 0);
+
 // Number of usages of the web console or scratchpad.
 // If this is less than 5, then pasting code into the web console or scratchpad is disabled
-pref("devtools.selfxss.count", 5);
\ No newline at end of file
+pref("devtools.selfxss.count", 5);
--- a/browser/branding/official/pref/firefox-branding.js
+++ b/browser/branding/official/pref/firefox-branding.js
@@ -18,11 +18,15 @@ pref("app.update.url.manual", "https://w
 // supplied in the "An update is available" page of the update wizard. 
 pref("app.update.url.details", "https://www.mozilla.org/%LOCALE%/firefox/notes");
 
 // The number of days a binary is permitted to be old
 // without checking for an update.  This assumes that
 // app.update.checkInstallTime is true.
 pref("app.update.checkInstallTime.days", 63);
 
+// Give the user x seconds to reboot before showing a badge on the hamburger
+// button. default=immediately
+pref("app.update.badgeWaitTime", 0);
+
 // Number of usages of the web console or scratchpad.
 // If this is less than 5, then pasting code into the web console or scratchpad is disabled
-pref("devtools.selfxss.count", 0);
\ No newline at end of file
+pref("devtools.selfxss.count", 0);
--- a/browser/branding/unofficial/pref/firefox-branding.js
+++ b/browser/branding/unofficial/pref/firefox-branding.js
@@ -18,11 +18,15 @@ pref("app.update.url.manual", "https://n
 // supplied in the "An update is available" page of the update wizard. 
 pref("app.update.url.details", "https://nightly.mozilla.org");
 
 // The number of days a binary is permitted to be old
 // without checking for an update.  This assumes that
 // app.update.checkInstallTime is true.
 pref("app.update.checkInstallTime.days", 2);
 
+// Give the user x seconds to reboot before showing a badge on the hamburger
+// button. default=immediately
+pref("app.update.badgeWaitTime", 0);
+
 // Number of usages of the web console or scratchpad.
 // If this is less than 5, then pasting code into the web console or scratchpad is disabled
-pref("devtools.selfxss.count", 0);
\ No newline at end of file
+pref("devtools.selfxss.count", 0);
new file mode 100644
--- /dev/null
+++ b/browser/components/controlcenter/content/panel.inc.xul
@@ -0,0 +1,59 @@
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<panel id="identity-popup"
+       type="arrow"
+       hidden="true"
+       noautofocus="true"
+       onpopupshown="if (event.target == this)
+                       gIdentityHandler.onPopupShown(event);"
+       orient="vertical"
+       level="top">
+  <hbox id="identity-popup-container" align="top">
+    <image id="identity-popup-icon"/>
+    <vbox id="identity-popup-content-box">
+      <label id="identity-popup-brandName"
+             class="identity-popup-label"
+             value="&brandFullName;"/>
+      <label id="identity-popup-chromeLabel"
+             class="identity-popup-label"/>
+      <label id="identity-popup-connectedToLabel"
+             class="identity-popup-label"
+             value="&identity.connectedTo;"/>
+      <label id="identity-popup-connectedToLabel2"
+             class="identity-popup-label"
+             value="&identity.unverifiedsite2;"/>
+      <description id="identity-popup-content-host"
+                   class="identity-popup-description"/>
+      <label id="identity-popup-runByLabel"
+             class="identity-popup-label"
+             value="&identity.runBy;"/>
+      <description id="identity-popup-content-owner"
+                   class="identity-popup-description"/>
+      <description id="identity-popup-content-supplemental"
+                   class="identity-popup-description"/>
+      <description id="identity-popup-content-verifier"
+                   class="identity-popup-description"/>
+      <hbox id="identity-popup-encryption" flex="1">
+        <vbox>
+          <image id="identity-popup-encryption-icon"/>
+        </vbox>
+        <description id="identity-popup-encryption-label" flex="1"
+                     class="identity-popup-description"/>
+      </hbox>
+      <vbox id="identity-popup-permissions">
+        <separator class="thin"/>
+        <label class="identity-popup-label header"
+               value="&identity.permissions;"/>
+        <vbox id="identity-popup-permission-list" class="indent"/>
+      </vbox>
+    </vbox>
+  </hbox>
+  <!-- Footer button to open security page info -->
+  <hbox id="identity-popup-button-container" align="center">
+    <button id="identity-popup-more-info-button" flex="1"
+            label="&identity.moreInfoLinkText2;"
+            oncommand="gIdentityHandler.handleMoreInfoClick(event);"/>
+  </hbox>
+</panel>
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -1502,16 +1502,31 @@ let CustomizableUIInternal = {
     let menuitemCloseMenu = "auto";
     // whether the toolbarbutton/item has a valid closemenu attribute.
     let closemenu = "auto";
 
     // While keeping track of that, we go from the original target back up,
     // to the panel if we have to. We bail as soon as we find an input,
     // a toolbarbutton/item, or the panel:
     while (true && target) {
+      // Skip out of iframes etc:
+      if (target.nodeType == target.DOCUMENT_NODE) {
+        if (!target.defaultView) {
+          // Err, we're done.
+          break;
+        }
+        // Cue some voodoo
+        target = target.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
+                                   .getInterface(Ci.nsIWebNavigation)
+                                   .QueryInterface(Ci.nsIDocShell)
+                                   .chromeEventHandler;
+        if (!target) {
+          break;
+        }
+      }
       let tagName = target.localName;
       inInput = tagName == "input" || tagName == "textbox";
       inItem = tagName == "toolbaritem" || tagName == "toolbarbutton";
       let isMenuItem = tagName == "menuitem";
       inMenu = inMenu || isMenuItem;
       if (inItem && target.hasAttribute("closemenu")) {
         let closemenuVal = target.getAttribute("closemenu");
         closemenu = (closemenuVal == "single" || closemenuVal == "none") ?
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -1152,20 +1152,22 @@ let e10sDisabled = Services.appinfo.inSa
 // On OS X, "Disable Hardware Acceleration" also disables OMTC and forces
 // a fallback to Basic Layers. This is incompatible with e10s.
 e10sDisabled |= Services.prefs.getBoolPref("layers.acceleration.disabled");
 #endif
 
 if (Services.appinfo.browserTabsRemoteAutostart) {
   CustomizableWidgets.push({
     id: "e10s-button",
-    label: "New Non-e10s Window",
-    tooltiptext: "New Non-e10s Window",
     disabled: e10sDisabled,
     defaultArea: CustomizableUI.AREA_PANEL,
+    onBuild: function(aDocument) {
+        node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
+        node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
+    },
     onCommand: function(aEvent) {
       let win = aEvent.view;
       if (win && typeof win.OpenBrowserWindow == "function") {
         win.OpenBrowserWindow({remote: false});
       }
     },
   });
 }
--- a/browser/components/loop/.eslintrc
+++ b/browser/components/loop/.eslintrc
@@ -35,36 +35,33 @@
     // problems they find, one at a time.
 
     // Eslint built-in rules are documented at <http://eslint.org/docs/rules/>
     "camelcase": 0,               // TODO: Remove (use default)
     "consistent-return": 0,       // TODO: Remove (use default)
     dot-location: 0,              // [2, property],
     "eqeqeq": 0,                  // TBD. Might need to be separate for content & chrome
     "global-strict": 0,           // Leave as zero (this will be unsupported in eslint 1.0.0)
-    "key-spacing": 0,             // TODO: Remove (use default)
     "linebreak-style": [2, "unix"],
     "new-cap": 0,                 // TODO: Remove (use default)
     "no-catch-shadow": 0,         // TODO: Remove (use default)
     "no-console": 0,              // Leave as 0. We use console logging in content code.
     "no-empty": 0,                // TODO: Remove (use default)
     "no-extra-bind": 0,           // Leave as 0
     "no-extra-boolean-cast": 0,   // TODO: Remove (use default)
     "no-multi-spaces": 0,         // TBD.
     "no-new": 0,                  // TODO: Remove (use default)
     "no-redeclare": 0,            // TODO: Remove (use default)
     "no-return-assign": 0,        // TODO: Remove (use default)
     "no-shadow": 0,               // TODO: Remove (use default)
-    "no-spaced-func": 0,          // TODO: Remove (use default)
     "no-underscore-dangle": 0,    // Leave as 0. Commonly used for private variables.
     "no-unneeded-ternary": 2,
     "no-unused-expressions": 0,   // TODO: Remove (use default)
     "no-unused-vars": 0,          // TODO: Remove (use default)
     "no-use-before-define": 0,    // TODO: Remove (use default)
-    "no-wrap-func": 0,            // TODO: Remove (use default)
     "quotes": [2, "double", "avoid-escape"],
     "strict": 0,                  // [2, "function"],
     // eslint-plugin-react rules. These are documented at
     // <https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules>
     "react/jsx-quotes": [2, "double", "avoid-escape"],
     "react/jsx-no-undef": 2,
     // Need to fix instances where this is failing.
     "react/jsx-sort-props": 0,
--- a/browser/components/loop/content/js/roomStore.js
+++ b/browser/components/loop/content/js/roomStore.js
@@ -22,23 +22,23 @@ loop.store = loop.store || {};
    */
   var MAX_ROOM_CREATION_SIZE = loop.store.MAX_ROOM_CREATION_SIZE = 2;
 
   /**
    * Room validation schema. See validate.js.
    * @type {Object}
    */
   var roomSchema = {
-    roomToken:    String,
-    roomUrl:      String,
-    // roomName:     String - Optional.
-    // roomKey:      String - Optional.
-    maxSize:      Number,
+    roomToken: String,
+    roomUrl: String,
+    // roomName: String - Optional.
+    // roomKey: String - Optional.
+    maxSize: Number,
     participants: Array,
-    ctime:        Number
+    ctime: Number
   };
 
   /**
    * Room type. Basically acts as a typed object constructor.
    *
    * @param {Object} values Room property values.
    */
   function Room(values) {
@@ -72,17 +72,16 @@ loop.store = loop.store || {};
      */
     maxRoomCreationSize: MAX_ROOM_CREATION_SIZE,
 
     /**
      * Registered actions.
      * @type {Array}
      */
     actions: [
-      "addSocialShareButton",
       "addSocialShareProvider",
       "createRoom",
       "createdRoom",
       "createRoomError",
       "copyRoomUrl",
       "deleteRoom",
       "deleteRoomError",
       "emailRoomUrl",
@@ -258,20 +257,20 @@ loop.store = loop.store || {};
     createRoom: function(actionData) {
       this.setStoreState({
         pendingCreation: true,
         error: null
       });
 
       var roomCreationData = {
         decryptedContext: {
-          roomName:  this._generateNewRoomName(actionData.nameTemplate)
+          roomName: this._generateNewRoomName(actionData.nameTemplate)
         },
         roomOwner: actionData.roomOwner,
-        maxSize:   this.maxRoomCreationSize
+        maxSize: this.maxRoomCreationSize
       };
 
       if ("urls" in actionData) {
         roomCreationData.decryptedContext.urls = actionData.urls;
       }
 
       this._notifications.remove("create-room-error");
 
@@ -371,25 +370,16 @@ loop.store = loop.store || {};
       }
 
       this._mozLoop.socialShareRoom(actionData.provider.origin, actionData.roomUrl,
         shareTitle, shareBody);
       this._mozLoop.notifyUITour("Loop:RoomURLShared");
     },
 
     /**
-     * Add the Social Share button to the browser toolbar.
-     *
-     * @param {sharedActions.AddSocialShareButton} actionData The action data.
-     */
-    addSocialShareButton: function(actionData) {
-      this._mozLoop.addSocialShareButton();
-    },
-
-    /**
      * Open the share panel to add a Social share provider.
      *
      * @param {sharedActions.AddSocialShareProvider} actionData The action data.
      */
     addSocialShareProvider: function(actionData) {
       this._mozLoop.addSocialShareProvider();
     },
 
--- a/browser/components/loop/content/js/roomViews.js
+++ b/browser/components/loop/content/js/roomViews.js
@@ -74,26 +74,19 @@ loop.roomViews = (function(mozL10n) {
     }
   };
 
   var SocialShareDropdown = React.createClass({displayName: "SocialShareDropdown",
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       roomUrl: React.PropTypes.string,
       show: React.PropTypes.bool.isRequired,
-      socialShareButtonAvailable: React.PropTypes.bool,
       socialShareProviders: React.PropTypes.array
     },
 
-    handleToolbarAddButtonClick: function(event) {
-      event.preventDefault();
-
-      this.props.dispatcher.dispatch(new sharedActions.AddSocialShareButton());
-    },
-
     handleAddServiceClick: function(event) {
       event.preventDefault();
 
       this.props.dispatcher.dispatch(new sharedActions.AddSocialShareProvider());
     },
 
     handleProviderClick: function(event) {
       event.preventDefault();
@@ -116,44 +109,19 @@ loop.roomViews = (function(mozL10n) {
         return null;
       }
 
       var cx = React.addons.classSet;
       var shareDropdown = cx({
         "share-service-dropdown": true,
         "dropdown-menu": true,
         "visually-hidden": true,
-        "share-button-unavailable": !this.props.socialShareButtonAvailable,
         "hide": !this.props.show
       });
 
-      // When the button is not yet available, we offer to put it in the navbar
-      // for the user.
-      if (!this.props.socialShareButtonAvailable) {
-        return (
-          React.createElement("div", {className: shareDropdown}, 
-            React.createElement("div", {className: "share-panel-header"}, 
-              mozL10n.get("share_panel_header")
-            ), 
-            React.createElement("div", {className: "share-panel-body"}, 
-              
-                mozL10n.get("share_panel_body", {
-                  brandShortname: mozL10n.get("brandShortname"),
-                  clientSuperShortname: mozL10n.get("clientSuperShortname")
-                })
-              
-            ), 
-            React.createElement("button", {className: "btn btn-info btn-toolbar-add", 
-                    onClick: this.handleToolbarAddButtonClick}, 
-              mozL10n.get("add_to_toolbar_button")
-            )
-          )
-        );
-      }
-
       return (
         React.createElement("ul", {className: shareDropdown}, 
           React.createElement("li", {className: "dropdown-menu-item", onClick: this.handleAddServiceClick}, 
             React.createElement("i", {className: "icon icon-add-share-service"}), 
             React.createElement("span", null, mozL10n.get("share_add_service_button"))
           ), 
           this.props.socialShareProviders.length ? React.createElement("li", {className: "dropdown-menu-separator"}) : null, 
           
@@ -183,17 +151,18 @@ loop.roomViews = (function(mozL10n) {
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       error: React.PropTypes.object,
       mozLoop: React.PropTypes.object.isRequired,
       // This data is supplied by the activeRoomStore.
       roomData: React.PropTypes.object.isRequired,
       savingContext: React.PropTypes.bool,
       show: React.PropTypes.bool.isRequired,
-      showContext: React.PropTypes.bool.isRequired
+      showContext: React.PropTypes.bool.isRequired,
+      socialShareProviders: React.PropTypes.array
     },
 
     getInitialState: function() {
       return {
         copiedUrl: false,
         editMode: false,
         newRoomName: ""
       };
@@ -218,16 +187,24 @@ loop.roomViews = (function(mozL10n) {
         new sharedActions.CopyRoomUrl({roomUrl: this.props.roomData.roomUrl}));
 
       this.setState({copiedUrl: true});
     },
 
     handleShareButtonClick: function(event) {
       event.preventDefault();
 
+      var providers = this.props.socialShareProviders;
+      // If there are no providers available currently, save a click by dispatching
+      // the 'AddSocialShareProvider' right away.
+      if (!providers || !providers.length) {
+        this.props.dispatcher.dispatch(new sharedActions.AddSocialShareProvider());
+        return;
+      }
+
       this.toggleDropdownMenu();
     },
 
     handleAddContextClick: function(event) {
       event.preventDefault();
 
       this.handleEditModeChange(true);
     },
@@ -275,17 +252,16 @@ loop.roomViews = (function(mozL10n) {
                     onClick: this.handleShareButtonClick}, 
               mozL10n.get("share_button3")
             )
           ), 
           React.createElement(SocialShareDropdown, {
             dispatcher: this.props.dispatcher, 
             roomUrl: this.props.roomData.roomUrl, 
             show: this.state.showMenu, 
-            socialShareButtonAvailable: this.props.socialShareButtonAvailable, 
             socialShareProviders: this.props.socialShareProviders, 
             ref: "menu"}), 
           React.createElement(DesktopRoomContextView, {
             dispatcher: this.props.dispatcher, 
             editMode: this.state.editMode, 
             error: this.props.error, 
             savingContext: this.props.savingContext, 
             mozLoop: this.props.mozLoop, 
@@ -704,17 +680,16 @@ loop.roomViews = (function(mozL10n) {
               React.createElement(DesktopRoomInvitationView, {
                 dispatcher: this.props.dispatcher, 
                 error: this.state.error, 
                 mozLoop: this.props.mozLoop, 
                 roomData: roomData, 
                 savingContext: this.state.savingContext, 
                 show: shouldRenderInvitationOverlay, 
                 showContext: shouldRenderContextView, 
-                socialShareButtonAvailable: this.state.socialShareButtonAvailable, 
                 socialShareProviders: this.state.socialShareProviders}), 
               React.createElement("div", {className: "video-layout-wrapper"}, 
                 React.createElement("div", {className: "conversation room-conversation"}, 
                   React.createElement("div", {className: "media nested"}, 
                     React.createElement("div", {className: "video_wrapper remote_wrapper"}, 
                       React.createElement("div", {className: "video_inner remote focus-stream"})
                     ), 
                     React.createElement("div", {className: localStreamClasses}), 
--- a/browser/components/loop/content/js/roomViews.jsx
+++ b/browser/components/loop/content/js/roomViews.jsx
@@ -74,26 +74,19 @@ loop.roomViews = (function(mozL10n) {
     }
   };
 
   var SocialShareDropdown = React.createClass({
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       roomUrl: React.PropTypes.string,
       show: React.PropTypes.bool.isRequired,
-      socialShareButtonAvailable: React.PropTypes.bool,
       socialShareProviders: React.PropTypes.array
     },
 
-    handleToolbarAddButtonClick: function(event) {
-      event.preventDefault();
-
-      this.props.dispatcher.dispatch(new sharedActions.AddSocialShareButton());
-    },
-
     handleAddServiceClick: function(event) {
       event.preventDefault();
 
       this.props.dispatcher.dispatch(new sharedActions.AddSocialShareProvider());
     },
 
     handleProviderClick: function(event) {
       event.preventDefault();
@@ -116,44 +109,19 @@ loop.roomViews = (function(mozL10n) {
         return null;
       }
 
       var cx = React.addons.classSet;
       var shareDropdown = cx({
         "share-service-dropdown": true,
         "dropdown-menu": true,
         "visually-hidden": true,
-        "share-button-unavailable": !this.props.socialShareButtonAvailable,
         "hide": !this.props.show
       });
 
-      // When the button is not yet available, we offer to put it in the navbar
-      // for the user.
-      if (!this.props.socialShareButtonAvailable) {
-        return (
-          <div className={shareDropdown}>
-            <div className="share-panel-header">
-              {mozL10n.get("share_panel_header")}
-            </div>
-            <div className="share-panel-body">
-              {
-                mozL10n.get("share_panel_body", {
-                  brandShortname: mozL10n.get("brandShortname"),
-                  clientSuperShortname: mozL10n.get("clientSuperShortname")
-                })
-              }
-            </div>
-            <button className="btn btn-info btn-toolbar-add"
-                    onClick={this.handleToolbarAddButtonClick}>
-              {mozL10n.get("add_to_toolbar_button")}
-            </button>
-          </div>
-        );
-      }
-
       return (
         <ul className={shareDropdown}>
           <li className="dropdown-menu-item" onClick={this.handleAddServiceClick}>
             <i className="icon icon-add-share-service"></i>
             <span>{mozL10n.get("share_add_service_button")}</span>
           </li>
           {this.props.socialShareProviders.length ? <li className="dropdown-menu-separator"/> : null}
           {
@@ -183,17 +151,18 @@ loop.roomViews = (function(mozL10n) {
     propTypes: {
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       error: React.PropTypes.object,
       mozLoop: React.PropTypes.object.isRequired,
       // This data is supplied by the activeRoomStore.
       roomData: React.PropTypes.object.isRequired,
       savingContext: React.PropTypes.bool,
       show: React.PropTypes.bool.isRequired,
-      showContext: React.PropTypes.bool.isRequired
+      showContext: React.PropTypes.bool.isRequired,
+      socialShareProviders: React.PropTypes.array
     },
 
     getInitialState: function() {
       return {
         copiedUrl: false,
         editMode: false,
         newRoomName: ""
       };
@@ -218,16 +187,24 @@ loop.roomViews = (function(mozL10n) {
         new sharedActions.CopyRoomUrl({roomUrl: this.props.roomData.roomUrl}));
 
       this.setState({copiedUrl: true});
     },
 
     handleShareButtonClick: function(event) {
       event.preventDefault();
 
+      var providers = this.props.socialShareProviders;
+      // If there are no providers available currently, save a click by dispatching
+      // the 'AddSocialShareProvider' right away.
+      if (!providers || !providers.length) {
+        this.props.dispatcher.dispatch(new sharedActions.AddSocialShareProvider());
+        return;
+      }
+
       this.toggleDropdownMenu();
     },
 
     handleAddContextClick: function(event) {
       event.preventDefault();
 
       this.handleEditModeChange(true);
     },
@@ -275,17 +252,16 @@ loop.roomViews = (function(mozL10n) {
                     onClick={this.handleShareButtonClick}>
               {mozL10n.get("share_button3")}
             </button>
           </div>
           <SocialShareDropdown
             dispatcher={this.props.dispatcher}
             roomUrl={this.props.roomData.roomUrl}
             show={this.state.showMenu}
-            socialShareButtonAvailable={this.props.socialShareButtonAvailable}
             socialShareProviders={this.props.socialShareProviders}
             ref="menu" />
           <DesktopRoomContextView
             dispatcher={this.props.dispatcher}
             editMode={this.state.editMode}
             error={this.props.error}
             savingContext={this.props.savingContext}
             mozLoop={this.props.mozLoop}
@@ -704,17 +680,16 @@ loop.roomViews = (function(mozL10n) {
               <DesktopRoomInvitationView
                 dispatcher={this.props.dispatcher}
                 error={this.state.error}
                 mozLoop={this.props.mozLoop}
                 roomData={roomData}
                 savingContext={this.state.savingContext}
                 show={shouldRenderInvitationOverlay}
                 showContext={shouldRenderContextView}
-                socialShareButtonAvailable={this.state.socialShareButtonAvailable}
                 socialShareProviders={this.state.socialShareProviders} />
               <div className="video-layout-wrapper">
                 <div className="conversation room-conversation">
                   <div className="media nested">
                     <div className="video_wrapper remote_wrapper">
                       <div className="video_inner remote focus-stream"></div>
                     </div>
                     <div className={localStreamClasses}></div>
--- a/browser/components/loop/content/shared/css/conversation.css
+++ b/browser/components/loop/content/shared/css/conversation.css
@@ -939,50 +939,22 @@ body[dir="rtl"] .room-invitation-addcont
 }
 
 /* When the dropdown is showing a vertical scrollbar, compensate for its width. */
 body[platform="other"] .share-service-dropdown.overflow > .dropdown-menu-item,
 body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
   -moz-padding-end: 20px;
 }
 
-.share-service-dropdown.share-button-unavailable {
-  width: 230px;
-  padding: 8px;
-}
-
 .share-service-dropdown > .dropdown-menu-item > .icon {
   width: 14px;
   height: 14px;
   margin-right: 4px;
 }
 
-.share-service-dropdown .share-panel-header {
-  background-image: url("../img/icons-16x16.svg#share-darkgrey");
-  background-size: 3em 3em;
-  background-repeat: no-repeat;
-  min-height: 3em;
-  font-weight: bold;
-  margin-bottom: 1em;
-  padding-left: 4.5em;
-}
-
-body[dir=rtl] .share-service-dropdown .share-panel-header {
-  background-position: top right;
-  padding-left: 0;
-  padding-right: 4.5em;
-}
-
-.share-service-dropdown .btn-toolbar-add {
-  padding: 4px 2px;
-  border-radius: 2px;
-  margin-top: 1em;
-  width: 100%;
-}
-
 .dropdown-menu-item > .icon-add-share-service {
   background-image: url("../img/icons-16x16.svg#add");
   background-repeat: no-repeat;
   background-size: 12px 12px;
   width: 12px;
   height: 12px;
 }
 
--- a/browser/components/loop/content/shared/js/actions.js
+++ b/browser/components/loop/content/shared/js/actions.js
@@ -396,23 +396,16 @@ loop.shared.actions = (function() {
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     ShareRoomUrl: Action.define("shareRoomUrl", {
       provider: Object,
       roomUrl: String
     }),
 
     /**
-     * Add the Social Share button to the browser toolbar.
-     * XXX: should move to some roomActions module - refs bug 1079284
-     */
-    AddSocialShareButton: Action.define("addSocialShareButton", {
-    }),
-
-    /**
      * Open the share panel to add a Social share provider.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     AddSocialShareProvider: Action.define("addSocialShareProvider", {
     }),
 
     /**
      * XXX: should move to some roomActions module - refs bug 1079284
@@ -431,17 +424,16 @@ loop.shared.actions = (function() {
      */
     SetupRoomInfo: Action.define("setupRoomInfo", {
       // roomContextUrls: Array - Optional.
       // roomDescription: String - Optional.
       // roomName: String - Optional.
       roomOwner: String,
       roomToken: String,
       roomUrl: String,
-      socialShareButtonAvailable: Boolean,
       socialShareProviders: Array
     }),
 
     /**
      * Updates the room information when it is received.
      * XXX: should move to some roomActions module - refs bug 1079284
      *
      * @see https://wiki.mozilla.org/Loop/Architecture/Rooms#GET_.2Frooms.2F.7Btoken.7D
@@ -455,17 +447,16 @@ loop.shared.actions = (function() {
       // See https://wiki.mozilla.org/Loop/Architecture/Context#Format_of_context.value
     }),
 
     /**
      * Updates the Social API information when it is received.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     UpdateSocialShareInfo: Action.define("updateSocialShareInfo", {
-      socialShareButtonAvailable: Boolean,
       socialShareProviders: Array
     }),
 
     /**
      * Starts the process for the user to join the room.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     JoinRoom: Action.define("joinRoom", {
--- a/browser/components/loop/content/shared/js/activeRoomStore.js
+++ b/browser/components/loop/content/shared/js/activeRoomStore.js
@@ -110,18 +110,16 @@ loop.store.ActiveRoomStore = (function()
         // The roomCryptoKey to decode the context data if necessary.
         roomCryptoKey: null,
         // The description for a room as stored in the context data.
         roomDescription: null,
         // Room information failed to be obtained for a reason. See ROOM_INFO_FAILURES.
         roomInfoFailure: null,
         // The name of the room.
         roomName: null,
-        // Social API state.
-        socialShareButtonAvailable: false,
         socialShareProviders: null
       };
     },
 
     /**
      * Handles a room failure.
      *
      * @param {sharedActions.RoomFailure} actionData
@@ -213,17 +211,16 @@ loop.store.ActiveRoomStore = (function()
 
           this.dispatchAction(new sharedActions.SetupRoomInfo({
             roomToken: actionData.roomToken,
             roomContextUrls: roomData.decryptedContext.urls,
             roomDescription: roomData.decryptedContext.description,
             roomName: roomData.decryptedContext.roomName,
             roomOwner: roomData.roomOwner,
             roomUrl: roomData.roomUrl,
-            socialShareButtonAvailable: this._mozLoop.isSocialShareButtonAvailable(),
             socialShareProviders: this._mozLoop.getSocialShareProviders()
           }));
 
           // For the conversation window, we need to automatically
           // join the room.
           this.dispatchAction(new sharedActions.JoinRoom());
         }.bind(this));
     },
@@ -332,17 +329,16 @@ loop.store.ActiveRoomStore = (function()
       this.setStoreState({
         roomContextUrls: actionData.roomContextUrls,
         roomDescription: actionData.roomDescription,
         roomName: actionData.roomName,
         roomOwner: actionData.roomOwner,
         roomState: ROOM_STATES.READY,
         roomToken: actionData.roomToken,
         roomUrl: actionData.roomUrl,
-        socialShareButtonAvailable: actionData.socialShareButtonAvailable,
         socialShareProviders: actionData.socialShareProviders
       });
 
       this._onUpdateListener = this._handleRoomUpdate.bind(this);
       this._onDeleteListener = this._handleRoomDelete.bind(this);
       this._onSocialShareUpdate = this._handleSocialShareUpdate.bind(this);
 
       this._mozLoop.rooms.on("update:" + actionData.roomToken, this._onUpdateListener);
@@ -374,17 +370,16 @@ loop.store.ActiveRoomStore = (function()
     /**
      * Handles the updateSocialShareInfo action. Updates the room data with new
      * Social API info.
      *
      * @param  {sharedActions.UpdateSocialShareInfo} actionData
      */
     updateSocialShareInfo: function(actionData) {
       this.setStoreState({
-        socialShareButtonAvailable: actionData.socialShareButtonAvailable,
         socialShareProviders: actionData.socialShareProviders
       });
     },
 
     /**
      * Handles room updates notified by the mozLoop rooms API.
      *
      * @param {String} eventName The name of the event
@@ -413,17 +408,16 @@ loop.store.ActiveRoomStore = (function()
     },
 
     /**
      * Handles an update of the position of the Share widget and changes to list
      * of Social API providers, notified by the mozLoop API.
      */
     _handleSocialShareUpdate: function() {
       this.dispatchAction(new sharedActions.UpdateSocialShareInfo({
-        socialShareButtonAvailable: this._mozLoop.isSocialShareButtonAvailable(),
         socialShareProviders: this._mozLoop.getSocialShareProviders()
       }));
     },
 
     /**
      * Handles the action to join to a room.
      */
     joinRoom: function() {
--- a/browser/components/loop/content/shared/js/conversationStore.js
+++ b/browser/components/loop/content/shared/js/conversationStore.js
@@ -424,17 +424,17 @@ loop.store = loop.store || {};
     /**
      * Fetches a new room URL intended to be sent over email when a contact
      * can't be reached.
      */
     fetchRoomEmailLink: function(actionData) {
       this.mozLoop.rooms.create({
         roomName: actionData.roomName,
         roomOwner: actionData.roomOwner,
-        maxSize:   loop.store.MAX_ROOM_CREATION_SIZE,
+        maxSize: loop.store.MAX_ROOM_CREATION_SIZE,
         expiresIn: loop.store.DEFAULT_EXPIRES_IN
       }, function(err, createdRoomData) {
         if (err) {
           this.trigger("error:emailLink");
           return;
         }
         this.setStoreState({"emailLink": createdRoomData.roomUrl});
       }.bind(this));
--- a/browser/components/loop/content/shared/js/feedbackApiClient.js
+++ b/browser/components/loop/content/shared/js/feedbackApiClient.js
@@ -85,20 +85,20 @@ loop.FeedbackAPIClient = (function($, _)
     /**
      * Sends feedback data.
      *
      * @param  {Object}   fields Feedback form data.
      * @param  {Function} cb     Callback(err, result)
      */
     send: function(fields, cb) {
       var req = $.ajax({
-        url:         this.baseUrl,
-        method:      "POST",
+        url: this.baseUrl,
+        method: "POST",
         contentType: "application/json",
-        dataType:    "json",
+        dataType: "json",
         data: JSON.stringify(this._createPayload(fields))
       });
 
       req.done(function(result) {
         console.info("User feedback data have been submitted", result);
         cb(null, result);
       });
 
--- a/browser/components/loop/content/shared/js/feedbackViews.js
+++ b/browser/components/loop/content/shared/js/feedbackViews.js
@@ -49,35 +49,35 @@ loop.shared.views.FeedbackView = (functi
   });
 
   /**
    * Detailed feedback form.
    */
   var FeedbackForm = React.createClass({displayName: "FeedbackForm",
     propTypes: {
       feedbackStore: React.PropTypes.instanceOf(loop.store.FeedbackStore),
-      pending:       React.PropTypes.bool,
-      reset:         React.PropTypes.func
+      pending: React.PropTypes.bool,
+      reset: React.PropTypes.func
     },
 
     getInitialState: function() {
       return {category: "", description: ""};
     },
 
     getDefaultProps: function() {
       return {pending: false};
     },
 
     _getCategories: function() {
       return {
         audio_quality: l10n.get("feedback_category_audio_quality"),
         video_quality: l10n.get("feedback_category_video_quality"),
-        disconnected : l10n.get("feedback_category_was_disconnected"),
-        confusing:     l10n.get("feedback_category_confusing2"),
-        other:         l10n.get("feedback_category_other2")
+        disconnected: l10n.get("feedback_category_was_disconnected"),
+        confusing: l10n.get("feedback_category_confusing2"),
+        other: l10n.get("feedback_category_other2")
       };
     },
 
     _getCategoryFields: function() {
       var categories = this._getCategories();
       return Object.keys(categories).map(function(category, key) {
         return (
           React.createElement("label", {key: key, className: "feedback-category-label"}, 
--- a/browser/components/loop/content/shared/js/feedbackViews.jsx
+++ b/browser/components/loop/content/shared/js/feedbackViews.jsx
@@ -49,35 +49,35 @@ loop.shared.views.FeedbackView = (functi
   });
 
   /**
    * Detailed feedback form.
    */
   var FeedbackForm = React.createClass({
     propTypes: {
       feedbackStore: React.PropTypes.instanceOf(loop.store.FeedbackStore),
-      pending:       React.PropTypes.bool,
-      reset:         React.PropTypes.func
+      pending: React.PropTypes.bool,
+      reset: React.PropTypes.func
     },
 
     getInitialState: function() {
       return {category: "", description: ""};
     },
 
     getDefaultProps: function() {
       return {pending: false};
     },
 
     _getCategories: function() {
       return {
         audio_quality: l10n.get("feedback_category_audio_quality"),
         video_quality: l10n.get("feedback_category_video_quality"),
-        disconnected : l10n.get("feedback_category_was_disconnected"),
-        confusing:     l10n.get("feedback_category_confusing2"),
-        other:         l10n.get("feedback_category_other2")
+        disconnected: l10n.get("feedback_category_was_disconnected"),
+        confusing: l10n.get("feedback_category_confusing2"),
+        other: l10n.get("feedback_category_other2")
       };
     },
 
     _getCategoryFields: function() {
       var categories = this._getCategories();
       return Object.keys(categories).map(function(category, key) {
         return (
           <label key={key} className="feedback-category-label">
--- a/browser/components/loop/content/shared/js/fxOSActiveRoomStore.js
+++ b/browser/components/loop/content/shared/js/fxOSActiveRoomStore.js
@@ -104,17 +104,17 @@ loop.store.FxOSActiveRoomStore = (functi
       request.onerror = (function(event) {
         if (!installApp) {
           // This really should not happen ever.
           console.error(
            "Unexpected activity launch error after the app has been installed");
           return;
         }
         if (event.target.error.name !== "NO_PROVIDER") {
-          console.error ("Unexpected " + event.target.error.name);
+          console.error("Unexpected " + event.target.error.name);
           return;
         }
         // We need to install the FxOS app.
         this.setStoreState({
             marketplaceSrc: loop.config.marketplaceUrl,
             onMarketplaceMessage: this._onMarketplaceMessage.bind(this)
         });
       }).bind(this);
--- a/browser/components/loop/content/shared/js/models.js
+++ b/browser/components/loop/content/shared/js/models.js
@@ -7,36 +7,36 @@ loop.shared = loop.shared || {};
 loop.shared.models = (function(l10n) {
   "use strict";
 
   /**
    * Conversation model.
    */
   var ConversationModel = Backbone.Model.extend({
     defaults: {
-      connected:    false,         // Session connected flag
-      ongoing:      false,         // Ongoing call flag
-      callerId:     undefined,     // Loop caller id
-      loopToken:    undefined,     // Loop conversation token
-      sessionId:    undefined,     // OT session id
+      connected: false,            // Session connected flag
+      ongoing: false,              // Ongoing call flag
+      callerId: undefined,         // Loop caller id
+      loopToken: undefined,        // Loop conversation token
+      sessionId: undefined,        // OT session id
       sessionToken: undefined,     // OT session token
-      sessionType:  undefined,     // Hawk session type
-      apiKey:       undefined,     // OT api key
-      windowId:     undefined,     // The window id
-      callId:       undefined,     // The callId on the server
-      progressURL:  undefined,     // The websocket url to use for progress
+      sessionType: undefined,      // Hawk session type
+      apiKey: undefined,           // OT api key
+      windowId: undefined,         // The window id
+      callId: undefined,           // The callId on the server
+      progressURL: undefined,      // The websocket url to use for progress
       websocketToken: undefined,   // The token to use for websocket auth, this is
                                    // stored as a hex string which is what the server
                                    // requires.
-      callType:     undefined,     // The type of incoming call selected by
+      callType: undefined,         // The type of incoming call selected by
                                    // other peer ("audio" or "audio-video")
       selectedCallType: "audio-video", // The selected type for the call that was
                                        // initiated ("audio" or "audio-video")
-      callToken:    undefined,     // Incoming call token.
-      callUrl:      undefined,     // Incoming call url
+      callToken: undefined,        // Incoming call token.
+      callUrl: undefined,          // Incoming call url
                                    // Used for blocking a call url
       subscribedStream: false,     // Used to indicate that a stream has been
                                    // subscribed to
       publishedStream: false       // Used to indicate that a stream has been
                                    // published
     },
 
     /**
@@ -129,45 +129,45 @@ loop.shared.models = (function(l10n) {
      * Sets session information.
      * Session data received by creating an outgoing call.
      *
      * @param {Object} sessionData Conversation session information.
      */
     setOutgoingSessionData: function(sessionData) {
       // Explicit property assignment to prevent later "surprises"
       this.set({
-        sessionId:      sessionData.sessionId,
-        sessionToken:   sessionData.sessionToken,
-        apiKey:         sessionData.apiKey,
-        callId:         sessionData.callId,
-        progressURL:    sessionData.progressURL,
+        sessionId: sessionData.sessionId,
+        sessionToken: sessionData.sessionToken,
+        apiKey: sessionData.apiKey,
+        callId: sessionData.callId,
+        progressURL: sessionData.progressURL,
         websocketToken: sessionData.websocketToken.toString(16)
       });
     },
 
     /**
      * Sets session information about the incoming call.
      *
      * @param {Object} sessionData Conversation session information.
      */
     setIncomingSessionData: function(sessionData) {
       // Explicit property assignment to prevent later "surprises"
       this.set({
-        sessionId:       sessionData.sessionId,
-        sessionToken:    sessionData.sessionToken,
-        sessionType:     sessionData.sessionType,
-        apiKey:          sessionData.apiKey,
-        callId:          sessionData.callId,
-        callerId:        sessionData.callerId,
+        sessionId: sessionData.sessionId,
+        sessionToken: sessionData.sessionToken,
+        sessionType: sessionData.sessionType,
+        apiKey: sessionData.apiKey,
+        callId: sessionData.callId,
+        callerId: sessionData.callerId,
         urlCreationDate: sessionData.urlCreationDate,
-        progressURL:     sessionData.progressURL,
-        websocketToken:  sessionData.websocketToken.toString(16),
-        callType:        sessionData.callType || "audio-video",
-        callToken:       sessionData.callToken,
-        callUrl:         sessionData.callUrl
+        progressURL: sessionData.progressURL,
+        websocketToken: sessionData.websocketToken.toString(16),
+        callType: sessionData.callType || "audio-video",
+        callToken: sessionData.callToken,
+        callUrl: sessionData.callUrl
       });
     },
 
     /**
      * Starts a SDK session and subscribe to call events.
      */
     startSession: function() {
       if (!this.isSessionReady()) {
--- a/browser/components/loop/modules/LoopContacts.jsm
+++ b/browser/components/loop/modules/LoopContacts.jsm
@@ -263,17 +263,17 @@ const validateContact = function(obj, de
  *                             an `Error` object or `null`. The second argument
  *                             will be the `data` Array, if all operations finished
  *                             successfully.
  */
 const batch = function(operation, data, callback) {
   let processed = [];
   if (!LoopContactsInternal.hasOwnProperty(operation) ||
     typeof LoopContactsInternal[operation] != "function") {
-    callback(new Error ("LoopContactsInternal does not contain a '" +
+    callback(new Error("LoopContactsInternal does not contain a '" +
              operation + "' method"));
     return;
   }
   LoopStorage.asyncForEach(data, (item, next) => {
     LoopContactsInternal[operation](item, (err, result) => {
       if (err) {
         next(err);
         return;
--- a/browser/components/loop/modules/MozLoopAPI.jsm
+++ b/browser/components/loop/modules/MozLoopAPI.jsm
@@ -965,92 +965,35 @@ function injectLoopAPI(targetWindow) {
       enumerable: true,
       writable: true,
       value: function(windowId, active) {
         MozLoopService.setScreenShareState(windowId, active);
       }
     },
 
     /**
-     * Checks if the Social Share widget is available in any of the registered
-     * widget areas (navbar, MenuPanel, etc).
-     *
-     * @return {Boolean} `true` if the widget is available and `false` when it's
-     *                   still in the Customization palette.
-     */
-    isSocialShareButtonAvailable: {
-      enumerable: true,
-      writable: true,
-      value: function() {
-        let win = Services.wm.getMostRecentWindow("navigator:browser");
-        if (!win || !win.CustomizableUI) {
-          return false;
-        }
-
-        let widget = win.CustomizableUI.getWidget(kShareWidgetId);
-        if (widget) {
-          if (!socialShareButtonListenersAdded) {
-            let eventName = "social:" + kShareWidgetId;
-            Services.obs.addObserver(onShareWidgetChanged, eventName + "-added", false);
-            Services.obs.addObserver(onShareWidgetChanged, eventName + "-removed", false);
-            socialShareButtonListenersAdded = true;
-          }
-          return !!widget.areaType;
-        }
-
-        return false;
-      }
-    },
-
-    /**
-     * Add the Social Share widget to the navbar area, but only when it's not
-     * located anywhere else than the Customization palette.
-     */
-    addSocialShareButton: {
-      enumerable: true,
-      writable: true,
-      value: function() {
-        // Don't do anything if the button is already available.
-        if (api.isSocialShareButtonAvailable.value()) {
-          return;
-        }
-
-        let win = Services.wm.getMostRecentWindow("navigator:browser");
-        if (!win || !win.CustomizableUI) {
-          return;
-        }
-        win.CustomizableUI.addWidgetToArea(kShareWidgetId, win.CustomizableUI.AREA_NAVBAR);
-      }
-    },
-
-    /**
      * Activates the Social Share panel with the Social Provider panel opened
      * when the popup open.
      */
     addSocialShareProvider: {
       enumerable: true,
       writable: true,
       value: function() {
-        // Don't do anything if the button is _not_ available.
-        if (!api.isSocialShareButtonAvailable.value()) {
-          return;
-        }
-
         let win = Services.wm.getMostRecentWindow("navigator:browser");
         if (!win || !win.SocialShare) {
           return;
         }
-        win.SocialShare.showDirectory();
+        win.SocialShare.showDirectory(win.LoopUI.toolbarButton.anchor);
       }
     },
 
     /**
      * Returns a sorted list of Social Providers that can share URLs. See
      * `updateSocialProvidersCache()` for more information.
-     * 
+     *
      * @return {Array} Sorted list of share-capable Social Providers.
      */
     getSocialShareProviders: {
       enumerable: true,
       writable: true,
       value: function() {
         if (socialProviders) {
           return socialProviders;
@@ -1082,17 +1025,18 @@ function injectLoopAPI(targetWindow) {
 
         let graphData = {
           url: roomURL,
           title: title
         };
         if (body) {
           graphData.body = body;
         }
-        win.SocialShare.sharePage(providerOrigin, graphData);
+        win.SocialShare.sharePage(providerOrigin, graphData, null,
+          win.LoopUI.toolbarButton.anchor);
       }
     }
   };
 
   /**
    * Send an event to the content window to indicate that the state on the chrome
    * side was updated.
    *
--- a/browser/components/loop/modules/MozLoopPushHandler.jsm
+++ b/browser/components/loop/modules/MozLoopPushHandler.jsm
@@ -42,17 +42,17 @@ PushSocket.prototype = {
    *                   both near and far side close events map to this
    *                   callback.
    *                   aCode is any status code returned on close
    *                   aReason is any string returned on close
    */
 
   connect: function(pushUri, onMsg, onStart, onClose) {
     if (!pushUri || !onMsg || !onStart || !onClose) {
-      throw new Error("PushSocket: missing required parameter(s):"
+      throw new Error("PushSocket: missing required parameter(s):" +
                       (pushUri ? "" : " pushUri") +
                       (onMsg ? "" : " onMsg") +
                       (onStart ? "" : " onStart") +
                       (onClose ? "" : " onClose"));
     }
 
     this._onMsg = onMsg;
     this._onStart = onStart;
--- a/browser/components/loop/standalone/content/js/standaloneClient.js
+++ b/browser/components/loop/standalone/content/js/standaloneClient.js
@@ -104,20 +104,20 @@ loop.StandaloneClient = (function($) {
      * @param  {Function} cb Callback(err, sessionData)
      */
     requestCallInfo: function(loopToken, callType, cb) {
       if (!loopToken) {
         throw new Error("missing required parameter loopToken");
       }
 
       var req = $.ajax({
-        url:         this.settings.baseServerUrl + "/calls/" + loopToken,
-        method:      "POST",
+        url: this.settings.baseServerUrl + "/calls/" + loopToken,
+        method: "POST",
         contentType: "application/json",
-        dataType:    "json",
+        dataType: "json",
         data: JSON.stringify({callType: callType, channel: "standalone"})
       });
 
       req.done(function(sessionData) {
         try {
           cb(null, this._validate(sessionData, expectedCallsProperties));
         } catch (err) {
           console.error("Error requesting call info", err.message);
--- a/browser/components/loop/standalone/content/js/standaloneMozLoop.js
+++ b/browser/components/loop/standalone/content/js/standaloneMozLoop.js
@@ -72,18 +72,18 @@ loop.StandaloneMozLoop = (function(mozL1
      * @param {String}   roomToken Room identifier
      * @param {Function} callback  Function that will be invoked once the operation
      *                             finished. The first argument passed will be an
      *                             `Error` object or `null`. The second argument will
      *                             be the list of rooms, if it was fetched successfully.
      */
     get: function(roomToken, callback) {
       var req = $.ajax({
-        url:         this._baseServerUrl + "/rooms/" + roomToken,
-        method:      "GET",
+        url: this._baseServerUrl + "/rooms/" + roomToken,
+        method: "GET",
         contentType: "application/json",
         beforeSend: function(xhr) {
           if (this.sessionToken) {
             xhr.setRequestHeader("Authorization", "Basic " + btoa(this.sessionToken));
           }
         }.bind(this)
       });
 
@@ -114,20 +114,20 @@ loop.StandaloneMozLoop = (function(mozL1
      * @param {Boolean} async       Set to true for an async request, false for sync.
      * @param {Function} callback The callback for when the request completes. The
      *                            first parameter is non-null on error, the second parameter
      *                            is the response data.
      */
     _postToRoom: function(roomToken, sessionToken, roomData, expectedProps,
                           async, callback) {
       var req = $.ajax({
-        url:         this._baseServerUrl + "/rooms/" + roomToken,
-        method:      "POST",
+        url: this._baseServerUrl + "/rooms/" + roomToken,
+        method: "POST",
         contentType: "application/json",
-        dataType:    "json",
+        dataType: "json",
         data: JSON.stringify(roomData),
         beforeSend: function(xhr) {
           if (sessionToken) {
             xhr.setRequestHeader("Authorization", "Basic " + btoa(sessionToken));
           }
         },
         async: async,
         success: function(responseData) {
--- a/browser/components/loop/standalone/content/js/webapp.js
+++ b/browser/components/loop/standalone/content/js/webapp.js
@@ -160,17 +160,17 @@ loop.webapp = (function($, _, OT, mozL10
           video: this.get("selectedCallType") === "audio-video"
         }
       });
 
       request.onsuccess = function() {};
 
       request.onerror = (function(event) {
         if (event.target.error.name !== "NO_PROVIDER") {
-          console.error ("Unexpected " + event.target.error.name);
+          console.error("Unexpected " + event.target.error.name);
           this.trigger("session:error", "fxos_app_needed", {
             fxosAppName: loop.config.fxosApp.name
           });
           return;
         }
         this.trigger("fxos:app-needed");
       }).bind(this);
     },
@@ -812,17 +812,17 @@ loop.webapp = (function($, _, OT, mozL10
       }
     },
 
     /**
      * Asks the user for the media privileges, handling the result appropriately.
      */
     getMediaPrivs: function() {
       this.setState({callStatus: "gumPrompt"});
-      multiplexGum.getPermsAndCacheMedia({audio:true, video:true},
+      multiplexGum.getPermsAndCacheMedia({audio: true, video: true},
         function(localStream) {
           this.props.conversation.gotMediaPrivs();
         }.bind(this),
         function(errorCode) {
           multiplexGum.reset();
           this.setState({callStatus: "failure"});
         }.bind(this)
       );
--- a/browser/components/loop/standalone/content/js/webapp.jsx
+++ b/browser/components/loop/standalone/content/js/webapp.jsx
@@ -160,17 +160,17 @@ loop.webapp = (function($, _, OT, mozL10
           video: this.get("selectedCallType") === "audio-video"
         }
       });
 
       request.onsuccess = function() {};
 
       request.onerror = (function(event) {
         if (event.target.error.name !== "NO_PROVIDER") {
-          console.error ("Unexpected " + event.target.error.name);
+          console.error("Unexpected " + event.target.error.name);
           this.trigger("session:error", "fxos_app_needed", {
             fxosAppName: loop.config.fxosApp.name
           });
           return;
         }
         this.trigger("fxos:app-needed");
       }).bind(this);
     },
@@ -812,17 +812,17 @@ loop.webapp = (function($, _, OT, mozL10
       }
     },
 
     /**
      * Asks the user for the media privileges, handling the result appropriately.
      */
     getMediaPrivs: function() {
       this.setState({callStatus: "gumPrompt"});
-      multiplexGum.getPermsAndCacheMedia({audio:true, video:true},
+      multiplexGum.getPermsAndCacheMedia({audio: true, video: true},
         function(localStream) {
           this.props.conversation.gotMediaPrivs();
         }.bind(this),
         function(errorCode) {
           multiplexGum.reset();
           this.setState({callStatus: "failure"});
         }.bind(this)
       );
--- a/browser/components/loop/test/desktop-local/l10n_test.js
+++ b/browser/components/loop/test/desktop-local/l10n_test.js
@@ -27,11 +27,11 @@ describe("document.mozL10n", function() 
     document.mozL10n.initialize(fakeMozLoop);
   });
 
   it("should get a simple string", function() {
     expect(document.mozL10n.get("test")).eql("test");
   });
 
   it("should get a plural form", function() {
-    expect(document.mozL10n.get("plural", {num:10})).eql("10 plural forms");
+    expect(document.mozL10n.get("plural", {num: 10})).eql("10 plural forms");
   });
 });
--- a/browser/components/loop/test/desktop-local/roomStore_test.js
+++ b/browser/components/loop/test/desktop-local/roomStore_test.js
@@ -164,17 +164,17 @@ describe("loop.store.RoomStore", functio
           expect(store.getStoreState().rooms).to.have.length.of(2);
           expect(store.getStoreState().rooms.some(function(room) {
             return room.roomToken === "_nxD4V4FflQ";
           })).eql(false);
         });
       });
 
       describe("refresh", function() {
-        it ("should clear the list of rooms", function() {
+        it("should clear the list of rooms", function() {
           fakeMozLoop.rooms.trigger("refresh", "refresh");
 
           expect(store.getStoreState().rooms).to.have.length.of(0);
         });
       });
     });
 
     describe("#findNextAvailableRoomNumber", function() {
@@ -317,17 +317,17 @@ describe("loop.store.RoomStore", functio
    });
 
    describe("#createdRoom", function() {
       beforeEach(function() {
         sandbox.stub(dispatcher, "dispatch");
       });
 
       it("should switch the pendingCreation state flag to false", function() {
-        store.setStoreState({pendingCreation:true});
+        store.setStoreState({pendingCreation: true});
 
         store.createdRoom(new sharedActions.CreatedRoom({
           roomToken: "fakeToken"
         }));
 
         expect(store.getStoreState().pendingCreation).eql(false);
       });
 
@@ -342,17 +342,17 @@ describe("loop.store.RoomStore", functio
             new sharedActions.OpenRoom({
               roomToken: "fakeToken"
             }));
         });
     });
 
     describe("#createRoomError", function() {
       it("should switch the pendingCreation state flag to false", function() {
-        store.setStoreState({pendingCreation:true});
+        store.setStoreState({pendingCreation: true});
 
         store.createRoomError({
           error: new Error("fake")
         });
 
         expect(store.getStoreState().pendingCreation).eql(false);
       });
 
@@ -442,26 +442,16 @@ describe("loop.store.RoomStore", functio
         }));
 
         sinon.assert.calledOnce(fakeMozLoop.socialShareRoom);
         sinon.assert.calledWithExactly(fakeMozLoop.socialShareRoom, origin,
           roomUrl, "share_tweet", null);
       });
     });
 
-    describe("#addSocialShareButton", function() {
-      it("should invoke to the correct mozLoop function", function() {
-        fakeMozLoop.addSocialShareButton = sinon.stub();
-
-        store.addSocialShareButton(new sharedActions.AddSocialShareButton());
-
-        sinon.assert.calledOnce(fakeMozLoop.addSocialShareButton);
-      });
-    });
-
     describe("#addSocialShareProvider", function() {
       it("should invoke to the correct mozLoop function", function() {
         fakeMozLoop.addSocialShareProvider = sinon.stub();
 
         store.addSocialShareProvider(new sharedActions.AddSocialShareProvider());
 
         sinon.assert.calledOnce(fakeMozLoop.addSocialShareProvider);
       });
--- a/browser/components/loop/test/desktop-local/roomViews_test.js
+++ b/browser/components/loop/test/desktop-local/roomViews_test.js
@@ -23,17 +23,16 @@ describe("loop.roomViews", function () {
     fakeMozLoop = {
       getAudioBlob: sinon.stub(),
       getLoopPref: sinon.stub(),
       getSelectedTabMetadata: sinon.stub().callsArgWith(0, {
         favicon: favicon,
         previews: [],
         title: ""
       }),
-      isSocialShareButtonAvailable: sinon.stub(),
       rooms: {
         get: sinon.stub().callsArgWith(1, null, {
           roomToken: "fakeToken",
           roomName: "fakeName",
           decryptedContext: {
             roomName: "fakeName",
             urls: []
           }
@@ -206,21 +205,37 @@ describe("loop.roomViews", function () {
           React.addons.TestUtils.Simulate.click(copyBtn);
 
           // copied_url_button is the l10n string.
           expect(copyBtn.textContent).eql("copied_url_button");
       });
     });
 
     describe("Share button", function() {
-      beforeEach(function() {
+      it("should dispatch a AddSocialShareProvider action when the share button is clicked", function() {
         view = mountTestComponent();
+
+        var shareBtn = view.getDOMNode().querySelector(".btn-share");
+
+        React.addons.TestUtils.Simulate.click(shareBtn);
+
+        sinon.assert.calledOnce(dispatcher.dispatch);
+        sinon.assert.calledWith(dispatcher.dispatch,
+          new sharedActions.AddSocialShareProvider());
       });
 
       it("should toggle the share dropdown when the share button is clicked", function() {
+        view = mountTestComponent({
+          socialShareProviders: [{
+            name: "foo",
+            origin: "https://foo",
+            iconURL: "http://example.com/foo.png"
+          }]
+        });
+
         var shareBtn = view.getDOMNode().querySelector(".btn-share");
 
         React.addons.TestUtils.Simulate.click(shareBtn);
 
         expect(view.state.showMenu).to.eql(true);
         expect(view.refs.menu.props.show).to.eql(true);
       });
     });
@@ -547,90 +562,62 @@ describe("loop.roomViews", function () {
 
     describe("#render", function() {
       it("should show no contents when the Social Providers have not been fetched yet", function() {
         view = mountTestComponent();
 
         expect(view.getDOMNode()).to.eql(null);
       });
 
-      it("should show different contents when the Share XUL button is not available", function() {
-        view = mountTestComponent({
-          socialShareProviders: []
-        });
-
-        var node = view.getDOMNode();
-        expect(node.querySelector(".share-panel-header")).to.not.eql(null);
-      });
-
       it("should show an empty list when no Social Providers are available", function() {
         view = mountTestComponent({
-          socialShareButtonAvailable: true,
           socialShareProviders: []
         });
 
         var node = view.getDOMNode();
         expect(node.querySelector(".icon-add-share-service")).to.not.eql(null);
         expect(node.querySelectorAll(".dropdown-menu-item").length).to.eql(1);
       });
 
       it("should show a list of available Social Providers", function() {
         view = mountTestComponent({
-          socialShareButtonAvailable: true,
           socialShareProviders: [fakeProvider]
         });
 
         var node = view.getDOMNode();
         expect(node.querySelector(".icon-add-share-service")).to.not.eql(null);
         expect(node.querySelector(".dropdown-menu-separator")).to.not.eql(null);
 
         var dropdownNodes = node.querySelectorAll(".dropdown-menu-item");
         expect(dropdownNodes.length).to.eql(2);
         expect(dropdownNodes[1].querySelector("img").src).to.eql(fakeProvider.iconURL);
         expect(dropdownNodes[1].querySelector("span").textContent)
           .to.eql(fakeProvider.name);
       });
     });
 
-    describe("#handleToolbarAddButtonClick", function() {
-      it("should dispatch an action when the 'add to toolbar' button is clicked", function() {
-        view = mountTestComponent({
-          socialShareProviders: []
-        });
-
-        var addButton = view.getDOMNode().querySelector(".btn-toolbar-add");
-        React.addons.TestUtils.Simulate.click(addButton);
-
-        sinon.assert.calledOnce(dispatcher.dispatch);
-        sinon.assert.calledWithExactly(dispatcher.dispatch,
-          new sharedActions.AddSocialShareButton());
-      });
-    });
-
     describe("#handleAddServiceClick", function() {
       it("should dispatch an action when the 'add provider' item is clicked", function() {
         view = mountTestComponent({
-          socialShareProviders: [],
-          socialShareButtonAvailable: true
+          socialShareProviders: []
         });
 
         var addItem = view.getDOMNode().querySelector(".dropdown-menu-item:first-child");
         React.addons.TestUtils.Simulate.click(addItem);
 
         sinon.assert.calledOnce(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.AddSocialShareProvider());
       });
     });
 
     describe("#handleProviderClick", function() {
       it("should dispatch an action when a provider item is clicked", function() {
         view = mountTestComponent({
           roomUrl: "http://example.com",
-          socialShareButtonAvailable: true,
           socialShareProviders: [fakeProvider]
         });
 
         var providerItem = view.getDOMNode().querySelector(".dropdown-menu-item:last-child");
         React.addons.TestUtils.Simulate.click(providerItem);
 
         sinon.assert.calledOnce(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
--- a/browser/components/loop/test/mochitest/browser_CardDavImporter.js
+++ b/browser/components/loop/test/mochitest/browser_CardDavImporter.js
@@ -165,17 +165,17 @@ const monkeyPatchImporter = function(imp
       resolve({"responseXML": responseXML});
     });
   }.bind(importer);
   return importer;
 };
 
 add_task(function* test_CardDavImport() {
   let importer = monkeyPatchImporter(new CardDavImporter());
-  yield new Promise ((resolve, reject) => {
+  yield new Promise((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.com",
         "auth": kAuth.method,
         "user": kAuth.user,
         "password": kAuth.password
       }, (err, result) => { err ? reject(err) : resolve(result); }, mockDb);
   });
@@ -260,67 +260,67 @@ add_task(function* test_CardDavImport() 
   c = mockDb._store[6];
   Assert.equal(c.name[0], "Trip", "Full name should be synthesized correctly");
   c = mockDb._store[7];
   Assert.equal(c.name[0], "Acme, Inc.", "Full name should be synthesized correctly");
   c = mockDb._store[8];
   Assert.equal(c.name[0], "anyone@example.com", "Full name should be synthesized correctly");
 
   // Check that a re-import doesn't cause contact duplication.
-  yield new Promise ((resolve, reject) => {
+  yield new Promise((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.com",
         "auth": kAuth.method,
         "user": kAuth.user,
         "password": kAuth.password
       }, (err, result) => { err ? reject(err) : resolve(result); }, mockDb);
   });
   Assert.equal(vcards.length, Object.keys(mockDb._store).length,
                "Second import shouldn't increase DB size");
 
   // Check that errors are propagated back to caller
-  let error = yield new Promise ((resolve, reject) => {
+  let error = yield new Promise((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.com",
         "auth": kAuth.method,
         "user": kAuth.user,
         "password": "invalidpassword"
       }, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
   });
   Assert.equal(error.message, "401 Auth Failure", "Auth error should propagate");
 
-  error = yield new Promise ((resolve, reject) => {
+  error = yield new Promise((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.invalid",
         "auth": kAuth.method,
         "user": kAuth.user,
         "password": kAuth.password
       }, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
   });
   Assert.equal(error.message, "404 Not Found", "Not found error should propagate");
 
   let tmp = mockDb.getByServiceId;
   mockDb.getByServiceId = function(serviceId, callback) {
     callback(new Error("getByServiceId failed"));
   };
-  error = yield new Promise ((resolve, reject) => {
+  error = yield new Promise((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.com",
         "auth": kAuth.method,
         "user": kAuth.user,
         "password": kAuth.password
       }, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
   });
   Assert.equal(error.message, "getByServiceId failed", "Database error should propagate");
   mockDb.getByServiceId = tmp;
 
-  error = yield new Promise ((resolve, reject) => {
+  error = yield new Promise((resolve, reject) => {
     info("Initiating import");
     importer.startImport({
         "host": "example.com"
       }, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
   });
   Assert.equal(error.message, "No authentication specified", "Missing parameters should generate error");
 });
--- a/browser/components/loop/test/mochitest/browser_mozLoop_socialShare.js
+++ b/browser/components/loop/test/mochitest/browser_mozLoop_socialShare.js
@@ -8,17 +8,16 @@
 
 "use strict";
 
 Cu.import("resource://gre/modules/Promise.jsm");
 const {SocialService} = Cu.import("resource://gre/modules/SocialService.jsm", {});
 
 add_task(loadLoopPanel);
 
-const kShareWidgetId = "social-share-button";
 const kShareProvider = {
   name: "provider 1",
   origin: "https://example.com",
   iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png",
   shareURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar_empty.html"
 };
 const kShareProviderInvalid = {
   name: "provider 1",
@@ -27,70 +26,25 @@ const kShareProviderInvalid = {
 
 registerCleanupFunction(function* () {
   yield new Promise(resolve => SocialService.disableProvider(kShareProvider.origin, resolve));
   yield new Promise(resolve => SocialService.disableProvider(kShareProviderInvalid.origin, resolve));
   Assert.strictEqual(Social.providers.length, 0, "all providers should be removed");
   SocialShare.uninit();
 });
 
-add_task(function* test_mozLoop_isSocialShareButtonAvailable() {
-  Assert.ok(gMozLoopAPI, "mozLoop should exist");
-
-  // First make sure the Social Share button is not available. This is probably
-  // already the case, but make it explicit here.
-  CustomizableUI.removeWidgetFromArea(kShareWidgetId);
-
-  Assert.ok(!gMozLoopAPI.isSocialShareButtonAvailable(),
-    "Social Share button should not be available");
-
-  // Add the widget to the navbar.
-  CustomizableUI.addWidgetToArea(kShareWidgetId, CustomizableUI.AREA_NAVBAR);
-
-  Assert.ok(gMozLoopAPI.isSocialShareButtonAvailable(),
-    "Social Share button should be available");
-
-  // Add the widget to the MenuPanel.
-  CustomizableUI.addWidgetToArea(kShareWidgetId, CustomizableUI.AREA_PANEL);
-
-  Assert.ok(gMozLoopAPI.isSocialShareButtonAvailable(),
-    "Social Share button should still be available");
-
-  // Test button removal during the same session.
-  CustomizableUI.removeWidgetFromArea(kShareWidgetId);
-
-  Assert.ok(!gMozLoopAPI.isSocialShareButtonAvailable(),
-    "Social Share button should not be available");
-});
-
-add_task(function* test_mozLoop_addSocialShareButton() {
-  gMozLoopAPI.addSocialShareButton();
-
-  Assert.ok(gMozLoopAPI.isSocialShareButtonAvailable(),
-    "Social Share button should be available");
-
-  let widget = CustomizableUI.getWidget(kShareWidgetId);
-  Assert.strictEqual(widget.areaType, CustomizableUI.TYPE_TOOLBAR,
-    "Social Share button should be placed in the navbar");
-
-  CustomizableUI.removeWidgetFromArea(kShareWidgetId);
-});
-
 add_task(function* test_mozLoop_addSocialShareProvider() {
-  gMozLoopAPI.addSocialShareButton();
-
   gMozLoopAPI.addSocialShareProvider();
 
   yield promiseWaitForCondition(() => SocialShare.panel.state == "open");
 
   Assert.equal(SocialShare.iframe.getAttribute("src"), "about:providerdirectory",
     "Provider directory page should be visible");
 
   SocialShare.panel.hidePopup();
-  CustomizableUI.removeWidgetFromArea(kShareWidgetId);
 });
 
 add_task(function* test_mozLoop_getSocialShareProviders() {
   Assert.strictEqual(gMozLoopAPI.getSocialShareProviders().length, 0,
     "Provider list should be empty initially");
 
   // Add a provider.
   yield new Promise(resolve => SocialService.addProvider(kShareProvider, resolve));
@@ -126,22 +80,19 @@ add_task(function* test_mozLoop_getSocia
   yield new Promise(resolve => SocialService.disableProvider(provider2.origin, resolve));
   providers = gMozLoopAPI.getSocialShareProviders();
   Assert.strictEqual(providers.length, 1,
     "The uninstalled provider should not be part of the list");
   Assert.strictEqual(providers[0].name, kShareProvider.name, "Names should match");
 });
 
 add_task(function* test_mozLoop_socialShareRoom() {
-  gMozLoopAPI.addSocialShareButton();
-
   gMozLoopAPI.socialShareRoom(kShareProvider.origin, "https://someroom.com", "Some Title");
 
   yield promiseWaitForCondition(() => SocialShare.panel.state == "open");
 
   Assert.equal(SocialShare.iframe.getAttribute("origin"), kShareProvider.origin,
     "Origins should match");
   Assert.equal(SocialShare.iframe.getAttribute("src"), kShareProvider.shareURL,
     "Provider's share page should be displayed");
 
   SocialShare.panel.hidePopup();
-  CustomizableUI.removeWidgetFromArea(kShareWidgetId);
 });
--- a/browser/components/loop/test/shared/activeRoomStore_test.js
+++ b/browser/components/loop/test/shared/activeRoomStore_test.js
@@ -32,17 +32,16 @@ describe("loop.store.ActiveRoomStore", f
         refreshMembership: sinon.stub(),
         leave: sinon.stub(),
         on: sinon.stub(),
         off: sinon.stub(),
         sendConnectionStatus: sinon.stub()
       },
       setScreenShareState: sinon.stub(),
       getActiveTabWindowId: sandbox.stub().callsArgWith(0, null, 42),
-      isSocialShareButtonAvailable: sinon.stub().returns(false),
       getSocialShareProviders: sinon.stub().returns([])
     };
 
     fakeSdkDriver = {
       connectSession: sinon.stub(),
       disconnectSession: sinon.stub(),
       forceDisconnectAll: sinon.stub().callsArg(0),
       retryPublishWithoutVideo: sinon.stub(),
@@ -284,17 +283,16 @@ describe("loop.store.ActiveRoomStore", f
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.SetupRoomInfo({
             roomContextUrls: undefined,
             roomDescription: undefined,
             roomToken: fakeToken,
             roomName: fakeRoomData.decryptedContext.roomName,
             roomOwner: fakeRoomData.roomOwner,
             roomUrl: fakeRoomData.roomUrl,
-            socialShareButtonAvailable: false,
             socialShareProviders: []
           }));
       });
 
     it("should dispatch a JoinRoom action if the get is successful",
       function() {
         store.setupWindowData(new sharedActions.SetupWindowData({
           windowId: "42",
@@ -545,17 +543,16 @@ describe("loop.store.ActiveRoomStore", f
     var fakeRoomInfo;
 
     beforeEach(function() {
       fakeRoomInfo = {
         roomName: "Its a room",
         roomOwner: "Me",
         roomToken: "fakeToken",
         roomUrl: "http://invalid",
-        socialShareButtonAvailable: false,
         socialShareProviders: []
       };
     });
 
     it("should set the state to READY", function() {
       store.setupRoomInfo(new sharedActions.SetupRoomInfo(fakeRoomInfo));
 
       expect(store._storeState.roomState).eql(ROOM_STATES.READY);
@@ -564,17 +561,16 @@ describe("loop.store.ActiveRoomStore", f
     it("should save the room information", function() {
       store.setupRoomInfo(new sharedActions.SetupRoomInfo(fakeRoomInfo));
 
       var state = store.getStoreState();
       expect(state.roomName).eql(fakeRoomInfo.roomName);
       expect(state.roomOwner).eql(fakeRoomInfo.roomOwner);
       expect(state.roomToken).eql(fakeRoomInfo.roomToken);
       expect(state.roomUrl).eql(fakeRoomInfo.roomUrl);
-      expect(state.socialShareButtonAvailable).eql(false);
       expect(state.socialShareProviders).eql([]);
     });
   });
 
   describe("#updateRoomInfo", function() {
     var fakeRoomInfo;
 
     beforeEach(function() {
@@ -601,31 +597,28 @@ describe("loop.store.ActiveRoomStore", f
     });
   });
 
   describe("#updateSocialShareInfo", function() {
     var fakeSocialShareInfo;
 
     beforeEach(function() {
       fakeSocialShareInfo = {
-        socialShareButtonAvailable: true,
         socialShareProviders: [{
           name: "foo",
           origin: "https://example.com",
           iconURL: "icon.png"
         }]
       };
     });
 
     it("should save the Social API information", function() {
       store.updateSocialShareInfo(new sharedActions.UpdateSocialShareInfo(fakeSocialShareInfo));
 
       var state = store.getStoreState();
-      expect(state.socialShareButtonAvailable)
-        .eql(fakeSocialShareInfo.socialShareButtonAvailable);
       expect(state.socialShareProviders)
         .eql(fakeSocialShareInfo.socialShareProviders);
     });
   });
 
   describe("#joinRoom", function() {
     beforeEach(function() {
       store.setStoreState({roomState: ROOM_STATES.READY});
@@ -1363,38 +1356,35 @@ describe("loop.store.ActiveRoomStore", f
 
   describe("#_handleSocialShareUpdate", function() {
     it("should dispatch an UpdateRoomInfo action", function() {
       store._handleSocialShareUpdate();
 
       sinon.assert.calledOnce(dispatcher.dispatch);
       sinon.assert.calledWithExactly(dispatcher.dispatch,
         new sharedActions.UpdateSocialShareInfo({
-          socialShareButtonAvailable: false,
           socialShareProviders: []
         }));
     });
 
     it("should call respective mozLoop methods", function() {
       store._handleSocialShareUpdate();
 
-      sinon.assert.calledOnce(fakeMozLoop.isSocialShareButtonAvailable);
       sinon.assert.calledOnce(fakeMozLoop.getSocialShareProviders);
     });
   });
 
   describe("Events", function() {
     describe("update:{roomToken}", function() {
       beforeEach(function() {
         store.setupRoomInfo(new sharedActions.SetupRoomInfo({
           roomName: "Its a room",
           roomOwner: "Me",
           roomToken: "fakeToken",
           roomUrl: "http://invalid",
-          socialShareButtonAvailable: false,
           socialShareProviders: []
         }));
       });
 
       it("should dispatch an UpdateRoomInfo action", function() {
         sinon.assert.calledTwice(fakeMozLoop.rooms.on);
 
         var fakeRoomData = {
@@ -1433,17 +1423,16 @@ describe("loop.store.ActiveRoomStore", f
         roomOwner: "Me",
         roomToken: "fakeToken",
         roomUrl: "http://invalid"
       };
 
       beforeEach(function() {
         store.setupRoomInfo(new sharedActions.SetupRoomInfo(
           _.extend(fakeRoomData, {
-            socialShareButtonAvailable: false,
             socialShareProviders: []
           })
         ));
       });
 
       it("should disconnect all room connections", function() {
         fakeMozLoop.rooms.on.callArgWith(1, "delete:" + fakeRoomData.roomToken, fakeRoomData);
 
--- a/browser/components/loop/test/shared/models_test.js
+++ b/browser/components/loop/test/shared/models_test.js
@@ -15,24 +15,24 @@ describe("loop.shared.models", function(
     sandbox.useFakeTimers();
     fakeXHR = sandbox.useFakeXMLHttpRequest();
     requests = [];
     // https://github.com/cjohansen/Sinon.JS/issues/393
     fakeXHR.xhr.onCreate = function(xhr) {
       requests.push(xhr);
     };
     fakeSessionData = {
-      sessionId:      "sessionId",
-      sessionToken:   "sessionToken",
-      apiKey:         "apiKey",
-      callType:       "callType",
+      sessionId: "sessionId",
+      sessionToken: "sessionToken",
+      apiKey: "apiKey",
+      callType: "callType",
       websocketToken: 123,
-      callToken:      "callToken",
-      callUrl:        "http://invalid/callToken",
-      callerId:       "mrssmith"
+      callToken: "callToken",
+      callUrl: "http://invalid/callToken",
+      callerId: "mrssmith"
     };
     fakeSession = _.extend({
       connect: function () {},
       endSession: sandbox.stub(),
       set: sandbox.stub(),
       disconnect: sandbox.spy(),
       unpublish: sandbox.spy()
     }, Backbone.Events);
--- a/browser/components/loop/test/shared/views_test.js
+++ b/browser/components/loop/test/shared/views_test.js
@@ -370,19 +370,19 @@ describe("loop.shared.views", function()
       fakeAudio = {
         play: sinon.spy(),
         pause: sinon.spy(),
         removeAttribute: sinon.spy()
       };
       sandbox.stub(window, "Audio").returns(fakeAudio);
 
       fakeSessionData = {
-        sessionId:    "sessionId",
+        sessionId: "sessionId",
         sessionToken: "sessionToken",
-        apiKey:       "apiKey"
+        apiKey: "apiKey"
       };
       fakeSession = _.extend({
         connection: {connectionId: 42},
         connect: sandbox.spy(),
         disconnect: sandbox.spy(),
         publish: sandbox.spy(),
         unpublish: sandbox.spy(),
         subscribe: sandbox.spy()
--- a/browser/components/loop/test/standalone/webapp_test.js
+++ b/browser/components/loop/test/standalone/webapp_test.js
@@ -124,21 +124,21 @@ describe("loop.webapp", function() {
       });
     });
 
     // This is tested separately to ease testing, although it isn't really a
     // public API. This will probably be refactored soon anyway.
     describe("#_setupWebSocket", function() {
       beforeEach(function() {
         conversation.setOutgoingSessionData({
-          sessionId:      "sessionId",
-          sessionToken:   "sessionToken",
-          apiKey:         "apiKey",
-          callId:         "Hello",
-          progressURL:    "http://invalid/url",
+          sessionId: "sessionId",
+          sessionToken: "sessionToken",
+          apiKey: "apiKey",
+          callId: "Hello",
+          progressURL: "http://invalid/url",
           websocketToken: 123
         });
       });
 
       describe("Websocket connection successful", function() {
         var promise;
 
         beforeEach(function() {
@@ -198,21 +198,21 @@ describe("loop.webapp", function() {
             done();
           });
         });
       });
 
       describe("Websocket Events", function() {
         beforeEach(function() {
           conversation.setOutgoingSessionData({
-            sessionId:      "sessionId",
-            sessionToken:   "sessionToken",
-            apiKey:         "apiKey",
-            callId:         "Hello",
-            progressURL:    "http://progress.example.com",
+            sessionId: "sessionId",
+            sessionToken: "sessionToken",
+            apiKey: "apiKey",
+            callId: "Hello",
+            progressURL: "http://progress.example.com",
             websocketToken: 123
           });
 
           sandbox.stub(loop.CallConnectionWebSocket.prototype,
                        "promiseConnect").returns({
             then: sandbox.spy()
           });
 
@@ -293,22 +293,22 @@ describe("loop.webapp", function() {
       });
     });
 
     describe("Events", function() {
       var fakeSessionData, promiseConnectStub;
 
       beforeEach(function() {
         fakeSessionData = {
-          sessionId:      "sessionId",
-          sessionToken:   "sessionToken",
-          apiKey:         "apiKey",
+          sessionId: "sessionId",
+          sessionToken: "sessionToken",
+          apiKey: "apiKey",
           websocketToken: 123,
-          progressURL:    "fakeUrl",
-          callId:         "fakeCallId"
+          progressURL: "fakeUrl",
+          callId: "fakeCallId"
         };
         conversation.set(fakeSessionData);
         conversation.set("loopToken", "fakeToken");
         sandbox.stub(notifications, "errorL10n");
         sandbox.stub(notifications, "warnL10n");
         promiseConnectStub =
           sandbox.stub(loop.CallConnectionWebSocket.prototype, "promiseConnect");
         promiseConnectStub.returns(new Promise(function(resolve, reject) {}));
--- a/browser/components/loop/test/xpcshell/test_loopservice_busy.js
+++ b/browser/components/loop/test/xpcshell/test_loopservice_busy.js
@@ -50,19 +50,19 @@ add_task(function* test_busy_2fxa_calls(
 });
 
 function run_test() {
   setupFakeLoopServer();
 
   // Setup fake login state so we get FxA requests.
   const MozLoopServiceInternal = Cu.import("resource:///modules/loop/MozLoopService.jsm", {}).MozLoopServiceInternal;
   MozLoopServiceInternal.fxAOAuthTokenData = {
-    token_type:"bearer",
-    access_token:"1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",
-    scope:"profile"
+    token_type: "bearer",
+    access_token: "1bad3e44b12f77a88fe09f016f6a37c42e40f974bc7a8b432bb0d2f0e37e1752",
+    scope: "profile"
   };
   MozLoopServiceInternal.fxAOAuthProfile = {email: "test@example.com", uid: "abcd1234"};
 
   let mockWebSocket = new MockWebSocketChannel();
   mockWebSocket.defaultMsgHandler = msgHandler;
   LoopCallsInternal.mocks.webSocket = mockWebSocket;
 
   Services.io.offline = false;
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -530,17 +530,17 @@
                                   model: mockConversationModel})
               )
             )
           ), 
 
           React.createElement(Section, {name: "ConversationView-640"}, 
             React.createElement(Example, {summary: "640px breakpoint for conversation view"}, 
               React.createElement("div", {className: "breakpoint", 
-                   style: {"text-align":"center"}, 
+                   style: {"text-align": "center"}, 
                    "data-breakpoint-width": "400px", 
                    "data-breakpoint-height": "780px"}, 
                 React.createElement("div", {className: "standalone"}, 
                   React.createElement(ConversationView, {sdk: mockSDK, 
                                     video: {enabled: true}, 
                                     audio: {enabled: true}, 
                                     model: mockConversationModel})
                 )
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -530,17 +530,17 @@
                                   model={mockConversationModel} />
               </div>
             </Example>
           </Section>
 
           <Section name="ConversationView-640">
             <Example summary="640px breakpoint for conversation view">
               <div className="breakpoint"
-                   style={{"text-align":"center"}}
+                   style={{"text-align": "center"}}
                    data-breakpoint-width="400px"
                    data-breakpoint-height="780px">
                 <div className="standalone">
                   <ConversationView sdk={mockSDK}
                                     video={{enabled: true}}
                                     audio={{enabled: true}}
                                     model={mockConversationModel} />
                 </div>
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -49,8 +49,11 @@ BROWSER_CHROME_MANIFESTS += [
     'test/browser.ini'
 ]
 
 if CONFIG['MOZ_SAFE_BROWSING']:
     BROWSER_CHROME_MANIFESTS += ['safebrowsing/content/test/browser.ini']
 
 with Files('safebrowsing/*'):
     BUG_COMPONENT = ('Toolkit', 'Phishing Protection')
+
+with Files('controlcenter/**'):
+    BUG_COMPONENT = ('Firefox', 'General')
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -2623,19 +2623,19 @@ let DefaultBrowserCheck = {
       this._notification.close();
     }
   },
 
   setAsDefault: function() {
     let claimAllTypes = true;
 #ifdef XP_WIN
     try {
-      // In Windows 8, the UI for selecting default protocol is much
+      // In Windows 8+, the UI for selecting default protocol is much
       // nicer than the UI for setting file type associations. So we
-      // only show the protocol association screen on Windows 8.
+      // only show the protocol association screen on Windows 8+.
       // Windows 8 is version 6.2.
       let version = Services.sysinfo.getProperty("version");
       claimAllTypes = (parseFloat(version) < 6.2);
     } catch (ex) { }
 #endif
     try {
       ShellService.setDefaultBrowser(claimAllTypes, false);
     } catch (ex) {
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -1466,19 +1466,16 @@ XPCOMUtils.defineLazyGetter(PlacesUIUtil
       new PlacesSetItemAnnotationTransaction(aItemId, aAnnotationObject),
 
     setPageAnnotation: function(aURI, aAnnotationObject)
       new PlacesSetPageAnnotationTransaction(aURI, aAnnotationObject),
 
     editBookmarkKeyword: function(aItemId, aNewKeyword)
       new PlacesEditBookmarkKeywordTransaction(aItemId, aNewKeyword),
 
-    editBookmarkPostData: function(aItemId, aPostData)
-      new PlacesEditBookmarkPostDataTransaction(aItemId, aPostData),
-
     editLivemarkSiteURI: function(aLivemarkId, aSiteURI)
       new PlacesEditLivemarkSiteURITransaction(aLivemarkId, aSiteURI),
 
     editLivemarkFeedURI: function(aLivemarkId, aFeedURI)
       new PlacesEditLivemarkFeedURITransaction(aLivemarkId, aFeedURI),
 
     editItemDateAdded: function(aItemId, aNewDateAdded)
       new PlacesEditItemDateAddedTransaction(aItemId, aNewDateAdded),
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -278,17 +278,18 @@ var BookmarkPropertiesPanel = {
         gEditItemOverlay.initPanel({ node: this._node
                                    , hiddenRows: this._hiddenRows });
         acceptButton.disabled = gEditItemOverlay.readOnly;
         break;
       case ACTION_ADD:
         this._node = yield this._promiseNewItem();
         // Edit the new item
         gEditItemOverlay.initPanel({ node: this._node
-                                   , hiddenRows: this._hiddenRows });
+                                   , hiddenRows: this._hiddenRows
+                                   , postData: this._postData });
 
         // Empty location field if the uri is about:blank, this way inserting a new
         // url will be easier for the user, Accept button will be automatically
         // disabled by the input listener until the user fills the field.
         let locationField = this._element("locationField");
         if (locationField.value == "about:blank")
           locationField.value = "";
 
@@ -520,32 +521,28 @@ var BookmarkPropertiesPanel = {
 
     if (this._loadInSidebar) {
       let annoObj = { name   : PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
                       value  : true };
       let setLoadTxn = new PlacesSetItemAnnotationTransaction(-1, annoObj);
       childTransactions.push(setLoadTxn);
     }
 
-    if (this._postData) {
-      let postDataTxn = new PlacesEditBookmarkPostDataTransaction(-1, this._postData);
-      childTransactions.push(postDataTxn);
-    }
-
     //XXX TODO: this should be in a transaction!
     if (this._charSet && !PrivateBrowsingUtils.isWindowPrivate(window))
       PlacesUtils.setCharsetForURI(this._uri, this._charSet);
 
     let createTxn = new PlacesCreateBookmarkTransaction(this._uri,
                                                         aContainer,
                                                         aIndex,
                                                         this._title,
                                                         this._keyword,
                                                         annotations,
-                                                        childTransactions);
+                                                        childTransactions,
+                                                        this._postData);
 
     return new PlacesAggregatedTransaction(this._getDialogTitle(),
                                            [createTxn]);
   },
 
   /**
    * Returns a childItems-transactions array representing the URIList with
    * which the dialog has been opened.
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -37,29 +37,30 @@ let gEditItemOverlay = {
     let isURI = node && PlacesUtils.nodeIsURI(node);
     let uri = isURI ? NetUtil.newURI(node.uri) : null;
     let title = node ? node.title : null;
     let isBookmark = isItem && isURI;
     let bulkTagging = !node;
     let uris = bulkTagging ? aInitInfo.uris : null;
     let visibleRows = new Set();
     let isParentReadOnly = false;
+    let postData = aInitInfo.postData;
     if (node && "parent" in node) {
       let parent = node.parent;
       if (parent) {
         isParentReadOnly = !PlacesUtils.nodeIsFolder(parent) ||
                             PlacesUIUtils.isContentsReadOnly(parent);
       }
     }
 
     return this._paneInfo = { itemId, itemGuid, isItem,
                               isURI, uri, title,
                               isBookmark, isFolderShortcut, isParentReadOnly,
                               bulkTagging, uris,
-                              visibleRows };
+                              visibleRows, postData };
   },
 
   get initialized() {
     return this._paneInfo != null;
   },
 
   // Backwards-compatibility getters
   get itemId() {
@@ -591,17 +592,17 @@ let gEditItemOverlay = {
 
   onKeywordFieldChange() {
     if (this.readOnly || !this._paneInfo.isBookmark)
       return;
 
     let itemId = this._paneInfo.itemId;
     let newKeyword = this._keywordField.value;
     if (!PlacesUIUtils.useAsyncTransactions) {
-      let txn = new PlacesEditBookmarkKeywordTransaction(itemId, newKeyword);
+      let txn = new PlacesEditBookmarkKeywordTransaction(itemId, newKeyword, this._paneInfo.postData);
       PlacesUtils.transactionManager.doTransaction(txn);
       return;
     }
     let guid = this._paneInfo.itemGuid;
     PlacesTransactions.EditKeyword({ guid, keyword: newKeyword })
                       .transact().catch(Components.utils.reportError);
   },
 
--- a/browser/components/places/tests/browser/browser.ini
+++ b/browser/components/places/tests/browser/browser.ini
@@ -5,47 +5,45 @@
 [DEFAULT]
 skip-if = buildapp == "mulet"
 support-files =
   head.js
   framedPage.html
   frameLeft.html
   frameRight.html
   sidebarpanels_click_test_page.html
+  keyword_form.html
 
 [browser_0_library_left_pane_migration.js]
-[browser_library_left_pane_fixnames.js]
-[browser_425884.js]
-[browser_475045.js]
+[browser_410196_paste_into_tags.js]
+[browser_416459_cut.js]
 [browser_423515.js]
-[browser_410196_paste_into_tags.js]
-[browser_sort_in_library.js]
-[browser_library_open_leak.js]
-[browser_library_panel_leak.js]
-[browser_library_search.js]
-[browser_history_sidebar_search.js]
-skip-if = e10s && (os == 'linux' || os == 'mac') # Bug 1116457
+[browser_425884.js]
+[browser_435851_copy_query.js]
+[browser_475045.js]
+[browser_555547.js]
+[browser_bookmarkProperties_addKeywordForThisSearch.js]
 [browser_bookmarksProperties.js]
-
-[browser_forgetthissite_single.js]
-[browser_library_commands.js]
 [browser_drag_bookmarks_on_toolbar.js]
 skip-if = e10s # Bug ?????? - test fails - "Number of dragged items should be the same. - Got 0, expected 1"
+[browser_forgetthissite_single.js]
+[browser_history_sidebar_search.js]
+skip-if = e10s && (os == 'linux' || os == 'mac') # Bug 1116457
+[browser_library_batch_delete.js]
+[browser_library_commands.js]
+[browser_library_downloads.js]
+[browser_library_infoBox.js]
+[browser_library_left_pane_fixnames.js]
+[browser_library_left_pane_select_hierarchy.js]
 [browser_library_middleclick.js]
+[browser_library_open_leak.js]
+[browser_library_openFlatContainer.js]
+[browser_library_panel_leak.js]
+[browser_library_search.js]
 [browser_library_views_liveupdate.js]
-[browser_views_liveupdate.js]
-
-[browser_sidebarpanels_click.js]
-# temporarily disabled for breaking the treeview - bug 658744
-skip-if = true
-
-[browser_library_infoBox.js]
 [browser_markPageAsFollowedLink.js]
 skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly (test does EventUtils.sendMouseEvent...)
+[browser_sidebarpanels_click.js]
+skip-if = true # temporarily disabled for breaking the treeview - bug 658744
+[browser_sort_in_library.js]
 [browser_toolbar_migration.js]
-[browser_library_batch_delete.js]
-[browser_555547.js]
-[browser_416459_cut.js]
-[browser_library_downloads.js]
-[browser_library_left_pane_select_hierarchy.js]
-[browser_435851_copy_query.js]
 [browser_toolbarbutton_menu_context.js]
-[browser_library_openFlatContainer.js]
+[browser_views_liveupdate.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/browser_bookmarkProperties_addKeywordForThisSearch.js
@@ -0,0 +1,57 @@
+"use strict"
+
+const TEST_URL = "http://mochi.test:8888/browser/browser/components/places/tests/browser/keyword_form.html";
+
+add_task(function* () {
+  yield BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: TEST_URL,
+  }, function* (browser) {
+    // We must wait for the context menu code to build metadata.
+    yield openContextMenuForContentSelector(browser, 'form > input[name="search"]');
+
+    yield withBookmarksDialog(function*() {
+      AddKeywordForSearchField();
+    }, function* (dialogWin) {
+      let acceptBtn = dialogWin.document.documentElement.getButton("accept");
+      ok(acceptBtn.disabled, "Accept button is disabled");
+
+      let promiseKeywordNotification = promiseBookmarksNotification(
+        "onItemChanged", (itemId, prop, isAnno, val) => prop == "keyword" && val =="kw");
+
+      fillBookmarkTextField("editBMPanel_keywordField", "kw", dialogWin);
+
+      ok(!acceptBtn.disabled, "Accept button is enabled");
+
+      // The dialog is instant apply.
+      yield promiseKeywordNotification;
+
+      // After the notification, the keywords cache will update asynchronously.
+      info("Check the keyword entry has been created");
+      let entry;
+      yield waitForCondition(function* () {
+        entry = yield PlacesUtils.keywords.fetch("kw");
+        return !!entry;
+      },"Unable to find the expected keyword");
+      is(entry.keyword, "kw", "keyword is correct");
+      is(entry.url.href, TEST_URL, "URL is correct");
+      is(entry.postData, "accenti%3D%E0%E8%EC%F2%F9&search%3D%25s", "POST data is correct");
+
+      info("Check the charset has been saved");
+      let charset = yield PlacesUtils.getCharsetForURI(NetUtil.newURI(TEST_URL));
+      is(charset, "windows-1252", "charset is correct");
+
+      // Now check getShortcutOrURI.
+      let data = yield getShortcutOrURIAndPostData("kw test");
+      is(getPostDataString(data.postData), "accenti=\u00E0\u00E8\u00EC\u00F2\u00F9&search=test", "getShortcutOrURI POST data is correct");
+      is(data.url, TEST_URL, "getShortcutOrURI URL is correct");
+    });
+  });
+});
+
+function getPostDataString(stream) {
+  let sis = Cc["@mozilla.org/scriptableinputstream;1"]
+              .createInstance(Ci.nsIScriptableInputStream);
+  sis.init(stream);
+  return sis.read(stream.available()).split("\n").pop();
+}
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -157,28 +157,31 @@ function promiseIsURIVisited(aURI) {
   PlacesUtils.asyncHistory.isURIVisited(aURI, function(aURI, aIsVisited) {
     deferred.resolve(aIsVisited);
   });
 
   return deferred.promise;
 }
 
 function promiseBookmarksNotification(notification, conditionFn) {
-  info(`Waiting for ${notification}`);
+  info(`promiseBookmarksNotification: waiting for ${notification}`);
   return new Promise((resolve, reject) => {
     let proxifiedObserver = new Proxy({}, {
       get: (target, name) => {
         if (name == "QueryInterface")
           return XPCOMUtils.generateQI([ Ci.nsINavBookmarkObserver ]);
+        info(`promiseBookmarksNotification: got ${name} notification`);
         if (name == notification)
           return () => {
             if (conditionFn.apply(this, arguments)) {
               clearTimeout(timeout);
               PlacesUtils.bookmarks.removeObserver(proxifiedObserver, false);
               executeSoon(resolve);
+            } else {
+              info(`promiseBookmarksNotification: skip cause condition doesn't apply to ${JSON.stringify(arguments)}`);
             }
           }
         return () => {};
       }
     });
     PlacesUtils.bookmarks.addObserver(proxifiedObserver, false);
     let timeout = setTimeout(() => {
       PlacesUtils.bookmarks.removeObserver(proxifiedObserver, false);
@@ -273,8 +276,136 @@ function promiseSetToolbarVisibility(aTo
 function isToolbarVisible(aToolbar) {
   let hidingAttribute = aToolbar.getAttribute("type") == "menubar"
                         ? "autohide"
                         : "collapsed";
   let hidingValue = aToolbar.getAttribute(hidingAttribute).toLowerCase();
   // Check for both collapsed="true" and collapsed="collapsed"
   return hidingValue !== "true" && hidingValue !== hidingAttribute;
 }
+
+/**
+ * Executes a task after opening the bookmarks dialog, then cancels the dialog.
+ *
+ * @param openFn
+ *        generator function causing the dialog to open
+ * @param task
+ *        the task to execute once the dialog is open
+ */
+let withBookmarksDialog = Task.async(function* (openFn, taskFn) {
+  let dialogPromise = new Promise(resolve => {
+    Services.ww.registerNotification(function winObserver(subject, topic, data) {
+      if (topic != "domwindowopened")
+        return;
+      let win = subject.QueryInterface(Ci.nsIDOMWindow);
+      win.addEventListener("load", function load() {
+        win.removeEventListener("load", load);
+        ok(win.location.href.startsWith("chrome://browser/content/places/bookmarkProperties"),
+           "The bookmark properties dialog is ready");
+        Services.ww.unregisterNotification(winObserver);
+        // This is needed for the overlay.
+        waitForFocus(() => {
+          resolve(win);
+        }, win);
+      });
+    });
+  });
+
+  info("withBookmarksDialog: opening the dialog");
+  yield openFn();
+  info("withBookmarksDialog: waiting for the dialog");
+  let dialogWin = yield dialogPromise;
+
+  // Ensure overlay is loaded
+  ok(dialogWin.gEditItemOverlay.initialized, "EditItemOverlay is initialized");
+
+  info("withBookmarksDialog: executing the task");
+  try {
+    yield taskFn(dialogWin);
+  } finally {
+    info("withBookmarksDialog: canceling the dialog");
+    dialogWin.document.documentElement.cancelDialog();
+  }
+});
+
+/**
+ * Opens the contextual menu on the element pointed by the given selector.
+ *
+ * @param selector
+ *        Valid selector syntax
+ * @return the target DOM node.
+ */
+let openContextMenuForContentSelector = Task.async(function* (browser, selector) {
+  info("wait for the context menu");
+  let contextPromise = BrowserTestUtils.waitForEvent(document.getElementById("contentAreaContextMenu"),
+                                                     "popupshown");
+  yield ContentTask.spawn(browser, { selector }, function* (args) {
+    let doc = content.document;
+    let elt = doc.querySelector(args.selector)
+    dump(`openContextMenuForContentSelector: found ${elt}\n`);
+
+    /* Open context menu so chrome can access the element */
+    const domWindowUtils =
+      content.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+             .getInterface(Components.interfaces.nsIDOMWindowUtils);
+    let rect = elt.getBoundingClientRect();
+    let left = rect.left + rect.width / 2;
+    let top = rect.top + rect.height / 2;
+    domWindowUtils.sendMouseEvent("contextmenu", left, top, 2,
+                                  1, 0, false, 0, 0, true);
+  });
+  yield contextPromise;
+
+  return gContextMenuContentData.popupNode;
+});
+
+/**
+ * Waits for a specified condition to happen.
+ *
+ * @param conditionFn
+ *        a Function or a generator function, returning a boolean for whether
+ *        the condition is fulfilled.
+ * @param errorMsg
+ *        Error message to use if the condition has not been satisfied after a
+ *        meaningful amount of tries.
+ */
+let waitForCondition = Task.async(function* (conditionFn, errorMsg) {
+  for (let tries = 0; tries < 100; ++tries) {
+    if ((yield conditionFn()))
+      return;
+    yield new Promise(resolve => {
+      if (!waitForCondition._timers) {
+        waitForCondition._timers = new Set();
+        registerCleanupFunction(() => {
+          is(waitForCondition._timers.size, 0, "All the wait timers have been removed");
+          delete waitForCondition._timers;
+        });
+      }
+      let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+      waitForCondition._timers.add(timer);
+      timer.init(() => {
+        waitForCondition._timers.delete(timer);
+        resolve();
+      }, 100, Ci.nsITimer.TYPE_ONE_SHOT);
+    });
+  }
+  ok(false, errorMsg);
+});
+
+/**
+ * Fills a bookmarks dialog text field ensuring to cause expected edit events.
+ *
+ * @param id
+ *        id of the text field
+ * @param text
+ *        text to fill in
+ * @param win
+ *        dialog window
+ */
+function fillBookmarkTextField(id, text, win) {
+  let elt = win.document.getElementById(id);
+  elt.focus();
+  elt.select();
+  for (let c of text.split("")) {
+    EventUtils.synthesizeKey(c, {}, win);
+  }
+  elt.blur();
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/places/tests/browser/keyword_form.html
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML>
+
+<html lang="en">
+<head>
+  <meta http-equiv="Content-Type" content="text/html;charset=windows-1252">
+</head>
+<body>
+  <form method="POST" action="keyword_form.html">
+    <input type="hidden" name="accenti" value="אטלעש">
+    <input type="text" name="search">
+  </form>
+</body>
+</html>
--- a/browser/components/preferences/in-content/main.js
+++ b/browser/components/preferences/in-content/main.js
@@ -163,17 +163,17 @@ var gMainPane = {
         for (let prefToChange of prefsToChange) {
           prefToChange.value = e10sCheckbox.checked;
         }
 
         let tmp = {};
         Components.utils.import("resource://gre/modules/UpdateChannel.jsm", tmp);
         if (!e10sCheckbox.checked && tmp.UpdateChannel.get() != "default") {
           Services.prefs.setBoolPref("browser.requestE10sFeedback", true);
-          Services.prompt.alert(window, brandName, "After restart, a tab will open to input.mozilla.org where you can provide us feedback about your e10s experience.");
+          Services.prompt.alert(window, brandName, bundle.getString("e10sFeedbackAfterRestart"));
         }
         Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit |  Ci.nsIAppStartup.eRestart);
       }
     }
 
     // Revert the checkbox in case we didn't quit
     e10sCheckbox.checked = e10sPref.value || e10sTempPref.value;
   },
@@ -682,43 +682,67 @@ var gMainPane = {
   /*
    * Preferences:
    *
    * browser.shell.checkDefault
    * - true if a default-browser check (and prompt to make it so if necessary)
    *   occurs at startup, false otherwise
    */
 
+   /**
+    * Firefox can attempt to set itself as the default application
+    * for all related filetypes or just for HTML. Some platforms
+    * such as Windows have terrible UIs for all filetypes. In those
+    * platforms, Firefox only attempts to associate itself with HTML.
+    */
+   shouldClaimAllTypes: function()
+   {
+    let claimAllTypes = true;
+    try {
+      if (AppConstants.platform == "win") {
+        // In Windows 8+, the UI for selecting default protocol is much
+        // nicer than the UI for setting file type associations. So we
+        // only show the protocol association screen on Windows 8+.
+        // Windows 8 is version 6.2.
+        let version = Services.sysinfo.getProperty("version");
+        claimAllTypes = (parseFloat(version) < 6.2);
+      }
+    } catch (ex) {}
+    return claimAllTypes;
+   },
+
   /**
    * Show button for setting browser as default browser or information that
    * browser is already the default browser.
    */
   updateSetDefaultBrowser: function()
   {
     let shellSvc = getShellService();
     let defaultBrowserBox = document.getElementById("defaultBrowserBox");
     if (!shellSvc) {
       defaultBrowserBox.hidden = true;
       return;
     }
     let setDefaultPane = document.getElementById("setDefaultPane");
-    let selectedIndex = shellSvc.isDefaultBrowser(false, true) ? 1 : 0;
+    let claimAllTypes = gMainPane.shouldClaimAllTypes();
+    let selectedIndex = shellSvc.isDefaultBrowser(false, claimAllTypes) ? 1 : 0;
     setDefaultPane.selectedIndex = selectedIndex;
   },
 
   /**
    * Set browser as the operating system default browser.
    */
   setDefaultBrowser: function()
   {
     let shellSvc = getShellService();
     if (!shellSvc)
       return;
     try {
-      shellSvc.setDefaultBrowser(true, false);
+      let claimAllTypes = gMainPane.shouldClaimAllTypes();
+      shellSvc.setDefaultBrowser(claimAllTypes, false);
     } catch (ex) {
       Cu.reportError(ex);
       return;
     }
     let selectedIndex =
       shellSvc.isDefaultBrowser(false, true) ? 1 : 0;
     document.getElementById("setDefaultPane").selectedIndex = selectedIndex;
   }
--- a/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css
+++ b/browser/components/privatebrowsing/content/aboutPrivateBrowsing.css
@@ -3,17 +3,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 %endif
 
 @import url("chrome://global/skin/in-content/common.css");
 
 body {
   display: flex;
-  box-sizing: padding-box;
+  box-sizing: border-box;
   min-height: 100vh;
   padding: 0 48px;
   align-items: center;
   justify-content: center;
 }
 
 body.normal .showPrivate,
 body.private .showNormal {
--- a/browser/components/selfsupport/SelfSupportService.js
+++ b/browser/components/selfsupport/SelfSupportService.js
@@ -16,16 +16,23 @@ const policy = Cc["@mozilla.org/datarepo
 
 XPCOMUtils.defineLazyGetter(this, "reporter", () => {
   return Cc["@mozilla.org/datareporting/service;1"]
            .getService(Ci.nsISupports)
            .wrappedJSObject
            .healthReporter;
 });
 
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryArchive",
+                                  "resource://gre/modules/TelemetryArchive.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryEnvironment",
+                                  "resource://gre/modules/TelemetryEnvironment.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "TelemetryController",
+                                  "resource://gre/modules/TelemetryController.jsm");
+
 function MozSelfSupportInterface() {
 }
 
 MozSelfSupportInterface.prototype = {
   classDescription: "MozSelfSupport",
   classID: Components.ID("{d30aae8b-f352-4de3-b936-bb9d875df0bb}"),
   contractID: "@mozilla.org/mozselfsupport;1",
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer]),
@@ -68,11 +75,34 @@ MozSelfSupportInterface.prototype = {
   resetPref: function(name) {
     Services.prefs.clearUserPref(name);
   },
 
   resetSearchEngines: function() {
     Services.search.restoreDefaultEngines();
     Services.search.resetToOriginalDefaultEngine();
   },
+
+  getTelemetryPingList: function() {