Merge m-c to inbound, a=merge CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Fri, 04 Nov 2016 15:19:49 -0700
changeset 347755 f092853e564086a98e14f0018ce784bb033e1d85
parent 347754 8fcf8b6ea2c9f25198ae807fb1eb0b96ab43c8f4 (current diff)
parent 347671 753433776a5e16b1c80c062bc6cdda05f26a81dd (diff)
child 347784 a7c654513f2ffd9d9ef38fa2bf512b9e8dae3cdd
child 347796 3d200aa1872f6cdbe8191715cd8053006a99812a
child 347898 825b955d94df324138255e4ee8e5a4e241171a0d
push id10298
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:33:03 +0000
treeherdermozilla-aurora@7e29173b1641 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone52.0a1
Merge m-c to inbound, a=merge CLOSED TREE
browser/base/content/test/general/browser_sanitizeDialog.js
browser/components/places/PlacesUIUtils.jsm
browser/components/search/test/head.js
browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm
dom/base/test/file_navigator_resolve_identity.html
dom/base/test/test_navigator_resolve_identity.html
dom/bindings/Bindings.conf
dom/bindings/test/file_bug707564-2.html
dom/bindings/test/file_bug707564.html
dom/bindings/test/test_bug707564.html
dom/bindings/test/test_dom_xrays.html
dom/contacts/ContactManager.js
dom/contacts/ContactManager.manifest
dom/contacts/fallback/ContactDB.jsm
dom/contacts/fallback/ContactService.jsm
dom/contacts/moz.build
dom/contacts/tests/chrome.ini
dom/contacts/tests/file_contacts_basics.html
dom/contacts/tests/file_contacts_basics2.html
dom/contacts/tests/file_contacts_blobs.html
dom/contacts/tests/file_contacts_events.html
dom/contacts/tests/file_contacts_getall.html
dom/contacts/tests/file_contacts_getall2.html
dom/contacts/tests/file_contacts_international.html
dom/contacts/tests/file_contacts_substringmatching.html
dom/contacts/tests/file_contacts_substringmatchingCL.html
dom/contacts/tests/file_contacts_substringmatchingVE.html
dom/contacts/tests/file_migration.html
dom/contacts/tests/file_permission_denied.html
dom/contacts/tests/mochitest.ini
dom/contacts/tests/shared.js
dom/contacts/tests/test_contacts_a_cache.xul
dom/contacts/tests/test_contacts_a_shutdown.xul
dom/contacts/tests/test_contacts_a_upgrade.xul
dom/contacts/tests/test_contacts_basics.html
dom/contacts/tests/test_contacts_basics2.html
dom/contacts/tests/test_contacts_blobs.html
dom/contacts/tests/test_contacts_events.html
dom/contacts/tests/test_contacts_getall.html
dom/contacts/tests/test_contacts_getall2.html
dom/contacts/tests/test_contacts_international.html
dom/contacts/tests/test_contacts_substringmatching.html
dom/contacts/tests/test_contacts_substringmatchingCL.html
dom/contacts/tests/test_contacts_substringmatchingVE.html
dom/contacts/tests/test_migration.html
dom/contacts/tests/test_migration_chrome.js
dom/contacts/tests/test_permission_denied.html
dom/icc/Assertions.cpp
dom/icc/Icc.cpp
dom/icc/Icc.h
dom/icc/IccCallback.cpp
dom/icc/IccCallback.h
dom/icc/IccCardLockError.cpp
dom/icc/IccCardLockError.h
dom/icc/IccContact.cpp
dom/icc/IccContact.h
dom/icc/IccInfo.cpp
dom/icc/IccInfo.h
dom/icc/IccListener.cpp
dom/icc/IccListener.h
dom/icc/IccManager.cpp
dom/icc/IccManager.h
dom/icc/gonk/IccService.js
dom/icc/gonk/IccService.manifest
dom/icc/gonk/StkCmdFactory.js
dom/icc/gonk/StkCmdFactory.manifest
dom/icc/interfaces/moz.build
dom/icc/interfaces/nsIGonkIccService.idl
dom/icc/interfaces/nsIIccContact.idl
dom/icc/interfaces/nsIIccInfo.idl
dom/icc/interfaces/nsIIccMessenger.idl
dom/icc/interfaces/nsIIccService.idl
dom/icc/interfaces/nsIStkCmdFactory.idl
dom/icc/interfaces/nsIStkProactiveCmd.idl
dom/icc/ipc/IccChild.cpp
dom/icc/ipc/IccChild.h
dom/icc/ipc/IccIPCService.cpp
dom/icc/ipc/IccIPCService.h
dom/icc/ipc/IccIPCUtils.cpp
dom/icc/ipc/IccIPCUtils.h
dom/icc/ipc/IccParent.cpp
dom/icc/ipc/IccParent.h
dom/icc/ipc/PIcc.ipdl
dom/icc/ipc/PIccRequest.ipdl
dom/icc/ipc/PIccTypes.ipdlh
dom/icc/moz.build
dom/icc/tests/marionette/head.js
dom/icc/tests/marionette/manifest.ini
dom/icc/tests/marionette/test_icc_access_invalid_object.js
dom/icc/tests/marionette/test_icc_card_lock_change_pin.js
dom/icc/tests/marionette/test_icc_card_lock_enable_pin.js
dom/icc/tests/marionette/test_icc_card_lock_get_retry_count.js
dom/icc/tests/marionette/test_icc_card_lock_unlock_pin.js
dom/icc/tests/marionette/test_icc_card_lock_unlock_puk.js
dom/icc/tests/marionette/test_icc_card_state.js
dom/icc/tests/marionette/test_icc_contact_add.js
dom/icc/tests/marionette/test_icc_contact_read.js
dom/icc/tests/marionette/test_icc_contact_update.js
dom/icc/tests/marionette/test_icc_detected_undetected_event.js
dom/icc/tests/marionette/test_icc_info.js
dom/icc/tests/marionette/test_icc_match_mvno.js
dom/icc/tests/marionette/test_icc_service_state.js
dom/icc/tests/marionette/test_stk_bip_command.js
dom/icc/tests/marionette/test_stk_display_text.js
dom/icc/tests/marionette/test_stk_event_download.js
dom/icc/tests/marionette/test_stk_get_inkey.js
dom/icc/tests/marionette/test_stk_get_input.js
dom/icc/tests/marionette/test_stk_launch_browser.js
dom/icc/tests/marionette/test_stk_local_info.js
dom/icc/tests/marionette/test_stk_menu_selection.js
dom/icc/tests/marionette/test_stk_play_tone.js
dom/icc/tests/marionette/test_stk_poll_interval.js
dom/icc/tests/marionette/test_stk_poll_off.js
dom/icc/tests/marionette/test_stk_refresh.js
dom/icc/tests/marionette/test_stk_response.js
dom/icc/tests/marionette/test_stk_select_item.js
dom/icc/tests/marionette/test_stk_send_dtmf.js
dom/icc/tests/marionette/test_stk_send_sms.js
dom/icc/tests/marionette/test_stk_send_ss.js
dom/icc/tests/marionette/test_stk_send_ussd.js
dom/icc/tests/marionette/test_stk_setup_call.js
dom/icc/tests/marionette/test_stk_setup_event_list.js
dom/icc/tests/marionette/test_stk_setup_idle_mode_text.js
dom/icc/tests/marionette/test_stk_setup_menu.js
dom/icc/tests/marionette/test_stk_timer_expiration.js
dom/icc/tests/marionette/test_stk_timer_management.js
dom/mobileconnection/Assertions.cpp
dom/mobileconnection/MobileCallForwardingOptions.cpp
dom/mobileconnection/MobileCallForwardingOptions.h
dom/mobileconnection/MobileCellInfo.cpp
dom/mobileconnection/MobileCellInfo.h
dom/mobileconnection/MobileConnection.cpp
dom/mobileconnection/MobileConnection.h
dom/mobileconnection/MobileConnectionArray.cpp
dom/mobileconnection/MobileConnectionArray.h
dom/mobileconnection/MobileConnectionCallback.cpp
dom/mobileconnection/MobileConnectionCallback.h
dom/mobileconnection/MobileConnectionInfo.cpp
dom/mobileconnection/MobileConnectionInfo.h
dom/mobileconnection/MobileNetworkInfo.cpp
dom/mobileconnection/MobileNetworkInfo.h
dom/mobileconnection/gonk/MobileConnectionService.js
dom/mobileconnection/gonk/MobileConnectionService.manifest
dom/mobileconnection/gonk/nsIGonkMobileConnectionService.idl
dom/mobileconnection/gonk/nsIMobileConnectionMessenger.idl
dom/mobileconnection/interfaces/nsICellInfo.idl
dom/mobileconnection/interfaces/nsIMobileCallForwardingOptions.idl
dom/mobileconnection/interfaces/nsIMobileCellInfo.idl
dom/mobileconnection/interfaces/nsIMobileConnectionInfo.idl
dom/mobileconnection/interfaces/nsIMobileConnectionService.idl
dom/mobileconnection/interfaces/nsIMobileDeviceIdentities.idl
dom/mobileconnection/interfaces/nsIMobileNetworkInfo.idl
dom/mobileconnection/interfaces/nsINeighboringCellInfo.idl
dom/mobileconnection/ipc/MobileConnectionChild.cpp
dom/mobileconnection/ipc/MobileConnectionChild.h
dom/mobileconnection/ipc/MobileConnectionIPCSerializer.h
dom/mobileconnection/ipc/MobileConnectionIPCService.cpp
dom/mobileconnection/ipc/MobileConnectionIPCService.h
dom/mobileconnection/ipc/MobileConnectionParent.cpp
dom/mobileconnection/ipc/MobileConnectionParent.h
dom/mobileconnection/ipc/PMobileConnection.ipdl
dom/mobileconnection/ipc/PMobileConnectionRequest.ipdl
dom/mobileconnection/ipc/PMobileConnectionTypes.ipdlh
dom/mobileconnection/moz.build
dom/mobileconnection/tests/marionette/head.js
dom/mobileconnection/tests/marionette/head_chrome.js
dom/mobileconnection/tests/marionette/manifest.ini
dom/mobileconnection/tests/marionette/test_call_barring_basic_operations.js
dom/mobileconnection/tests/marionette/test_call_barring_change_password.js
dom/mobileconnection/tests/marionette/test_call_barring_get_error.js
dom/mobileconnection/tests/marionette/test_call_barring_set_error.js
dom/mobileconnection/tests/marionette/test_call_waiting.js
dom/mobileconnection/tests/marionette/test_dsds_mobile_data_connection.js
dom/mobileconnection/tests/marionette/test_mobile_call_forwarding.js
dom/mobileconnection/tests/marionette/test_mobile_call_forwarding_get_error.js
dom/mobileconnection/tests/marionette/test_mobile_call_forwarding_set_error.js
dom/mobileconnection/tests/marionette/test_mobile_cell_Info_list.js
dom/mobileconnection/tests/marionette/test_mobile_clir.js
dom/mobileconnection/tests/marionette/test_mobile_clir_radio_off.js
dom/mobileconnection/tests/marionette/test_mobile_connections_array_uninitialized.js
dom/mobileconnection/tests/marionette/test_mobile_data_connection.js
dom/mobileconnection/tests/marionette/test_mobile_data_ipv6.js
dom/mobileconnection/tests/marionette/test_mobile_data_location.js
dom/mobileconnection/tests/marionette/test_mobile_data_state.js
dom/mobileconnection/tests/marionette/test_mobile_icc_change.js
dom/mobileconnection/tests/marionette/test_mobile_last_known_network.js
dom/mobileconnection/tests/marionette/test_mobile_neighboring_cell_ids.js
dom/mobileconnection/tests/marionette/test_mobile_networks.js
dom/mobileconnection/tests/marionette/test_mobile_operator_names.js
dom/mobileconnection/tests/marionette/test_mobile_operator_names_plmnlist.js
dom/mobileconnection/tests/marionette/test_mobile_operator_names_roaming.js
dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type.js
dom/mobileconnection/tests/marionette/test_mobile_preferred_network_type_radio_off.js
dom/mobileconnection/tests/marionette/test_mobile_roaming_preference.js
dom/mobileconnection/tests/marionette/test_mobile_set_radio.js
dom/mobileconnection/tests/marionette/test_mobile_signal_strength.js
dom/mobileconnection/tests/marionette/test_mobile_supported_network_types.js
dom/mobileconnection/tests/marionette/test_mobile_voice_location.js
dom/mobileconnection/tests/marionette/test_mobile_voice_privacy.js
dom/mobileconnection/tests/marionette/test_mobile_voice_state.js
dom/mobileconnection/tests/mochitest/mochitest.ini
dom/mobileconnection/tests/mochitest/test_mobileconnection_permission.html
dom/mobileconnection/tests/mochitest/test_mobilenetwork_permission.html
dom/permission/tests/mochitest-ril.ini
dom/permission/tests/test_mobileconnection.html
dom/webidl/CFStateChangeEvent.webidl
dom/webidl/Contacts.webidl
dom/webidl/DataErrorEvent.webidl
dom/webidl/IccCardLockError.webidl
dom/webidl/IccChangeEvent.webidl
dom/webidl/MozClirModeEvent.webidl
dom/webidl/MozContactChangeEvent.webidl
dom/webidl/MozEmergencyCbModeEvent.webidl
dom/webidl/MozIcc.webidl
dom/webidl/MozIccInfo.webidl
dom/webidl/MozIccManager.webidl
dom/webidl/MozMobileCellInfo.webidl
dom/webidl/MozMobileConnection.webidl
dom/webidl/MozMobileConnectionArray.webidl
dom/webidl/MozMobileConnectionInfo.webidl
dom/webidl/MozMobileNetworkInfo.webidl
dom/webidl/MozOtaStatusEvent.webidl
dom/webidl/MozStkCommandEvent.webidl
mobile/android/geckoview/src/main/java/org/mozilla/gecko/util/DrawableUtil.java
taskcluster/taskgraph/transforms/job/toolchain.py
toolkit/components/passwordmgr/storage-mozStorage.js
toolkit/components/places/tests/queries/test_querySerialization.js
toolkit/components/printing/content/printUtils.js
--- a/b2g/app/b2g.js
+++ b/b2g/app/b2g.js
@@ -195,17 +195,16 @@ pref("privacy.item.downloads", true);
 pref("privacy.item.passwords", true);
 pref("privacy.item.sessions", true);
 pref("privacy.item.geolocation", true);
 pref("privacy.item.siteSettings", true);
 pref("privacy.item.syncAccount", true);
 
 // base url for the wifi geolocation network provider
 pref("geo.provider.use_mls", false);
-pref("geo.cell.scan", true);
 pref("geo.wifi.uri", "https://location.services.mozilla.com/v1/geolocate?key=%MOZILLA_API_KEY%");
 
 // base url for the stumbler
 pref("geo.stumbler.url", "https://location.services.mozilla.com/v1/geosubmit?key=%MOZILLA_API_KEY%");
 
 // enable geo
 pref("geo.enabled", true);
 
--- a/b2g/chrome/content/shell.js
+++ b/b2g/chrome/content/shell.js
@@ -1,17 +1,16 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 window.performance.mark('gecko-shell-loadstart');
 
-Cu.import('resource://gre/modules/ContactService.jsm');
 Cu.import('resource://gre/modules/NotificationDB.jsm');
 Cu.import("resource://gre/modules/AppsUtils.jsm");
 Cu.import('resource://gre/modules/UserAgentOverrides.jsm');
 Cu.import('resource://gre/modules/Keyboard.jsm');
 Cu.import('resource://gre/modules/ErrorPage.jsm');
 Cu.import('resource://gre/modules/AlertsHelper.jsm');
 Cu.import('resource://gre/modules/SystemUpdateService.jsm');
 
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -152,21 +152,17 @@
 @RESPATH@/components/dom_audiochannel.xpt
 @RESPATH@/components/dom_base.xpt
 @RESPATH@/components/dom_system.xpt
 @RESPATH@/components/dom_workers.xpt
 #ifdef MOZ_WIDGET_GONK
 @RESPATH@/components/dom_wifi.xpt
 @RESPATH@/components/dom_system_gonk.xpt
 #endif
-#ifdef MOZ_B2G_RIL
-@RESPATH@/components/dom_mobileconnection.xpt
-#endif
 @RESPATH@/components/dom_canvas.xpt
-@RESPATH@/components/dom_contacts.xpt
 @RESPATH@/components/dom_core.xpt
 @RESPATH@/components/dom_css.xpt
 @RESPATH@/components/dom_events.xpt
 @RESPATH@/components/dom_geolocation.xpt
 @RESPATH@/components/dom_media.xpt
 @RESPATH@/components/dom_network.xpt
 #ifdef MOZ_SECUREELEMENT
 @RESPATH@/components/dom_secureelement.xpt
@@ -332,18 +328,16 @@
 
 ; JavaScript components
 @RESPATH@/components/ConsoleAPI.manifest
 @RESPATH@/components/ConsoleAPIStorage.js
 @RESPATH@/components/BrowserElementParent.manifest
 @RESPATH@/components/BrowserElementParent.js
 @RESPATH@/components/BrowserElementProxy.manifest
 @RESPATH@/components/BrowserElementProxy.js
-@RESPATH@/components/ContactManager.js
-@RESPATH@/components/ContactManager.manifest
 @RESPATH@/components/PhoneNumberService.js
 @RESPATH@/components/PhoneNumberService.manifest
 @RESPATH@/components/NotificationStorage.js
 @RESPATH@/components/NotificationStorage.manifest
 @RESPATH@/components/PermissionSettings.js
 @RESPATH@/components/PermissionSettings.manifest
 @RESPATH@/components/PermissionPromptService.js
 @RESPATH@/components/PermissionPromptService.manifest
@@ -445,18 +439,16 @@
 @RESPATH@/components/IccService.manifest
 @RESPATH@/components/MmsService.js
 @RESPATH@/components/MmsService.manifest
 @RESPATH@/components/MobileMessageDatabaseService.js
 @RESPATH@/components/MobileMessageDatabaseService.manifest
 #ifndef DISABLE_MOZ_RIL_GEOLOC
 @RESPATH@/components/DataCallInterfaceService.js
 @RESPATH@/components/DataCallInterfaceService.manifest
-@RESPATH@/components/MobileConnectionService.js
-@RESPATH@/components/MobileConnectionService.manifest
 @RESPATH@/components/RadioInterfaceLayer.js
 @RESPATH@/components/RadioInterfaceLayer.manifest
 @RESPATH@/components/SmsService.js
 @RESPATH@/components/SmsService.manifest
 #endif
 @RESPATH@/components/StkCmdFactory.js
 @RESPATH@/components/StkCmdFactory.manifest
 @RESPATH@/components/RILSystemMessengerHelper.js
--- a/browser/app/blocklist.xml
+++ b/browser/app/blocklist.xml
@@ -1,31 +1,31 @@
 <?xml version='1.0' encoding='UTF-8'?>
-<blocklist lastupdate="1478178431981" xmlns="http://www.mozilla.org/2006/addons-blocklist">
+<blocklist lastupdate="1478262128876" xmlns="http://www.mozilla.org/2006/addons-blocklist">
   <emItems>
     <emItem blockID="i988" id="{b12785f5-d8d0-4530-a3ea-5c4263b85bef}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i398" id="{377e5d4d-77e5-476a-8716-7e70a9272da0}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i698" id="{6b2a75c8-6e2e-4267-b955-43e25b54e575}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i1231" id="youtube@downloader.yt">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i1263" id="axtara__web@axtara.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="1.1.1" severity="3"/>
     </emItem>
-    <emItem blockID="i1231" id="youtube@downloader.yt">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i922" id="{34712C68-7391-4c47-94F3-8F88D49AD632}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="39.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
@@ -144,28 +144,28 @@
     <emItem blockID="i1266" id="@stopad">
       <prefs/>
       <versionRange minVersion="0" maxVersion="0.0.4" severity="1"/>
     </emItem>
     <emItem blockID="i473" id="{81b13b5d-fba1-49fd-9a6b-189483ac548a}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i496" id="{ACAA314B-EEBA-48e4-AD47-84E31C44796C}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i914" id="{0153E448-190B-4987-BDE1-F256CADA672F}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="39.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem blockID="i496" id="{ACAA314B-EEBA-48e4-AD47-84E31C44796C}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i690" id="{55dce8ba-9dec-4013-937e-adbf9317d990">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i218" id="ffxtlbr@claro.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
@@ -202,44 +202,44 @@
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i684" id="{9edd0ea8-2819-47c2-8320-b007d5996f8a}">
       <prefs>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i69" id="{977f3b97-5461-4346-92c8-a14c749b77c9}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i444" id="fplayer@adobe.flash">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i69" id="{977f3b97-5461-4346-92c8-a14c749b77c9}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i550" id="colmer@yopmail.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i362" id="addon@defaulttab.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="1.4.4" severity="1"/>
     </emItem>
     <emItem blockID="i140" id="mozillahmpg@mozilla.org">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i503" id="{9CE11043-9A15-4207-A565-0C94C42D590D}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i16" id="{27182e60-b5f3-411c-b545-b44205977502}">
       <prefs/>
       <versionRange minVersion="1.0" maxVersion="1.0"/>
     </emItem>
-    <emItem blockID="i503" id="{9CE11043-9A15-4207-A565-0C94C42D590D}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i549" id="/^firefox@(albrechto|swiftbrowse|springsmart|storimbo|squirrelweb|betterbrowse|lizardlink|rolimno|browsebeyond|clingclang|weblayers|kasimos|higher-aurum|xaven|bomlabio)\.(com?|net|org|info|biz)$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i1079" id="/^(@9338379C-DD5C-4A45-9A36-9733DC806FAE|9338379C-DD5C-4A45-9A36-9733DC806FAE|@EBC7B466-8A28-4061-81B5-10ACC05FFE53|@bd6a97c0-4b18-40ed-bce7-3b7d3309e3c4222|@bd6a97c0-4b18-40ed-bce7-3b7d3309e3c4|@b2d6a97c0-4b18-40ed-bce7-3b7d3309e3c4222)$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
@@ -262,21 +262,21 @@
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i706" id="thefoxonlybetter@quicksaver">
       <prefs/>
       <versionRange minVersion="1.10" maxVersion="*" severity="3"/>
       <versionRange minVersion="1.6.160" maxVersion="1.6.160" severity="3"/>
       <versionRange minVersion="0" maxVersion="0.*" severity="3"/>
     </emItem>
-    <emItem blockID="i497" id="{872b5b88-9db5-4310-bdd0-ac189557e5f5}">
+    <emItem blockID="i1210" id="auto-plugin-checker@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i1210" id="auto-plugin-checker@jetpack">
+    <emItem blockID="i497" id="{872b5b88-9db5-4310-bdd0-ac189557e5f5}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i91" id="crossriderapp4926@crossrider.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="0.81.43" severity="1"/>
     </emItem>
     <emItem blockID="i376" id="{9e09ac65-43c0-4b9d-970f-11e2e9616c55}">
@@ -302,24 +302,24 @@
     <emItem blockID="i318" id="ffxtlbr@incredibar.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i754" id="{bb7b7a60-f574-47c2-8a0b-4c56f2da9802}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i694" id="59D317DB041748fdB89B47E6F96058F3@jetpack">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i1016" id="jid1-uabu5A9hduqzCw@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i694" id="59D317DB041748fdB89B47E6F96058F3@jetpack">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i12" id="masterfiler@gmail.com">
       <prefs/>
       <versionRange severity="3"/>
     </emItem>
     <emItem blockID="i71" id="youtube@2youtube.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
@@ -346,18 +346,18 @@
     <emItem blockID="i618" id="toolbar@ask.com">
       <prefs/>
       <versionRange minVersion="3.15.24" maxVersion="3.15.24.*" severity="1"/>
       <versionRange minVersion="3.15.13" maxVersion="3.15.13.*" severity="1"/>
       <versionRange minVersion="3.15.28" maxVersion="3.15.28.*" severity="1"/>
       <versionRange minVersion="3.15.22" maxVersion="3.15.22.*" severity="1"/>
       <versionRange minVersion="3.15.8" maxVersion="3.15.8.*" severity="1"/>
       <versionRange minVersion="3.15.10" maxVersion="3.15.11.*" severity="1"/>
+      <versionRange minVersion="3.15.5" maxVersion="3.15.5.*" severity="1"/>
       <versionRange minVersion="3.15.18" maxVersion="3.15.20.*" severity="1"/>
-      <versionRange minVersion="3.15.5" maxVersion="3.15.5.*" severity="1"/>
       <versionRange minVersion="3.15.31" maxVersion="3.15.31.*" severity="1"/>
       <versionRange minVersion="3.15.26" maxVersion="3.15.26.*" severity="1"/>
     </emItem>
     <emItem blockID="i15" id="personas@christopher.beard">
       <prefs/>
       <versionRange minVersion="1.6" maxVersion="1.6">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="3.6.*" minVersion="3.6"/>
@@ -657,44 +657,44 @@
     <emItem blockID="i1038" id="344141-fasf9jas08hasoiesj9ia8ws@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i471" id="firefox@luckyleap.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i560" id="adsremoval@adsremoval.net">
+    <emItem blockID="i396" id="/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\.com$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i396" id="/@(ft|putlocker|clickmovie|m2k|sharerepo|smarter-?)downloader\.com$/">
+    <emItem blockID="i560" id="adsremoval@adsremoval.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i538" id="{354dbb0a-71d5-4e9f-9c02-6c88b9d387ba}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i968" id="{184AA5E6-741D-464a-820E-94B3ABC2F3B4}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i792" id="{8f894ed3-0bf2-498e-a103-27ef6e88899f}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i742" id="{f894a29a-f065-40c3-bb19-da6057778493}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i658" id="low_quality_flash@pie2k.com">
       <prefs/>
       <versionRange minVersion="46.2" maxVersion="47.1" severity="3"/>
     </emItem>
+    <emItem blockID="i792" id="{8f894ed3-0bf2-498e-a103-27ef6e88899f}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i17" id="{3252b9ae-c69a-4eaf-9502-dc9c1f6c009e}">
       <prefs/>
       <versionRange minVersion="2.2" maxVersion="2.2"/>
     </emItem>
     <emItem blockID="i109" id="{392e123b-b691-4a5e-b52f-c4c1027e749c}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
@@ -709,21 +709,21 @@
     <emItem blockID="i167" id="{b64982b1-d112-42b5-b1e4-d3867c4533f8}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i352" id="vpyekkifgv@vpyekkifgv.org">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i1278" id="/^(ff\-)?dodate(kKKK|XkKKK|k|kk|kkx|kR)@(firefox|flash(1)?)\.pl|dode(ee)?k@firefoxnet\.pl|addon@upsolutions\.pl$/">
+    <emItem blockID="i256" id="/^[0-9a-f]+@[0-9a-f]+\.info/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i256" id="/^[0-9a-f]+@[0-9a-f]+\.info/">
+    <emItem blockID="i1278" id="/^(ff\-)?dodate(kKKK|XkKKK|k|kk|kkx|kR)@(firefox|flash(1)?)\.pl|dode(ee)?k@firefoxnet\.pl|addon@upsolutions\.pl$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i980" id="wHO@W9.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i127" id="plugin@youtubeplayer.com">
@@ -745,36 +745,36 @@
     <emItem blockID="i380" id="{cc8f597b-0765-404e-a575-82aefbd81daf}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i432" id="lugcla21@gmail.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i724" id="{1cdbda58-45f8-4d91-b566-8edce18f8d0a}">
+    <emItem blockID="i429" id="{B40794A0-7477-4335-95C5-8CB9BBC5C4A5}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i392" id="{EEE6C361-6118-11DC-9C72-001320C79847}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i429" id="{B40794A0-7477-4335-95C5-8CB9BBC5C4A5}">
+    <emItem blockID="i724" id="{1cdbda58-45f8-4d91-b566-8edce18f8d0a}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i533" id="extension@Fast_Free_Converter.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i638" id="{7b1bf0b6-a1b9-42b0-b75d-252036438bdc}">
       <prefs/>
       <versionRange minVersion="27.8" maxVersion="27.9" severity="3"/>
     </emItem>
-    <emItem blockID="i533" id="extension@Fast_Free_Converter.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i38" id="{B7082FAA-CB62-4872-9106-E42DD88EDE45}">
       <prefs/>
       <versionRange minVersion="3.3.1" maxVersion="*">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="5.0a1"/>
         </targetApplication>
       </versionRange>
       <versionRange minVersion="0.1" maxVersion="3.3.0.*">
@@ -782,27 +782,27 @@
           <versionRange maxVersion="*" minVersion="3.7a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
     <emItem blockID="i746" id="{58d2a791-6199-482f-a9aa-9b725ec61362}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i20" id="{AB2CE124-6272-4b12-94A9-7303C7397BD1}">
-      <prefs/>
-      <versionRange minVersion="0.1" maxVersion="5.2.0.7164" severity="1"/>
-    </emItem>
     <emItem blockID="i686" id="{a7f2cb14-0472-42a1-915a-8adca2280a2c}">
       <prefs>
         <pref>browser.startup.homepage</pref>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i20" id="{AB2CE124-6272-4b12-94A9-7303C7397BD1}">
+      <prefs/>
+      <versionRange minVersion="0.1" maxVersion="5.2.0.7164" severity="1"/>
+    </emItem>
     <emItem blockID="i1279" id="dodatek@flash2.pl">
       <prefs/>
       <versionRange minVersion="1.3" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i998" id="meOYKQEbBBjH5Ml91z0p9Aosgus8P55bjTa4KPfl@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
@@ -875,88 +875,88 @@
     </emItem>
     <emItem blockID="i499" id="{babb9931-ad56-444c-b935-38bffe18ad26}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i21" id="support@update-firefox.com">
       <prefs/>
     </emItem>
+    <emItem blockID="i491" id="{515b2424-5911-40bd-8a2c-bdb20286d8f5}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i65" id="activity@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
-    <emItem blockID="i491" id="{515b2424-5911-40bd-8a2c-bdb20286d8f5}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i532" id="249911bc-d1bd-4d66-8c17-df533609e6d8@c76f3de9-939e-4922-b73c-5d7a3139375d.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i1264" id="suchpony@suchpony.de">
       <prefs/>
       <versionRange minVersion="0" maxVersion="1.6.7" severity="3"/>
     </emItem>
     <emItem blockID="i476" id="mbroctone@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i722" id="{9802047e-5a84-4da3-b103-c55995d147d1}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i656" id="hdv@vovcacik.addons.mozilla.org">
       <prefs/>
       <versionRange minVersion="102.0" maxVersion="102.0" severity="3"/>
     </emItem>
-    <emItem blockID="i722" id="{9802047e-5a84-4da3-b103-c55995d147d1}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i228" id="crossriderapp5060@crossrider.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i470" id="extension@FastFreeConverter.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i478" id="{7e8a1050-cf67-4575-92df-dcc60e7d952d}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i1223" id="tmbepff@trendmicro.com">
       <prefs/>
       <versionRange minVersion="9.2" maxVersion="9.2.0.1023" severity="1"/>
       <versionRange minVersion="0" maxVersion="9.1.0.1035" severity="1"/>
     </emItem>
+    <emItem blockID="i478" id="{7e8a1050-cf67-4575-92df-dcc60e7d952d}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i370" id="happylyrics@hpyproductions.net">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i440" id="{2d069a16-fca1-4e81-81ea-5d5086dcbd0c}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i1077" id="helper@vidscrab.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i55" id="youtube@youtube7.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
+    <emItem blockID="i664" id="123456789@offeringmedia.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i630" id="webbooster@iminent.com">
       <prefs>
         <pref>browser.startup.homepage</pref>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i664" id="123456789@offeringmedia.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i93" id="{68b8676b-99a5-46d1-b390-22411d8bcd61}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
     <emItem blockID="i624" id="/^({b95faac1-a3d7-4d69-8943-ddd5a487d966}|{ecce0073-a837-45a2-95b9-600420505f7e}|{2713b394-286f-4d7c-89ea-4174eeab9f5a}|{da7a20cf-bef4-4342-ad78-0240fdf87055})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
@@ -993,24 +993,24 @@
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i505" id="extacylife@a.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i1414" id="/^new@kuot\.pro|{13ec6687-0b15-4f01-a5a0-7a891c18e4ee}|rebeccahoppkins(ty(tr)?)?@gmail\.com|{501815af-725e-45be-b0f2-8f36f5617afc}|{9bdb5f1f-b1e1-4a75-be31-bdcaace20a99}|{e9d93e1d-792f-4f95-b738-7adb0e853b7b}|dojadewaskurwa@gmail\.com$/">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i528" id="008abed2-b43a-46c9-9a5b-a771c87b82da@1ad61d53-2bdc-4484-a26b-b888ecae1906.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i1414" id="/^new@kuot\.pro|{13ec6687-0b15-4f01-a5a0-7a891c18e4ee}|rebeccahoppkins(ty(tr)?)?@gmail\.com|{501815af-725e-45be-b0f2-8f36f5617afc}|{9bdb5f1f-b1e1-4a75-be31-bdcaace20a99}|{e9d93e1d-792f-4f95-b738-7adb0e853b7b}|dojadewaskurwa@gmail\.com$/">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i712" id="{a2bfe612-4cf5-48ea-907c-f3fb25bc9d6b}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i652" id="garg_sms@yahoo.in">
       <prefs/>
       <versionRange minVersion="67.9" maxVersion="67.9" severity="3"/>
     </emItem>
@@ -1137,62 +1137,62 @@
     <emItem blockID="i174" id="info@thebflix.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i822" id="{6af08a71-380e-42dd-9312-0111d2bc0630}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i888" id="istart_ffnt@gmail.com">
+    <emItem blockID="i846" id="PDVDZDW52397720@XDDWJXW57740856.com">
       <prefs>
         <pref>browser.startup.homepage</pref>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i846" id="PDVDZDW52397720@XDDWJXW57740856.com">
+    <emItem blockID="i888" id="istart_ffnt@gmail.com">
       <prefs>
         <pref>browser.startup.homepage</pref>
         <pref>browser.search.defaultenginename</pref>
       </prefs>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i972" id="831778-poidjao88DASfsAnindsd@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i515" id="/^({bf9194c2-b86d-4ebc-9b53-1c08b6ff779e}|{61a83e16-7198-49c6-8874-3e4e8faeb4f3}|{f0af464e-5167-45cf-9cf0-66b396d1918c}|{5d9968c3-101c-4944-ba71-72d77393322d}|{01e86e69-a2f8-48a0-b068-83869bdba3d0})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i844" id="e9d197d59f2f45f382b1aa5c14d82@8706aaed9b904554b5cb7984e9.com">
-      <prefs>
-        <pref>browser.startup.homepage</pref>
-        <pref>browser.search.defaultenginename</pref>
-      </prefs>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i216" id="fdm_ffext@freedownloadmanager.org">
       <prefs/>
       <versionRange minVersion="1.0" maxVersion="1.3.1">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="3.0a1"/>
         </targetApplication>
       </versionRange>
       <versionRange minVersion="1.5.7.5" maxVersion="1.5.7.5" severity="1"/>
     </emItem>
-    <emItem blockID="i818" id="contentarget@maildrop.cc">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    <emItem blockID="i844" id="e9d197d59f2f45f382b1aa5c14d82@8706aaed9b904554b5cb7984e9.com">
+      <prefs>
+        <pref>browser.startup.homepage</pref>
+        <pref>browser.search.defaultenginename</pref>
+      </prefs>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i596" id="{b99c8534-7800-48fa-bd71-519a46cdc7e1}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i818" id="contentarget@maildrop.cc">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i461" id="{8E9E3331-D360-4f87-8803-52DE43566502}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i23" id="firefox@bandoo.com">
       <prefs/>
       <versionRange minVersion="5.0" maxVersion="5.0" severity="1">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
@@ -1359,32 +1359,32 @@
     <emItem blockID="i1034" id="a88a77ahjjfjakckmmabsy278djasi@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i562" id="iobitapps@mybrowserbar.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
+    <emItem blockID="i970" id="hha8771ui3-Fo9j9h7aH98jsdfa8sda@jetpack">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="3"/>
+    </emItem>
     <emItem blockID="i916" id="{97E22097-9A2F-45b1-8DAF-36AD648C7EF4}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="39.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
     <emItem blockID="i338" id="{1FD91A9C-410C-4090-BBCC-55D3450EF433}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i970" id="hha8771ui3-Fo9j9h7aH98jsdfa8sda@jetpack">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="3"/>
-    </emItem>
     <emItem blockID="i430" id="1chtw@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i344" id="lrcsTube@hansanddeta.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
@@ -1543,21 +1543,21 @@
     <emItem blockID="i314" id="crossriderapp8812@crossrider.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i838" id="{87b5a11e-3b54-42d2-9102-0a7cb1f79ebf}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i570" id="jid1-vW9nopuIAJiRHw@jetpack">
+    <emItem blockID="i678" id="{C4A4F5A0-4B89-4392-AFAC-D58010E349AF}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i678" id="{C4A4F5A0-4B89-4392-AFAC-D58010E349AF}">
+    <emItem blockID="i570" id="jid1-vW9nopuIAJiRHw@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i14" id="mozilla_cc@internetdownloadmanager.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="6.9.8">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="3.7a1pre"/>
@@ -1587,24 +1587,24 @@
     <emItem blockID="i465" id="trtv3@trtv.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i8" id="{B13721C7-F507-4982-B2E5-502A71474FED}">
       <prefs/>
       <versionRange minVersion=" " severity="1"/>
     </emItem>
+    <emItem blockID="i73" id="a1g0a9g219d@a1.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*"/>
+    </emItem>
     <emItem blockID="i854" id="/^(7tG@zEb\.net|ru@gfK0J\.edu)$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i73" id="a1g0a9g219d@a1.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*"/>
-    </emItem>
     <emItem blockID="i662" id="imbaty@taringamp3.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i1126" id="{bbea93c6-64a3-4a5a-854a-9cc61c8d309e}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
@@ -1670,21 +1670,21 @@
     <emItem blockID="i103" id="kdrgun@gmail.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
     <emItem blockID="i1119" id="/^(test3@test.org|test2@test.org|test@test.org|support@mozilla.org)$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i484" id="plugin@getwebcake.com">
+    <emItem blockID="i519" id="703db0db-5fe9-44b6-9f53-c6a91a0ad5bd@7314bc82-969e-4d2a-921b-e5edd0b02cf1.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i519" id="703db0db-5fe9-44b6-9f53-c6a91a0ad5bd@7314bc82-969e-4d2a-921b-e5edd0b02cf1.com">
+    <emItem blockID="i484" id="plugin@getwebcake.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i477" id="mbrnovone@facebook.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i495" id="kallow@facebook.com">
@@ -1836,21 +1836,21 @@
     <emItem blockID="i472" id="linksicle@linksicle.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i98" id="youtubeeing@youtuberie.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*"/>
     </emItem>
-    <emItem blockID="i578" id="jid1-XLjasWL55iEE1Q@jetpack">
+    <emItem blockID="i1213" id="unblocker20__web@unblocker.yt">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i1213" id="unblocker20__web@unblocker.yt">
+    <emItem blockID="i578" id="jid1-XLjasWL55iEE1Q@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i1233" id="cloudmask@cloudmask.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="2.0.788"/>
     </emItem>
     <emItem blockID="i582" id="discoverypro@discoverypro.com">
@@ -1892,45 +1892,45 @@
     <emItem blockID="i1129" id="youtubeunblocker__web@unblocker.yt">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
     <emItem blockID="i1214" id="firefoxdav@icloud.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="1.4.22" severity="1"/>
     </emItem>
+    <emItem blockID="i66" id="youtubeer@youtuber.com">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*"/>
+    </emItem>
     <emItem blockID="i808" id="{c96d1ae6-c4cf-4984-b110-f5f561b33b5a}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
-    <emItem blockID="i66" id="youtubeer@youtuber.com">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*"/>
-    </emItem>
     <emItem blockID="i4" id="{4B3803EA-5230-4DC3-A7FC-33638F3D3542}">
       <prefs/>
       <versionRange minVersion="1.2" maxVersion="1.2">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="3.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
     <emItem blockID="i517" id="/^({16e193c8-1706-40bf-b6f3-91403a9a22be}|{284fed43-2e13-4afe-8aeb-50827d510e20}|{5e3cc5d8-ed11-4bed-bc47-35b4c4bc1033}|{7429e64a-1fd4-4112-a186-2b5630816b91}|{8c9980d7-0f09-4459-9197-99b3e559660c}|{8f1d9545-0bb9-4583-bb3c-5e1ac1e2920c})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i460" id="{845cab51-d8d2-472f-8bd9-2b44642d97c2}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i136" id="Adobe@flash.com">
+    <emItem blockID="i441" id="{49c53dce-afa0-49a1-a08b-2eb8e8444128}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
-    <emItem blockID="i441" id="{49c53dce-afa0-49a1-a08b-2eb8e8444128}">
+    <emItem blockID="i136" id="Adobe@flash.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i527" id="/^({bfec236d-e122-4102-864f-f5f19d897f5e}|{3f842035-47f4-4f10-846b-6199b07f09b8}|{92ed4bbd-83f2-4c70-bb4e-f8d3716143fe})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="1"/>
     </emItem>
     <emItem blockID="i800" id="{424b0d11-e7fe-4a04-b7df-8f2c77f58aaf}">
@@ -1943,28 +1943,28 @@
     <emItem blockID="i920" id="{FCE04E1F-9378-4f39-96F6-5689A9159E45}">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3">
         <targetApplication id="{ec8030f7-c20a-464f-9b0e-13a3a9e97384}">
           <versionRange maxVersion="*" minVersion="39.0a1"/>
         </targetApplication>
       </versionRange>
     </emItem>
-    <emItem blockID="i224" id="{336D0C35-8A85-403a-B9D2-65C292C39087}">
-      <prefs/>
-      <versionRange minVersion="0" maxVersion="*" severity="1"/>
-    </emItem>
     <emItem blockID="i507" id="4zffxtbr-bs@VideoDownloadConverter_4z.com">
       <prefs/>
       <versionRange minVersion="0" maxVersion="5.75.3.25126" severity="1"/>
     </emItem>
     <emItem blockID="i1050" id="87aukfkausiopoawjsuifhasefgased278djasi@jetpack">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
+    <emItem blockID="i224" id="{336D0C35-8A85-403a-B9D2-65C292C39087}">
+      <prefs/>
+      <versionRange minVersion="0" maxVersion="*" severity="1"/>
+    </emItem>
     <emItem blockID="i22" id="ShopperReports@ShopperReports.com">
       <prefs/>
       <versionRange minVersion="3.1.22.0" maxVersion="3.1.22.0"/>
     </emItem>
     <emItem blockID="i1137" id="/^({d50bfa5f-291d-48a8-909c-5f1a77b31948}|{d54bc985-6e7b-46cd-ad72-a4a266ad879e}|{d89e5de3-5543-4363-b320-a98cf150f86a}|{f3465017-6f51-4980-84a5-7bee2f961eba}|{fae25f38-ff55-46ea-888f-03b49aaf8812})$/">
       <prefs/>
       <versionRange minVersion="0" maxVersion="*" severity="3"/>
     </emItem>
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1222,16 +1222,18 @@ pref("security.mixed_content.block_activ
 // Show degraded UI for http pages with password fields.
 // Only for Nightly, Dev Edition and early beta, not for late beta or release.
 #ifdef EARLY_BETA_OR_EARLIER
 pref("security.insecure_password.ui.enabled", true);
 #else
 pref("security.insecure_password.ui.enabled", false);
 #endif
 
+pref("security.insecure_field_warning.contextual.enabled", false);
+
 // 1 = allow MITM for certificate pinning checks.
 pref("security.cert_pinning.enforcement_level", 1);
 
 
 // Override the Gecko-default value of false for Firefox.
 pref("plain_text.wrap_long_lines", true);
 
 // If this turns true, Moz*Gesture events are not called stopPropagation()
--- a/browser/base/content/browser-fullZoom.js
+++ b/browser/base/content/browser-fullZoom.js
@@ -23,26 +23,24 @@ var FullZoom = {
   // Stores initial locations if we receive onLocationChange
   // events before we're initialized.
   _initialLocations: new WeakMap(),
 
   get siteSpecific() {
     return this._siteSpecificPref;
   },
 
-  //* *************************************************************************//
   // nsISupports
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener,
                                          Ci.nsIObserver,
                                          Ci.nsIContentPrefObserver,
                                          Ci.nsISupportsWeakReference,
                                          Ci.nsISupports]),
 
-  //* *************************************************************************//
   // Initialization & Destruction
 
   init: function FullZoom_init() {
     gBrowser.addEventListener("ZoomChangeUsingMouseWheel", this);
 
     // Register ourselves with the service so we know when our pref changes.
     this._cps2 = Cc["@mozilla.org/content-pref/service;1"].
                  getService(Ci.nsIContentPrefService2);
@@ -70,17 +68,16 @@ var FullZoom = {
 
   destroy: function FullZoom_destroy() {
     gPrefService.removeObserver("browser.zoom.", this);
     this._cps2.removeObserverForName(this.name, this);
     gBrowser.removeEventListener("ZoomChangeUsingMouseWheel", this);
   },
 
 
-  //* *************************************************************************//
   // Event Handlers
 
   // nsIDOMEventListener
 
   handleEvent: function FullZoom_handleEvent(event) {
     switch (event.type) {
       case "ZoomChangeUsingMouseWheel":
         let browser = this._getTargetedBrowser(event);
@@ -241,17 +238,16 @@ var FullZoom = {
   // update state of zoom type menu item
 
   updateMenu: function FullZoom_updateMenu() {
     var menuItem = document.getElementById("toggle_zoom");
 
     menuItem.setAttribute("checked", !ZoomManager.useFullZoom);
   },
 
-  //* *************************************************************************//
   // Setting & Pref Manipulation
 
   /**
    * Reduces the zoom level of the page in the current browser.
    */
   reduce: function FullZoom_reduce() {
     ZoomManager.reduce();
     let browser = gBrowser.selectedBrowser;
@@ -386,17 +382,16 @@ var FullZoom = {
     let ctxt = this._loadContextFromBrowser(browser);
     this._cps2.removeByDomainAndName(browser.currentURI.spec, this.name, ctxt, {
       handleCompletion: function () {
         this._isNextContentPrefChangeInternal = true;
       }.bind(this),
     });
   },
 
-  //* *************************************************************************//
   // Utilities
 
   /**
    * Returns the zoom change token of the given browser.  Asynchronous
    * operations that access the given browser's zoom should use this method to
    * capture the token before starting and use token.isCurrent to determine if
    * it's safe to access the zoom when done.  If token.isCurrent is false, then
    * after the async operation started, either the browser's zoom was changed or
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1,15 +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/. */
 
-// //////////////////////////////////////////////////////////////////////////////
-// // StarUI
-
 var StarUI = {
   _itemId: -1,
   uri: null,
   _batching: false,
   _isNewBookmark: false,
   _autoCloseTimer: 0,
 
   _element: function(aID) {
@@ -340,19 +337,16 @@ var StarUI = {
     }
     else {
       PlacesUtils.transactionManager.endBatch(false);
     }
     this._batching = false;
   }
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // PlacesCommandHook
-
 var PlacesCommandHook = {
   /**
    * Adds a bookmark to the page loaded in the given browser.
    *
    * @param aBrowser
    *        a <browser> element.
    * @param [optional] aParent
    *        The folder in which to create a new bookmark if the page loaded in
@@ -667,19 +661,16 @@ var PlacesCommandHook = {
     }
     else {
       organizer.PlacesOrganizer.selectLeftPaneContainerByHierarchy(aLeftPaneRoot);
       organizer.focus();
     }
   }
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // HistoryMenu
-
 XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
   "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
 
 // View for the history menu.
 function HistoryMenu(aPopupShowingEvent) {
   // Workaround for Bug 610187.  The sidebar does not include all the Places
   // views definitions, and we don't need them there.
   // Defining the prototype inheritance in the prototype itself would cause
@@ -803,19 +794,16 @@ HistoryMenu.prototype = {
     if (placesNode) {
       if (!PrivateBrowsingUtils.isWindowPrivate(window))
         PlacesUIUtils.markPageAsTyped(placesNode.uri);
       openUILink(placesNode.uri, aEvent, { ignoreAlt: true });
     }
   }
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // BookmarksEventHandler
-
 /**
  * Functions for handling events in the Bookmarks Toolbar and menu.
  */
 var BookmarksEventHandler = {
   /**
    * Handler for click event for an item in the bookmarks toolbar or menu.
    * Menus and submenus from the folder buttons bubble up to this handler.
    * Left-click is handled in the onCommand function.
@@ -932,19 +920,16 @@ var BookmarksEventHandler = {
     if (!tooltipUrl.hidden)
       tooltipUrl.value = url;
 
     // Show tooltip.
     return true;
   }
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // PlacesMenuDNDHandler
-
 // Handles special drag and drop functionality for Places menus that are not
 // part of a Places view (e.g. the bookmarks menu in the menubar).
 var PlacesMenuDNDHandler = {
   _springLoadDelayMs: 350,
   _closeDelayMs: 500,
   _loadTimer: null,
   _closeTimer: null,
   _closingTimerNode: null,
@@ -1063,19 +1048,16 @@ var PlacesMenuDNDHandler = {
                                 PlacesUtils.bookmarks.DEFAULT_INDEX,
                                 Components.interfaces.nsITreeView.DROP_ON);
     PlacesControllerDragHelper.onDrop(ip, event.dataTransfer);
     PlacesControllerDragHelper.currentDropTarget = null;
     event.stopPropagation();
   }
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // PlacesToolbarHelper
-
 /**
  * This object handles the initialization and uninitialization of the bookmarks
  * toolbar.
  */
 var PlacesToolbarHelper = {
   _place: "place:folder=TOOLBAR",
 
   get _viewElt() {
@@ -1210,19 +1192,16 @@ var PlacesToolbarHelper = {
       if (this._viewElt._placesView) {
         this._viewElt._placesView.uninit();
       }
       this.init(true);
     }
   },
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // BookmarkingUI
-
 /**
  * Handles the bookmarks menu-button in the toolbar.
  */
 
 var BookmarkingUI = {
   BOOKMARK_BUTTON_ID: "bookmarks-menu-button",
   BOOKMARK_BUTTON_SHORTCUT: "addBookmarkAsKb",
   get button() {
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -479,16 +479,36 @@ toolbar:not(#TabsToolbar) > #personal-bo
 #PopupAutoComplete > richlistbox > richlistitem > .ac-type-icon,
 #PopupAutoComplete > richlistbox > richlistitem > .ac-site-icon,
 #PopupAutoComplete > richlistbox > richlistitem > .ac-tags,
 #PopupAutoComplete > richlistbox > richlistitem > .ac-separator,
 #PopupAutoComplete > richlistbox > richlistitem > .ac-url {
   display: none;
 }
 
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] {
+  -moz-binding: url("chrome://global/content/bindings/autocomplete.xml#autocomplete-richlistitem-insecure-field");
+  height: auto;
+  background-color: #F6F6F6;
+}
+
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] > .ac-site-icon {
+  display: initial;
+  list-style-image: url(chrome://browser/skin/connection-mixed-active-loaded.svg#icon);
+}
+
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] > .ac-title > .ac-text-overflow-container > .ac-title-text {
+  text-overflow: initial;
+  white-space: initial;
+}
+
+#PopupAutoComplete > richlistbox > richlistitem[originaltype="insecureWarning"] > .ac-title > label {
+  margin-inline-start: 0;
+}
+
 #PopupSearchAutoComplete {
   -moz-binding: url("chrome://browser/content/search/search.xml#browser-search-autocomplete-result-popup");
 }
 
 /* Overlay a badge on top of the icon of additional open search providers
    in the search panel. */
 .addengine-item > .button-box > .button-icon {
   -moz-binding: url("chrome://browser/content/search/search.xml#addengine-icon");
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -5845,17 +5845,16 @@ var LanguageDetectionListener = {
     });
   }
 };
 
 
 var BrowserOffline = {
   _inited: false,
 
-  // ///////////////////////////////////////////////////////////////////////////
   // BrowserOffline Public Methods
   init: function ()
   {
     if (!this._uiElement)
       this._uiElement = document.getElementById("workOfflineMenuitemState");
 
     Services.obs.addObserver(this, "network:offline-status-changed", false);
 
@@ -5878,29 +5877,27 @@ var BrowserOffline = {
     if (!ioService.offline && !this._canGoOffline()) {
       this._updateOfflineUI(false);
       return;
     }
 
     ioService.offline = !ioService.offline;
   },
 
-  // ///////////////////////////////////////////////////////////////////////////
   // nsIObserver
   observe: function (aSubject, aTopic, aState)
   {
     if (aTopic != "network:offline-status-changed")
       return;
 
     // This notification is also received because of a loss in connectivity,
     // which we ignore by updating the UI to the current value of io.offline
     this._updateOfflineUI(Services.io.offline);
   },
 
-  // ///////////////////////////////////////////////////////////////////////////
   // BrowserOffline Implementation Methods
   _canGoOffline: function ()
   {
     try {
       var cancelGoOffline = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
       Services.obs.notifyObservers(cancelGoOffline, "offline-requested", null);
 
       // Something aborted the quit process.
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -152,17 +152,18 @@
     <panel type="autocomplete" id="PopupSearchAutoComplete" noautofocus="true" hidden="true"/>
 
     <!-- for url bar autocomplete -->
     <panel type="autocomplete-richlistbox"
            id="PopupAutoCompleteRichResult"
            noautofocus="true"
            hidden="true"
            flip="none"
-           level="parent"/>
+           level="parent"
+           overflowpadding="30" />
 
     <panel id="DateTimePickerPanel"
            type="arrow"
            hidden="true"
            orient="vertical"
            noautofocus="true"
            consumeoutsideclicks="false"
            level="parent">
--- a/browser/base/content/content.js
+++ b/browser/base/content/content.js
@@ -1298,17 +1298,17 @@ var PageInfoListener = {
       result.SVGImageElementHeight = item.height.baseVal.value;
     }
 
     result.baseURI = item.baseURI;
 
     return result;
   },
 
-  //* ******* Other Misc Stuff
+  // Other Misc Stuff
   // Modified from the Links Panel v2.3, http://segment7.net/mozilla/links/links.html
   // parse a node to extract the contents of the node
   getValueText: function(node)
   {
 
     let valueText = "";
 
     // Form input elements don't generally contain information that is useful to our callers, so return nothing.
--- a/browser/base/content/pageinfo/pageInfo.js
+++ b/browser/base/content/pageinfo/pageInfo.js
@@ -1,16 +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/. */
 
 Components.utils.import("resource://gre/modules/LoadContextInfo.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
-//* ******* define a js object to implement nsITreeView
+// define a js object to implement nsITreeView
 function pageInfoTreeView(treeid, copycol)
 {
   // copycol is the index number for the column that we want to add to
   // the copy-n-paste buffer when the user hits accel-c
   this.treeid = treeid;
   this.copycol = copycol;
   this.rows = 0;
   this.tree = null;
@@ -631,17 +631,17 @@ function addImage(imageViewRow)
         gImageElement.width == elem.width &&
         gImageElement.height == elem.height &&
         gImageElement.imageText == elem.imageText) {
       gImageView.data[i][COL_IMAGE_NODE] = elem;
     }
   }
 }
 
-//* ******* Link Stuff
+// Link Stuff
 function openURL(target)
 {
   var url = target.parentNode.childNodes[2].value;
   window.open(url, "_blank", "chrome");
 }
 
 function onBeginLinkDrag(event, urlField, descField)
 {
@@ -663,17 +663,17 @@ function onBeginLinkDrag(event, urlField
   var desc = tree.view.getCellText(row, col);
 
   var dt = event.dataTransfer;
   dt.setData("text/x-moz-url", url + "\n" + desc);
   dt.setData("text/url-list", url);
   dt.setData("text/plain", url);
 }
 
-//* ******* Image Stuff
+// Image Stuff
 function getSelectedRows(tree)
 {
   var start = { };
   var end   = { };
   var numRanges = tree.view.selection.getRangeCount();
 
   var rowArray = [ ];
   for (var t = 0; t < numRanges; t++) {
--- a/browser/base/content/test/general/browser_aboutAccounts.js
+++ b/browser/base/content/test/general/browser_aboutAccounts.js
@@ -1,13 +1,12 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: window.location is null");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/Promise.jsm");
--- a/browser/base/content/test/general/browser_aboutSupport_newtab_security_state.js
+++ b/browser/base/content/test/general/browser_aboutSupport_newtab_security_state.js
@@ -1,12 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: window.location is null");
 
 
 add_task(function* checkIdentityOfAboutSupport() {
--- a/browser/base/content/test/general/browser_fxa_oauth.js
+++ b/browser/base/content/test/general/browser_fxa_oauth.js
@@ -1,13 +1,12 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
 
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
--- a/browser/base/content/test/general/browser_gZipOfflineChild.js
+++ b/browser/base/content/test/general/browser_gZipOfflineChild.js
@@ -11,17 +11,17 @@ registerCleanupFunction(function() {
   let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
   Services.perms.removeFromPrincipal(principal, "offline-app");
   Services.prefs.clearUserPref("offline-apps.allow_by_default");
 });
 
 var cacheCount = 0;
 var intervalID = 0;
 
-// //
+//
 // Handle "message" events which are posted from the iframe upon
 // offline cache events.
 //
 function handleMessageEvents(event) {
   cacheCount++;
   switch (cacheCount) {
     case 1:
       // This is the initial caching off offline data.
--- a/browser/base/content/test/general/browser_sanitizeDialog.js
+++ b/browser/base/content/test/general/browser_sanitizeDialog.js
@@ -627,18 +627,16 @@ add_task(function* test_offline_apps_per
   };
   wh.open();
   yield wh.promiseClosed;
 });
 
 var now_mSec = Date.now();
 var now_uSec = now_mSec * 1000;
 
-// /////////////////////////////////////////////////////////////////////////////
-
 /**
  * This wraps the dialog and provides some convenience methods for interacting
  * with it.
  *
  * @param aWin
  *        The dialog's nsIDOMWindow
  */
 function WindowHelper(aWin) {
--- a/browser/base/content/test/general/browser_scope.js
+++ b/browser/base/content/test/general/browser_scope.js
@@ -1,9 +1,8 @@
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
 
 function test() {
   ok(!!gBrowser, "gBrowser exists");
--- a/browser/base/content/test/general/browser_tabs_owner.js
+++ b/browser/base/content/test/general/browser_tabs_owner.js
@@ -1,16 +1,14 @@
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: gBrowser._finalizeTabSwitch is not a function");
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: gBrowser._finalizeTabSwitch is not a function");
 
 function test() {
   gBrowser.addTab();
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -611,49 +611,36 @@ var FullZoomHelper = {
  * @param [optional] url
  *        The url to load, or the current url.
  * @return {Promise} resolved when the event is handled.
  * @resolves to the received event
  * @rejects if a valid load event is not received within a meaningful interval
  */
 function promiseTabLoadEvent(tab, url)
 {
-  let deferred = Promise.defer();
   info("Wait tab event: load");
 
   function handle(loadedUrl) {
     if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
       info(`Skipping spurious load event for ${loadedUrl}`);
       return false;
     }
 
     info("Tab event received: load");
     return true;
   }
 
   // Create two promises: one resolved from the content process when the page
   // loads and one that is rejected if we take too long to load the url.
   let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
 
-  let timeout = setTimeout(() => {
-    deferred.reject(new Error("Timed out while waiting for a 'load' event"));
-  }, 30000);
-
-  loaded.then(() => {
-    clearTimeout(timeout);
-    deferred.resolve()
-  });
-
   if (url)
     BrowserTestUtils.loadURI(tab.linkedBrowser, url);
 
-  // Promise.all rejects if either promise rejects (i.e. if we time out) and
-  // if our loaded promise resolves before the timeout, then we resolve the
-  // timeout promise as well, causing the all promise to resolve.
-  return Promise.all([deferred.promise, loaded]);
+  return loaded;
 }
 
 /**
  * Returns a Promise that resolves once a new tab has been opened in
  * a xul:tabbrowser.
  *
  * @param aTabBrowser
  *        The xul:tabbrowser to monitor for a new tab.
--- a/browser/base/content/test/plugins/browser_private_clicktoplay.js
+++ b/browser/base/content/test/plugins/browser_private_clicktoplay.js
@@ -99,22 +99,20 @@ add_task(function* test2a() {
   yield ContentTask.spawn(gTestBrowser, null, function* () {
     let plugin = content.document.getElementById("test");
     let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
     let condition = () => objLoadingContent.activated;
     yield ContentTaskUtils.waitForCondition(condition, "Test 2a, Waited too long for plugin to activate");
   });
 });
 
-add_task(function* test2b() {
+add_task(function* test2c() {
+  let topicObserved = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
   yield createPrivateWindow(gHttpTestRoot + "plugin_test.html");
-});
-
-add_task(function* test2c() {
-  yield TestUtils.topicObserved("PopupNotifications-updateNotShowing");
+  yield topicObserved;
 
   let popupNotification = gPrivateWindow.PopupNotifications.getNotification("click-to-play-plugins", gPrivateBrowser);
   ok(popupNotification, "Test 2c, Should have a click-to-play notification");
 
   yield ContentTask.spawn(gPrivateBrowser, null, function() {
     let plugin = content.document.getElementById("test");
     let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
     ok(objLoadingContent.activated, "Test 2c, Plugin should be activated");
@@ -156,22 +154,21 @@ add_task(function* test3a() {
   yield ContentTask.spawn(gTestBrowser, null, function* () {
     let plugin = content.document.getElementById("test");
     let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
     let condition = () => objLoadingContent.activated;
     yield ContentTaskUtils.waitForCondition(condition, "Test 3a, Waited too long for plugin to activate");
   });
 });
 
-add_task(function* test3b() {
+add_task(function* test3c() {
+  let topicObserved = TestUtils.topicObserved("PopupNotifications-updateNotShowing");
   yield createPrivateWindow(gHttpTestRoot + "plugin_test.html");
-});
+  yield topicObserved;
 
-add_task(function* test3c() {
-  yield TestUtils.topicObserved("PopupNotifications-updateNotShowing");
   let popupNotification = gPrivateWindow.PopupNotifications.getNotification("click-to-play-plugins", gPrivateBrowser);
   ok(popupNotification, "Test 3c, Should have a click-to-play notification");
 
   // Check the button status
   let promiseShown = BrowserTestUtils.waitForEvent(gPrivateWindow.PopupNotifications.panel,
                                                    "Shown");
   popupNotification.reshow();
   yield promiseShown;
--- a/browser/base/content/test/plugins/head.js
+++ b/browser/base/content/test/plugins/head.js
@@ -73,49 +73,36 @@ function waitForEvent(subject, eventName
  *        The tab to load into.
  * @param [optional] url
  *        The url to load, or the current url.
  * @return {Promise} resolved when the event is handled.
  * @resolves to the received event
  * @rejects if a valid load event is not received within a meaningful interval
  */
 function promiseTabLoadEvent(tab, url) {
-  let deferred = PromiseUtils.defer();
   info("Wait tab event: load");
 
   function handle(loadedUrl) {
     if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
       info(`Skipping spurious load event for ${loadedUrl}`);
       return false;
     }
 
     info("Tab event received: load");
     return true;
   }
 
   // Create two promises: one resolved from the content process when the page
   // loads and one that is rejected if we take too long to load the url.
   let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
 
-  let timeout = setTimeout(() => {
-    deferred.reject(new Error("Timed out while waiting for a 'load' event"));
-  }, 30000);
-
-  loaded.then(() => {
-    clearTimeout(timeout);
-    deferred.resolve()
-  });
-
   if (url)
     BrowserTestUtils.loadURI(tab.linkedBrowser, url);
 
-  // Promise.all rejects if either promise rejects (i.e. if we time out) and
-  // if our loaded promise resolves before the timeout, then we resolve the
-  // timeout promise as well, causing the all promise to resolve.
-  return Promise.all([deferred.promise, loaded]);
+  return loaded;
 }
 
 function waitForCondition(condition, nextTest, errorMsg, aTries, aWait) {
   let tries = 0;
   let maxTries = aTries || 100; // 100 tries
   let maxWait = aWait || 100; // 100 msec x 100 tries = ten seconds
   let interval = setInterval(function() {
     if (tries >= maxTries) {
--- a/browser/base/content/test/social/browser_social_activation.js
+++ b/browser/base/content/test/social/browser_social_activation.js
@@ -1,13 +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/. */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: Assert is null");
 
 
 var SocialService = Cu.import("resource:///modules/SocialService.jsm", {}).SocialService;
--- a/browser/base/content/test/urlbar/head.js
+++ b/browser/base/content/test/urlbar/head.js
@@ -202,49 +202,36 @@ function waitForDocLoadAndStopIt(aExpect
  * @param [optional] url
  *        The url to load, or the current url.
  * @return {Promise} resolved when the event is handled.
  * @resolves to the received event
  * @rejects if a valid load event is not received within a meaningful interval
  */
 function promiseTabLoadEvent(tab, url)
 {
-  let deferred = Promise.defer();
   info("Wait tab event: load");
 
   function handle(loadedUrl) {
     if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
       info(`Skipping spurious load event for ${loadedUrl}`);
       return false;
     }
 
     info("Tab event received: load");
     return true;
   }
 
   // Create two promises: one resolved from the content process when the page
   // loads and one that is rejected if we take too long to load the url.
   let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
 
-  let timeout = setTimeout(() => {
-    deferred.reject(new Error("Timed out while waiting for a 'load' event"));
-  }, 30000);
-
-  loaded.then(() => {
-    clearTimeout(timeout);
-    deferred.resolve()
-  });
-
   if (url)
     BrowserTestUtils.loadURI(tab.linkedBrowser, url);
 
-  // Promise.all rejects if either promise rejects (i.e. if we time out) and
-  // if our loaded promise resolves before the timeout, then we resolve the
-  // timeout promise as well, causing the all promise to resolve.
-  return Promise.all([deferred.promise, loaded]);
+  return loaded;
 }
 
 function makeActionURI(action, params) {
   let encodedParams = {};
   for (let key in params) {
     encodedParams[key] = encodeURIComponent(params[key]);
   }
   let url = "moz-action:" + action + "," + JSON.stringify(encodedParams);
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/ext-sessions.js
@@ -0,0 +1,44 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
+                                  "resource:///modules/sessionstore/SessionStore.jsm");
+
+function getRecentlyClosed(maxResults, extension) {
+  let recentlyClosed = [];
+
+  // Get closed windows
+  let closedWindowData = SessionStore.getClosedWindowData(false);
+  for (let window of closedWindowData) {
+    recentlyClosed.push({
+      lastModified: window.closedAt,
+      window: WindowManager.convertFromSessionStoreClosedData(window, extension)});
+  }
+
+  // Get closed tabs
+  for (let window of WindowListManager.browserWindows()) {
+    let closedTabData = SessionStore.getClosedTabData(window, false);
+    for (let tab of closedTabData) {
+      recentlyClosed.push({
+        lastModified: tab.closedAt,
+        tab: TabManager.for(extension).convertFromSessionStoreClosedData(tab, window)});
+    }
+  }
+
+  // Sort windows and tabs
+  recentlyClosed.sort((a, b) => b.lastModified - a.lastModified);
+  return recentlyClosed.slice(0, maxResults);
+}
+
+extensions.registerSchemaAPI("sessions", "addon_parent", context => {
+  let {extension} = context;
+  return {
+    sessions: {
+      getRecentlyClosed: function(filter) {
+        let maxResults = filter.maxResults == undefined ? this.MAX_SESSION_RESULTS : filter.maxResults;
+        return Promise.resolve(getRecentlyClosed(maxResults, extension));
+      },
+    },
+  };
+});
--- a/browser/components/extensions/ext-utils.js
+++ b/browser/components/extensions/ext-utils.js
@@ -656,16 +656,33 @@ ExtensionTabManager.prototype = {
       if (icon) {
         result.favIconUrl = icon;
       }
     }
 
     return result;
   },
 
+  // Converts tabs returned from SessionStore.getClosedTabData and
+  // SessionStore.getClosedWindowData into API tab objects
+  convertFromSessionStoreClosedData(tab, window) {
+    let result = {
+      sessionId: String(tab.closedId),
+      index: tab.pos ? tab.pos : 0,
+      windowId: WindowManager.getId(window),
+      selected: false,
+      highlighted: false,
+      active: false,
+      pinned: false,
+      incognito: Boolean(tab.state && tab.state.isPrivate),
+    };
+
+    return result;
+  },
+
   getTabs(window) {
     return Array.from(window.gBrowser.tabs)
                 .filter(tab => !tab.closing)
                 .map(tab => this.convert(tab));
   },
 };
 
 // Sends the tab and windowId upon request. This is primarily used to support
@@ -903,16 +920,29 @@ global.WindowManager = {
     for (let window of WindowListManager.browserWindows(true)) {
       if (this.getId(window) == id) {
         return window;
       }
     }
     return null;
   },
 
+  getState(window) {
+    const STATES = {
+      [window.STATE_MAXIMIZED]: "maximized",
+      [window.STATE_MINIMIZED]: "minimized",
+      [window.STATE_NORMAL]: "normal",
+    };
+    let state = STATES[window.windowState];
+    if (window.fullScreen) {
+      state = "fullscreen";
+    }
+    return state;
+  },
+
   setState(window, state) {
     if (state != "fullscreen" && window.fullScreen) {
       window.fullScreen = false;
     }
 
     switch (state) {
       case "maximized":
         window.maximize();
@@ -943,50 +973,62 @@ global.WindowManager = {
         break;
 
       default:
         throw new Error(`Unexpected window state: ${state}`);
     }
   },
 
   convert(extension, window, getInfo) {
-    const STATES = {
-      [window.STATE_MAXIMIZED]: "maximized",
-      [window.STATE_MINIMIZED]: "minimized",
-      [window.STATE_NORMAL]: "normal",
-    };
-    let state = STATES[window.windowState];
-    if (window.fullScreen) {
-      state = "fullscreen";
-    }
-
     let xulWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIDocShell)
                           .treeOwner.QueryInterface(Ci.nsIInterfaceRequestor)
                           .getInterface(Ci.nsIXULWindow);
 
     let result = {
       id: this.getId(window),
       focused: window.document.hasFocus(),
       top: window.screenY,
       left: window.screenX,
       width: window.outerWidth,
       height: window.outerHeight,
       incognito: PrivateBrowsingUtils.isWindowPrivate(window),
       type: this.windowType(window),
-      state,
+      state: this.getState(window),
       alwaysOnTop: xulWindow.zLevel >= Ci.nsIXULWindow.raisedZ,
     };
 
     if (getInfo && getInfo.populate) {
       result.tabs = TabManager.for(extension).getTabs(window);
     }
 
     return result;
   },
+
+  // Converts windows returned from SessionStore.getClosedWindowData
+  // into API window objects
+  convertFromSessionStoreClosedData(window, extension) {
+    let result = {
+      sessionId: String(window.closedId),
+      focused: false,
+      incognito: false,
+      type: "normal", // this is always "normal" for a closed window
+      state: this.getState(window),
+      alwaysOnTop: false,
+    };
+
+    if (window.tabs.length) {
+      result.tabs = [];
+      window.tabs.forEach((tab, index) => {
+        result.tabs.push(TabManager.for(extension).convertFromSessionStoreClosedData(tab, window, index));
+      });
+    }
+
+    return result;
+  },
 };
 
 // Manages listeners for window opening and closing. A window is
 // considered open when the "load" event fires on it. A window is
 // closed when a "domwindowclosed" notification fires for it.
 global.WindowListManager = {
   _openListeners: new Set(),
   _closeListeners: new Set(),
--- a/browser/components/extensions/extensions-browser.manifest
+++ b/browser/components/extensions/extensions-browser.manifest
@@ -1,16 +1,17 @@
 # scripts
 category webextension-scripts bookmarks chrome://browser/content/ext-bookmarks.js
 category webextension-scripts browserAction chrome://browser/content/ext-browserAction.js
 category webextension-scripts commands chrome://browser/content/ext-commands.js
 category webextension-scripts contextMenus chrome://browser/content/ext-contextMenus.js
 category webextension-scripts desktop-runtime chrome://browser/content/ext-desktop-runtime.js
 category webextension-scripts history chrome://browser/content/ext-history.js
 category webextension-scripts pageAction chrome://browser/content/ext-pageAction.js
+category webextension-scripts sessions chrome://browser/content/ext-sessions.js
 category webextension-scripts tabs chrome://browser/content/ext-tabs.js
 category webextension-scripts utils chrome://browser/content/ext-utils.js
 category webextension-scripts windows chrome://browser/content/ext-windows.js
 
 # scripts that must run in the same process as addon code.
 category webextension-scripts-addon browserAction chrome://browser/content/ext-c-browserAction.js
 category webextension-scripts-addon contextMenus chrome://browser/content/ext-c-contextMenus.js
 category webextension-scripts-addon pageAction chrome://browser/content/ext-c-pageAction.js
@@ -19,10 +20,11 @@ category webextension-scripts-addon tabs
 # schemas
 category webextension-schemas bookmarks chrome://browser/content/schemas/bookmarks.json
 category webextension-schemas browser_action chrome://browser/content/schemas/browser_action.json
 category webextension-schemas commands chrome://browser/content/schemas/commands.json
 category webextension-schemas context_menus chrome://browser/content/schemas/context_menus.json
 category webextension-schemas context_menus_internal chrome://browser/content/schemas/context_menus_internal.json
 category webextension-schemas history chrome://browser/content/schemas/history.json
 category webextension-schemas page_action chrome://browser/content/schemas/page_action.json
+category webextension-schemas sessions chrome://browser/content/schemas/sessions.json
 category webextension-schemas tabs chrome://browser/content/schemas/tabs.json
 category webextension-schemas windows chrome://browser/content/schemas/windows.json
--- a/browser/components/extensions/jar.mn
+++ b/browser/components/extensions/jar.mn
@@ -14,15 +14,16 @@ browser.jar:
     content/browser/extension.svg
     content/browser/ext-bookmarks.js
     content/browser/ext-browserAction.js
     content/browser/ext-commands.js
     content/browser/ext-contextMenus.js
     content/browser/ext-desktop-runtime.js
     content/browser/ext-history.js
     content/browser/ext-pageAction.js
+    content/browser/ext-sessions.js
     content/browser/ext-tabs.js
     content/browser/ext-utils.js
     content/browser/ext-windows.js
     content/browser/ext-c-browserAction.js
     content/browser/ext-c-contextMenus.js
     content/browser/ext-c-pageAction.js
     content/browser/ext-c-tabs.js
--- a/browser/components/extensions/schemas/jar.mn
+++ b/browser/components/extensions/schemas/jar.mn
@@ -5,10 +5,11 @@
 browser.jar:
     content/browser/schemas/bookmarks.json
     content/browser/schemas/browser_action.json
     content/browser/schemas/commands.json
     content/browser/schemas/context_menus.json
     content/browser/schemas/context_menus_internal.json
     content/browser/schemas/history.json
     content/browser/schemas/page_action.json
+    content/browser/schemas/sessions.json
     content/browser/schemas/tabs.json
     content/browser/schemas/windows.json
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/schemas/sessions.json
@@ -0,0 +1,147 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+[
+  {
+    "namespace": "manifest",
+    "types": [
+      {
+        "$extend": "Permission",
+        "choices": [{
+          "type": "string",
+          "enum": [
+            "sessions"
+          ]
+        }]
+      }
+    ]
+  },
+  {
+    "namespace": "sessions",
+    "description": "Use the <code>chrome.sessions</code> API to query and restore tabs and windows from a browsing session.",
+    "permissions": ["sessions"],
+    "types": [
+      {
+        "id": "Filter",
+        "type": "object",
+        "properties": {
+          "maxResults": {
+            "type": "integer",
+            "minimum": 0,
+            "maximum": 25,
+            "optional": true,
+            "description": "The maximum number of entries to be fetched in the requested list. Omit this parameter to fetch the maximum number of entries ($(ref:sessions.MAX_SESSION_RESULTS))."
+          }
+        }
+      },
+      {
+        "id": "Session",
+        "type": "object",
+        "properties": {
+          "lastModified": {"type": "integer", "description": "The time when the window or tab was closed or modified, represented in milliseconds since the epoch."},
+          "tab": {"$ref": "tabs.Tab", "optional": true, "description": "The $(ref:tabs.Tab), if this entry describes a tab. Either this or $(ref:sessions.Session.window) will be set."},
+          "window": {"$ref": "windows.Window", "optional": true, "description": "The $(ref:windows.Window), if this entry describes a window. Either this or $(ref:sessions.Session.tab) will be set."}
+        }
+      },
+      {
+        "id": "Device",
+        "type": "object",
+        "properties": {
+          "info": {"type": "string"},
+          "deviceName": {"type": "string", "description": "The name of the foreign device."},
+          "sessions": {"type": "array", "items": {"$ref": "Session"}, "description": "A list of open window sessions for the foreign device, sorted from most recently to least recently modified session."}
+        }
+      }
+    ],
+    "functions": [
+      {
+        "name": "getRecentlyClosed",
+        "type": "function",
+        "description": "Gets the list of recently closed tabs and/or windows.",
+        "async": "callback",
+        "parameters": [
+          {
+            "$ref": "Filter",
+            "name": "filter",
+            "optional": true,
+            "default": {}
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "parameters": [
+              {
+                "name": "sessions", "type": "array", "items": { "$ref": "Session" }, "description": "The list of closed entries in reverse order that they were closed (the most recently closed tab or window will be at index <code>0</code>). The entries may contain either tabs or windows."
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "getDevices",
+        "unsupported": true,
+        "type": "function",
+        "description": "Retrieves all devices with synced sessions.",
+        "async": "callback",
+        "parameters": [
+          {
+            "$ref": "Filter",
+            "name": "filter",
+            "optional": true
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "parameters": [
+              {
+                "name": "devices", "type": "array", "items": { "$ref": "Device" }, "description": "The list of $(ref:sessions.Device) objects for each synced session, sorted in order from device with most recently modified session to device with least recently modified session. $(ref:tabs.Tab) objects are sorted by recency in the $(ref:windows.Window) of the $(ref:sessions.Session) objects."
+              }
+            ]
+          }
+        ]
+      },
+      {
+        "name": "restore",
+        "unsupported": true,
+        "type": "function",
+        "description": "Reopens a $(ref:windows.Window) or $(ref:tabs.Tab), with an optional callback to run when the entry has been restored.",
+        "async": "callback",
+        "parameters": [
+          {
+            "type": "string",
+            "name": "sessionId",
+            "optional": true,
+            "description": "The $(ref:windows.Window.sessionId), or $(ref:tabs.Tab.sessionId) to restore. If this parameter is not specified, the most recently closed session is restored."
+          },
+          {
+            "type": "function",
+            "name": "callback",
+            "optional": true,
+            "parameters": [
+              {
+                "$ref": "Session",
+                "name": "restoredSession",
+                "description": "A $(ref:sessions.Session) containing the restored $(ref:windows.Window) or $(ref:tabs.Tab) object."
+              }
+            ]
+          }
+        ]
+      }
+    ],
+    "events": [
+      {
+        "name": "onChanged",
+        "unsupported": true,
+        "description": "Fired when recently closed tabs and/or windows are changed. This event does not monitor synced sessions changes.",
+        "type": "function"
+      }
+    ],
+    "properties": {
+      "MAX_SESSION_RESULTS": {
+        "value": 25,
+        "description": "The maximum number of $(ref:sessions.Session) that will be included in a requested list."
+      }
+    }
+  }
+]
--- a/browser/components/extensions/schemas/windows.json
+++ b/browser/components/extensions/schemas/windows.json
@@ -73,17 +73,16 @@
             "optional": true,
             "description": "The state of this browser window."
           },
           "alwaysOnTop": {
             "type": "boolean",
             "description": "Whether the window is set to be always on top."
           },
           "sessionId": {
-            "unsupported": true,
             "type": "string",
             "optional": true,
             "description": "The session ID used to uniquely identify a Window obtained from the $(ref:sessions) API."
           }
         }
       },
       {
         "id": "CreateType",
--- a/browser/components/extensions/test/browser/browser.ini
+++ b/browser/components/extensions/test/browser/browser.ini
@@ -53,16 +53,17 @@ tags = webextensions
 [browser_ext_popup_api_injection.js]
 [browser_ext_popup_background.js]
 [browser_ext_popup_corners.js]
 [browser_ext_popup_sendMessage.js]
 [browser_ext_popup_shutdown.js]
 [browser_ext_runtime_openOptionsPage.js]
 [browser_ext_runtime_openOptionsPage_uninstall.js]
 [browser_ext_runtime_setUninstallURL.js]
+[browser_ext_sessions.js]
 [browser_ext_simple.js]
 [browser_ext_tab_runtimeConnect.js]
 [browser_ext_tabs_audio.js]
 [browser_ext_tabs_captureVisibleTab.js]
 [browser_ext_tabs_create.js]
 [browser_ext_tabs_create_invalid_url.js]
 [browser_ext_tabs_detectLanguage.js]
 [browser_ext_tabs_duplicate.js]
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_sessions.js
@@ -0,0 +1,182 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+SimpleTest.requestCompleteLog();
+
+let initialTimestamps = [];
+
+function onlyNewItemsFilter(item) {
+  return !initialTimestamps.includes(item.lastModified);
+}
+
+function checkWindow(window) {
+  for (let prop of ["focused", "incognito", "alwaysOnTop"]) {
+    is(window[prop], false, `closed window has the expected value for ${prop}`);
+  }
+  for (let prop of ["state", "type"]) {
+    is(window[prop], "normal", `closed window has the expected value for ${prop}`);
+  }
+}
+
+function checkTab(tab, windowId, incognito) {
+  for (let prop of ["selected", "highlighted", "active", "pinned"]) {
+    is(tab[prop], false, `closed tab has the expected value for ${prop}`);
+  }
+  is(tab.windowId, windowId, "closed tab has the expected value for windowId");
+  is(tab.incognito, incognito, "closed tab has the expected value for incognito");
+}
+
+function checkRecentlyClosed(recentlyClosed, expectedCount, windowId, incognito = false) {
+  let sessionIds = new Set();
+  is(recentlyClosed.length, expectedCount, "the expected number of closed tabs/windows was found");
+  for (let item of recentlyClosed) {
+    if (item.window) {
+      sessionIds.add(item.window.sessionId);
+      checkWindow(item.window);
+    } else if (item.tab) {
+      sessionIds.add(item.tab.sessionId);
+      checkTab(item.tab, windowId, incognito);
+    }
+  }
+  is(sessionIds.size, expectedCount, "each item has a unique sessionId");
+}
+
+add_task(function* test_sessions_get_recently_closed() {
+  function* openAndCloseWindow(url = "http://example.com", tabUrls) {
+    let win = yield BrowserTestUtils.openNewBrowserWindow();
+    yield BrowserTestUtils.loadURI(win.gBrowser.selectedBrowser, url);
+    yield BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
+    if (tabUrls) {
+      for (let url of tabUrls) {
+        yield BrowserTestUtils.openNewForegroundTab(win.gBrowser, url);
+      }
+    }
+    yield BrowserTestUtils.closeWindow(win);
+  }
+
+  function background() {
+    Promise.all([
+      browser.sessions.getRecentlyClosed(),
+      browser.tabs.query({active: true, currentWindow: true}),
+    ]).then(([recentlyClosed, tabs]) => {
+      browser.test.sendMessage("initialData", {recentlyClosed, currentWindowId: tabs[0].windowId});
+    });
+
+    browser.test.onMessage.addListener((msg, filter) => {
+      if (msg == "check-sessions") {
+        browser.sessions.getRecentlyClosed(filter).then(recentlyClosed => {
+          browser.test.sendMessage("recentlyClosed", recentlyClosed);
+        });
+      }
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["sessions", "tabs"],
+    },
+    background,
+  });
+
+  // Open and close a window that will be ignored, to prove that we are removing previous entries
+  yield openAndCloseWindow();
+
+  yield extension.startup();
+
+  let {recentlyClosed, currentWindowId} = yield extension.awaitMessage("initialData");
+  initialTimestamps = recentlyClosed.map(item => item.lastModified);
+
+  yield openAndCloseWindow();
+  extension.sendMessage("check-sessions");
+  recentlyClosed = yield extension.awaitMessage("recentlyClosed");
+  checkRecentlyClosed(recentlyClosed.filter(onlyNewItemsFilter), 1, currentWindowId);
+
+  yield openAndCloseWindow("about:config", ["about:robots", "about:mozilla"]);
+  extension.sendMessage("check-sessions");
+  recentlyClosed = yield extension.awaitMessage("recentlyClosed");
+  // Check for multiple tabs in most recently closed window
+  is(recentlyClosed[0].window.tabs.length, 3, "most recently closed window has the expected number of tabs");
+
+  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com");
+  yield BrowserTestUtils.removeTab(tab);
+
+  tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "http://example.com");
+  yield BrowserTestUtils.removeTab(tab);
+
+  yield openAndCloseWindow();
+  extension.sendMessage("check-sessions");
+  recentlyClosed = yield extension.awaitMessage("recentlyClosed");
+  let finalResult = recentlyClosed.filter(onlyNewItemsFilter);
+  checkRecentlyClosed(finalResult, 5, currentWindowId);
+
+  isnot(finalResult[0].window, undefined, "first item is a window");
+  is(finalResult[0].tab, undefined, "first item is not a tab");
+  isnot(finalResult[1].tab, undefined, "second item is a tab");
+  is(finalResult[1].window, undefined, "second item is not a window");
+  isnot(finalResult[2].tab, undefined, "third item is a tab");
+  is(finalResult[2].window, undefined, "third item is not a window");
+  isnot(finalResult[3].window, undefined, "fourth item is a window");
+  is(finalResult[3].tab, undefined, "fourth item is not a tab");
+  isnot(finalResult[4].window, undefined, "fifth item is a window");
+  is(finalResult[4].tab, undefined, "fifth item is not a tab");
+
+  // test with filter
+  extension.sendMessage("check-sessions", {maxResults: 2});
+  recentlyClosed = yield extension.awaitMessage("recentlyClosed");
+  checkRecentlyClosed(recentlyClosed.filter(onlyNewItemsFilter), 2, currentWindowId);
+
+  yield extension.unload();
+});
+
+add_task(function* test_sessions_get_recently_closed_private() {
+  function background() {
+    browser.test.onMessage.addListener((msg, filter) => {
+      if (msg == "check-sessions") {
+        browser.sessions.getRecentlyClosed(filter).then(recentlyClosed => {
+          browser.test.sendMessage("recentlyClosed", recentlyClosed);
+        });
+      }
+    });
+  }
+
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      permissions: ["sessions", "tabs"],
+    },
+    background,
+  });
+
+  // Open a private browsing window.
+  let privateWin = yield BrowserTestUtils.openNewBrowserWindow({private: true});
+
+  let {Management: {global: {WindowManager}}} = Cu.import("resource://gre/modules/Extension.jsm", {});
+
+  let privateWinId = WindowManager.getId(privateWin);
+
+  yield extension.startup();
+
+  extension.sendMessage("check-sessions");
+  let recentlyClosed = yield extension.awaitMessage("recentlyClosed");
+  initialTimestamps = recentlyClosed.map(item => item.lastModified);
+
+  // Open and close two tabs in the private window
+  let tab = yield BrowserTestUtils.openNewForegroundTab(privateWin.gBrowser, "http://example.com");
+  yield BrowserTestUtils.removeTab(tab);
+
+  tab = yield BrowserTestUtils.openNewForegroundTab(privateWin.gBrowser, "http://example.com");
+  yield BrowserTestUtils.removeTab(tab);
+
+  extension.sendMessage("check-sessions");
+  recentlyClosed = yield extension.awaitMessage("recentlyClosed");
+  checkRecentlyClosed(recentlyClosed.filter(onlyNewItemsFilter), 2, privateWinId, true);
+
+  // Close the private window.
+  yield BrowserTestUtils.closeWindow(privateWin);
+
+  extension.sendMessage("check-sessions");
+  recentlyClosed = yield extension.awaitMessage("recentlyClosed");
+  is(recentlyClosed.filter(onlyNewItemsFilter).length, 0, "the closed private window info was not found in recently closed data");
+
+  yield extension.unload();
+});
--- a/browser/components/migration/IEProfileMigrator.js
+++ b/browser/components/migration/IEProfileMigrator.js
@@ -27,20 +27,18 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "OSCrypto",
                                   "resource://gre/modules/OSCrypto.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WindowsRegistry",
                                   "resource://gre/modules/WindowsRegistry.jsm");
 
 Cu.importGlobalProperties(["URL"]);
 
-// //////////////////////////////////////////////////////////////////////////////
 // Resources
 
-
 function History() {
 }
 
 History.prototype = {
   type: MigrationUtils.resourceTypes.HISTORY,
 
   get exists() {
     return true;
@@ -460,19 +458,16 @@ Settings.prototype = {
         Services.prefs.setBoolPref(aPref, value);
         break;
       default:
         throw new Error("Unexpected value type: " + (typeof value));
     }
   }
 };
 
-// //////////////////////////////////////////////////////////////////////////////
-// // Migrator
-
 function IEProfileMigrator()
 {
   this.wrappedJSObject = this; // export this to be able to use it in the unittest.
 }
 
 IEProfileMigrator.prototype = Object.create(MigratorPrototype);
 
 IEProfileMigrator.prototype.getResources = function IE_getResources() {
--- a/browser/components/migration/MSMigrationUtils.jsm
+++ b/browser/components/migration/MSMigrationUtils.jsm
@@ -35,19 +35,16 @@ const RESULT_SUCCESS = 0;
 const VAULT_ENUMERATE_ALL_ITEMS = 512;
 const WEB_CREDENTIALS_VAULT_ID = [0x4BF4C442,
                                   0x41A09B8A,
                                   0x4ADD80B3,
                                   0x28DB4D70];
 
 Cu.importGlobalProperties(["File"]);
 
-// //////////////////////////////////////////////////////////////////////////////
-// // Helpers.
-
 const wintypes = {
   BOOL: ctypes.int,
   DWORD: ctypes.uint32_t,
   DWORDLONG: ctypes.uint64_t,
   CHAR: ctypes.char,
   PCHAR: ctypes.char.ptr,
   LPCWSTR: ctypes.char16_t.ptr,
   PDWORD: ctypes.uint32_t.ptr,
--- a/browser/components/originattributes/test/browser/browser_favicon_userContextId.js
+++ b/browser/components/originattributes/test/browser/browser_favicon_userContextId.js
@@ -2,24 +2,27 @@
  * Bug 1277803 - A test caes for testing favicon loading across different userContextId.
  */
 
 const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
 
 XPCOMUtils.defineLazyModuleGetter(this, "Promise",
   "resource://gre/modules/Promise.jsm");
 
-const TEST_SITE = "http://mochi.test:8888";
+const TEST_SITE = "http://example.net";
+const TEST_THIRD_PARTY_SITE = "http://mochi.test:8888";
 
 const TEST_PAGE = TEST_SITE + "/browser/browser/components/originattributes/" +
                   "test/browser/file_favicon.html";
 const FAVICON_URI = TEST_SITE + "/browser/browser/components/originattributes/" +
                     "test/browser/file_favicon.png";
 const TEST_THIRD_PARTY_PAGE = "http://example.com/browser/browser/components/" +
                               "originattributes/test/browser/file_favicon_thirdParty.html";
+const THIRD_PARTY_FAVICON_URI = TEST_THIRD_PARTY_SITE + "/browser/browser/components/" +
+                                "originattributes/test/browser/file_favicon.png";
 
 const USER_CONTEXT_ID_PERSONAL = 1;
 const USER_CONTEXT_ID_WORK     = 2;
 
 let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
 let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
 
 function clearAllImageCaches() {
@@ -44,18 +47,18 @@ function clearAllPlacesFavicons() {
       }
     };
 
     Services.obs.addObserver(observer, "places-favicons-expired", false);
     faviconService.expireAllFavicons();
   });
 }
 
-function FaviconObserver(aUserContextId, aExpectedCookie, aPageURI) {
-  this.reset(aUserContextId, aExpectedCookie, aPageURI);
+function FaviconObserver(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL) {
+  this.reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL);
 }
 
 FaviconObserver.prototype = {
   observe(aSubject, aTopic, aData) {
     // Make sure that the topic is 'http-on-modify-request'.
     if (aTopic === "http-on-modify-request") {
       // We check the userContextId for the originAttributes of the loading
       // channel. All requests for the favicon should contain the correct
@@ -65,17 +68,17 @@ FaviconObserver.prototype = {
       // principal and the XUL image will use the system principal.
 
       let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
       let reqLoadInfo = httpChannel.loadInfo;
       let loadingPrincipal;
       let triggeringPrincipal;
 
       // Make sure this is a favicon request.
-      if (httpChannel.URI.spec !== FAVICON_URI) {
+      if (httpChannel.URI.spec !== this._faviconURL) {
         return;
       }
 
       if (reqLoadInfo) {
         loadingPrincipal = reqLoadInfo.loadingPrincipal;
         triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
       }
 
@@ -100,23 +103,24 @@ FaviconObserver.prototype = {
       ok(false, "Received unexpected topic: ", aTopic);
     }
 
     if (this._faviconReqXUL && this._faviconReqPlaces) {
       this._faviconLoaded.resolve();
     }
   },
 
-  reset(aUserContextId, aExpectedCookie, aPageURI) {
+  reset(aUserContextId, aExpectedCookie, aPageURI, aFaviconURL) {
     this._curUserContextId = aUserContextId;
     this._expectedCookie = aExpectedCookie;
     this._expectedPrincipal = Services.scriptSecurityManager
                                       .createCodebasePrincipal(aPageURI, { userContextId: aUserContextId });
     this._faviconReqXUL = false;
     this._faviconReqPlaces = false;
+    this._faviconURL = aFaviconURL;
     this._faviconLoaded = new Promise.defer();
   },
 
   get promise() {
     return this._faviconLoaded.promise;
   }
 };
 
@@ -132,63 +136,66 @@ function waitOnFaviconLoaded(aFaviconURL
         }
       },
     };
 
     PlacesUtils.history.addObserver(observer, false);
   });
 }
 
-function* generateCookies() {
+function* generateCookies(aHost) {
   // we generate two different cookies for two userContextIds.
   let cookies = [];
   cookies.push(Math.random().toString());
   cookies.push(Math.random().toString());
 
   // Then, we add cookies into the site for 'personal' and 'work'.
-  let tabInfoA = yield openTabInUserContext(TEST_SITE, USER_CONTEXT_ID_PERSONAL);
-  let tabInfoB = yield openTabInUserContext(TEST_SITE, USER_CONTEXT_ID_WORK);
+  let tabInfoA = yield openTabInUserContext(aHost, USER_CONTEXT_ID_PERSONAL);
+  let tabInfoB = yield openTabInUserContext(aHost, USER_CONTEXT_ID_WORK);
 
   yield ContentTask.spawn(tabInfoA.browser, cookies[0], function* (value) {
     content.document.cookie = value;
   });
 
   yield ContentTask.spawn(tabInfoB.browser, cookies[1], function* (value) {
     content.document.cookie = value;
   });
 
   yield BrowserTestUtils.removeTab(tabInfoA.tab);
   yield BrowserTestUtils.removeTab(tabInfoB.tab);
 
   return cookies;
 }
 
-function* doTest(aTestPage) {
-  let cookies = yield generateCookies();
+function* doTest(aTestPage, aFaviconHost, aFaviconURL) {
+  let cookies = yield generateCookies(aFaviconHost);
   let pageURI = makeURI(aTestPage);
 
   // Create the observer object for observing request channels of the personal
   // container.
-  let observer = new FaviconObserver(USER_CONTEXT_ID_PERSONAL, cookies[0], pageURI);
+  let observer = new FaviconObserver(USER_CONTEXT_ID_PERSONAL, cookies[0], pageURI, aFaviconURL);
+
+  // Add the observer earlier in case we miss it.
+  let promiseWaitOnFaviconLoaded = waitOnFaviconLoaded(aFaviconURL);
 
   Services.obs.addObserver(observer, "http-on-modify-request", false);
 
   // Open the tab with the personal container.
   let tabInfo = yield openTabInUserContext(aTestPage, USER_CONTEXT_ID_PERSONAL);
 
   // Waiting for favicon requests are all made.
   yield observer.promise;
   // Waiting for favicon loaded.
-  yield waitOnFaviconLoaded(FAVICON_URI);
+  yield promiseWaitOnFaviconLoaded;
 
   // Close the tab.
   yield BrowserTestUtils.removeTab(tabInfo.tab);
 
   // Reset the observer for observing requests for the work container.
-  observer.reset(USER_CONTEXT_ID_WORK, cookies[1], pageURI);
+  observer.reset(USER_CONTEXT_ID_WORK, cookies[1], pageURI, aFaviconURL);
   tabInfo = yield openTabInUserContext(aTestPage, USER_CONTEXT_ID_WORK);
 
   // Waiting for favicon requests are all made.
   yield observer.promise;
 
   Services.obs.removeObserver(observer, "http-on-modify-request", false);
 
   yield BrowserTestUtils.removeTab(tabInfo.tab);
@@ -226,25 +233,25 @@ add_task(function* test_favicon_userCont
   // Clear all network caches.
   let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
                         .getService(Ci.nsICacheStorageService);
   networkCache.clear();
 
   // Clear Places favicon caches.
   yield clearAllPlacesFavicons();
 
-  yield doTest(TEST_PAGE);
+  yield doTest(TEST_PAGE, TEST_SITE, FAVICON_URI);
 });
 
 add_task(function* test_thirdPartyFavicon_userContextId() {
   // Clear all image caches before running the test.
   clearAllImageCaches();
 
   // Clear all network caches.
   let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
                         .getService(Ci.nsICacheStorageService);
   networkCache.clear();
 
   // Clear Places favicon caches.
   yield clearAllPlacesFavicons();
 
-  yield doTest(TEST_THIRD_PARTY_PAGE);
+  yield doTest(TEST_THIRD_PARTY_PAGE, TEST_THIRD_PARTY_SITE, THIRD_PARTY_FAVICON_URI);
 });
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -1715,18 +1715,17 @@ XPCOMUtils.defineLazyGetter(PlacesUIUtil
       let annoObj = { name: PlacesUIUtils.DESCRIPTION_ANNO,
                       type: Ci.nsIAnnotationService.TYPE_STRING,
                       flags: 0,
                       value: aDescription,
                       expires: Ci.nsIAnnotationService.EXPIRE_NEVER };
       return new PlacesSetItemAnnotationTransaction(aItemId, annoObj);
     },
 
-    // //////////////////////////////////////////////////////////////////////////
-    // // nsITransactionManager forwarders.
+    // nsITransactionManager forwarders.
 
     beginBatch: () =>
       PlacesUtils.transactionManager.beginBatch(null),
 
     endBatch: () =>
       PlacesUtils.transactionManager.endBatch(false),
 
     doTransaction: (txn) =>
--- a/browser/components/places/tests/browser/browser_library_search.js
+++ b/browser/components/places/tests/browser/browser_library_search.js
@@ -42,18 +42,16 @@ var testCases = [
   },
 
   function downloadsScope() {
     let defScope = getDefaultScope(PlacesUIUtils.leftPaneQueries["Downloads"]);
     search(PlacesUIUtils.leftPaneQueries["Downloads"], "dummy", defScope);
   },
 ];
 
-// /////////////////////////////////////////////////////////////////////////////
-
 /**
  * Returns the default search scope for a given folder.
  *
  * @param  aFolderId
  *         the item ID of a node in the left pane's tree
  * @return the default scope when the folder is newly selected
  */
 function getDefaultScope(aFolderId) {
@@ -155,18 +153,16 @@ function onLibraryAvailable() {
   gLibrary = null;
 
   // Cleanup.
   PlacesUtils.tagging.untagURI(PlacesUtils._uri(TEST_URL), ["dummyTag"]);
   PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
   PlacesTestUtils.clearHistory().then(finish);
 }
 
-// /////////////////////////////////////////////////////////////////////////////
-
 function test() {
   waitForExplicitFinish();
 
   // Sanity:
   ok(PlacesUtils, "PlacesUtils in context");
 
   // Add visits, a bookmark and a tag.
   PlacesTestUtils.addVisits(
--- a/browser/components/places/tests/browser/browser_sort_in_library.js
+++ b/browser/components/places/tests/browser/browser_sort_in_library.js
@@ -49,18 +49,16 @@ const SORT_LOOKUP_TABLE = {
 // determines this value.
 const DEFAULT_SORT_KEY = "TITLE";
 
 // Part of the test is checking that sorts stick, so each time we sort we need
 // to remember it.
 var prevSortDir = null;
 var prevSortKey = null;
 
-// /////////////////////////////////////////////////////////////////////////////
-
 /**
  * Ensures that the sort of aTree is aSortingMode and aSortingAnno.
  *
  * @param aTree
  *        the tree to check
  * @param aSortingMode
  *        one of the Ci.nsINavHistoryQueryOptions.SORT_BY_* constants
  * @param aSortingAnno
@@ -225,18 +223,16 @@ function testSortByDir(aOrganizerWin, aP
     let key = (aUnsortFirst ? DEFAULT_SORT_KEY : prevSortKey);
     let sortConst = "SORT_BY_" + key + "_" + dir.toUpperCase();
     let expectedSortMode = Ci.nsINavHistoryQueryOptions[sortConst];
     setSort(aOrganizerWin, aPlaceContentTree, aUnsortFirst, false, null, dir);
     checkSort(aPlaceContentTree, expectedSortMode, "");
   });
 }
 
-// /////////////////////////////////////////////////////////////////////////////
-
 function test() {
   waitForExplicitFinish();
 
   openLibrary(function (win) {
         let tree = win.document.getElementById("placeContent");
         isnot(tree, null, "sanity check: placeContent tree should exist");
         // Run the tests.
         testSortByColAndDir(win, tree, true);
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -154,66 +154,56 @@ function promiseIsURIVisited(aURI) {
     deferred.resolve(aIsVisited);
   });
 
   return deferred.promise;
 }
 
 function promiseBookmarksNotification(notification, conditionFn) {
   info(`promiseBookmarksNotification: waiting for ${notification}`);
-  return new Promise((resolve, reject) => {
+  return new Promise((resolve) => {
     let proxifiedObserver = new Proxy({}, {
       get: (target, name) => {
         if (name == "QueryInterface")
           return XPCOMUtils.generateQI([ Ci.nsINavBookmarkObserver ]);
         info(`promiseBookmarksNotification: got ${name} notification`);
         if (name == notification)
           return (...args) => {
             if (conditionFn.apply(this, args)) {
-              clearTimeout(timeout);
               PlacesUtils.bookmarks.removeObserver(proxifiedObserver, false);
               executeSoon(resolve);
             } else {
               info(`promiseBookmarksNotification: skip cause condition doesn't apply to ${JSON.stringify(args)}`);
             }
           }
         return () => {};
       }
     });
     PlacesUtils.bookmarks.addObserver(proxifiedObserver, false);
-    let timeout = setTimeout(() => {
-      PlacesUtils.bookmarks.removeObserver(proxifiedObserver, false);
-      reject(new Error("Timed out while waiting for bookmarks notification"));
-    }, 2000);
   });
 }
 
 function promiseHistoryNotification(notification, conditionFn) {
   info(`Waiting for ${notification}`);
-  return new Promise((resolve, reject) => {
+  return new Promise((resolve) => {
     let proxifiedObserver = new Proxy({}, {
       get: (target, name) => {
         if (name == "QueryInterface")
           return XPCOMUtils.generateQI([ Ci.nsINavHistoryObserver ]);
         if (name == notification)
           return (...args) => {
             if (conditionFn.apply(this, args)) {
-              clearTimeout(timeout);
               PlacesUtils.history.removeObserver(proxifiedObserver, false);
               executeSoon(resolve);
             }
           }
         return () => {};
       }
     });
     PlacesUtils.history.addObserver(proxifiedObserver, false);
-    let timeout = setTimeout(() => {
-      PlacesUtils.history.removeObserver(proxifiedObserver, false);
-      reject(new Error("Timed out while waiting for history notification"));
-    }, 2000);
   });
 }
 
 /**
  * Makes the specified toolbar visible or invisible and returns a Promise object
  * that is resolved when the toolbar has completed any animations associated
  * with hiding or showing the toolbar.
  *
--- a/browser/components/preferences/in-content/applications.js
+++ b/browser/components/preferences/in-content/applications.js
@@ -1,15 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-//* ***************************************************************************//
 // Constants & Enumeration Values
 
 Components.utils.import('resource://gre/modules/Services.jsm');
 Components.utils.import('resource://gre/modules/AppConstants.jsm');
 const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
 const TYPE_MAYBE_VIDEO_FEED = "application/vnd.mozilla.maybe.video.feed";
 const TYPE_MAYBE_AUDIO_FEED = "application/vnd.mozilla.maybe.audio.feed";
 const TYPE_PDF = "application/pdf";
@@ -71,17 +70,16 @@ const kActionUsePlugin = 5;
 const ICON_URL_APP = AppConstants.platform == "linux" ?
                      "moz-icon://dummy.exe?size=16" :
                      "chrome://browser/skin/preferences/application.png";
 
 // For CSS. Can be one of "ask", "save", "plugin" or "feed". If absent, the icon URL
 // was set by us to a custom handler icon and CSS should not try to override it.
 const APP_ICON_ATTR_NAME = "appHandlerIcon";
 
-//* ***************************************************************************//
 // Utilities
 
 function getFileDisplayName(file) {
   if (AppConstants.platform == "win") {
     if (file instanceof Ci.nsILocalFileWin) {
       try {
         return file.getVersionInfoField("FileDescription");
       } catch (e) {}
@@ -129,17 +127,16 @@ ArrayEnumerator.prototype = {
     return this._contents[this._index++];
   }
 };
 
 function isFeedType(t) {
   return t == TYPE_MAYBE_FEED || t == TYPE_MAYBE_VIDEO_FEED || t == TYPE_MAYBE_AUDIO_FEED;
 }
 
-//* ***************************************************************************//
 // HandlerInfoWrapper
 
 /**
  * This object wraps nsIHandlerInfo with some additional functionality
  * the Applications prefpane needs to display and allow modification of
  * the list of handled types.
  *
  * We create an instance of this wrapper for each entry we might display
@@ -159,34 +156,32 @@ function HandlerInfoWrapper(aType, aHand
 
 HandlerInfoWrapper.prototype = {
   // The wrapped nsIHandlerInfo object.  In general, this object is private,
   // but there are a couple cases where callers access it directly for things
   // we haven't (yet?) implemented, so we make it a public property.
   wrappedHandlerInfo: null,
 
 
-  //* *************************************************************************//
   // Convenience Utils
 
   _handlerSvc: Cc["@mozilla.org/uriloader/handler-service;1"].
                getService(Ci.nsIHandlerService),
 
   _prefSvc: Cc["@mozilla.org/preferences-service;1"].
             getService(Ci.nsIPrefBranch),
 
   _categoryMgr: Cc["@mozilla.org/categorymanager;1"].
                 getService(Ci.nsICategoryManager),
 
   element: function(aID) {
     return document.getElementById(aID);
   },
 
 
-  //* *************************************************************************//
   // nsIHandlerInfo
 
   // The MIME type or protocol scheme.
   _type: null,
   get type() {
     return this._type;
   },
 
@@ -317,17 +312,16 @@ HandlerInfoWrapper.prototype = {
     return this.wrappedHandlerInfo.alwaysAskBeforeHandling;
   },
 
   set alwaysAskBeforeHandling(aNewValue) {
     this.wrappedHandlerInfo.alwaysAskBeforeHandling = aNewValue;
   },
 
 
-  //* *************************************************************************//
   // nsIMIMEInfo
 
   // The primary file extension associated with this type, if any.
   //
   // XXX Plugin objects contain an array of MimeType objects with "suffixes"
   // properties; if this object has an associated plugin, shouldn't we check
   // those properties for an extension?
   get primaryExtension() {
@@ -336,17 +330,16 @@ HandlerInfoWrapper.prototype = {
           this.wrappedHandlerInfo.primaryExtension)
         return this.wrappedHandlerInfo.primaryExtension
     } catch (ex) {}
 
     return null;
   },
 
 
-  //* *************************************************************************//
   // Plugin Handling
 
   // A plugin that can handle this type, if any.
   //
   // Note: just because we have one doesn't mean it *will* handle the type.
   // That depends on whether or not the type is in the list of types for which
   // plugin handling is disabled.
   plugin: null,
@@ -412,25 +405,23 @@ HandlerInfoWrapper.prototype = {
       addCategoryEntry("Gecko-Content-Viewers",
                        this.type,
                        "@mozilla.org/content/plugin/document-loader-factory;1",
                        false,
                        true);
   },
 
 
-  //* *************************************************************************//
   // Storage
 
   store: function() {
     this._handlerSvc.store(this.wrappedHandlerInfo);
   },
 
 
-  //* *************************************************************************//
   // Icons
 
   get smallIcon() {
     return this._getIcon(16);
   },
 
   _getIcon: function(aSize) {
     if (this.primaryExtension)
@@ -442,17 +433,16 @@ HandlerInfoWrapper.prototype = {
     // FIXME: consider returning some generic icon when we can't get a URL for
     // one (for example in the case of protocol schemes).  Filed as bug 395141.
     return null;
   }
 
 };
 
 
-//* ***************************************************************************//
 // Feed Handler Info
 
 /**
  * This object implements nsIHandlerInfo for the feed types.  It's a separate
  * object because we currently store handling information for the feed type
  * in a set of preferences rather than the nsIHandlerService-managed datastore.
  *
  * This object inherits from HandlerInfoWrapper in order to get functionality
@@ -466,26 +456,24 @@ HandlerInfoWrapper.prototype = {
 
 function FeedHandlerInfo(aMIMEType) {
   HandlerInfoWrapper.call(this, aMIMEType, null);
 }
 
 FeedHandlerInfo.prototype = {
   __proto__: HandlerInfoWrapper.prototype,
 
-  //* *************************************************************************//
   // Convenience Utils
 
   _converterSvc:
     Cc["@mozilla.org/embeddor.implemented/web-content-handler-registrar;1"].
     getService(Ci.nsIWebContentConverterService),
 
   _shellSvc: AppConstants.HAVE_SHELL_SERVICE ? getShellService() : null,
 
-  //* *************************************************************************//
   // nsIHandlerInfo
 
   get description() {
     return this.element("bundlePreferences").getString(this._appPrefLabel);
   },
 
   get preferredApplicationHandler() {
     switch (this.element(this._prefSelectedReader).value) {
@@ -718,25 +706,23 @@ FeedHandlerInfo.prototype = {
   // We use this to suppress notification-triggered updates to the list when
   // we make changes that may spawn such updates, specifically when we change
   // the action for the feed type, which results in feed preference updates,
   // which spawn "pref changed" notifications that would otherwise cause us
   // to rebuild the view unnecessarily.
   _storingAction: false,
 
 
-  //* *************************************************************************//
   // nsIMIMEInfo
 
   get primaryExtension() {
     return "xml";
   },
 
 
-  //* *************************************************************************//
   // Storage
 
   // Changes to the preferred action and handler take effect immediately
   // (we write them out to the preferences right as they happen),
   // so we when the controller calls store() after modifying the handlers,
   // the only thing we need to store is the removal of possible handlers
   // XXX Should we hold off on making the changes until this method gets called?
   store: function() {
@@ -754,17 +740,16 @@ FeedHandlerInfo.prototype = {
         app.QueryInterface(Ci.nsIWebContentHandlerInfo);
         this._converterSvc.removeContentHandler(app.contentType, app.uri);
       }
     }
     this._possibleApplicationHandlers._removed = [];
   },
 
 
-  //* *************************************************************************//
   // Icons
 
   get smallIcon() {
     return this._smallIcon;
   }
 
 };
 
@@ -834,17 +819,16 @@ var pdfHandlerInfo = {
   _handlerChanged: TOPIC_PDFJS_HANDLER_CHANGED,
   _appPrefLabel: "portableDocumentFormat",
   get enabled() {
     return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED);
   },
 };
 
 
-//* ***************************************************************************//
 // Prefpane Controller
 
 var gApplicationsPane = {
   // The set of types the app knows how to handle.  A hash of HandlerInfoWrapper
   // objects, indexed by type.
   _handledTypes: {},
 
   // The list of types we can show, sorted by the sort column/direction.
@@ -858,17 +842,16 @@ var gApplicationsPane = {
 
   // A count of the number of times each visible type description appears.
   // We use these counts to determine whether or not to annotate descriptions
   // with their types to distinguish duplicate descriptions from each other.
   // A hash of integer counts, indexed by string description.
   _visibleTypeDescriptionCount: {},
 
 
-  //* *************************************************************************//
   // Convenience & Performance Shortcuts
 
   // These get defined by init().
   _brandShortName : null,
   _prefsBundle    : null,
   _list           : null,
   _filter         : null,
 
@@ -883,17 +866,16 @@ var gApplicationsPane = {
 
   _handlerSvc   : Cc["@mozilla.org/uriloader/handler-service;1"].
                   getService(Ci.nsIHandlerService),
 
   _ioSvc        : Cc["@mozilla.org/network/io-service;1"].
                   getService(Ci.nsIIOService),
 
 
-  //* *************************************************************************//
   // Initialization & Destruction
 
   init: function() {
     function setEventListener(aId, aEventType, aCallback)
     {
       document.getElementById(aId)
               .addEventListener(aEventType, aCallback.bind(gApplicationsPane));
     }
@@ -986,30 +968,28 @@ var gApplicationsPane = {
 
     this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_APP, this);
     this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_WEB, this);
     this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_ACTION, this);
     this._prefSvc.removeObserver(PREF_AUDIO_FEED_SELECTED_READER, this);
   },
 
 
-  //* *************************************************************************//
   // nsISupports
 
   QueryInterface: function(aIID) {
     if (aIID.equals(Ci.nsIObserver) ||
         aIID.equals(Ci.nsIDOMEventListener ||
         aIID.equals(Ci.nsISupports)))
       return this;
 
     throw Cr.NS_ERROR_NO_INTERFACE;
   },
 
 
-  //* *************************************************************************//
   // nsIObserver
 
   observe: function (aSubject, aTopic, aData) {
     // Rebuild the list when there are changes to preferences that influence
     // whether or not to show certain entries in the list.
     if (aTopic == "nsPref:changed" && !this._storingAction) {
       // These two prefs alter the list of visible types, so we have to rebuild
       // that list when they change.
@@ -1021,27 +1001,25 @@ var gApplicationsPane = {
 
       // All the prefs we observe can affect what we display, so we rebuild
       // the view when any of them changes.
       this._rebuildView();
     }
   },
 
 
-  //* *************************************************************************//
   // nsIDOMEventListener
 
   handleEvent: function(aEvent) {
     if (aEvent.type == "unload") {
       this.destroy();
     }
   },
 
 
-  //* *************************************************************************//
   // Composed Model Construction
 
   _loadData: function() {
     this._loadFeedHandler();
     this._loadInternalHandlers();
     this._loadPluginHandlers();
     this._loadApplicationHandlers();
   },
@@ -1126,17 +1104,16 @@ var gApplicationsPane = {
         this._handledTypes[type] = handlerInfoWrapper;
       }
 
       handlerInfoWrapper.handledOnlyByPlugin = false;
     }
   },
 
 
-  //* *************************************************************************//
   // View Construction
 
   _rebuildVisibleTypes: function() {
     // Reset the list of visible types and the visible type description counts.
     this._visibleTypes = [];
     this._visibleTypeDescriptionCount = {};
 
     // Get the preferences that help determine what types to show.
@@ -1550,17 +1527,16 @@ var gApplicationsPane = {
         break;
       case Ci.nsIHandlerInfo.saveToDisk:
         menu.selectedItem = saveMenuItem;
         break;
     }
   },
 
 
-  //* *************************************************************************//
   // Sorting & Filtering
 
   _sortColumn: null,
 
   /**
    * Sort the list when the user clicks on a column header.
    */
   sort: function (event) {
@@ -1623,17 +1599,16 @@ var gApplicationsPane = {
   },
 
   focusFilterBox: function() {
     this._filter.focus();
     this._filter.select();
   },
 
 
-  //* *************************************************************************//
   // Changes
 
   onSelectAction: function(aActionItem) {
     this._storingAction = true;
 
     try {
       this._storeAction(aActionItem);
     }
--- a/browser/components/safebrowsing/content/test/head.js
+++ b/browser/components/safebrowsing/content/test/head.js
@@ -16,17 +16,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
  * @param [optional] event
  *        The load event type to wait for.  Defaults to "load".
  * @return {Promise} resolved when the event is handled.
  * @resolves to the received event
  * @rejects if a valid load event is not received within a meaningful interval
  */
 function promiseTabLoadEvent(tab, url, eventType="load")
 {
-  let deferred = Promise.defer();
   info(`Wait tab event: ${eventType}`);
 
   function handle(loadedUrl) {
     if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
       info(`Skipping spurious load event for ${loadedUrl}`);
       return false;
     }
 
@@ -41,30 +40,18 @@ function promiseTabLoadEvent(tab, url, e
     loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
   } else {
     // No need to use handle.
     loaded =
       BrowserTestUtils.waitForContentEvent(tab.linkedBrowser, eventType,
                                            true, undefined, true);
   }
 
-  let timeout = setTimeout(() => {
-    deferred.reject(new Error(`Timed out while waiting for a ${eventType} event`));
-  }, 30000);
-
-  loaded.then(() => {
-    clearTimeout(timeout);
-    deferred.resolve()
-  });
-
   if (url)
     BrowserTestUtils.loadURI(tab.linkedBrowser, url);
 
-  // Promise.all rejects if either promise rejects (i.e. if we time out) and
-  // if our loaded promise resolves before the timeout, then we resolve the
-  // timeout promise as well, causing the all promise to resolve.
-  return Promise.all([deferred.promise, loaded]);
+  return loaded;
 }
 
 Services.prefs.setCharPref("urlclassifier.malwareTable", "test-malware-simple,test-unwanted-simple");
 Services.prefs.setCharPref("urlclassifier.phishTable", "test-phish-simple");
 Services.prefs.setCharPref("urlclassifier.blockedTable", "test-block-simple");
 SafeBrowsing.init();
--- a/browser/components/search/test/head.js
+++ b/browser/components/search/test/head.js
@@ -95,49 +95,36 @@ function promiseNewEngine(basename, opti
  * @param [optional] url
  *        The url to load, or the current url.
  * @return {Promise} resolved when the event is handled.
  * @resolves to the received event
  * @rejects if a valid load event is not received within a meaningful interval
  */
 function promiseTabLoadEvent(tab, url)
 {
-  let deferred = Promise.defer();
   info("Wait tab event: load");
 
   function handle(loadedUrl) {
     if (loadedUrl === "about:blank" || (url && loadedUrl !== url)) {
       info(`Skipping spurious load event for ${loadedUrl}`);
       return false;
     }
 
     info("Tab event received: load");
     return true;
   }
 
   // Create two promises: one resolved from the content process when the page
   // loads and one that is rejected if we take too long to load the url.
   let loaded = BrowserTestUtils.browserLoaded(tab.linkedBrowser, false, handle);
 
-  let timeout = setTimeout(() => {
-    deferred.reject(new Error("Timed out while waiting for a 'load' event"));
-  }, 30000);
-
-  loaded.then(() => {
-    clearTimeout(timeout);
-    deferred.resolve()
-  });
-
   if (url)
     BrowserTestUtils.loadURI(tab.linkedBrowser, url);
 
-  // Promise.all rejects if either promise rejects (i.e. if we time out) and
-  // if our loaded promise resolves before the timeout, then we resolve the
-  // timeout promise as well, causing the all promise to resolve.
-  return Promise.all([deferred.promise, loaded]);
+  return loaded;
 }
 
 // Get an array of the one-off buttons.
 function getOneOffs() {
   let oneOffs = [];
   let searchPopup = document.getElementById("PopupSearchAutoComplete");
   let oneOffsContainer =
     document.getAnonymousElementByAttribute(searchPopup, "anonid",
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -230,11 +230,11 @@ run-if = e10s
 [browser_sessionStoreContainer.js]
 [browser_windowStateContainer.js]
 [browser_1234021.js]
 [browser_remoteness_flip_on_restore.js]
 run-if = e10s
 [browser_background_tab_crash.js]
 run-if = e10s && crashreporter
 
-# Disabled on Linux debug for frequent intermittent failures:
+# Disabled on debug for frequent intermittent failures:
 [browser_undoCloseById.js]
-skip-if = os == "linux" && debug
+skip-if = debug
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/content/ProfileStorage.jsm
@@ -0,0 +1,251 @@
+/* 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/. */
+
+/*
+ * Implements an interface of the storage of Form Autofill.
+ *
+ * The data is stored in JSON format, without indentation, using UTF-8 encoding.
+ * With indentation applied, the file would look like this:
+ *
+ * {
+ *   version: 1,
+ *   profiles: [
+ *     {
+ *       guid,             // 12 character...
+ *
+ *       // profile
+ *       organization,     // Company
+ *       streetAddress,    // (Multiline)
+ *       addressLevel2,    // City/Town
+ *       addressLevel1,    // Province (Standardized code if possible)
+ *       postalCode,
+ *       country,          // ISO 3166
+ *       tel,
+ *       email,
+ *
+ *       // metadata
+ *       timeCreated,      // in ms
+ *       timeLastUsed,     // in ms
+ *       timeLastModified, // in ms
+ *       timesUsed
+ *     },
+ *     {
+ *       // ...
+ *     }
+ *   ]
+ * }
+ */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/Task.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "JSONFile",
+                                  "resource://gre/modules/JSONFile.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "gUUIDGenerator",
+                                   "@mozilla.org/uuid-generator;1",
+                                   "nsIUUIDGenerator");
+
+const SCHEMA_VERSION = 1;
+
+// Name-related fields will be handled in follow-up bugs due to the complexity.
+const VALID_FIELDS = [
+  "organization",
+  "streetAddress",
+  "addressLevel2",
+  "addressLevel1",
+  "postalCode",
+  "country",
+  "tel",
+  "email",
+];
+
+function ProfileStorage(path) {
+  this._path = path;
+}
+
+ProfileStorage.prototype = {
+  /**
+   * Loads the profile data from file to memory.
+   *
+   * @returns {Promise}
+   * @resolves When the operation finished successfully.
+   * @rejects  JavaScript exception.
+   */
+  initialize() {
+    this._store = new JSONFile({
+      path: this._path,
+      dataPostProcessor: this._dataPostProcessor.bind(this),
+    });
+    return this._store.load();
+  },
+
+  /**
+   * Adds a new profile.
+   *
+   * @param {Profile} profile
+   *        The new profile for saving.
+   */
+  add(profile) {
+    this._store.ensureDataReady();
+
+    let profileToSave = this._normalizeProfile(profile);
+
+    profileToSave.guid = gUUIDGenerator.generateUUID().toString()
+                                       .replace(/[{}-]/g, "").substring(0, 12);
+
+    // Metadata
+    let now = Date.now();
+    profileToSave.timeCreated = now;
+    profileToSave.timeLastModified = now;
+    profileToSave.timeLastUsed = 0;
+    profileToSave.timesUsed = 0;
+
+    this._store.data.profiles.push(profileToSave);
+
+    this._store.saveSoon();
+  },
+
+  /**
+   * Update the specified profile.
+   *
+   * @param  {string} guid
+   *         Indicates which profile to update.
+   * @param  {Profile} profile
+   *         The new profile used to overwrite the old one.
+   */
+  update(guid, profile) {
+    this._store.ensureDataReady();
+
+    let profileFound = this._findByGUID(guid);
+    if (!profileFound) {
+      throw new Error("No matching profile.");
+    }
+
+    let profileToUpdate = this._normalizeProfile(profile);
+    for (let field of VALID_FIELDS) {
+      if (profileToUpdate[field] !== undefined) {
+        profileFound[field] = profileToUpdate[field];
+      } else {
+        delete profileFound[field];
+      }
+    }
+
+    profileFound.timeLastModified = Date.now();
+
+    this._store.saveSoon();
+  },
+
+  /**
+   * Notifies the stroage of the use of the specified profile, so we can update
+   * the metadata accordingly.
+   *
+   * @param  {string} guid
+   *         Indicates which profile to be notified.
+   */
+  notifyUsed(guid) {
+    this._store.ensureDataReady();
+
+    let profileFound = this._findByGUID(guid);
+    if (!profileFound) {
+      throw new Error("No matching profile.");
+    }
+
+    profileFound.timesUsed++;
+    profileFound.timeLastUsed = Date.now();
+
+    this._store.saveSoon();
+  },
+
+  /**
+   * Removes the specified profile. No error occurs if the profile isn't found.
+   *
+   * @param  {string} guid
+   *         Indicates which profile to remove.
+   */
+  remove(guid) {
+    this._store.ensureDataReady();
+
+    this._store.data.profiles =
+      this._store.data.profiles.filter(profile => profile.guid != guid);
+    this._store.saveSoon();
+  },
+
+  /**
+   * Returns the profile with the specified GUID.
+   *
+   * @param   {string} guid
+   *          Indicates which profile to retrieve.
+   * @returns {Profile}
+   *          A clone of the profile.
+   */
+  get(guid) {
+    this._store.ensureDataReady();
+
+    let profileFound = this._findByGUID(guid);
+    if (!profileFound) {
+      throw new Error("No matching profile.");
+    }
+
+    // Profile is cloned to avoid accidental modifications from outside.
+    return this._clone(profileFound);
+  },
+
+  /**
+   * Returns all profiles.
+   *
+   * @returns {Array.<Profile>}
+   *          An array containing clones of all profiles.
+   */
+  getAll() {
+    this._store.ensureDataReady();
+
+    // Profiles are cloned to avoid accidental modifications from outside.
+    return this._store.data.profiles.map(this._clone);
+  },
+
+  _clone(profile) {
+    return Object.assign({}, profile);
+  },
+
+  _findByGUID(guid) {
+    return this._store.data.profiles.find(profile => profile.guid == guid);
+  },
+
+  _normalizeProfile(profile) {
+    let result = {};
+    for (let key in profile) {
+      if (!VALID_FIELDS.includes(key)) {
+        throw new Error(`"${key}" is not a valid field.`);
+      }
+      if (typeof profile[key] !== "string" &&
+          typeof profile[key] !== "number") {
+        throw new Error(`"${key}" contains invalid data type.`);
+      }
+
+      result[key] = profile[key];
+    }
+    return result;
+  },
+
+  _dataPostProcessor(data) {
+    data.version = SCHEMA_VERSION;
+    if (!data.profiles) {
+      data.profiles = [];
+    }
+    return data;
+  },
+
+  // For test only.
+  _saveImmediately() {
+    return this._store._save();
+  },
+};
+
+this.EXPORTED_SYMBOLS = ["ProfileStorage"];
--- a/browser/extensions/formautofill/test/unit/head.js
+++ b/browser/extensions/formautofill/test/unit/head.js
@@ -1,26 +1,71 @@
 /**
  * Provides infrastructure for automated login components tests.
  */
 
- /* exported importAutofillModule */
+ /* exported importAutofillModule, getTempFile */
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://testing-common/MockDocument.jsm");
 
 // Load the module by Service newFileURI API for running extension's XPCShell test
 function importAutofillModule(module) {
   return Cu.import(Services.io.newFileURI(do_get_file(module)).spec);
 }
 
+XPCOMUtils.defineLazyModuleGetter(this, "DownloadPaths",
+                                  "resource://gre/modules/DownloadPaths.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
+                                  "resource://gre/modules/FileUtils.jsm");
+
+// While the previous test file should have deleted all the temporary files it
+// used, on Windows these might still be pending deletion on the physical file
+// system.  Thus, start from a new base number every time, to make a collision
+// with a file that is still pending deletion highly unlikely.
+let gFileCounter = Math.floor(Math.random() * 1000000);
+
+/**
+ * Returns a reference to a temporary file, that is guaranteed not to exist, and
+ * to have never been created before.
+ *
+ * @param {string} leafName
+ *        Suggested leaf name for the file to be created.
+ *
+ * @returns {nsIFile} pointing to a non-existent file in a temporary directory.
+ *
+ * @note It is not enough to delete the file if it exists, or to delete the file
+ *       after calling nsIFile.createUnique, because on Windows the delete
+ *       operation in the file system may still be pending, preventing a new
+ *       file with the same name to be created.
+ */
+function getTempFile(leafName) {
+  // Prepend a serial number to the extension in the suggested leaf name.
+  let [base, ext] = DownloadPaths.splitBaseNameAndExtension(leafName);
+  let finalLeafName = base + "-" + gFileCounter + ext;
+  gFileCounter++;
+
+  // Get a file reference under the temporary directory for this test file.
+  let file = FileUtils.getFile("TmpD", [finalLeafName]);
+  do_check_false(file.exists());
+
+  do_register_cleanup(function() {
+    if (file.exists()) {
+      file.remove(false);
+    }
+  });
+
+  return file;
+}
+
 add_task(function* test_common_initialize() {
   Services.prefs.setBoolPref("dom.forms.autocomplete.experimental", true);
 
   // Clean up after every test.
   do_register_cleanup(() => {
     Services.prefs.setBoolPref("dom.forms.autocomplete.experimental", false);
   });
 });
new file mode 100644
--- /dev/null
+++ b/browser/extensions/formautofill/test/unit/test_profileStorage.js
@@ -0,0 +1,222 @@
+/**
+ * Tests ProfileStorage object.
+ */
+
+/* global ProfileStorage */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Task.jsm");
+Cu.import(Services.io.newFileURI(do_get_file("ProfileStorage.jsm")).spec);
+
+const TEST_STORE_FILE_NAME = "test-profile.json";
+
+const TEST_PROFILE_1 = {
+  organization: "World Wide Web Consortium",
+  streetAddress: "32 Vassar Street\nMIT Room 32-G524",
+  addressLevel2: "Cambridge",
+  addressLevel1: "MA",
+  postalCode: "02139",
+  country: "US",
+  tel: "+1 617 253 5702",
+  email: "timbl@w3.org",
+};
+
+const TEST_PROFILE_2 = {
+  streetAddress: "Some Address",
+  country: "US",
+};
+
+const TEST_PROFILE_3 = {
+  streetAddress: "Other Address",
+  postalCode: "12345",
+};
+
+const TEST_PROFILE_WITH_INVALID_FIELD = {
+  streetAddress: "Another Address",
+  invalidField: "INVALID",
+};
+
+let prepareTestProfiles = Task.async(function* (path) {
+  let profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  profileStorage.add(TEST_PROFILE_1);
+  profileStorage.add(TEST_PROFILE_2);
+  yield profileStorage._saveImmediately();
+});
+
+let do_check_profile_matches = (profileWithMeta, profile) => {
+  for (let key in profile) {
+    do_check_eq(profileWithMeta[key], profile[key]);
+  }
+};
+
+add_task(function* test_initialize() {
+  let path = getTempFile(TEST_STORE_FILE_NAME).path;
+  let profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  do_check_eq(profileStorage._store.data.version, 1);
+  do_check_eq(profileStorage._store.data.profiles.length, 0);
+
+  let data = profileStorage._store.data;
+
+  yield profileStorage._saveImmediately();
+
+  profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  Assert.deepEqual(profileStorage._store.data, data);
+});
+
+add_task(function* test_getAll() {
+  let path = getTempFile(TEST_STORE_FILE_NAME).path;
+  yield prepareTestProfiles(path);
+
+  let profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  let profiles = profileStorage.getAll();
+
+  do_check_eq(profiles.length, 2);
+  do_check_profile_matches(profiles[0], TEST_PROFILE_1);
+  do_check_profile_matches(profiles[1], TEST_PROFILE_2);
+
+  // Modifying output shouldn't affect the storage.
+  profiles[0].organization = "test";
+  do_check_profile_matches(profileStorage.getAll()[0], TEST_PROFILE_1);
+});
+
+add_task(function* test_get() {
+  let path = getTempFile(TEST_STORE_FILE_NAME).path;
+  yield prepareTestProfiles(path);
+
+  let profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  let profiles = profileStorage.getAll();
+  let guid = profiles[0].guid;
+
+  let profile = profileStorage.get(guid);
+  do_check_profile_matches(profile, TEST_PROFILE_1);
+
+  // Modifying output shouldn't affect the storage.
+  profile.organization = "test";
+  do_check_profile_matches(profileStorage.get(guid), TEST_PROFILE_1);
+
+  Assert.throws(() => profileStorage.get("INVALID_GUID"),
+    /No matching profile\./);
+});
+
+add_task(function* test_add() {
+  let path = getTempFile(TEST_STORE_FILE_NAME).path;
+  yield prepareTestProfiles(path);
+
+  let profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  let profiles = profileStorage.getAll();
+
+  do_check_eq(profiles.length, 2);
+
+  do_check_profile_matches(profiles[0], TEST_PROFILE_1);
+  do_check_profile_matches(profiles[1], TEST_PROFILE_2);
+
+  do_check_neq(profiles[0].guid, undefined);
+  do_check_neq(profiles[0].timeCreated, undefined);
+  do_check_eq(profiles[0].timeLastModified, profiles[0].timeCreated);
+  do_check_eq(profiles[0].timeLastUsed, 0);
+  do_check_eq(profiles[0].timesUsed, 0);
+
+  Assert.throws(() => profileStorage.add(TEST_PROFILE_WITH_INVALID_FIELD),
+    /"invalidField" is not a valid field\./);
+});
+
+add_task(function* test_update() {
+  let path = getTempFile(TEST_STORE_FILE_NAME).path;
+  yield prepareTestProfiles(path);
+
+  let profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  let profiles = profileStorage.getAll();
+  let guid = profiles[1].guid;
+  let timeLastModified = profiles[1].timeLastModified;
+
+  do_check_neq(profiles[1].country, undefined);
+
+  profileStorage.update(guid, TEST_PROFILE_3);
+  yield profileStorage._saveImmediately();
+
+  profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  let profile = profileStorage.get(guid);
+
+  do_check_eq(profile.country, undefined);
+  do_check_neq(profile.timeLastModified, timeLastModified);
+  do_check_profile_matches(profile, TEST_PROFILE_3);
+
+  Assert.throws(
+    () => profileStorage.update("INVALID_GUID", TEST_PROFILE_3),
+    /No matching profile\./
+  );
+
+  Assert.throws(
+    () => profileStorage.update(guid, TEST_PROFILE_WITH_INVALID_FIELD),
+    /"invalidField" is not a valid field\./
+  );
+});
+
+add_task(function* test_notifyUsed() {
+  let path = getTempFile(TEST_STORE_FILE_NAME).path;
+  yield prepareTestProfiles(path);
+
+  let profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  let profiles = profileStorage.getAll();
+  let guid = profiles[1].guid;
+  let timeLastUsed = profiles[1].timeLastUsed;
+  let timesUsed = profiles[1].timesUsed;
+
+  profileStorage.notifyUsed(guid);
+  yield profileStorage._saveImmediately();
+
+  profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  let profile = profileStorage.get(guid);
+
+  do_check_eq(profile.timesUsed, timesUsed + 1);
+  do_check_neq(profile.timeLastUsed, timeLastUsed);
+
+  Assert.throws(() => profileStorage.notifyUsed("INVALID_GUID"),
+    /No matching profile\./);
+});
+
+add_task(function* test_remove() {
+  let path = getTempFile(TEST_STORE_FILE_NAME).path;
+  yield prepareTestProfiles(path);
+
+  let profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  let profiles = profileStorage.getAll();
+  let guid = profiles[1].guid;
+
+  do_check_eq(profiles.length, 2);
+
+  profileStorage.remove(guid);
+  yield profileStorage._saveImmediately();
+
+  profileStorage = new ProfileStorage(path);
+  yield profileStorage.initialize();
+
+  profiles = profileStorage.getAll();
+
+  do_check_eq(profiles.length, 1);
+
+  Assert.throws(() => profileStorage.get(guid), /No matching profile\./);
+});
--- a/browser/extensions/formautofill/test/unit/xpcshell.ini
+++ b/browser/extensions/formautofill/test/unit/xpcshell.ini
@@ -1,7 +1,10 @@
 [DEFAULT]
 head = head.js
 tail =
-support-files = ../../content/FormAutofillContent.jsm
+support-files =
+  ../../content/FormAutofillContent.jsm
+  ../../content/ProfileStorage.jsm
 
 [test_autofillFormFields.js]
 [test_collectFormFields.js]
+[test_profileStorage.js]
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -188,17 +188,16 @@
 @RESPATH@/components/dom_core.xpt
 @RESPATH@/components/dom_css.xpt
 @RESPATH@/components/dom_events.xpt
 @RESPATH@/components/dom_geolocation.xpt
 @RESPATH@/components/dom_media.xpt
 @RESPATH@/components/dom_network.xpt
 @RESPATH@/components/dom_notification.xpt
 @RESPATH@/components/dom_html.xpt
-@RESPATH@/components/dom_icc.xpt
 @RESPATH@/components/dom_offline.xpt
 @RESPATH@/components/dom_json.xpt
 @RESPATH@/components/dom_power.xpt
 @RESPATH@/components/dom_push.xpt
 @RESPATH@/components/dom_quota.xpt
 @RESPATH@/components/dom_range.xpt
 @RESPATH@/components/dom_security.xpt
 @RESPATH@/components/dom_settings.xpt
@@ -504,18 +503,16 @@
 @RESPATH@/components/AppsService.manifest
 @RESPATH@/components/recording-cmdline.js
 @RESPATH@/components/recording-cmdline.manifest
 @RESPATH@/components/htmlMenuBuilder.js
 @RESPATH@/components/htmlMenuBuilder.manifest
 
 @RESPATH@/components/PermissionSettings.js
 @RESPATH@/components/PermissionSettings.manifest
-@RESPATH@/components/ContactManager.js
-@RESPATH@/components/ContactManager.manifest
 @RESPATH@/components/PhoneNumberService.js
 @RESPATH@/components/PhoneNumberService.manifest
 @RESPATH@/components/NotificationStorage.js
 @RESPATH@/components/NotificationStorage.manifest
 @RESPATH@/components/Push.js
 @RESPATH@/components/Push.manifest
 @RESPATH@/components/PushComponents.js
 
--- a/browser/modules/WindowsJumpLists.jsm
+++ b/browser/modules/WindowsJumpLists.jsm
@@ -80,17 +80,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 /**
  * Global functions
  */
 
 function _getString(name) {
   return _stringBundle.GetStringFromName(name);
 }
 
-// ///////////////////////////////////////////////////////////////////////////
 // Task list configuration data object.
 
 var tasksCfg = [
   /**
    * Task configuration options: title, description, args, iconIndex, open, close.
    *
    * title       - Task title displayed in the list. (strings in the table are temp fillers.)
    * description - Tooltip description on the list item.
@@ -130,17 +129,16 @@ var tasksCfg = [
     args:             "-private-window",
     iconIndex:        4, // Private browsing mode icon
     open:             true,
     close:            true, // No point, but we don't always update the list on
                             // shutdown. Thus true for consistency.
   },
 ];
 
-// ///////////////////////////////////////////////////////////////////////////
 // Implementation
 
 this.WinTaskbarJumpList =
 {
   _builder: null,
   _tasks: null,
   _shuttingDown: false,
 
--- a/browser/modules/WindowsPreviewPerTab.jsm
+++ b/browser/modules/WindowsPreviewPerTab.jsm
@@ -57,18 +57,17 @@ Cu.import("resource://gre/modules/XPCOMU
 const TOGGLE_PREF_NAME = "browser.taskbar.previews.enable";
 // Pref to determine the magic auto-disable threshold
 const DISABLE_THRESHOLD_PREF_NAME = "browser.taskbar.previews.max";
 // Pref to control the time in seconds that tab contents live in the cache
 const CACHE_EXPIRATION_TIME_PREF_NAME = "browser.taskbar.previews.cachetime";
 
 const WINTASKBAR_CONTRACTID = "@mozilla.org/windows-taskbar;1";
 
-// //////////////////////////////////////////////////////////////////////////////
-// // Various utility properties
+// Various utility properties
 XPCOMUtils.defineLazyServiceGetter(this, "imgTools",
                                    "@mozilla.org/image/tools;1",
                                    "imgITools");
 XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
                                   "resource://gre/modules/PageThumbs.jsm");
 
 // nsIURI -> imgIContainer
 function _imageFromURI(uri, privateMode, callback) {
@@ -118,18 +117,17 @@ function snapRectAtScale(r, scale) {
   let height = Math.ceil((r.y + r.height) * scale) - y;
 
   r.x = x / scale;
   r.y = y / scale;
   r.width = width / scale;
   r.height = height / scale;
 }
 
-// //////////////////////////////////////////////////////////////////////////////
-// // PreviewController
+// PreviewController
 
 /*
  * This class manages the behavior of thumbnails and previews. It has the following
  * responsibilities:
  * 1) responding to requests from Windows taskbar for a thumbnail or window
  *    preview.
  * 2) listens for dom events that result in a thumbnail or window preview needing
  *    to be refresh, and communicates this to the taskbar.
@@ -234,18 +232,17 @@ PreviewController.prototype = {
   },
 
   updateTitleAndTooltip: function () {
     let title = this.win.tabbrowser.getWindowTitleForBrowser(this.linkedBrowser);
     this.preview.title = title;
     this.preview.tooltip = title;
   },
 
-  // ////////////////////////////////////////////////////////////////////////////
-  // // nsITaskbarPreviewController
+  // nsITaskbarPreviewController
 
   // window width and height, not browser
   get width() {
     return this.win.width;
   },
 
   // window width and height, not browser
   get height() {
@@ -317,32 +314,31 @@ PreviewController.prototype = {
    */
   requestThumbnail: function (aTaskbarCallback, aRequestedWidth, aRequestedHeight) {
     this.resizeCanvasPreview(aRequestedWidth, aRequestedHeight);
     this.updateCanvasPreview(false, (aThumbnailCanvas) => {
       aTaskbarCallback.done(aThumbnailCanvas, false);
     });
   },
 
-  // ////////////////////////////////////////////////////////////////////////////
-  // // Event handling
+  // Event handling
 
   onClose: function () {
     this.win.tabbrowser.removeTab(this.tab);
   },
 
   onActivate: function () {
     this.win.tabbrowser.selectedTab = this.tab;
 
     // Accept activation - this will restore the browser window
     // if it's minimized
     return true;
   },
 
-  // // nsIDOMEventListener
+  // nsIDOMEventListener
   handleEvent: function (evt) {
     switch (evt.type) {
       case "TabAttrModified":
         this.updateTitleAndTooltip();
         break;
     }
   }
 };
@@ -350,18 +346,17 @@ PreviewController.prototype = {
 XPCOMUtils.defineLazyGetter(PreviewController.prototype, "canvasPreviewFlags",
   function () { let canvasInterface = Ci.nsIDOMCanvasRenderingContext2D;
                 return canvasInterface.DRAWWINDOW_DRAW_VIEW
                      | canvasInterface.DRAWWINDOW_DRAW_CARET
                      | canvasInterface.DRAWWINDOW_ASYNC_DECODE_IMAGES
                      | canvasInterface.DRAWWINDOW_DO_NOT_FLUSH;
 });
 
-// //////////////////////////////////////////////////////////////////////////////
-// // TabWindow
+// TabWindow
 
 /*
  * This class monitors a browser window for changes to its tabs
  *
  * @param win
  *        The nsIDOMWindow browser window
  */
 function TabWindow(win) {
@@ -504,17 +499,17 @@ TabWindow.prototype = {
     // on it the sorting order of our local array.  To do so we must walk
     // the local array backwards, otherwise we would send move requests in the
     // wrong order.  See bug 522610 for details.
     for (let i = inorder.length - 1; i >= 0; i--) {
       inorder[i].move(inorder[i + 1] || null);
     }
   },
 
-  // // nsIDOMEventListener
+  // nsIDOMEventListener
   handleEvent: function (evt) {
     let tab = evt.originalTarget;
     switch (evt.type) {
       case "TabOpen":
         this.newTab(tab);
         this.updateTabOrdering();
         break;
       case "TabClose":
@@ -578,17 +573,17 @@ TabWindow.prototype = {
     for (let [tab, preview] of this.previews) {
       if (aBrowser == tab.linkedBrowser) {
         preview.invalidate();
         break;
       }
     }
   },
 
-  // // Browser progress listener
+  // Browser progress listener
 
   onLocationChange: function (aBrowser) {
     // I'm not sure we need this, onStateChange does a really good job
     // of picking up page changes.
     // this.invalidateTabPreview(aBrowser);
   },
 
   onStateChange: function (aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) {
@@ -632,18 +627,17 @@ TabWindow.prototype = {
             preview.icon = img;
           }
         }
       }
     );
   }
 }
 
-// //////////////////////////////////////////////////////////////////////////////
-// // AeroPeek
+// AeroPeek
 
 /*
  * This object acts as global storage and external interface for this feature.
  * It maintains the values of the prefs.
  */
 this.AeroPeek = {
   available: false,
   // Does the pref say we're enabled?
@@ -796,17 +790,17 @@ this.AeroPeek = {
       this.destroy();
   },
 
   resetCacheTimer: function () {
     this.cacheTimer.cancel();
     this.cacheTimer.init(this, 1000*this.cacheLifespan, Ci.nsITimer.TYPE_ONE_SHOT);
   },
 
-  // // nsIObserver
+  // nsIObserver
   observe: function (aSubject, aTopic, aData) {
     if (aTopic == "nsPref:changed" && aData == TOGGLE_PREF_NAME) {
       this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
     }
     if (!this._prefenabled) {
       return;
     }
     switch (aTopic) {
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/Screenshot.jsm
@@ -67,17 +67,17 @@ this.Screenshot = {
   // Capture the whole screen using an external application.
   captureExternal(filename) {
     let imagePath = this._buildImagePath(filename);
     return this._screenshotFunction(imagePath).then(() => {
       log.debug("saved screenshot: " + filename);
     });
   },
 
-  // /// helpers /////
+  // helpers
 
   _screenshotWindows(filename) {
     return new Promise((resolve, reject) => {
       let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile);
       exe.append("screenshot.exe");
       if (!exe.exists()) {
         exe = Services.dirsvc.get("CurWorkD", Ci.nsIFile).parent;
         exe.append("bin");
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/TestRunner.jsm
@@ -143,17 +143,17 @@ this.TestRunner = {
     while (gBrowser.tabs.length > 1) {
       gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
     }
     gBrowser.unpinTab(gBrowser.selectedTab);
     gBrowser.selectedBrowser.loadURI("data:text/html;charset=utf-8,<h1>Done!");
     browserWindow.restore();
   },
 
-  // /// helpers /////
+  // helpers
 
   _performCombo: function*(combo) {
     let paddedComboIndex = padLeft(this.currentComboIndex + 1, String(this.combos.length).length);
     log.info("Combination " + paddedComboIndex + "/" + this.combos.length + ": " +
              this._comboName(combo).substring(1));
 
     function changeConfig(config) {
       log.debug("calling " + config.name);
--- a/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm
+++ b/browser/tools/mozscreenshots/mozscreenshots/extension/configurations/Toolbars.jsm
@@ -40,17 +40,17 @@ this.Toolbars = {
         return undefined;
       }),
     },
 
   },
 };
 
 
-// /// helpers /////
+// helpers
 
 function toggleMenubarIfNecessary(visible) {
   let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
   // The menubar is not shown on OS X or while in fullScreen
   if (Services.appinfo.OS != "Darwin" /* && !browserWindow.fullScreen*/) {
     let menubar = browserWindow.document.getElementById("toolbar-menubar");
     browserWindow.setToolbarVisibility(menubar, visible);
   }
--- a/build/moz.configure/android-ndk.configure
+++ b/build/moz.configure/android-ndk.configure
@@ -49,17 +49,17 @@ def ndk(value, build_project):
     if value:
         return value[0]
 
 set_config('ANDROID_NDK', ndk)
 add_old_configure_assignment('android_ndk', ndk)
 
 @depends(target, android_version, ndk)
 @checking('for android platform directory')
-@imports('os')
+@imports(_from='os.path', _import='isdir')
 def android_platform(target, android_version, ndk):
     if target.os != 'Android':
         return
 
     if 'mips' in target.cpu:
         target_dir_name = 'mips'
     elif 'aarch64' == target.cpu:
         target_dir_name = 'arm64'
@@ -75,17 +75,17 @@ def android_platform(target, android_ver
     else:
         platform_version = android_version
 
     platform_dir = os.path.join(ndk,
                                 'platforms',
                                 'android-%s' % platform_version,
                                 'arch-%s' % target_dir_name)
 
-    if not os.path.isdir(platform_dir):
+    if not isdir(platform_dir):
         die("Android platform directory not found. With the current "
             "configuration, it should be in %s" % platform_dir)
 
     return platform_dir
 
 add_old_configure_assignment('android_platform', android_platform)
 
 @depends(android_platform)
@@ -93,17 +93,17 @@ def extra_toolchain_flags(platform_dir):
     if not platform_dir:
         return []
     return ['-idirafter',
             os.path.join(platform_dir, 'usr', 'include')]
 
 @depends(target, host, ndk, '--with-android-toolchain',
          '--with-android-gnu-compiler-version')
 @checking('for the Android toolchain directory', lambda x: x or 'not found')
-@imports('os')
+@imports(_from='os.path', _import='isdir')
 @imports(_from='mozbuild.shellutil', _import='quote')
 def android_toolchain(target, host, ndk, toolchain, gnu_compiler_version):
     if not ndk:
         return
     if toolchain:
         return toolchain[0]
     else:
         if target.cpu == 'arm' and target.endianness == 'little':
@@ -118,21 +118,21 @@ def android_toolchain(target, host, ndk,
             die('Target cpu is not supported.')
 
         toolchain_format = '%s/toolchains/%s-%s/prebuilt/%s-%s'
 
         for version in gnu_compiler_version or ['4.9', '4.8', '4.7']:
             toolchain = toolchain_format % (ndk, target_base, version,
                                             host.kernel.lower(), host.cpu)
             log.debug('Trying %s' % quote(toolchain))
-            if not os.path.isdir(toolchain) and host.cpu == 'x86_64':
+            if not isdir(toolchain) and host.cpu == 'x86_64':
                 toolchain = toolchain_format % (ndk, target_base, version,
                                                 host.kernel.lower(), 'x86')
                 log.debug('Trying %s' % quote(toolchain))
-            if os.path.isdir(toolchain):
+            if isdir(toolchain):
                 return toolchain
         else:
             if gnu_compiler_version:
                 die('Your --with-android-gnu-compiler-version may be wrong')
             die('You have to specify --with-android-toolchain='
                 '/path/to/ndk/toolchain.')
 
 set_config('ANDROID_TOOLCHAIN', android_toolchain)
--- a/build/moz.configure/init.configure
+++ b/build/moz.configure/init.configure
@@ -7,17 +7,17 @@
 include('util.configure')
 include('checks.configure')
 
 option(env='DIST', nargs=1, help='DIST directory')
 
 # Do not allow objdir == srcdir builds.
 # ==============================================================
 @depends('--help', 'DIST')
-@imports('os')
+@imports(_from='os.path', _import='exists')
 def check_build_environment(help, dist):
     topobjdir = os.path.realpath(os.path.abspath('.'))
     topsrcdir = os.path.realpath(os.path.abspath(
         os.path.join(os.path.dirname(__file__), '..', '..')))
 
     if dist:
         dist = normsep(dist[0])
     else:
@@ -42,17 +42,17 @@ def check_build_environment(help, dist):
             '  * If you are building with a mozconfig, you will need to change your\n'
             '  * mozconfig to point to a different object directory.\n'
             '  ***'
         )
 
     # Check for a couple representative files in the source tree
     conflict_files = [
         '*         %s' % f for f in ('Makefile', 'config/autoconf.mk')
-        if os.path.exists(os.path.join(topsrcdir, f))
+        if exists(os.path.join(topsrcdir, f))
     ]
     if conflict_files:
         die('  ***\n'
             '  *   Your source tree contains these files:\n'
             '  %s\n'
             '  *   This indicates that you previously built in the source tree.\n'
             '  *   A source tree build can confuse the separate objdir build.\n'
             '  *\n'
@@ -629,27 +629,27 @@ def default_project(build_env, help):
 option('--enable-project', nargs=1, default=default_project,
        help='Project to build')
 
 option('--with-external-source-dir', env='EXTERNAL_SOURCE_DIR', nargs=1,
        help='External directory containing additional build files')
 
 @depends('--enable-project', '--with-external-source-dir',
          check_build_environment, '--help')
-@imports('os')
+@imports(_from='os.path', _import='exists')
 def include_project_configure(project, external_source_dir, build_env, help):
     if not project:
         die('--enable-project is required.')
 
     base_dir = build_env.topsrcdir
     if external_source_dir:
         base_dir = os.path.join(base_dir, external_source_dir[0])
 
     path = os.path.join(base_dir, project[0], 'moz.configure')
-    if not os.path.exists(path):
+    if not exists(path):
         die('Cannot find project %s', project[0])
     return path
 
 @depends('--with-external-source-dir')
 def external_source_dir(value):
     if value:
         return value[0]
 
--- a/build/moz.configure/old.configure
+++ b/build/moz.configure/old.configure
@@ -10,17 +10,17 @@ def encoded_open(path, mode):
     encoding = 'mbcs' if sys.platform == 'win32' else 'utf-8'
     return codecs.open(path, mode, encoding)
 
 
 option(env='AUTOCONF', nargs=1, help='Path to autoconf 2.13')
 
 @depends(mozconfig, 'AUTOCONF')
 @checking('for autoconf')
-@imports('os')
+@imports(_from='os.path', _import='exists')
 @imports('re')
 def autoconf(mozconfig, autoconf):
     mozconfig_autoconf = None
     if mozconfig['path']:
         make_extra = mozconfig['make_extra']
         if make_extra:
             for assignment in make_extra:
                 m = re.match('(?:export\s+)?AUTOCONF\s*:?=\s*(.+)$',
@@ -46,50 +46,50 @@ def autoconf(mozconfig, autoconf):
             if brew:
                 autoconf = os.path.normpath(os.path.join(
                     brew, '..', '..', 'Cellar', 'autoconf213', '2.13', 'bin',
                     'autoconf213'))
 
     if not autoconf:
         die('Could not find autoconf 2.13')
 
-    if not os.path.exists(autoconf):
+    if not exists(autoconf):
         die('Could not find autoconf 2.13 at %s', autoconf)
 
     return autoconf
 
 set_config('AUTOCONF', autoconf)
 
 
 @depends('OLD_CONFIGURE', mozconfig, autoconf, check_build_environment, shell,
          old_configure_assignments, build_project)
 @imports(_from='__builtin__', _import='open')
 @imports(_from='__builtin__', _import='print')
 @imports('glob')
 @imports('itertools')
-@imports('os')
 @imports('subprocess')
 # Import getmtime without overwriting the sandbox os.path.
 @imports(_from='os.path', _import='getmtime')
+@imports(_from='os.path', _import='exists')
 @imports(_from='mozbuild.shellutil', _import='quote')
 def prepare_configure(old_configure, mozconfig, autoconf, build_env, shell,
                       old_configure_assignments, build_project):
     # os.path.abspath in the sandbox will ensure forward slashes on Windows,
     # which is actually necessary because this path actually ends up literally
     # as $0, and backslashes there breaks autoconf's detection of the source
     # directory.
     old_configure = os.path.abspath(old_configure[0])
     if build_project == 'js':
         old_configure_dir = os.path.dirname(old_configure)
-        if not old_configure_dir.replace(os.sep, '/').endswith('/js/src'):
+        if not old_configure_dir.endswith('/js/src'):
             old_configure = os.path.join(old_configure_dir, 'js', 'src',
                                          os.path.basename(old_configure))
 
     refresh = True
-    if os.path.exists(old_configure):
+    if exists(old_configure):
         mtime = getmtime(old_configure)
         aclocal = os.path.join(build_env.topsrcdir, 'build', 'autoconf',
                                '*.m4')
         for input in itertools.chain(
             (old_configure + '.in',
              os.path.join(os.path.dirname(old_configure), 'aclocal.m4')),
             glob.iglob(aclocal),
         ):
--- a/build/moz.configure/windows.configure
+++ b/build/moz.configure/windows.configure
@@ -260,21 +260,21 @@ def vc_path(c_compiler):
         result = next
         if p.lower() == 'bin':
             break
     return result
 
 
 @depends_win(vc_path)
 @checking('for the Debug Interface Access SDK', lambda x: x or 'not found')
-@imports('os')
+@imports(_from='os.path', _import='isdir')
 def dia_sdk_dir(vc_path):
     if vc_path:
         path = os.path.join(os.path.dirname(vc_path), 'DIA SDK')
-        if os.path.isdir(path):
+        if isdir(path):
             return path
 
 
 @depends_win(vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir)
 @imports('os')
 def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir):
     if not vc_path:
         return
--- a/devtools/client/commandline/test/helpers.js
+++ b/devtools/client/commandline/test/helpers.js
@@ -471,18 +471,16 @@ var { helpers, assert } = (function () {
       yield removedDeferred.promise;
 
     // And close everything down
       yield helpers.closeToolbar(options);
       yield helpers.closeTab(options);
     }).then(finish, helpers.handleError);
   };
 
-// /////////////////////////////////////////////////////////////////////////////
-
 /**
  * Ensure that the options object is setup correctly
  * options should contain an automator object that looks like this:
  * {
  *   getInputState: function() { ... },
  *   setCursor: function(cursor) { ... },
  *   getCompleterTemplateData: function() { ... },
  *   focus: function() { ... },
--- a/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-contextmenu.js
+++ b/devtools/client/debugger/test/mochitest/browser_dbg_breakpoints-contextmenu.js
@@ -176,17 +176,17 @@ function test() {
 
       // Test disabling all breakpoints.
       disableAll();
       yield waitForDispatch(gPanel, gDebugger.constants.REMOVE_BREAKPOINT, 5);
       for (let bp of queries.getBreakpoints(getState())) {
         ok(!!bp.disabled, "All breakpoints should be disabled.");
       }
 
-      // // Test re-enabling all breakpoints.
+      // Test re-enabling all breakpoints.
       enableAll();
       yield waitForDispatch(gPanel, gDebugger.constants.ADD_BREAKPOINT, 5);
       for (let bp of queries.getBreakpoints(getState())) {
         ok(!bp.disabled, "All breakpoints should be enabled.");
       }
     });
 
     const testDeleteAll = Task.async(function* () {
--- a/devtools/client/framework/test/browser_devtools_api.js
+++ b/devtools/client/framework/test/browser_devtools_api.js
@@ -1,14 +1,13 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejections should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.docShell is null");
 
 // When running in a standalone directory, we get this error
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.doc is undefined");
--- a/devtools/client/inspector/test/browser_inspector_highlighter-comments.js
+++ b/devtools/client/inspector/test/browser_inspector_highlighter-comments.js
@@ -1,16 +1,15 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* 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";
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("false");
 
 // Test that hovering over the markup-view's containers doesn't always show the
 // highlighter, depending on the type of node hovered over.
--- a/devtools/client/projecteditor/test/browser_projecteditor_editing_01.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_editing_01.js
@@ -1,15 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
 
 loadHelperScript("helper_edits.js");
 
--- a/devtools/client/projecteditor/test/browser_projecteditor_editors_image.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_editors_image.js
@@ -1,15 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
 
 loadHelperScript("helper_edits.js");
 
--- a/devtools/client/projecteditor/test/browser_projecteditor_immediate_destroy.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_immediate_destroy.js
@@ -1,15 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("TypeError: this.window is null");
 
 // Test that projecteditor can be destroyed in various states of loading
--- a/devtools/client/projecteditor/test/browser_projecteditor_saveall.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_saveall.js
@@ -1,15 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
 
 loadHelperScript("helper_edits.js");
 
--- a/devtools/client/projecteditor/test/browser_projecteditor_tree_selection_02.js
+++ b/devtools/client/projecteditor/test/browser_projecteditor_tree_selection_02.js
@@ -1,15 +1,14 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
  http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
 
 // Test that files get reselected in the tree when their editor
 // is focused.  https://bugzilla.mozilla.org/show_bug.cgi?id=1011116.
--- a/devtools/client/responsivedesign/test/browser_responsive_cmd.js
+++ b/devtools/client/responsivedesign/test/browser_responsive_cmd.js
@@ -1,14 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("destroy");
 
 function test() {
   let manager = ResponsiveUIManager;
--- a/devtools/client/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
+++ b/devtools/client/shared/test/browser_telemetry_toolboxtabs_shadereditor.js
@@ -1,12 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Shader Editor is still waiting for a WebGL context to be created.");
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>browser_telemetry_toolboxtabs_shadereditor.js</p>";
 
--- a/devtools/client/shared/test/browser_toolbar_tooltip.js
+++ b/devtools/client/shared/test/browser_toolbar_tooltip.js
@@ -1,14 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests that the developer toolbar works properly
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Protocol error (unknownError): Error: Got an invalid root window in DocumentWalker");
 
 const TEST_URI = "data:text/html;charset=utf-8,<p>Tooltip Tests</p>";
 const PREF_DEVTOOLS_THEME = "devtools.theme";
--- a/devtools/client/webaudioeditor/test/browser_wa_first-run.js
+++ b/devtools/client/webaudioeditor/test/browser_wa_first-run.js
@@ -1,12 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed");
 
 /**
  * Tests that the reloading/onContentLoaded hooks work.
--- a/devtools/client/webaudioeditor/test/browser_wa_reset-01.js
+++ b/devtools/client/webaudioeditor/test/browser_wa_reset-01.js
@@ -1,12 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed");
 
 /**
  * Tests that reloading a tab will properly listen for the `start-context`
--- a/devtools/client/webaudioeditor/test/browser_wa_reset-04.js
+++ b/devtools/client/webaudioeditor/test/browser_wa_reset-04.js
@@ -1,12 +1,11 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
-// /////////////////
 //
 // Whitelisting this test.
 // As part of bug 1077403, the leaking uncaught rejection should be fixed.
 //
 thisTestLeaksUncaughtRejectionsAndShouldBeFixed("Error: Connection closed");
 
 /**
  * Tests that switching to an iframe works fine.
--- a/devtools/client/webconsole/utils.js
+++ b/devtools/client/webconsole/utils.js
@@ -326,19 +326,17 @@ var WebConsoleUtils = {
       return false;
     };
     return handler;
   },
 };
 
 exports.Utils = WebConsoleUtils;
 
-// ////////////////////////////////////////////////////////////////////////
 // Localization
-// ////////////////////////////////////////////////////////////////////////
 
 WebConsoleUtils.L10n = function (bundleURI) {
   this._helper = new LocalizationHelper(bundleURI);
 };
 
 WebConsoleUtils.L10n.prototype = {
   /**
    * Generates a formatted timestamp string for displaying in console messages.
--- a/devtools/client/webconsole/webconsole.js
+++ b/devtools/client/webconsole/webconsole.js
@@ -2963,19 +2963,17 @@ var Utils = {
     } catch (e) {
       // Ignore any exceptions
     }
 
     return logLimit;
   },
 };
 
-// ////////////////////////////////////////////////////////////////////////////
 // CommandController
-// ////////////////////////////////////////////////////////////////////////////
 
 /**
  * A controller (an instance of nsIController) that makes editing actions
  * behave appropriately in the context of the Web Console.
  */
 function CommandController(webConsole) {
   this.owner = webConsole;
 }
@@ -3048,19 +3046,17 @@ CommandController.prototype = {
         break;
       case "cmd_selectAll":
         this.selectAll();
         break;
     }
   }
 };
 
-// ////////////////////////////////////////////////////////////////////////////
 // Web Console connection proxy
-// ////////////////////////////////////////////////////////////////////////////
 
 /**
  * The WebConsoleConnectionProxy handles the connection between the Web Console
  * and the application we connect to through the remote debug protocol.
  *
  * @constructor
  * @param object webConsoleFrame
  *        The WebConsoleFrame object that owns this connection proxy.
@@ -3536,19 +3532,17 @@ WebConsoleConnectionProxy.prototype = {
     this.connected = false;
     this.webConsoleFrame = null;
     this._disconnecter.resolve(null);
 
     return this._disconnecter.promise;
   },
 };
 
-// ////////////////////////////////////////////////////////////////////////////
 // Context Menu
-// ////////////////////////////////////////////////////////////////////////////
 
 /*
  * ConsoleContextMenu this used to handle the visibility of context menu items.
  *
  * @constructor
  * @param object owner
  *        The WebConsoleFrame instance that owns this object.
  */
--- a/devtools/server/actors/utils/webconsole-utils.js
+++ b/devtools/server/actors/utils/webconsole-utils.js
@@ -200,19 +200,17 @@ var WebConsoleUtils = {
                       + ": " + value);
         return null;
     }
   },
 };
 
 exports.Utils = WebConsoleUtils;
 
-// /////////////////////////////////////////////////////////////////////////////
 // The page errors listener
-// /////////////////////////////////////////////////////////////////////////////
 
 /**
  * The nsIConsoleService listener. This is used to send all of the console
  * messages (JavaScript, CSS and more) to the remote Web Console instance.
  *
  * @constructor
  * @param nsIDOMWindow [window]
  *        Optional - the window object for which we are created. This is used
@@ -362,19 +360,17 @@ ConsoleServiceListener.prototype =
    * Remove the nsIConsoleService listener.
    */
   destroy: function () {
     Services.console.unregisterListener(this);
     this.listener = this.window = null;
   },
 };
 
-// /////////////////////////////////////////////////////////////////////////////
 // The window.console API observer
-// /////////////////////////////////////////////////////////////////////////////
 
 /**
  * The window.console API observer. This allows the window.console API messages
  * to be sent to the remote Web Console instance.
  *
  * @constructor
  * @param nsIDOMWindow window
  *        Optional - the window object for which we are created. This is used
--- a/devtools/server/actors/webconsole.js
+++ b/devtools/server/actors/webconsole.js
@@ -546,19 +546,17 @@ WebConsoleActor.prototype =
    *
    * @return object
    */
   getLastConsoleInputEvaluation: function WCU_getLastConsoleInputEvaluation()
   {
     return this._lastConsoleInputEvaluation;
   },
 
-  // ////////////////
   // Request handlers for known packet types.
-  // ////////////////
 
   /**
    * Handler for the "startListeners" request.
    *
    * @param object aRequest
    *        The JSON request object received from the Web Console client.
    * @return object
    *         The response object which holds the startedListeners array.
@@ -1088,19 +1086,17 @@ WebConsoleActor.prototype =
             this.networkMonitorChild.throttleData = this._prefs[key];
           }
         }
       }
     }
     return { updated: Object.keys(aRequest.preferences) };
   },
 
-  // ////////////////
   // End of request handlers.
-  // ////////////////
 
   /**
    * Create an object with the API we expose to the Web Console during
    * JavaScript evaluation.
    * This object inherits properties and methods from the Web Console actor.
    *
    * @private
    * @param object aDebuggerGlobal
@@ -1424,19 +1420,17 @@ WebConsoleActor.prototype =
       result: result,
       helperResult: helperResult,
       dbg: dbg,
       frame: frame,
       window: dbgWindow,
     };
   },
 
-  // ////////////////
   // Event handlers for various listeners.
-  // ////////////////
 
   /**
    * Handler for messages received from the ConsoleServiceListener. This method
    * sends the nsIConsoleMessage to the remote Web Console client.
    *
    * @param nsIConsoleMessage aMessage
    *        The message we need to send to the client.
    */
@@ -1704,19 +1698,17 @@ WebConsoleActor.prototype =
       from: this.actorID,
       type: "serverLogCall",
       message: msg,
     };
 
     this.conn.send(packet);
   },
 
-  // ////////////////
   // End of event handlers for various listeners.
-  // ////////////////
 
   /**
    * Prepare a message from the console API to be sent to the remote Web Console
    * instance.
    *
    * @param object aMessage
    *        The original message received from console-api-log-event.
    * @param boolean aUseObjectGlobal
--- a/devtools/shared/webconsole/network-monitor.js
+++ b/devtools/shared/webconsole/network-monitor.js
@@ -19,19 +19,17 @@ loader.lazyRequireGetter(this, "flags",
 loader.lazyRequireGetter(this, "DebuggerServer",
                          "devtools/server/main", true);
 loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
 loader.lazyServiceGetter(this, "gActivityDistributor",
                          "@mozilla.org/network/http-activity-distributor;1",
                          "nsIHttpActivityDistributor");
 const {NetworkThrottleManager} = require("devtools/shared/webconsole/throttle");
 
-// /////////////////////////////////////////////////////////////////////////////
 // Network logging
-// /////////////////////////////////////////////////////////////////////////////
 
 // The maximum uint32 value.
 const PR_UINT32_MAX = 4294967295;
 
 // HTTP status codes.
 const HTTP_MOVED_PERMANENTLY = 301;
 const HTTP_FOUND = 302;
 const HTTP_SEE_OTHER = 303;
--- a/dom/apps/AppsServiceChild.jsm
+++ b/dom/apps/AppsServiceChild.jsm
@@ -98,23 +98,17 @@ this.DOMApplicationRegistry = {
   init: function init() {
     this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
                   .getService(Ci.nsISyncMessageSender);
 
     APPS_IPC_MSG_NAMES.forEach((function(aMsgName) {
       this.cpmm.addMessageListener(aMsgName, this);
     }).bind(this));
 
-    this.cpmm.sendAsyncMessage("Webapps:RegisterForMessages", {
-      messages: APPS_IPC_MSG_NAMES
-    });
-
-    // We need to prime the cache with the list of apps.
-    let list = this.cpmm.sendSyncMessage("Webapps:GetList", { })[0];
-    this.webapps = list ? list.webapps : { };
+    this.webapps = { };
     // We need a fast mapping from localId -> app, so we add an index.
     // We also add the manifest to the app object.
     this.localIdIndex = { };
     for (let id in this.webapps) {
       let app = this.webapps[id];
       this.localIdIndex[app.localId] = app;
       app.manifest = list.manifests[id];
     }
--- a/dom/apps/PermissionsTable.jsm
+++ b/dom/apps/PermissionsTable.jsm
@@ -131,21 +131,16 @@ this.PermissionsTable =  { geolocation: 
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "browser:embedded-system-app": {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
-                           mobileconnection: {
-                             app: DENY_ACTION,
-                             privileged: DENY_ACTION,
-                             certified: ALLOW_ACTION
-                           },
                            mobilenetwork: {
                              app: DENY_ACTION,
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            power: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -35,36 +35,32 @@
 #ifdef MOZ_GAMEPAD
 #include "mozilla/dom/GamepadServiceTest.h"
 #endif
 #include "mozilla/dom/PowerManager.h"
 #include "mozilla/dom/WakeLock.h"
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/FlyWebPublishedServer.h"
 #include "mozilla/dom/FlyWebService.h"
-#include "mozilla/dom/IccManager.h"
 #include "mozilla/dom/InputPortManager.h"
 #include "mozilla/dom/Permissions.h"
 #include "mozilla/dom/Presentation.h"
 #include "mozilla/dom/ServiceWorkerContainer.h"
 #include "mozilla/dom/StorageManager.h"
 #include "mozilla/dom/TCPSocket.h"
 #include "mozilla/dom/VRDisplay.h"
 #include "mozilla/dom/workers/RuntimeService.h"
 #include "mozilla/Hal.h"
 #include "nsISiteSpecificUserAgent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/SSE.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
 #include "nsGlobalWindow.h"
-#ifdef MOZ_B2G_RIL
-#include "mozilla/dom/MobileConnectionArray.h"
-#endif
 #include "nsIIdleObserver.h"
 #include "nsIPermissionManager.h"
 #include "nsMimeTypes.h"
 #include "nsNetUtil.h"
 #include "nsStringStream.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIStringStream.h"
 #include "nsIHttpChannel.h"
@@ -206,23 +202,19 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMimeTypes)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPlugins)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPermissions)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryPromise)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mInputPortManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
-#ifdef MOZ_B2G_RIL
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
-#endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioChannelManager)
 #endif
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
 
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
@@ -273,36 +265,25 @@ Navigator::Invalidate()
 
   mBatteryPromise = nullptr;
 
   if (mPowerManager) {
     mPowerManager->Shutdown();
     mPowerManager = nullptr;
   }
 
-  if (mIccManager) {
-    mIccManager->Shutdown();
-    mIccManager = nullptr;
-  }
-
   if (mInputPortManager) {
     mInputPortManager = nullptr;
   }
 
   if (mConnection) {
     mConnection->Shutdown();
     mConnection = nullptr;
   }
 
-#ifdef MOZ_B2G_RIL
-  if (mMobileConnections) {
-    mMobileConnections = nullptr;
-  }
-#endif
-
   mMediaDevices = nullptr;
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   if (mAudioChannelManager) {
     mAudioChannelManager = nullptr;
   }
 #endif
 
@@ -1621,50 +1602,16 @@ Navigator::GetInputPortManager(ErrorResu
 
 already_AddRefed<LegacyMozTCPSocket>
 Navigator::MozTCPSocket()
 {
   RefPtr<LegacyMozTCPSocket> socket = new LegacyMozTCPSocket(GetWindow());
   return socket.forget();
 }
 
-#ifdef MOZ_B2G_RIL
-
-MobileConnectionArray*
-Navigator::GetMozMobileConnections(ErrorResult& aRv)
-{
-  if (!mMobileConnections) {
-    if (!mWindow) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
-    mMobileConnections = new MobileConnectionArray(mWindow);
-  }
-
-  return mMobileConnections;
-}
-
-#endif // MOZ_B2G_RIL
-
-IccManager*
-Navigator::GetMozIccManager(ErrorResult& aRv)
-{
-  if (!mIccManager) {
-    if (!mWindow) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
-    NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
-
-    mIccManager = new IccManager(mWindow);
-  }
-
-  return mIccManager;
-}
-
 #ifdef MOZ_GAMEPAD
 void
 Navigator::GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads,
                        ErrorResult& aRv)
 {
   if (!mWindow) {
     aRv.Throw(NS_ERROR_UNEXPECTED);
     return;
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -67,22 +67,17 @@ class GamepadServiceTest;
 class NavigatorUserMediaSuccessCallback;
 class NavigatorUserMediaErrorCallback;
 class MozGetUserMediaDevicesSuccessCallback;
 
 namespace network {
 class Connection;
 } // namespace network
 
-#ifdef MOZ_B2G_RIL
-class MobileConnectionArray;
-#endif
-
 class PowerManager;
-class IccManager;
 class InputPortManager;
 class DeviceStorageAreaListener;
 class Presentation;
 class LegacyMozTCPSocket;
 class VRDisplay;
 class StorageManager;
 
 namespace time {
@@ -209,25 +204,21 @@ public:
                          nsTArray<RefPtr<nsDOMDeviceStorage> >& aStores,
                          ErrorResult& aRv);
 
   already_AddRefed<nsDOMDeviceStorage>
   GetDeviceStorageByNameAndType(const nsAString& aName, const nsAString& aType,
                                 ErrorResult& aRv);
 
   DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
-  IccManager* GetMozIccManager(ErrorResult& aRv);
   InputPortManager* GetInputPortManager(ErrorResult& aRv);
   already_AddRefed<LegacyMozTCPSocket> MozTCPSocket();
   network::Connection* GetConnection(ErrorResult& aRv);
   MediaDevices* GetMediaDevices(ErrorResult& aRv);
 
-#ifdef MOZ_B2G_RIL
-  MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
-#endif // MOZ_B2G_RIL
 #ifdef MOZ_GAMEPAD
   void GetGamepads(nsTArray<RefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
   GamepadServiceTest* RequestGamepadServiceTest();
 #endif // MOZ_GAMEPAD
   already_AddRefed<Promise> GetVRDisplays(ErrorResult& aRv);
   void GetActiveVRDisplays(nsTArray<RefPtr<VRDisplay>>& aDisplays) const;
 #ifdef MOZ_TIME_MANAGER
   time::TimeManager* GetMozTime(ErrorResult& aRv);
@@ -306,22 +297,18 @@ private:
   RefPtr<nsMimeTypeArray> mMimeTypes;
   RefPtr<nsPluginArray> mPlugins;
   RefPtr<Permissions> mPermissions;
   RefPtr<Geolocation> mGeolocation;
   RefPtr<DesktopNotificationCenter> mNotification;
   RefPtr<battery::BatteryManager> mBatteryManager;
   RefPtr<Promise> mBatteryPromise;
   RefPtr<PowerManager> mPowerManager;
-  RefPtr<IccManager> mIccManager;
   RefPtr<InputPortManager> mInputPortManager;
   RefPtr<network::Connection> mConnection;
-#ifdef MOZ_B2G_RIL
-  RefPtr<MobileConnectionArray> mMobileConnections;
-#endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   RefPtr<system::AudioChannelManager> mAudioChannelManager;
 #endif
   RefPtr<MediaDevices> mMediaDevices;
   nsTArray<nsWeakPtr> mDeviceStorageStores;
   RefPtr<time::TimeManager> mTimeManager;
   RefPtr<ServiceWorkerContainer> mServiceWorkerContainer;
   nsCOMPtr<nsPIDOMWindowInner> mWindow;
--- a/dom/base/test/chrome.ini
+++ b/dom/base/test/chrome.ini
@@ -8,18 +8,16 @@ support-files =
   mozbrowser_api_utils.js
 
 [test_anonymousContent_xul_window.xul]
 [test_bug715041.xul]
 [test_bug715041_removal.xul]
 [test_domrequesthelper.xul]
 [test_navigator_resolve_identity_xrays.xul]
 support-files = file_navigator_resolve_identity_xrays.xul
-[test_navigator_resolve_identity.html]
-support-files = file_navigator_resolve_identity.html
 [test_sendQueryContentAndSelectionSetEvent.html]
 [test_bug1016960.html]
 [test_copypaste.xul]
 subsuite = clipboard
 [test_messagemanager_principal.html]
 [test_messagemanager_send_principal.html]
 skip-if = buildapp == 'mulet'
 [test_bug945152.html]
deleted file mode 100644
--- a/dom/base/test/file_navigator_resolve_identity.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=985827
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 985827</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-  <script type="application/javascript">
-
-  function test() {
-    var is = parent.is;
-
-    // Test WebIDL NavigatorProperty objects
-    var x = navigator.mozContacts;
-    is(typeof x, "object", "Should have a mozContacts object");
-    delete navigator.mozContacts;
-    var y = navigator.mozContacts;
-    is(x, y, "Should have gotten the same mozContacts object again");
-  }
-
-  test();
-  </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=985827">Mozilla Bug 985827</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
--- a/dom/base/test/file_navigator_resolve_identity_xrays.xul
+++ b/dom/base/test/file_navigator_resolve_identity_xrays.xul
@@ -18,18 +18,13 @@ https://bugzilla.mozilla.org/show_bug.cg
 
   addLoadEvent(function() {
     var ok = parent.ok;
     var is = parent.is;
 
     var nav = document.getElementById("t").contentWindow.navigator;
 
     ok(Components.utils.isXrayWrapper(nav), "Should have an Xray here");
-
-    // Test WebIDL NavigatorProperty objects
-    is(typeof nav.mozContacts, "object", "Should have a mozContacts object");
-    is(nav.mozContacts, nav.mozContacts,
-       "Should have gotten the same mozContacts object again");
   });
 
   ]]>
   </script>
 </window>
deleted file mode 100644
--- a/dom/base/test/test_navigator_resolve_identity.html
+++ /dev/null
@@ -1,36 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=985827
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 985827</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-  <script type="application/javascript">
-
-  /** Test for Bug 985827 **/
-
-  SimpleTest.waitForExplicitFinish();
-
-  addEventListener('load', function() {
-    var iframe = document.createElement("iframe");
-    var dir = "chrome://mochitests/content/chrome/dom/base/test/";
-    iframe.src = dir + "file_navigator_resolve_identity.html";
-    document.body.appendChild(iframe);
-    iframe.onload = function() { SimpleTest.finish(); };
-  });
-
-  </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=985827">Mozilla Bug 985827</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -583,58 +583,16 @@ DOMInterfaces = {
     'nativeType': 'mozilla::dom::HTMLCanvasPrintState',
 },
 
 'MozChannel': {
     'nativeType': 'nsIChannel',
     'notflattened': True
 },
 
-'MozCdmaIccInfo': {
-    'headerFile': 'mozilla/dom/IccInfo.h',
-    'nativeType': 'mozilla::dom::CdmaIccInfo',
-},
-
-'MozGsmIccInfo': {
-    'headerFile': 'mozilla/dom/IccInfo.h',
-    'nativeType': 'mozilla::dom::GsmIccInfo',
-},
-
-'MozIcc': {
-    'nativeType': 'mozilla::dom::Icc',
-},
-
-'MozIccInfo': {
-    'nativeType': 'mozilla::dom::IccInfo',
-},
-
-'MozIccManager': {
-    'nativeType': 'mozilla::dom::IccManager',
-},
-
-'MozMobileCellInfo': {
-    'nativeType': 'mozilla::dom::MobileCellInfo',
-},
-
-'MozMobileConnection': {
-    'nativeType': 'mozilla::dom::MobileConnection',
-},
-
-'MozMobileConnectionArray': {
-    'nativeType': 'mozilla::dom::MobileConnectionArray',
-},
-
-'MozMobileConnectionInfo': {
-    'nativeType': 'mozilla::dom::MobileConnectionInfo',
-},
-
-'MozMobileNetworkInfo': {
-    'nativeType': 'mozilla::dom::MobileNetworkInfo',
-},
-
 'MozSpeakerManager': {
     'nativeType': 'mozilla::dom::SpeakerManager',
     'headerFile': 'SpeakerManager.h'
 },
 
 'MozPowerManager': {
     'nativeType': 'mozilla::dom::PowerManager',
 },
--- a/dom/bindings/test/chrome.ini
+++ b/dom/bindings/test/chrome.ini
@@ -1,20 +1,16 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g'
 support-files =
-  file_bug707564.html
-  file_bug707564-2.html
-  !/dom/bindings/test/file_bug707564.html
   !/dom/bindings/test/file_bug775543.html
   !/dom/bindings/test/file_document_location_set_via_xray.html
   !/dom/bindings/test/file_dom_xrays.html
   !/dom/bindings/test/file_proxies_via_xray.html
 
-[test_bug707564.html]
 [test_bug775543.html]
 [test_document_location_set_via_xray.html]
 [test_dom_xrays.html]
 [test_proxies_via_xray.html]
 [test_document_location_via_xray_cached.html]
 [test_blacklisted_prerendering_function.xul]
 support-files =
   file_focuser.html
deleted file mode 100644
--- a/dom/bindings/test/file_bug707564-2.html
+++ /dev/null
@@ -1,45 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=707564
--->
-<head>
-  <meta charset="utf-8">
-  <title>Test for Bug 707564</title>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-  <script type="application/javascript">
-
-  /** Test for Bug 707564 **/
-  var ok = parent.ok;
-  var isnot = parent.isnot;
-
-  addLoadEvent(function() {
-    var props = Object.getOwnPropertyNames(Object.getPrototypeOf(frames[0].navigator));
-    isnot(props.indexOf("mozContacts"), -1,
-          "Should enumerate a mozContacts property on navigator");
-
-    // Now enumerate a different navigator object
-    var found = false;
-    for (var name in frames[1].navigator) {
-      if (name == "mozContacts") {
-        found = true;
-      }
-    }
-    ok(found, "Should enumerate a mozContacts property on navigator via for...in");
-    parent.SimpleTest.finish();
-  });
-
-  </script>
-</head>
-<body>
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=707564">Mozilla Bug 707564</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-<iframe></iframe>
-<iframe></iframe>
-</div>
-<pre id="test">
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/bindings/test/file_bug707564.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<body>
-<script>
-  navigator.foopy = 5;
-</script>
-</body>
deleted file mode 100644
--- a/dom/bindings/test/test_bug707564.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
-</head>
-<body>
-<iframe></iframe>
-<pre id="test">
-<script type="application/javascript">
-
-function run_tests() {
-  var iframe = document.querySelector("iframe");
-  iframe.src = "file_bug707564-2.html";
-}
-
-SimpleTest.waitForExplicitFinish();
-
-addEventListener('load', run_tests);
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/bindings/test/test_dom_xrays.html
+++ b/dom/bindings/test/test_dom_xrays.html
@@ -143,30 +143,16 @@ function test()
   checkXrayProperty(coll, 0, [ doc.getElementById("shadowedIframe") ]);
 
   // WebIDL-defined properties live on the prototype, overriding any named properties.
   checkXrayProperty(coll, "item", [ undefined, win.HTMLCollection.prototype.item ]);
 
   // ECMAScript-defined properties live on the prototype, overriding any named properties.
   checkXrayProperty(coll, "toString", [ undefined, undefined, win.Object.prototype.toString ]);
 
-  // NavigatorProperty things should come from the target compartment, always.
-  var contacts = win.navigator.mozContacts;
-  isnot(contacts, undefined,
-        "Must have a mozContacts for this to work.  Find another " +
-        "NavigatorProperty, or remove all this NavigatorProperty code")
-  ok(Cu.isXrayWrapper(contacts),
-     "Should have an Xray for the underlying value, not a value newly " +
-     "created for us");
-  is(Cu.getGlobalForObject(contacts), win,
-     "contacts should come from the underlying window");
-  // Unfortunately, I can't figure out a decent way to test that we're not
-  // creating a separate thing from the thing content sees, because none of the
-  // NavigatorProperty things are available to content.
-
   // Frozen arrays should come from our compartment, not the target one.
   var languages1 = win.navigator.languages;
   isnot(languages1, undefined, "Must have .languages");
   ok(Array.isArray(languages1), ".languages should be an array");
   ok(Object.isFrozen(languages1), ".languages should be a frozen array");
   ok(!Cu.isXrayWrapper(languages1), "Should have our own version of array");
   is(Cu.getGlobalForObject(languages1), window,
      "languages1 should come from our window");
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -1048,18 +1048,19 @@ NS_INTERFACE_MAP_END
 
 
 // Initialize our static variables.
 uint32_t CanvasRenderingContext2D::sNumLivingContexts = 0;
 DrawTarget* CanvasRenderingContext2D::sErrorTarget = nullptr;
 
 
 
-CanvasRenderingContext2D::CanvasRenderingContext2D()
+CanvasRenderingContext2D::CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend)
   : mRenderingMode(RenderingMode::OpenGLBackendMode)
+  , mCompositorBackend(aCompositorBackend)
   // these are the default values from the Canvas spec
   , mWidth(0), mHeight(0)
   , mZero(false), mOpaque(false)
   , mResetLayer(true)
   , mIPC(false)
   , mIsSkiaGL(false)
   , mHasPendingStableStateCallback(false)
   , mDrawObserver(nullptr)
@@ -1070,17 +1071,17 @@ CanvasRenderingContext2D::CanvasRenderin
   , mInvalidateCount(0)
 {
   sNumLivingContexts++;
 
   mShutdownObserver = new CanvasShutdownObserver(this);
   nsContentUtils::RegisterShutdownObserver(mShutdownObserver);
 
   // The default is to use OpenGL mode
-  if (gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+  if (AllowOpenGLCanvas()) {
     mDrawObserver = new CanvasDrawObserver(this);
   } else {
     mRenderingMode = RenderingMode::SoftwareBackendMode;
   }
 }
 
 CanvasRenderingContext2D::~CanvasRenderingContext2D()
 {
@@ -1316,28 +1317,48 @@ CanvasRenderingContext2D::RedrawUser(con
     ++mInvalidateCount;
     return;
   }
 
   gfx::Rect newr = mTarget->GetTransform().TransformBounds(ToRect(aR));
   Redraw(newr);
 }
 
+bool
+CanvasRenderingContext2D::AllowOpenGLCanvas() const
+{
+  // If we somehow didn't have the correct compositor in the constructor,
+  // we could do something like this to get it:
+  //
+  // HTMLCanvasElement* el = GetCanvas();
+  // if (el) {
+  //   mCompositorBackend = el->GetCompositorBackendType();
+  // }
+  //
+  // We could have LAYERS_NONE if there was no widget at the time of
+  // canvas creation, but in that case the
+  // HTMLCanvasElement::GetCompositorBackendType would return LAYERS_NONE
+  // as well, so it wouldn't help much.
+
+  return (mCompositorBackend == LayersBackend::LAYERS_OPENGL) &&
+    gfxPlatform::GetPlatform()->AllowOpenGLCanvas();
+}
+
 bool CanvasRenderingContext2D::SwitchRenderingMode(RenderingMode aRenderingMode)
 {
   if (!IsTargetValid() || mRenderingMode == aRenderingMode) {
     return false;
   }
 
   MOZ_ASSERT(mBufferProvider);
 
 #ifdef USE_SKIA_GPU
   // Do not attempt to switch into GL mode if the platform doesn't allow it.
   if ((aRenderingMode == RenderingMode::OpenGLBackendMode) &&
-      !gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+      !AllowOpenGLCanvas()) {
       return false;
   }
 #endif
 
   RefPtr<PersistentBufferProvider> oldBufferProvider = mBufferProvider;
 
   // Return the old target to the buffer provider.
   // We need to do this before calling EnsureTarget.
@@ -1703,23 +1724,20 @@ LayerManagerFromCanvasElement(nsINode* a
 
 bool
 CanvasRenderingContext2D::TrySkiaGLTarget(RefPtr<gfx::DrawTarget>& aOutDT,
                                           RefPtr<layers::PersistentBufferProvider>& aOutProvider)
 {
   aOutDT = nullptr;
   aOutProvider = nullptr;
 
-
   mIsSkiaGL = false;
 
   IntSize size(mWidth, mHeight);
-  if (!gfxPlatform::GetPlatform()->AllowOpenGLCanvas() ||
-      !CheckSizeForSkiaGL(size)) {
-
+  if (!AllowOpenGLCanvas() || !CheckSizeForSkiaGL(size)) {
     return false;
   }
 
 
   RefPtr<LayerManager> layerManager = LayerManagerFromCanvasElement(mCanvasElement);
 
   if (!layerManager) {
     return false;
@@ -4755,17 +4773,17 @@ CanvasRenderingContext2D::DrawImage(cons
 
   nsLayoutUtils::DirectDrawInfo drawInfo;
 
 #ifdef USE_SKIA_GPU
   if (mRenderingMode == RenderingMode::OpenGLBackendMode &&
       mIsSkiaGL &&
       !srcSurf &&
       aImage.IsHTMLVideoElement() &&
-      gfxPlatform::GetPlatform()->AllowOpenGLCanvas()) {
+      AllowOpenGLCanvas()) {
     mozilla::gl::GLContext* gl = gfxPlatform::GetPlatform()->GetSkiaGLGlue()->GetGLContext();
     MOZ_ASSERT(gl);
 
     HTMLVideoElement* video = &aImage.GetAsHTMLVideoElement();
     if (!video) {
       return;
     }
 
--- a/dom/canvas/CanvasRenderingContext2D.h
+++ b/dom/canvas/CanvasRenderingContext2D.h
@@ -61,23 +61,23 @@ class CanvasShutdownObserver;
  **/
 class CanvasRenderingContext2D final :
   public nsICanvasRenderingContextInternal,
   public nsWrapperCache
 {
   virtual ~CanvasRenderingContext2D();
 
 public:
-  CanvasRenderingContext2D();
+  explicit CanvasRenderingContext2D(layers::LayersBackend aCompositorBackend);
 
   virtual JSObject* WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   HTMLCanvasElement* GetCanvas() const
   {
-    if (mCanvasElement->IsInNativeAnonymousSubtree()) {
+    if (!mCanvasElement || mCanvasElement->IsInNativeAnonymousSubtree()) {
       return nullptr;
     }
 
     // corresponds to changes to the old bindings made in bug 745025
     return mCanvasElement->GetOriginalCanvas();
   }
 
   void Save();
@@ -533,16 +533,20 @@ public:
   // Given a point, return hit region ID if it exists
   nsString GetHitRegion(const mozilla::gfx::Point& aPoint) override;
 
 
   // return true and fills in the bound rect if element has a hit region.
   bool GetHitRegionRect(Element* aElement, nsRect& aRect) override;
 
   void OnShutdown();
+
+  // Check the global setup, as well as the compositor type:
+  bool AllowOpenGLCanvas() const;
+
 protected:
   nsresult GetImageDataArray(JSContext* aCx, int32_t aX, int32_t aY,
                              uint32_t aWidth, uint32_t aHeight,
                              JSObject** aRetval);
 
   nsresult PutImageData_explicit(int32_t aX, int32_t aY, uint32_t aW, uint32_t aH,
                                  dom::Uint8ClampedArray* aArray,
                                  bool aHasDirtyRect, int32_t aDirtyX, int32_t aDirtyY,
@@ -728,16 +732,18 @@ protected:
   static std::vector<CanvasRenderingContext2D*>& DemotableContexts();
   static void DemoteOldestContextIfNecessary();
 
   static void AddDemotableContext(CanvasRenderingContext2D* aContext);
   static void RemoveDemotableContext(CanvasRenderingContext2D* aContext);
 
   RenderingMode mRenderingMode;
 
+  layers::LayersBackend mCompositorBackend;
+
   // Member vars
   int32_t mWidth, mHeight;
 
   // This is true when the canvas is valid, but of zero size, this requires
   // specific behavior on some operations.
   bool mZero;
 
   bool mOpaque;
--- a/dom/canvas/CanvasRenderingContextHelper.cpp
+++ b/dom/canvas/CanvasRenderingContextHelper.cpp
@@ -118,26 +118,33 @@ CanvasRenderingContextHelper::ToBlob(JSC
                                        format,
                                        GetWidthHeight(),
                                        callback);
 }
 
 already_AddRefed<nsICanvasRenderingContextInternal>
 CanvasRenderingContextHelper::CreateContext(CanvasContextType aContextType)
 {
+  return CreateContextHelper(aContextType, layers::LayersBackend::LAYERS_NONE);
+}
+
+already_AddRefed<nsICanvasRenderingContextInternal>
+CanvasRenderingContextHelper::CreateContextHelper(CanvasContextType aContextType,
+                                                  layers::LayersBackend aCompositorBackend)
+{
   MOZ_ASSERT(aContextType != CanvasContextType::NoContext);
   RefPtr<nsICanvasRenderingContextInternal> ret;
 
   switch (aContextType) {
   case CanvasContextType::NoContext:
     break;
 
   case CanvasContextType::Canvas2D:
     Telemetry::Accumulate(Telemetry::CANVAS_2D_USED, 1);
-    ret = new CanvasRenderingContext2D();
+    ret = new CanvasRenderingContext2D(aCompositorBackend);
     break;
 
   case CanvasContextType::WebGL1:
     Telemetry::Accumulate(Telemetry::CANVAS_WEBGL_USED, 1);
 
     ret = WebGL1Context::Create();
     if (!ret)
       return nullptr;
--- a/dom/canvas/CanvasRenderingContextHelper.h
+++ b/dom/canvas/CanvasRenderingContextHelper.h
@@ -2,16 +2,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/. */
 
 #ifndef MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
 #define MOZILLA_DOM_CANVASRENDERINGCONTEXTHELPER_H_
 
 #include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/layers/LayersTypes.h"
 #include "nsSize.h"
 
 class nsICanvasRenderingContextInternal;
 class nsIGlobalObject;
 
 namespace mozilla {
 
 class ErrorResult;
@@ -61,16 +62,20 @@ protected:
 
   void ToBlob(JSContext* aCx, nsIGlobalObject* aGlobal, EncodeCompleteCallback* aCallback,
               const nsAString& aType, JS::Handle<JS::Value> aParams,
               ErrorResult& aRv);
 
   virtual already_AddRefed<nsICanvasRenderingContextInternal>
   CreateContext(CanvasContextType aContextType);
 
+  already_AddRefed<nsICanvasRenderingContextInternal>
+  CreateContextHelper(CanvasContextType aContextType,
+                      layers::LayersBackend aCompositorBackend);
+
   virtual nsIntSize GetWidthHeight() = 0;
 
   CanvasContextType mCurrentContextType;
   nsCOMPtr<nsICanvasRenderingContextInternal> mCurrentContext;
 };
 
 } // namespace dom
 } // namespace mozilla
deleted file mode 100644
--- a/dom/contacts/ContactManager.js
+++ /dev/null
@@ -1,541 +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 DEBUG = false;
-function debug(s) { dump("-*- ContactManager: " + s + "\n"); }
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(Services, "DOMRequest",
-                                   "@mozilla.org/dom/dom-request-service;1",
-                                   "nsIDOMRequestService");
-
-XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
-                                   "@mozilla.org/childprocessmessagemanager;1",
-                                   "nsIMessageSender");
-
-const CONTACTS_SENDMORE_MINIMUM = 5;
-
-// We need this to create a copy of the mozContact object in ContactManager.save
-// Keep in sync with the interfaces.
-const PROPERTIES = [
-  "name", "honorificPrefix", "givenName", "additionalName", "familyName",
-  "phoneticGivenName", "phoneticFamilyName",
-  "honorificSuffix", "nickname", "photo", "category", "org", "jobTitle",
-  "bday", "note", "anniversary", "sex", "genderIdentity", "key", "adr", "email",
-  "url", "impp", "tel"
-];
-
-var mozContactInitWarned = false;
-
-function Contact() { }
-
-Contact.prototype = {
-  __init: function(aProp) {
-    for (let prop in aProp) {
-      this[prop] = aProp[prop];
-    }
-  },
-
-  init: function(aProp) {
-    // init is deprecated, warn once in the console if it's used
-    if (!mozContactInitWarned) {
-      mozContactInitWarned = true;
-      Cu.reportError("mozContact.init is DEPRECATED. Use the mozContact constructor instead. " +
-                     "See https://developer.mozilla.org/docs/WebAPI/Contacts for details.");
-    }
-
-    for (let prop of PROPERTIES) {
-      this[prop] = aProp[prop];
-    }
-  },
-
-  setMetadata: function(aId, aPublished, aUpdated) {
-    this.id = aId;
-    if (aPublished) {
-      this.published = aPublished;
-    }
-    if (aUpdated) {
-      this.updated = aUpdated;
-    }
-  },
-
-  classID: Components.ID("{72a5ee28-81d8-4af8-90b3-ae935396cc66}"),
-  contractID: "@mozilla.org/contact;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
-};
-
-function ContactManager() { }
-
-ContactManager.prototype = {
-  __proto__: DOMRequestIpcHelper.prototype,
-  hasListenPermission: false,
-  _cachedContacts: [] ,
-
-  set oncontactchange(aHandler) {
-    this.__DOM_IMPL__.setEventHandler("oncontactchange", aHandler);
-  },
-
-  get oncontactchange() {
-    return this.__DOM_IMPL__.getEventHandler("oncontactchange");
-  },
-
-  _convertContact: function(aContact) {
-    let properties = aContact.properties;
-    if (properties.photo && properties.photo.length) {
-      properties.photo = Cu.cloneInto(properties.photo, this._window);
-    }
-    let newContact = new this._window.mozContact(aContact.properties);
-    newContact.setMetadata(aContact.id, aContact.published, aContact.updated);
-    return newContact;
-  },
-
-  _convertContacts: function(aContacts) {
-    let contacts = new this._window.Array();
-    for (let i in aContacts) {
-      contacts.push(this._convertContact(aContacts[i]));
-    }
-    return contacts;
-  },
-
-  _fireSuccessOrDone: function(aCursor, aResult) {
-    if (aResult == null) {
-      Services.DOMRequest.fireDone(aCursor);
-    } else {
-      Services.DOMRequest.fireSuccess(aCursor, aResult);
-    }
-  },
-
-  _pushArray: function(aArr1, aArr2) {
-    aArr1.push.apply(aArr1, aArr2);
-  },
-
-  receiveMessage: function(aMessage) {
-    if (DEBUG) debug("receiveMessage: " + aMessage.name);
-    let msg = aMessage.json;
-    let contacts = msg.contacts;
-
-    let req;
-    switch (aMessage.name) {
-      case "Contacts:Find:Return:OK":
-        req = this.getRequest(msg.requestID);
-        if (req) {
-          let result = this._convertContacts(contacts);
-          Services.DOMRequest.fireSuccess(req.request, result);
-        } else {
-          if (DEBUG) debug("no request stored!" + msg.requestID);
-        }
-        break;
-      case "Contacts:GetAll:Next":
-        let data = this.getRequest(msg.cursorId);
-        if (!data) {
-          break;
-        }
-        let result = contacts ? this._convertContacts(contacts) : [null];
-        if (data.waitingForNext) {
-          if (DEBUG) debug("cursor waiting for contact, sending");
-          data.waitingForNext = false;
-          let contact = result.shift();
-          this._pushArray(data.cachedContacts, result);
-          this.nextTick(this._fireSuccessOrDone.bind(this, data.cursor, contact));
-          if (!contact) {
-            this.removeRequest(msg.cursorId);
-          }
-        } else {
-          if (DEBUG) debug("cursor not waiting, saving");
-          this._pushArray(data.cachedContacts, result);
-        }
-        break;
-      case "Contact:Save:Return:OK":
-        // If a cached contact was saved and a new contact ID was returned, update the contact's ID
-        if (this._cachedContacts[msg.requestID]) {
-          if (msg.contactID) {
-            this._cachedContacts[msg.requestID].id = msg.contactID;
-          }
-          delete this._cachedContacts[msg.requestID];
-        }
-      case "Contacts:Clear:Return:OK":
-      case "Contact:Remove:Return:OK":
-        req = this.getRequest(msg.requestID);
-        if (req)
-          Services.DOMRequest.fireSuccess(req.request, null);
-        break;
-      case "Contacts:Find:Return:KO":
-      case "Contact:Save:Return:KO":
-      case "Contact:Remove:Return:KO":
-      case "Contacts:Clear:Return:KO":
-      case "Contacts:GetRevision:Return:KO":
-      case "Contacts:Count:Return:KO":
-        req = this.getRequest(msg.requestID);
-        if (req) {
-          if (req.request) {
-            req = req.request;
-          }
-          Services.DOMRequest.fireError(req, msg.errorMsg);
-        }
-        break;
-      case "Contacts:GetAll:Return:KO":
-        req = this.getRequest(msg.requestID);
-        if (req) {
-          Services.DOMRequest.fireError(req.cursor, msg.errorMsg);
-        }
-        break;
-      case "Contact:Changed":
-        // Fire oncontactchange event
-        if (DEBUG) debug("Contacts:ContactChanged: " + msg.contactID + ", " + msg.reason);
-        let event = new this._window.MozContactChangeEvent("contactchange", {
-          contactID: msg.contactID,
-          reason: msg.reason
-        });
-        this.dispatchEvent(event);
-        break;
-      case "Contacts:Revision":
-        if (DEBUG) debug("new revision: " + msg.revision);
-        req = this.getRequest(msg.requestID);
-        if (req) {
-          Services.DOMRequest.fireSuccess(req.request, msg.revision);
-        }
-        break;
-      case "Contacts:Count":
-        if (DEBUG) debug("count: " + msg.count);
-        req = this.getRequest(msg.requestID);
-        if (req) {
-          Services.DOMRequest.fireSuccess(req.request, msg.count);
-        }
-        break;
-      default:
-        if (DEBUG) debug("Wrong message: " + aMessage.name);
-    }
-    this.removeRequest(msg.requestID);
-  },
-
-  dispatchEvent: function(event) {
-    if (this.hasListenPermission) {
-      this.__DOM_IMPL__.dispatchEvent(event);
-    }
-  },
-
-  askPermission: function (aAccess, aRequest, aAllowCallback, aCancelCallback) {
-    if (DEBUG) debug("askPermission for contacts");
-
-    let access;
-    switch(aAccess) {
-      case "create":
-        access = "create";
-        break;
-      case "update":
-      case "remove":
-        access = "write";
-        break;
-      case "find":
-      case "listen":
-      case "revision":
-      case "count":
-        access = "read";
-        break;
-      default:
-        access = "unknown";
-      }
-
-    // Shortcut for ALLOW_ACTION so we avoid a parent roundtrip
-    let principal = this._window.document.nodePrincipal;
-    let type = "contacts-" + access;
-    let permValue =
-      Services.perms.testExactPermissionFromPrincipal(principal, type);
-    DEBUG && debug("Existing permission " + permValue);
-    if (permValue == Ci.nsIPermissionManager.ALLOW_ACTION) {
-      if (aAllowCallback) {
-        aAllowCallback();
-      }
-      return;
-    } else if (permValue == Ci.nsIPermissionManager.DENY_ACTION ||
-               permValue == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
-      if (aCancelCallback) {
-        aCancelCallback("PERMISSION_DENIED");
-      }
-      return;
-    }
-
-    // Create an array with a single nsIContentPermissionType element.
-    type = {
-      type: "contacts",
-      access: access,
-      options: [],
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionType])
-    };
-    let typeArray = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
-    typeArray.appendElement(type, false);
-
-    // create a nsIContentPermissionRequest
-    let request = {
-      types: typeArray,
-      principal: principal,
-      QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionRequest]),
-      allow: function() {
-        aAllowCallback && aAllowCallback();
-        DEBUG && debug("Permission granted. Access " + access +"\n");
-      },
-      cancel: function() {
-        aCancelCallback && aCancelCallback("PERMISSION_DENIED");
-        DEBUG && debug("Permission denied. Access " + access +"\n");
-      },
-      window: this._window
-    };
-
-    // Using askPermission from nsIDOMWindowUtils that takes care of the
-    // remoting if needed.
-    let windowUtils = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
-                          .getInterface(Ci.nsIDOMWindowUtils);
-    windowUtils.askPermission(request);
-  },
-
-  save: function save(aContact) {
-    // We have to do a deep copy of the contact manually here because
-    // nsFrameMessageManager doesn't know how to create a structured clone of a
-    // mozContact object.
-    let newContact = {properties: {}};
-
-    try {
-      for (let field of PROPERTIES) {
-        // This hack makes sure modifications to the sequence attributes get validated.
-        aContact[field] = aContact[field];
-        newContact.properties[field] = aContact[field];
-      }
-    } catch (e) {
-      // And then make sure we throw a proper error message (no internal file and line #)
-      throw new this._window.Error(e.message);
-    }
-
-    let request = this.createRequest();
-    let requestID = this.getRequestId({request: request});
-
-    let reason;
-    if (aContact.id == "undefined") {
-      // for example {25c00f01-90e5-c545-b4d4-21E2ddbab9e0} becomes
-      // 25c00f0190e5c545b4d421E2ddbab9e0
-      aContact.id = this._getRandomId().replace(/[{}-]/g, "");
-      // Cache the contact so that its ID may be updated later if necessary
-      this._cachedContacts[requestID] = aContact;
-      reason = "create";
-    } else {
-      reason = "update";
-    }
-
-    newContact.id = aContact.id;
-    newContact.published = aContact.published;
-    newContact.updated = aContact.updated;
-
-    if (DEBUG) debug("send: " + JSON.stringify(newContact));
-
-    let options = { contact: newContact, reason: reason };
-    let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contact:Save", {
-        requestID: requestID,
-        options: options
-      });
-    }.bind(this);
-
-    let cancelCallback = function(reason) {
-      Services.DOMRequest.fireErrorAsync(request, reason);
-    };
-
-    this.askPermission(reason, request, allowCallback, cancelCallback);
-    return request;
-  },
-
-  find: function(aOptions) {
-    if (DEBUG) debug("find! " + JSON.stringify(aOptions));
-    let request = this.createRequest();
-    let options = { findOptions: aOptions };
-
-    let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:Find", {
-        requestID: this.getRequestId({request: request, reason: "find"}),
-        options: options
-      });
-    }.bind(this);
-
-    let cancelCallback = function(reason) {
-      Services.DOMRequest.fireErrorAsync(request, reason);
-    };
-
-    this.askPermission("find", request, allowCallback, cancelCallback);
-    return request;
-  },
-
-  createCursor: function CM_createCursor(aRequest) {
-    let data = {
-      cursor: Services.DOMRequest.createCursor(this._window, function() {
-        this.handleContinue(id);
-      }.bind(this)),
-      cachedContacts: [],
-      waitingForNext: true,
-    };
-    let id = this.getRequestId(data);
-    if (DEBUG) debug("saved cursor id: " + id);
-    return [id, data.cursor];
-  },
-
-  getAll: function CM_getAll(aOptions) {
-    if (DEBUG) debug("getAll: " + JSON.stringify(aOptions));
-    let [cursorId, cursor] = this.createCursor();
-
-    let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:GetAll", {
-        cursorId: cursorId,
-        findOptions: aOptions
-      });
-    }.bind(this);
-
-    let cancelCallback = function(reason) {
-      Services.DOMRequest.fireErrorAsync(cursor, reason);
-    };
-
-    this.askPermission("find", cursor, allowCallback, cancelCallback);
-    return cursor;
-  },
-
-  nextTick: function nextTick(aCallback) {
-    Services.tm.currentThread.dispatch(aCallback, Ci.nsIThread.DISPATCH_NORMAL);
-  },
-
-  handleContinue: function CM_handleContinue(aCursorId) {
-    if (DEBUG) debug("handleContinue: " + aCursorId);
-    let data = this.getRequest(aCursorId);
-    if (data.cachedContacts.length > 0) {
-      if (DEBUG) debug("contact in cache");
-      let contact = data.cachedContacts.shift();
-      this.nextTick(this._fireSuccessOrDone.bind(this, data.cursor, contact));
-      if (!contact) {
-        this.removeRequest(aCursorId);
-      } else if (data.cachedContacts.length === CONTACTS_SENDMORE_MINIMUM) {
-        cpmm.sendAsyncMessage("Contacts:GetAll:SendNow", { cursorId: aCursorId });
-      }
-    } else {
-      if (DEBUG) debug("waiting for contact");
-      data.waitingForNext = true;
-    }
-  },
-
-  remove: function removeContact(aRecordOrId) {
-    let request = this.createRequest();
-    let id;
-    if (typeof aRecordOrId === "string") {
-      id = aRecordOrId;
-    } else if (!aRecordOrId || !aRecordOrId.id) {
-      Services.DOMRequest.fireErrorAsync(request, true);
-      return request;
-    } else {
-      id = aRecordOrId.id;
-    }
-
-    let options = { id: id };
-
-    let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contact:Remove", {
-        requestID: this.getRequestId({request: request, reason: "remove"}),
-        options: options
-      });
-    }.bind(this);
-
-    let cancelCallback = function(reason) {
-      Services.DOMRequest.fireErrorAsync(request, reason);
-    };
-
-    this.askPermission("remove", request, allowCallback, cancelCallback);
-    return request;
-  },
-
-  clear: function() {
-    if (DEBUG) debug("clear");
-    let request = this.createRequest();
-    let options = {};
-
-    let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:Clear", {
-        requestID: this.getRequestId({request: request, reason: "remove"}),
-        options: options
-      });
-    }.bind(this);
-
-    let cancelCallback = function(reason) {
-      Services.DOMRequest.fireErrorAsync(request, reason);
-    };
-
-    this.askPermission("remove", request, allowCallback, cancelCallback);
-    return request;
-  },
-
-  getRevision: function() {
-    let request = this.createRequest();
-
-    let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:GetRevision", {
-        requestID: this.getRequestId({ request: request })
-      });
-    }.bind(this);
-
-    let cancelCallback = function(reason) {
-      Services.DOMRequest.fireErrorAsync(request, reason);
-    };
-
-    this.askPermission("revision", request, allowCallback, cancelCallback);
-    return request;
-  },
-
-  getCount: function() {
-    let request = this.createRequest();
-
-    let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:GetCount", {
-        requestID: this.getRequestId({ request: request })
-      });
-    }.bind(this);
-
-    let cancelCallback = function(reason) {
-      Services.DOMRequest.fireErrorAsync(request, reason);
-    };
-
-    this.askPermission("count", request, allowCallback, cancelCallback);
-    return request;
-  },
-
-  init: function(aWindow) {
-    // DOMRequestIpcHelper.initHelper sets this._window
-    this.initDOMRequestHelper(aWindow, ["Contacts:Find:Return:OK", "Contacts:Find:Return:KO",
-                              "Contacts:Clear:Return:OK", "Contacts:Clear:Return:KO",
-                              "Contact:Save:Return:OK", "Contact:Save:Return:KO",
-                              "Contact:Remove:Return:OK", "Contact:Remove:Return:KO",
-                              "Contact:Changed",
-                              "Contacts:GetAll:Next", "Contacts:GetAll:Return:KO",
-                              "Contacts:Count",
-                              "Contacts:Revision", "Contacts:GetRevision:Return:KO",]);
-
-
-    let allowCallback = function() {
-      cpmm.sendAsyncMessage("Contacts:RegisterForMessages");
-      this.hasListenPermission = true;
-    }.bind(this);
-
-    this.askPermission("listen", null, allowCallback);
-  },
-
-  classID: Components.ID("{8beb3a66-d70a-4111-b216-b8e995ad3aff}"),
-  contractID: "@mozilla.org/contactManager;1",
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference,
-                                         Ci.nsIObserver,
-                                         Ci.nsIDOMGlobalPropertyInitializer]),
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
-  Contact, ContactManager
-]);
deleted file mode 100644
--- a/dom/contacts/ContactManager.manifest
+++ /dev/null
@@ -1,5 +0,0 @@
-component {72a5ee28-81d8-4af8-90b3-ae935396cc66} ContactManager.js
-contract @mozilla.org/contact;1 {72a5ee28-81d8-4af8-90b3-ae935396cc66}
-
-component {8beb3a66-d70a-4111-b216-b8e995ad3aff} ContactManager.js
-contract @mozilla.org/contactManager;1 {8beb3a66-d70a-4111-b216-b8e995ad3aff}
deleted file mode 100644
--- a/dom/contacts/fallback/ContactDB.jsm
+++ /dev/null
@@ -1,1401 +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";
-
-// Everything but "ContactDB" is only exported here for testing.
-this.EXPORTED_SYMBOLS = ["ContactDB", "DB_NAME", "STORE_NAME", "SAVED_GETALL_STORE_NAME",
-                         "REVISION_STORE", "DB_VERSION"];
-
-const DEBUG = false;
-function debug(s) { dump("-*- ContactDB component: " + s + "\n"); }
-
-const Cu = Components.utils;
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PhoneNumberUtils",
-                                  "resource://gre/modules/PhoneNumberUtils.jsm");
-Cu.importGlobalProperties(["indexedDB"]);
-
-/* all exported symbols need to be bound to this on B2G - Bug 961777 */
-this.DB_NAME = "contacts";
-this.DB_VERSION = 20;
-this.STORE_NAME = "contacts";
-this.SAVED_GETALL_STORE_NAME = "getallcache";
-const CHUNK_SIZE = 20;
-this.REVISION_STORE = "revision";
-const REVISION_KEY = "revision";
-
-function exportContact(aRecord) {
-  if (aRecord) {
-    delete aRecord.search;
-  }
-  return aRecord;
-}
-
-function ContactDispatcher(aContacts, aFullContacts, aCallback, aNewTxn, aClearDispatcher, aFailureCb) {
-  let nextIndex = 0;
-
-  let sendChunk;
-  let count = 0;
-  if (aFullContacts) {
-    sendChunk = function() {
-      try {
-        let chunk = aContacts.splice(0, CHUNK_SIZE);
-        if (chunk.length > 0) {
-          aCallback(chunk);
-        }
-        if (aContacts.length === 0) {
-          aCallback(null);
-          aClearDispatcher();
-        }
-      } catch (e) {
-        aClearDispatcher();
-      }
-    }
-  } else {
-    sendChunk = function() {
-      try {
-        let start = nextIndex;
-        nextIndex += CHUNK_SIZE;
-        let chunk = [];
-        aNewTxn("readonly", STORE_NAME, function(txn, store) {
-          for (let i = start; i < Math.min(start+CHUNK_SIZE, aContacts.length); ++i) {
-            store.get(aContacts[i]).onsuccess = function(e) {
-              chunk.push(exportContact(e.target.result));
-              count++;
-              if (count === aContacts.length) {
-                aCallback(chunk);
-                aCallback(null);
-                aClearDispatcher();
-              } else if (chunk.length === CHUNK_SIZE) {
-                aCallback(chunk);
-                chunk.length = 0;
-              }
-            }
-          }
-        }, null, function(errorMsg) {
-          aFailureCb(errorMsg);
-        });
-      } catch (e) {
-        aClearDispatcher();
-      }
-    }
-  }
-
-  return {
-    sendNow: function() {
-      sendChunk();
-    }
-  };
-}
-
-this.ContactDB = function ContactDB() {
-  if (DEBUG) debug("Constructor");
-};
-
-ContactDB.prototype = {
-  __proto__: IndexedDBHelper.prototype,
-
-  _dispatcher: {},
-
-  useFastUpgrade: true,
-
-  upgradeSchema: function upgradeSchema(aTransaction, aDb, aOldVersion, aNewVersion) {
-    let loadInitialContacts = function() {
-      // Add default contacts
-      let jsm = {};
-      Cu.import("resource://gre/modules/FileUtils.jsm", jsm);
-      Cu.import("resource://gre/modules/NetUtil.jsm", jsm);
-      // Loading resource://app/defaults/contacts.json doesn't work because
-      // contacts.json is not in the omnijar.
-      // So we look for the app dir instead and go from here...
-      let contactsFile = jsm.FileUtils.getFile("DefRt", ["contacts.json"], false);
-      if (!contactsFile || (contactsFile && !contactsFile.exists())) {
-        // For b2g desktop
-        contactsFile = jsm.FileUtils.getFile("ProfD", ["contacts.json"], false);
-        if (!contactsFile || (contactsFile && !contactsFile.exists())) {
-          return;
-        }
-      }
-
-      let chan = jsm.NetUtil.newChannel({
-        uri: NetUtil.newURI(contactsFile),
-        loadUsingSystemPrincipal: true});
-
-      let stream = chan.open2();
-      // Obtain a converter to read from a UTF-8 encoded input stream.
-      let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
-                      .createInstance(Ci.nsIScriptableUnicodeConverter);
-      converter.charset = "UTF-8";
-      let rawstr = converter.ConvertToUnicode(jsm.NetUtil.readInputStreamToString(
-                                              stream,
-                                              stream.available()) || "");
-      stream.close();
-      let contacts;
-      try {
-        contacts = JSON.parse(rawstr);
-      } catch(e) {
-        if (DEBUG) debug("Error parsing " + contactsFile.path + " : " + e);
-        return;
-      }
-
-      let idService = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
-      objectStore = aTransaction.objectStore(STORE_NAME);
-
-      for (let i = 0; i < contacts.length; i++) {
-        let contact = {};
-        contact.properties = contacts[i];
-        contact.id = idService.generateUUID().toString().replace(/[{}-]/g, "");
-        contact = this.makeImport(contact);
-        this.updateRecordMetadata(contact);
-        if (DEBUG) debug("import: " + JSON.stringify(contact));
-        objectStore.put(contact);
-      }
-    }.bind(this);
-
-    function createFinalSchema() {
-      if (DEBUG) debug("creating final schema");
-      let objectStore = aDb.createObjectStore(STORE_NAME, {keyPath: "id"});
-      objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true });
-      objectStore.createIndex("givenName",  "properties.givenName",  { multiEntry: true });
-      objectStore.createIndex("name",      "properties.name",        { multiEntry: true });
-      objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true });
-      objectStore.createIndex("givenNameLowerCase",  "search.givenName",  { multiEntry: true });
-      objectStore.createIndex("nameLowerCase",       "search.name",       { multiEntry: true });
-      objectStore.createIndex("telLowerCase",        "search.tel",        { multiEntry: true });
-      objectStore.createIndex("emailLowerCase",      "search.email",      { multiEntry: true });
-      objectStore.createIndex("tel", "search.exactTel", { multiEntry: true });
-      objectStore.createIndex("category", "properties.category", { multiEntry: true });
-      objectStore.createIndex("email", "search.email", { multiEntry: true });
-      objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
-      objectStore.createIndex("phoneticFamilyName", "properties.phoneticFamilyName", { multiEntry: true });
-      objectStore.createIndex("phoneticGivenName", "properties.phoneticGivenName", { multiEntry: true });
-      objectStore.createIndex("phoneticFamilyNameLowerCase", "search.phoneticFamilyName", { multiEntry: true });
-      objectStore.createIndex("phoneticGivenNameLowerCase",  "search.phoneticGivenName",  { multiEntry: true });
-      aDb.createObjectStore(SAVED_GETALL_STORE_NAME);
-      aDb.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
-    }
-
-    let valueUpgradeSteps = [];
-
-    function scheduleValueUpgrade(upgradeFunc) {
-      var length = valueUpgradeSteps.push(upgradeFunc);
-      if (DEBUG) debug("Scheduled a value upgrade function, index " + (length - 1));
-    }
-
-    // We always output this debug line because it's useful and the noise ratio
-    // very low.
-    debug("upgrade schema from: " + aOldVersion + " to " + aNewVersion + " called!");
-    let db = aDb;
-    let objectStore;
-
-    if (aOldVersion === 0 && this.useFastUpgrade) {
-      createFinalSchema();
-      loadInitialContacts();
-      return;
-    }
-
-    let steps = [
-      function upgrade0to1() {
-        /**
-         * Create the initial database schema.
-         *
-         * The schema of records stored is as follows:
-         *
-         * {id:            "...",       // UUID
-         *  published:     Date(...),   // First published date.
-         *  updated:       Date(...),   // Last updated date.
-         *  properties:    {...}        // Object holding the ContactProperties
-         * }
-         */
-        if (DEBUG) debug("create schema");
-        objectStore = db.createObjectStore(STORE_NAME, {keyPath: "id"});
-
-        // Properties indexes
-        objectStore.createIndex("familyName", "properties.familyName", { multiEntry: true });
-        objectStore.createIndex("givenName",  "properties.givenName",  { multiEntry: true });
-
-        objectStore.createIndex("familyNameLowerCase", "search.familyName", { multiEntry: true });
-        objectStore.createIndex("givenNameLowerCase",  "search.givenName",  { multiEntry: true });
-        objectStore.createIndex("telLowerCase",        "search.tel",        { multiEntry: true });
-        objectStore.createIndex("emailLowerCase",      "search.email",      { multiEntry: true });
-        next();
-      },
-      function upgrade1to2() {
-        if (DEBUG) debug("upgrade 1");
-
-        // Create a new scheme for the tel field. We move from an array of tel-numbers to an array of
-        // ContactTelephone.
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-        // Delete old tel index.
-        if (objectStore.indexNames.contains("tel")) {
-          objectStore.deleteIndex("tel");
-        }
-
-        // Upgrade existing tel field in the DB.
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            if (DEBUG) debug("upgrade tel1: " + JSON.stringify(cursor.value));
-            for (let number in cursor.value.properties.tel) {
-              cursor.value.properties.tel[number] = {number: number};
-            }
-            cursor.update(cursor.value);
-            if (DEBUG) debug("upgrade tel2: " + JSON.stringify(cursor.value));
-            cursor.continue();
-          } else {
-            next();
-          }
-        };
-
-        // Create new searchable indexes.
-        objectStore.createIndex("tel", "search.tel", { multiEntry: true });
-        objectStore.createIndex("category", "properties.category", { multiEntry: true });
-      },
-      function upgrade2to3() {
-        if (DEBUG) debug("upgrade 2");
-        // Create a new scheme for the email field. We move from an array of emailaddresses to an array of
-        // ContactEmail.
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-
-        // Delete old email index.
-        if (objectStore.indexNames.contains("email")) {
-          objectStore.deleteIndex("email");
-        }
-
-        // Upgrade existing email field in the DB.
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            if (cursor.value.properties.email) {
-              if (DEBUG) debug("upgrade email1: " + JSON.stringify(cursor.value));
-              cursor.value.properties.email =
-                cursor.value.properties.email.map(function(address) { return { address: address }; });
-              cursor.update(cursor.value);
-              if (DEBUG) debug("upgrade email2: " + JSON.stringify(cursor.value));
-            }
-            cursor.continue();
-          } else {
-            next();
-          }
-        };
-
-        // Create new searchable indexes.
-        objectStore.createIndex("email", "search.email", { multiEntry: true });
-      },
-      function upgrade3to4() {
-        if (DEBUG) debug("upgrade 3");
-
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-
-        // Upgrade existing impp field in the DB.
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            if (cursor.value.properties.impp) {
-              if (DEBUG) debug("upgrade impp1: " + JSON.stringify(cursor.value));
-              cursor.value.properties.impp =
-                cursor.value.properties.impp.map(function(value) { return { value: value }; });
-              cursor.update(cursor.value);
-              if (DEBUG) debug("upgrade impp2: " + JSON.stringify(cursor.value));
-            }
-            cursor.continue();
-          }
-        };
-        // Upgrade existing url field in the DB.
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            if (cursor.value.properties.url) {
-              if (DEBUG) debug("upgrade url1: " + JSON.stringify(cursor.value));
-              cursor.value.properties.url =
-                cursor.value.properties.url.map(function(value) { return { value: value }; });
-              cursor.update(cursor.value);
-              if (DEBUG) debug("upgrade impp2: " + JSON.stringify(cursor.value));
-            }
-            cursor.continue();
-          } else {
-            next();
-          }
-        };
-      },
-      function upgrade4to5() {
-        if (DEBUG) debug("Add international phone numbers upgrade");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            if (cursor.value.properties.tel) {
-              if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
-              cursor.value.properties.tel.forEach(
-                function(duple) {
-                  let parsedNumber = PhoneNumberUtils.parse(duple.value.toString());
-                  if (parsedNumber) {
-                    if (DEBUG) {
-                      debug("InternationalFormat: " + parsedNumber.internationalFormat);
-                      debug("InternationalNumber: " + parsedNumber.internationalNumber);
-                      debug("NationalNumber: " + parsedNumber.nationalNumber);
-                      debug("NationalFormat: " + parsedNumber.nationalFormat);
-                    }
-                    if (duple.value.toString() !== parsedNumber.internationalNumber) {
-                      cursor.value.search.tel.push(parsedNumber.internationalNumber);
-                    }
-                  } else {
-                    dump("Warning: No international number found for " + duple.value + "\n");
-                  }
-                }
-              )
-              cursor.update(cursor.value);
-            }
-            if (DEBUG) debug("upgrade2 : " + JSON.stringify(cursor.value));
-            cursor.continue();
-          } else {
-            next();
-          }
-        };
-      },
-      function upgrade5to6() {
-        if (DEBUG) debug("Add index for equals tel searches");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-
-        // Delete old tel index (not on the right field).
-        if (objectStore.indexNames.contains("tel")) {
-          objectStore.deleteIndex("tel");
-        }
-
-        // Create new index for "equals" searches
-        objectStore.createIndex("tel", "search.exactTel", { multiEntry: true });
-
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            if (cursor.value.properties.tel) {
-              if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
-              cursor.value.properties.tel.forEach(
-                function(duple) {
-                  let number = duple.value.toString();
-                  let parsedNumber = PhoneNumberUtils.parse(number);
-
-                  cursor.value.search.exactTel = [number];
-                  if (parsedNumber &&
-                      parsedNumber.internationalNumber &&
-                      number !== parsedNumber.internationalNumber) {
-                    cursor.value.search.exactTel.push(parsedNumber.internationalNumber);
-                  }
-                }
-              )
-              cursor.update(cursor.value);
-            }
-            if (DEBUG) debug("upgrade : " + JSON.stringify(cursor.value));
-            cursor.continue();
-          } else {
-            next();
-          }
-        };
-      },
-      function upgrade6to7() {
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-        let names = objectStore.indexNames;
-        let whiteList = ["tel", "familyName", "givenName",  "familyNameLowerCase",
-                         "givenNameLowerCase", "telLowerCase", "category", "email",
-                         "emailLowerCase"];
-        for (var i = 0; i < names.length; i++) {
-          if (whiteList.indexOf(names[i]) < 0) {
-            objectStore.deleteIndex(names[i]);
-          }
-        }
-        next();
-      },
-      function upgrade7to8() {
-        if (DEBUG) debug("Adding object store for cached searches");
-        db.createObjectStore(SAVED_GETALL_STORE_NAME);
-        next();
-      },
-      function upgrade8to9() {
-        if (DEBUG) debug("Make exactTel only contain the value entered by the user");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            if (cursor.value.properties.tel) {
-              cursor.value.search.exactTel = [];
-              cursor.value.properties.tel.forEach(
-                function(tel) {
-                  let normalized = PhoneNumberUtils.normalize(tel.value.toString());
-                  cursor.value.search.exactTel.push(normalized);
-                }
-              );
-              cursor.update(cursor.value);
-            }
-            cursor.continue();
-          } else {
-            next();
-          }
-        };
-      },
-      function upgrade9to10() {
-        // no-op, see https://bugzilla.mozilla.org/show_bug.cgi?id=883770#c16
-        next();
-      },
-      function upgrade10to11() {
-        if (DEBUG) debug("Adding object store for database revision");
-        db.createObjectStore(REVISION_STORE).put(0, REVISION_KEY);
-        next();
-      },
-      function upgrade11to12() {
-        if (DEBUG) debug("Add a telMatch index with national and international numbers");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-        if (!objectStore.indexNames.contains("telMatch")) {
-          objectStore.createIndex("telMatch", "search.parsedTel", {multiEntry: true});
-        }
-        objectStore.openCursor().onsuccess = function(event) {
-          let cursor = event.target.result;
-          if (cursor) {
-            if (cursor.value.properties.tel) {
-              cursor.value.search.parsedTel = [];
-              cursor.value.properties.tel.forEach(
-                function(tel) {
-                  let parsed = PhoneNumberUtils.parse(tel.value.toString());
-                  if (parsed) {
-                    cursor.value.search.parsedTel.push(parsed.nationalNumber);
-                    cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.nationalFormat));
-                    cursor.value.search.parsedTel.push(parsed.internationalNumber);
-                    cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(parsed.internationalFormat));
-                  }
-                  cursor.value.search.parsedTel.push(PhoneNumberUtils.normalize(tel.value.toString()));
-                }
-              );
-              cursor.update(cursor.value);
-            }
-            cursor.continue();
-          } else {
-            next();
-          }
-        };
-      },
-      function upgrade12to13() {
-        if (DEBUG) debug("Add phone substring to the search index if appropriate for country");
-        if (this.substringMatching) {
-          scheduleValueUpgrade(function upgradeValue12to13(value) {
-            if (value.properties.tel) {
-              value.search.parsedTel = value.search.parsedTel || [];
-              value.properties.tel.forEach(
-                function(tel) {
-                  let normalized = PhoneNumberUtils.normalize(tel.value.toString());
-                  if (normalized) {
-                    if (this.substringMatching && normalized.length > this.substringMatching) {
-                      let sub = normalized.slice(-this.substringMatching);
-                      if (value.search.parsedTel.indexOf(sub) === -1) {
-                        if (DEBUG) debug("Adding substring index: " + tel + ", " + sub);
-                        value.search.parsedTel.push(sub);
-                      }
-                    }
-                  }
-                }.bind(this)
-              );
-              return true;
-            } else {
-              return false;
-            }
-          }.bind(this));
-        }
-        next();
-      },
-      function upgrade13to14() {
-        if (DEBUG) debug("Cleaning up empty substring entries in telMatch index");
-        scheduleValueUpgrade(function upgradeValue13to14(value) {
-          function removeEmptyStrings(value) {
-            if (value) {
-              const oldLength = value.length;
-              for (let i = 0; i < value.length; ++i) {
-                if (!value[i] || value[i] == "null") {
-                  value.splice(i, 1);
-                }
-              }
-              return oldLength !== value.length;
-            }
-          }
-
-          let modified = removeEmptyStrings(value.search.parsedTel);
-          let modified2 = removeEmptyStrings(value.search.tel);
-          return (modified || modified2);
-        });
-
-        next();
-      },
-      function upgrade14to15() {
-        if (DEBUG) debug("Fix array properties saved as scalars");
-        const ARRAY_PROPERTIES = ["photo", "adr", "email", "url", "impp", "tel",
-                                 "name", "honorificPrefix", "givenName",
-                                 "additionalName", "familyName", "honorificSuffix",
-                                 "nickname", "category", "org", "jobTitle",
-                                 "note", "key"];
-        const PROPERTIES_WITH_TYPE = ["adr", "email", "url", "impp", "tel"];
-
-        scheduleValueUpgrade(function upgradeValue14to15(value) {
-          let changed = false;
-
-          let props = value.properties;
-          for (let prop of ARRAY_PROPERTIES) {
-            if (props[prop]) {
-              if (!Array.isArray(props[prop])) {
-                value.properties[prop] = [props[prop]];
-                changed = true;
-              }
-              if (PROPERTIES_WITH_TYPE.indexOf(prop) !== -1) {
-                let subprop = value.properties[prop];
-                for (let i = 0; i < subprop.length; ++i) {
-                  if (!Array.isArray(subprop[i].type)) {
-                    value.properties[prop][i].type = [subprop[i].type];
-                    changed = true;
-                  }
-                }
-              }
-            }
-          }
-
-          return changed;
-        });
-
-        next();
-      },
-      function upgrade15to16() {
-        if (DEBUG) debug("Fix Date properties");
-        const DATE_PROPERTIES = ["bday", "anniversary"];
-
-        scheduleValueUpgrade(function upgradeValue15to16(value) {
-          let changed = false;
-          let props = value.properties;
-          for (let prop of DATE_PROPERTIES) {
-            if (props[prop] && !(props[prop] instanceof Date)) {
-              value.properties[prop] = new Date(props[prop]);
-              changed = true;
-            }
-          }
-
-          return changed;
-        });
-
-        next();
-      },
-      function upgrade16to17() {
-        if (DEBUG) debug("Fix array with null values");
-        const ARRAY_PROPERTIES = ["photo", "adr", "email", "url", "impp", "tel",
-                                 "name", "honorificPrefix", "givenName",
-                                 "additionalName", "familyName", "honorificSuffix",
-                                 "nickname", "category", "org", "jobTitle",
-                                 "note", "key"];
-
-        const PROPERTIES_WITH_TYPE = ["adr", "email", "url", "impp", "tel"];
-
-        const DATE_PROPERTIES = ["bday", "anniversary"];
-
-        scheduleValueUpgrade(function upgradeValue16to17(value) {
-          let changed;
-
-          function filterInvalidValues(val) {
-            let shouldKeep = val != null; // null or undefined
-            if (!shouldKeep) {
-              changed = true;
-            }
-            return shouldKeep;
-          }
-
-          function filteredArray(array) {
-            return array.filter(filterInvalidValues);
-          }
-
-          let props = value.properties;
-
-          for (let prop of ARRAY_PROPERTIES) {
-
-            // properties that were empty strings weren't converted to arrays
-            // in upgrade14to15
-            if (props[prop] != null && !Array.isArray(props[prop])) {
-              props[prop] = [props[prop]];
-              changed = true;
-            }
-
-            if (props[prop] && props[prop].length) {
-              props[prop] = filteredArray(props[prop]);
-
-              if (PROPERTIES_WITH_TYPE.indexOf(prop) !== -1) {
-                let subprop = props[prop];
-
-                for (let i = 0; i < subprop.length; ++i) {
-                  let curSubprop = subprop[i];
-                  // upgrade14to15 transformed type props into an array
-                  // without checking invalid values
-                  if (curSubprop.type) {
-                    curSubprop.type = filteredArray(curSubprop.type);
-                  }
-                }
-              }
-            }
-          }
-
-          for (let prop of DATE_PROPERTIES) {
-            if (props[prop] != null && !(props[prop] instanceof Date)) {
-              // props[prop] is probably '' and wasn't converted
-              // in upgrade15to16
-              props[prop] = null;
-              changed = true;
-            }
-          }
-
-          if (changed) {
-            value.properties = props;
-            return true;
-          } else {
-            return false;
-          }
-        });
-
-        next();
-      },
-      function upgrade17to18() {
-        // this upgrade function has been moved to the next upgrade path because
-        // a previous version of it had a bug
-        next();
-      },
-      function upgrade18to19() {
-        if (DEBUG) {
-          debug("Adding the name index");
-        }
-
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-
-        // an earlier version of this code could have run, so checking whether
-        // the index exists
-        if (!objectStore.indexNames.contains("name")) {
-          objectStore.createIndex("name", "properties.name", { multiEntry: true });
-          objectStore.createIndex("nameLowerCase", "search.name", { multiEntry: true });
-        }
-
-        scheduleValueUpgrade(function upgradeValue18to19(value) {
-          value.search.name = [];
-          if (value.properties.name) {
-            value.properties.name.forEach(function addNameIndex(name) {
-              var lowerName = name.toLowerCase();
-              // an earlier version of this code could have added it already
-              if (value.search.name.indexOf(lowerName) === -1) {
-                value.search.name.push(lowerName);
-              }
-            });
-          }
-          return true;
-        });
-
-        next();
-      },
-      function upgrade19to20() {
-        if (DEBUG) debug("upgrade19to20 create schema(phonetic)");
-        if (!objectStore) {
-          objectStore = aTransaction.objectStore(STORE_NAME);
-        }
-        objectStore.createIndex("phoneticFamilyName", "properties.phoneticFamilyName", { multiEntry: true });
-        objectStore.createIndex("phoneticGivenName", "properties.phoneticGivenName", { multiEntry: true });
-        objectStore.createIndex("phoneticFamilyNameLowerCase", "search.phoneticFamilyName", { multiEntry: true });
-        objectStore.createIndex("phoneticGivenNameLowerCase",  "search.phoneticGivenName",  { multiEntry: true });
-        next();
-      },
-    ];
-
-    let index = aOldVersion;
-    let outer = this;
-
-    /* This function runs all upgrade functions that are in the
-     * valueUpgradeSteps array. These functions have the following properties:
-     * - they must be synchronous
-     * - they must take the value as parameter and modify it directly. They
-     *   must not create a new object.
-     * - they must return a boolean true/false; true if the value was actually
-     *   changed
-     */
-    function runValueUpgradeSteps(done) {
-      if (DEBUG) debug("Running the value upgrade functions.");
-      if (!objectStore) {
-        objectStore = aTransaction.objectStore(STORE_NAME);
-      }
-      objectStore.openCursor().onsuccess = function(event) {
-        let cursor = event.target.result;
-        if (cursor) {
-          let changed = false;
-          let oldValue;
-          let value = cursor.value;
-          if (DEBUG) {
-            oldValue = JSON.stringify(value);
-          }
-          valueUpgradeSteps.forEach(function(upgradeFunc, i) {
-            if (DEBUG) debug("Running upgrade function " + i);
-            changed = upgradeFunc(value) || changed;
-          });
-
-          if (changed) {
-            cursor.update(value);
-          } else if (DEBUG) {
-            let newValue = JSON.stringify(value);
-            if (newValue !== oldValue) {
-              // oops something went wrong
-              debug("upgrade: `changed` was false and still the value changed! Aborting.");
-              aTransaction.abort();
-              return;
-            }
-          }
-          cursor.continue();
-        } else {
-          done();
-        }
-      };
-    }
-
-    function finish() {
-      // We always output this debug line because it's useful and the noise ratio
-      // very low.
-      debug("Upgrade finished");
-
-      outer.incrementRevision(aTransaction);
-    }
-
-    function next() {
-      if (index == aNewVersion) {
-        runValueUpgradeSteps(finish);
-        return;
-      }
-
-      try {
-        var i = index++;
-        if (DEBUG) debug("Upgrade step: " + i + "\n");
-        steps[i].call(outer);
-      } catch(ex) {
-        dump("Caught exception" + ex);
-        aTransaction.abort();
-        return;
-      }
-    }
-
-    function fail(why) {
-      why = why || "";
-      if (this.error) {
-        why += " (root cause: " + this.error.name + ")";
-      }
-
-      debug("Contacts DB upgrade error: " + why);
-      aTransaction.abort();
-    }
-
-    if (aNewVersion > steps.length) {
-      fail("No migration steps for the new version!");
-    }
-
-    this.cpuLock = Cc["@mozilla.org/power/powermanagerservice;1"]
-                     .getService(Ci.nsIPowerManagerService)
-                     .newWakeLock("cpu");
-
-    function unlockCPU() {
-      if (outer.cpuLock) {
-        if (DEBUG) debug("unlocking cpu wakelock");
-        outer.cpuLock.unlock();
-        outer.cpuLock = null;
-      }
-    }
-
-    aTransaction.addEventListener("complete", unlockCPU);
-    aTransaction.addEventListener("abort", unlockCPU);
-
-    next();
-  },
-
-  makeImport: function makeImport(aContact) {
-    let contact = {properties: {}};
-
-    contact.search = {
-      name:            [],
-      givenName:       [],
-      familyName:      [],
-      email:           [],
-      category:        [],
-      tel:             [],
-      exactTel:        [],
-      parsedTel:       [],
-      phoneticFamilyName:   [],
-      phoneticGivenName:    [],
-    };
-
-    for (let field in aContact.properties) {
-      contact.properties[field] = aContact.properties[field];
-      // Add search fields
-      if (aContact.properties[field] && contact.search[field]) {
-        for (let i = 0; i <= aContact.properties[field].length; i++) {
-          if (aContact.properties[field][i]) {
-            if (field == "tel" && aContact.properties[field][i].value) {
-              let number = aContact.properties.tel[i].value.toString();
-              let normalized = PhoneNumberUtils.normalize(number);
-              // We use an object here to avoid duplicates
-              let containsSearch = {};
-              let matchSearch = {};
-
-              if (normalized) {
-                // exactTel holds normalized version of entered phone number.
-                // normalized: +1 (949) 123 - 4567 -> +19491234567
-                contact.search.exactTel.push(normalized);
-                // matchSearch holds normalized version of entered phone number,
-                // nationalNumber, nationalFormat, internationalNumber, internationalFormat
-                matchSearch[normalized] = 1;
-                let parsedNumber = PhoneNumberUtils.parse(number);
-                if (parsedNumber) {
-                  if (DEBUG) {
-                    debug("InternationalFormat: " + parsedNumber.internationalFormat);
-                    debug("InternationalNumber: " + parsedNumber.internationalNumber);
-                    debug("NationalNumber: " + parsedNumber.nationalNumber);
-                    debug("NationalFormat: " + parsedNumber.nationalFormat);
-                    debug("NationalMatchingFormat: " + parsedNumber.nationalMatchingFormat);
-                  }
-                  matchSearch[parsedNumber.nationalNumber] = 1;
-                  matchSearch[parsedNumber.internationalNumber] = 1;
-                  matchSearch[PhoneNumberUtils.normalize(parsedNumber.nationalFormat)] = 1;
-                  matchSearch[PhoneNumberUtils.normalize(parsedNumber.internationalFormat)] = 1;
-                  matchSearch[PhoneNumberUtils.normalize(parsedNumber.nationalMatchingFormat)] = 1;
-                } else if (this.substringMatching && normalized.length > this.substringMatching) {
-                  matchSearch[normalized.slice(-this.substringMatching)] = 1;
-                }
-
-                // containsSearch holds incremental search values for:
-                // normalized number and national format
-                for (let i = 0; i < normalized.length; i++) {
-                  containsSearch[normalized.substring(i, normalized.length)] = 1;
-                }
-                if (parsedNumber && parsedNumber.nationalFormat) {
-                  let number = PhoneNumberUtils.normalize(parsedNumber.nationalFormat);
-                  for (let i = 0; i < number.length; i++) {
-                    containsSearch[number.substring(i, number.length)] = 1;
-                  }
-                }
-              }
-              for (let num in containsSearch) {
-                if (num && num != "null") {
-                  contact.search.tel.push(num);
-                }
-              }
-              for (let num in matchSearch) {
-                if (num && num != "null") {
-                  contact.search.parsedTel.push(num);
-                }
-              }
-            } else if ((field == "impp" || field == "email") && aContact.properties[field][i].value) {
-              let value = aContact.properties[field][i].value;
-              if (value && typeof value == "string") {
-                contact.search[field].push(value.toLowerCase());
-              }
-            } else {
-              let val = aContact.properties[field][i];
-              if (typeof val == "string") {
-                contact.search[field].push(val.toLowerCase());
-              }
-            }
-          }
-        }
-      }
-    }
-
-    contact.updated = aContact.updated;
-    contact.published = aContact.published;
-    contact.id = aContact.id;
-
-    return contact;
-  },
-
-  updateRecordMetadata: function updateRecordMetadata(record) {
-    if (!record.id) {
-      Cu.reportError("Contact without ID");
-    }
-    if (!record.published) {
-      record.published = new Date();
-    }
-    record.updated = new Date();
-  },
-
-  removeObjectFromCache: function CDB_removeObjectFromCache(aObjectId, aCallback, aFailureCb) {
-    if (DEBUG) debug("removeObjectFromCache: " + aObjectId);
-    if (!aObjectId) {
-      if (DEBUG) debug("No object ID passed");
-      return;
-    }
-    this.newTxn("readwrite", this.dbStoreNames, function(txn, stores) {
-      let store = txn.objectStore(SAVED_GETALL_STORE_NAME);
-      store.openCursor().onsuccess = function(e) {
-        let cursor = e.target.result;
-        if (cursor) {
-          for (let i = 0; i < cursor.value.length; ++i) {
-            if (cursor.value[i] == aObjectId) {
-              if (DEBUG) debug("id matches cache");
-              cursor.value.splice(i, 1);
-              cursor.update(cursor.value);
-              break;
-            }
-          }
-          cursor.continue();
-        } else {
-          aCallback(txn);
-        }
-      }.bind(this);
-    }.bind(this), null, aFailureCb);
-  },
-
-  incrementRevision: function CDB_incrementRevision(txn) {
-    let revStore = txn.objectStore(REVISION_STORE);
-    revStore.get(REVISION_KEY).onsuccess = function(e) {
-      revStore.put(parseInt(e.target.result, 10) + 1, REVISION_KEY);
-    };
-  },
-
-  saveContact: function CDB_saveContact(aContact, successCb, errorCb) {
-    let contact = this.makeImport(aContact);
-    this.newTxn("readwrite", this.dbStoreNames, function (txn, stores) {
-      if (DEBUG) debug("Going to update" + JSON.stringify(contact));
-      let store = txn.objectStore(STORE_NAME);
-
-      // Look up the existing record and compare the update timestamp.
-      // If no record exists, just add the new entry.
-      let newRequest = store.get(contact.id);
-      newRequest.onsuccess = function (event) {
-        if (!event.target.result) {
-          if (DEBUG) debug("new record!")
-          this.updateRecordMetadata(contact);
-          store.put(contact);
-        } else {
-          if (DEBUG) debug("old record!")
-          if (new Date(typeof contact.updated === "undefined" ? 0 : contact.updated) < new Date(event.target.result.updated)) {
-            if (DEBUG) debug("rev check fail!");
-            txn.abort();
-            return;
-          } else {
-            if (DEBUG) debug("rev check OK");
-            contact.published = event.target.result.published;
-            contact.updated = new Date();
-            store.put(contact);
-          }
-        }
-        // Invalidate the entire cache. It will be incrementally regenerated on demand
-        // See getCacheForQuery
-        let getAllStore = txn.objectStore(SAVED_GETALL_STORE_NAME);
-        getAllStore.clear().onerror = errorCb;
-      }.bind(this);
-
-      this.incrementRevision(txn);
-    }.bind(this), successCb, errorCb);
-  },
-
-  removeContact: function removeContact(aId, aSuccessCb, aErrorCb) {
-    if (DEBUG) debug("removeContact: " + aId);
-    this.removeObjectFromCache(aId, function(txn) {
-      let store = txn.objectStore(STORE_NAME)
-      store.delete(aId).onsuccess = function() {
-        aSuccessCb();
-      };
-      this.incrementRevision(txn);
-    }.bind(this), aErrorCb);
-  },
-
-  clear: function clear(aSuccessCb, aErrorCb) {
-    this.newTxn("readwrite", STORE_NAME, function (txn, store) {
-      if (DEBUG) debug("Going to clear all!");
-      store.clear();
-      this.incrementRevision(txn);
-    }.bind(this), aSuccessCb, aErrorCb);
-  },
-
-  createCacheForQuery: function CDB_createCacheForQuery(aQuery, aSuccessCb, aFailureCb) {
-    this.find(function (aContacts) {
-      if (aContacts) {
-        let contactsArray = [];
-        for (let i in aContacts) {
-          contactsArray.push(aContacts[i]);
-        }
-
-        let contactIdsArray = contactsArray.map(el => el.id);
-
-        // save contact ids in cache
-        this.newTxn("readwrite", SAVED_GETALL_STORE_NAME, function(txn, store) {
-          store.put(contactIdsArray, aQuery);
-        }, null, aFailureCb);
-
-        // send full contacts
-        aSuccessCb(contactsArray, true);
-      } else {
-        aSuccessCb([], true);
-      }
-    }.bind(this),
-    function (aErrorMsg) { aFailureCb(aErrorMsg); },
-    JSON.parse(aQuery));
-  },
-
-  getCacheForQuery: function CDB_getCacheForQuery(aQuery, aSuccessCb, aFailureCb) {
-    if (DEBUG) debug("getCacheForQuery");
-    // Here we try to get the cached results for query `aQuery'. If they don't
-    // exist, it means the cache was invalidated and needs to be recreated, so
-    // we do that. Otherwise, we just return the existing cache.
-    this.newTxn("readonly", SAVED_GETALL_STORE_NAME, function(txn, store) {
-      let req = store.get(aQuery);
-      req.onsuccess = function(e) {
-        if (e.target.result) {
-          if (DEBUG) debug("cache exists");
-          aSuccessCb(e.target.result, false);
-        } else {
-          if (DEBUG) debug("creating cache for query " + aQuery);
-          this.createCacheForQuery(aQuery, aSuccessCb);
-        }
-      }.bind(this);
-      req.onerror = function(e) {
-        aFailureCb(e.target.errorMessage);
-      };
-    }.bind(this), null, aFailureCb);
-  },
-
-  sendNow: function CDB_sendNow(aCursorId) {
-    if (aCursorId in this._dispatcher) {
-      this._dispatcher[aCursorId].sendNow();
-    }
-  },
-
-  clearDispatcher: function CDB_clearDispatcher(aCursorId) {
-    if (DEBUG) debug("clearDispatcher: " + aCursorId);
-    if (aCursorId in this._dispatcher) {
-      delete this._dispatcher[aCursorId];
-    }
-  },
-
-  getAll: function CDB_getAll(aSuccessCb, aFailureCb, aOptions, aCursorId) {
-    if (DEBUG) debug("getAll")
-    let optionStr = JSON.stringify(aOptions);
-    this.getCacheForQuery(optionStr, function(aCachedResults, aFullContacts) {
-      // aFullContacts is true if the cache didn't exist and had to be created.
-      // In that case, we receive the full contacts since we already have them
-      // in memory to create the cache. This allows us to avoid accessing the
-      // object store again.
-      if (aCachedResults && aCachedResults.length > 0) {
-        let newTxnFn = this.newTxn.bind(this);
-        let clearDispatcherFn = this.clearDispatcher.bind(this, aCursorId);
-        this._dispatcher[aCursorId] = new ContactDispatcher(aCachedResults, aFullContacts,
-                                                            aSuccessCb, newTxnFn,
-                                                            clearDispatcherFn, aFailureCb);
-        this._dispatcher[aCursorId].sendNow();
-      } else { // no contacts
-        if (DEBUG) debug("query returned no contacts");
-        aSuccessCb(null);
-      }
-    }.bind(this), aFailureCb);
-  },
-
-  getRevision: function CDB_getRevision(aSuccessCb, aErrorCb) {
-    if (DEBUG) debug("getRevision");
-    this.newTxn("readonly", REVISION_STORE, function (txn, store) {
-      store.get(REVISION_KEY).onsuccess = function (e) {
-        aSuccessCb(e.target.result);
-      };
-    },null, aErrorCb);
-  },
-
-  getCount: function CDB_getCount(aSuccessCb, aErrorCb) {
-    if (DEBUG) debug("getCount");
-    this.newTxn("readonly", STORE_NAME, function (txn, store) {
-      store.count().onsuccess = function (e) {
-        aSuccessCb(e.target.result);
-      };
-    }, null, aErrorCb);
-  },
-
-  getSortByParam: function CDB_getSortByParam(aFindOptions) {
-    switch (aFindOptions.sortBy) {
-      case "familyName":
-        return [ "familyName", "givenName" ];
-      case "givenName":
-        return [ "givenName" , "familyName" ];
-      case "phoneticFamilyName":
-        return [ "phoneticFamilyName" , "phoneticGivenName" ];
-      case "phoneticGivenName":
-        return [ "phoneticGivenName" , "phoneticFamilyName" ];
-      default:
-        return [ "givenName" , "familyName" ];
-    }
-  },
-
-  /*
-   * Sorting the contacts by sortBy field. aSortBy can either be familyName or givenName.
-   * If 2 entries have the same sortyBy field or no sortBy field is present, we continue
-   * sorting with the other sortyBy field.
-   */
-  sortResults: function CDB_sortResults(aResults, aFindOptions) {
-    if (!aFindOptions)
-      return;
-    if (aFindOptions.sortBy != "undefined") {
-      const sortOrder = aFindOptions.sortOrder;
-      const sortBy = this.getSortByParam(aFindOptions);
-
-      aResults.sort(function (a, b) {
-        let x, y;
-        let result = 0;
-        let xIndex = 0;
-        let yIndex = 0;
-
-        do {
-          while (xIndex < sortBy.length && !x) {
-            x = a.properties[sortBy[xIndex]];
-            if (x) {
-              x = x.join("").toLowerCase();
-            }
-            xIndex++;
-          }
-          while (yIndex < sortBy.length && !y) {
-            y = b.properties[sortBy[yIndex]];
-            if (y) {
-              y = y.join("").toLowerCase();
-            }
-            yIndex++;
-          }
-          if (!x) {
-            if (!y) {
-              let px, py;
-              px = JSON.stringify(a.published);
-              py = JSON.stringify(b.published);
-              if (px && py) {
-                return px.localeCompare(py);
-              }
-            } else {
-              return sortOrder == 'descending' ? 1 : -1;
-            }
-          }
-          if (!y) {
-            return sortOrder == "ascending" ? 1 : -1;
-          }
-
-          result = x.localeCompare(y);
-          x = null;
-          y = null;
-        } while (result == 0);
-
-        return sortOrder == "ascending" ? result : -result;
-      });
-    }
-    if (aFindOptions.filterLimit && aFindOptions.filterLimit != 0) {
-      if (DEBUG) debug("filterLimit is set: " + aFindOptions.filterLimit);
-      aResults.splice(aFindOptions.filterLimit, aResults.length);
-    }
-  },
-
-  /**
-   * @param successCb
-   *        Callback function to invoke with result array.
-   * @param failureCb [optional]
-   *        Callback function to invoke when there was an error.
-   * @param options [optional]
-   *        Object specifying search options. Possible attributes:
-   *        - filterBy
-   *        - filterOp
-   *        - filterValue
-   *        - count
-   */
-  find: function find(aSuccessCb, aFailureCb, aOptions) {
-    if (DEBUG) debug("ContactDB:find val:" + aOptions.filterValue + " by: " + aOptions.filterBy + " op: " + aOptions.filterOp);
-    let self = this;
-    this.newTxn("readonly", STORE_NAME, function (txn, store) {
-      let filterOps = ["equals", "contains", "match", "startsWith"];
-      if (aOptions && (filterOps.indexOf(aOptions.filterOp) >= 0)) {
-        self._findWithIndex(txn, store, aOptions);
-      } else {
-        self._findAll(txn, store, aOptions);
-      }
-    }, aSuccessCb, aFailureCb);
-  },
-
-  _findWithIndex: function _findWithIndex(txn, store, options) {
-    if (DEBUG) debug("_findWithIndex: " + options.filterValue +" " + options.filterOp + " " + options.filterBy + " ");
-    let fields = options.filterBy;
-    for (let key in fields) {
-      if (DEBUG) debug("key: " + fields[key]);
-      if (!store.indexNames.contains(fields[key]) && fields[key] != "id") {
-        if (DEBUG) debug("Key not valid!" + fields[key] + ", " + JSON.stringify(store.indexNames));
-        txn.abort();
-        return;
-      }
-    }
-
-    // lookup for all keys
-    if (options.filterBy.length == 0) {
-      if (DEBUG) debug("search in all fields!" + JSON.stringify(store.indexNames));
-      for(let myIndex = 0; myIndex < store.indexNames.length; myIndex++) {
-        fields = Array.concat(fields, store.indexNames[myIndex])
-      }
-    }
-
-    // Sorting functions takes care of limit if set.
-    let limit = options.sortBy === 'undefined' ? options.filterLimit : null;
-
-    let filter_keys = fields.slice();
-    for (let key = filter_keys.shift(); key; key = filter_keys.shift()) {
-      let request;
-      let substringResult = {};
-      if (key == "id") {
-        // store.get would return an object and not an array
-        request = store.mozGetAll(options.filterValue);
-      } else if (key == "category") {
-        let index = store.index(key);
-        request = index.mozGetAll(options.filterValue, limit);
-      } else if (options.filterOp == "equals") {
-        if (DEBUG) debug("Getting index: " + key);
-        // case sensitive
-        let index = store.index(key);
-        let filterValue = options.filterValue;
-        if (key == "tel") {
-          filterValue = PhoneNumberUtils.normalize(filterValue,
-                                                   /*numbersOnly*/ true);
-        }
-        request = index.mozGetAll(filterValue, limit);
-      } else if (options.filterOp == "match") {
-        if (DEBUG) debug("match");
-        if (key != "tel") {
-          dump("ContactDB: 'match' filterOp only works on tel\n");
-          return txn.abort();
-        }
-
-        let index = store.index("telMatch");
-        let normalized = PhoneNumberUtils.normalize(options.filterValue,
-                                                    /*numbersOnly*/ true);
-
-        if (!normalized.length) {
-          dump("ContactDB: normalized filterValue is empty, can't perform match search.\n");
-          return txn.abort();
-        }
-
-        // Some countries need special handling for number matching. Bug 877302
-        if (this.substringMatching && normalized.length > this.substringMatching) {
-          let substring = normalized.slice(-this.substringMatching);
-          if (DEBUG) debug("Substring: " + substring);
-
-          let substringRequest = index.mozGetAll(substring, limit);
-
-          substringRequest.onsuccess = function (event) {
-            if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
-            for (let i in event.target.result) {
-              substringResult[event.target.result[i].id] = event.target.result[i];
-            }
-          }.bind(this);
-        } else if (normalized[0] !== "+") {
-          // We might have an international prefix like '00'
-          let parsed = PhoneNumberUtils.parse(normalized);
-          if (parsed && parsed.internationalNumber &&
-              parsed.nationalNumber  &&
-              parsed.nationalNumber !== normalized &&
-              parsed.internationalNumber !== normalized) {
-            if (DEBUG) debug("Search with " + parsed.internationalNumber);
-            let prefixRequest = index.mozGetAll(parsed.internationalNumber, limit);
-
-            prefixRequest.onsuccess = function (event) {
-              if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
-              for (let i in event.target.result) {
-                substringResult[event.target.result[i].id] = event.target.result[i];
-              }
-            }.bind(this);
-          }
-        }
-
-        request = index.mozGetAll(normalized, limit);
-      } else {
-        // XXX: "contains" should be handled separately, this is "startsWith"
-        if (options.filterOp === 'contains' && key !== 'tel') {
-          dump("ContactDB: 'contains' only works for 'tel'. Falling back " +
-               "to 'startsWith'.\n");
-        }
-        // not case sensitive
-        let lowerCase = options.filterValue.toString().toLowerCase();
-        if (key === "tel") {
-          let origLength = lowerCase.length;
-          let tmp = PhoneNumberUtils.normalize(lowerCase, /*numbersOnly*/ true);
-          if (tmp.length != origLength) {
-            let NON_SEARCHABLE_CHARS = /[^#+\*\d\s()-]/;
-            // e.g. number "123". find with "(123)" but not with "123a"
-            if (tmp === "" || NON_SEARCHABLE_CHARS.test(lowerCase)) {
-              if (DEBUG) debug("Call continue!");
-              continue;
-            }
-            lowerCase = tmp;
-          }
-        }
-        if (DEBUG) debug("lowerCase: " + lowerCase);
-        let range = IDBKeyRange.bound(lowerCase, lowerCase + "\uFFFF");
-        let index = store.index(key + "LowerCase");
-        request = index.mozGetAll(range, limit);
-      }
-      if (!txn.result)
-        txn.result = {};
-
-      request.onsuccess = function (event) {
-        if (DEBUG) debug("Request successful. Record count: " + event.target.result.length);
-        if (Object.keys(substringResult).length > 0) {
-          for (let attrname in substringResult) {
-            event.target.result[attrname] = substringResult[attrname];
-          }
-        }
-        this.sortResults(event.target.result, options);
-        for (let i in event.target.result)
-          txn.result[event.target.result[i].id] = exportContact(event.target.result[i]);
-      }.bind(this);
-    }
-  },
-
-  _findAll: function _findAll(txn, store, options) {
-    if (DEBUG) debug("ContactDB:_findAll:  " + JSON.stringify(options));
-    if (!txn.result)
-      txn.result = {};
-    // Sorting functions takes care of limit if set.
-    let limit = options.sortBy === 'undefined' ? options.filterLimit : null;
-    store.mozGetAll(null, limit).onsuccess = function (event) {
-      if (DEBUG) debug("Request successful. Record count:" + event.target.result.length);
-      this.sortResults(event.target.result, options);
-      for (let i in event.target.result) {
-        txn.result[event.target.result[i].id] = exportContact(event.target.result[i]);
-      }
-    }.bind(this);
-  },
-
-  // Enable special phone number substring matching. Does not update existing DB entries.
-  enableSubstringMatching: function enableSubstringMatching(aDigits) {
-    if (DEBUG) debug("MCC enabling substring matching " + aDigits);
-    this.substringMatching = aDigits;
-  },
-
-  disableSubstringMatching: function disableSubstringMatching() {
-    if (DEBUG) debug("MCC disabling substring matching");
-    delete this.substringMatching;
-  },
-
-  init: function init() {
-    this.initDBHelper(DB_NAME, DB_VERSION, [STORE_NAME, SAVED_GETALL_STORE_NAME, REVISION_STORE]);
-  }
-};
deleted file mode 100644
--- a/dom/contacts/fallback/ContactService.jsm
+++ /dev/null
@@ -1,266 +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 DEBUG = false;
-function debug(s) { dump("-*- Fallback ContactService component: " + s + "\n"); }
-
-const Cu = Components.utils;
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-this.EXPORTED_SYMBOLS = ["ContactService"];
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "ContactDB",
-                                  "resource://gre/modules/ContactDB.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PhoneNumberUtils",
-                                  "resource://gre/modules/PhoneNumberUtils.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
-                                   "@mozilla.org/parentprocessmessagemanager;1",
-                                   "nsIMessageListenerManager");
-
-
-/* all exported symbols need to be bound to this on B2G - Bug 961777 */
-var ContactService = this.ContactService = {
-  init: function() {
-    if (DEBUG) debug("Init");
-    this._messages = ["Contacts:Find", "Contacts:GetAll", "Contacts:GetAll:SendNow",
-                      "Contacts:Clear", "Contact:Save",
-                      "Contact:Remove", "Contacts:RegisterForMessages",
-                      "child-process-shutdown", "Contacts:GetRevision",
-                      "Contacts:GetCount"];
-    this._children = [];
-    this._cursors = new Map();
-    this._messages.forEach(function(msgName) {
-      ppmm.addMessageListener(msgName, this);
-    }.bind(this));
-
-    this._db = new ContactDB();
-    this._db.init();
-
-    this.configureSubstringMatching();
-
-    Services.obs.addObserver(this, "profile-before-change", false);
-    Services.prefs.addObserver("ril.lastKnownSimMcc", this, false);
-  },
-
-  observe: function(aSubject, aTopic, aData) {
-    if (aTopic === 'profile-before-change') {
-      this._messages.forEach(function(msgName) {
-        ppmm.removeMessageListener(msgName, this);
-      }.bind(this));
-      Services.obs.removeObserver(this, "profile-before-change");
-      Services.prefs.removeObserver("dom.phonenumber.substringmatching", this);
-      ppmm = null;
-      this._messages = null;
-      if (this._db)
-        this._db.close();
-      this._db = null;
-      this._children = null;
-      this._cursors = null;
-    } else if (aTopic === 'nsPref:changed' && aData === "ril.lastKnownSimMcc") {
-      this.configureSubstringMatching();
-    }
-  },
-
-  configureSubstringMatching: function() {
-    let countryName = PhoneNumberUtils.getCountryName();
-    if (Services.prefs.getPrefType("dom.phonenumber.substringmatching." + countryName) == Ci.nsIPrefBranch.PREF_INT) {
-      let val = Services.prefs.getIntPref("dom.phonenumber.substringmatching." + countryName);
-      if (val) {
-        this._db.enableSubstringMatching(val);
-        return;
-      }
-    }
-    // if we got here, we dont have a substring setting
-    // for this country, so disable substring matching
-    this._db.disableSubstringMatching();
-  },
-
-  assertPermission: function(aMessage, aPerm) {
-    if (!aMessage.target.assertPermission(aPerm)) {
-      Cu.reportError("Contacts message " + aMessage.name +
-                     " from a content process with no" + aPerm + " privileges.");
-      return false;
-    }
-    return true;
-  },
-
-  broadcastMessage: function broadcastMessage(aMsgName, aContent) {
-    this._children.forEach(function(msgMgr) {
-      msgMgr.sendAsyncMessage(aMsgName, aContent);
-    });
-  },
-
-  receiveMessage: function(aMessage) {
-    if (DEBUG) debug("receiveMessage " + aMessage.name);
-    let mm = aMessage.target;
-    let msg = aMessage.data;
-    let cursorList;
-
-    switch (aMessage.name) {
-      case "Contacts:Find":
-        if (!this.assertPermission(aMessage, "contacts-read")) {
-          return null;
-        }
-        let result = [];
-        this._db.find(
-          function(contacts) {
-            for (let i in contacts) {
-              result.push(contacts[i]);
-            }
-
-            if (DEBUG) debug("result:" + JSON.stringify(result));
-            mm.sendAsyncMessage("Contacts:Find:Return:OK", {requestID: msg.requestID, contacts: result});
-          }.bind(this),
-          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:Find:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this),
-          msg.options.findOptions);
-        break;
-      case "Contacts:GetAll":
-        if (!this.assertPermission(aMessage, "contacts-read")) {
-          return null;
-        }
-        cursorList = this._cursors.get(mm);
-        if (!cursorList) {
-          cursorList = [];
-          this._cursors.set(mm, cursorList);
-        }
-        cursorList.push(msg.cursorId);
-
-        this._db.getAll(
-          function(aContacts) {
-            try {
-              mm.sendAsyncMessage("Contacts:GetAll:Next", {cursorId: msg.cursorId, contacts: aContacts});
-              if (aContacts === null) {
-                let cursorList = this._cursors.get(mm);
-                let index = cursorList.indexOf(msg.cursorId);
-                cursorList.splice(index, 1);
-              }
-            } catch (e) {
-              if (DEBUG) debug("Child is dead, DB should stop sending contacts");
-              throw e;
-            }
-          }.bind(this),
-          function(aErrorMsg) { mm.sendAsyncMessage("Contacts:GetAll:Return:KO", { requestID: msg.cursorId, errorMsg: aErrorMsg }); },
-          msg.findOptions, msg.cursorId);
-        break;
-      case "Contacts:GetAll:SendNow":
-        // sendNow is a no op if there isn't an existing cursor in the DB, so we
-        // don't need to assert the permission again.
-        this._db.sendNow(msg.cursorId);
-        break;
-      case "Contact:Save":
-        if (msg.options.reason === "create") {
-          if (!this.assertPermission(aMessage, "contacts-create")) {
-            return null;
-          }
-        } else {
-          if (!this.assertPermission(aMessage, "contacts-write")) {
-            return null;
-          }
-        }
-        this._db.saveContact(
-          msg.options.contact,
-          function() {
-            mm.sendAsyncMessage("Contact:Save:Return:OK", { requestID: msg.requestID, contactID: msg.options.contact.id });
-            this.broadcastMessage("Contact:Changed", { contactID: msg.options.contact.id, reason: msg.options.reason });
-          }.bind(this),
-          function(aErrorMsg) { mm.sendAsyncMessage("Contact:Save:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
-        );
-        break;
-      case "Contact:Remove":
-        if (!this.assertPermission(aMessage, "contacts-write")) {
-          return null;
-        }
-        this._db.removeContact(
-          msg.options.id,
-          function() {
-            mm.sendAsyncMessage("Contact:Remove:Return:OK", { requestID: msg.requestID, contactID: msg.options.id });
-            this.broadcastMessage("Contact:Changed", { contactID: msg.options.id, reason: "remove" });
-          }.bind(this),
-          function(aErrorMsg) { mm.sendAsyncMessage("Contact:Remove:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg }); }.bind(this)
-        );
-        break;
-      case "Contacts:Clear":
-        if (!this.assertPermission(aMessage, "contacts-write")) {
-          return null;
-        }
-        this._db.clear(
-          function() {
-            mm.sendAsyncMessage("Contacts:Clear:Return:OK", { requestID: msg.requestID });
-            this.broadcastMessage("Contact:Changed", { reason: "remove" });
-          }.bind(this),
-          function(aErrorMsg) {
-            mm.sendAsyncMessage("Contacts:Clear:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
-          }.bind(this)
-        );
-        break;
-      case "Contacts:GetRevision":
-        if (!this.assertPermission(aMessage, "contacts-read")) {
-          return null;
-        }
-        this._db.getRevision(
-          function(revision) {
-            mm.sendAsyncMessage("Contacts:Revision", {
-              requestID: msg.requestID,
-              revision: revision
-            });
-          },
-          function(aErrorMsg) {
-            mm.sendAsyncMessage("Contacts:GetRevision:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
-          }.bind(this)
-        );
-        break;
-      case "Contacts:GetCount":
-        if (!this.assertPermission(aMessage, "contacts-read")) {
-          return null;
-        }
-        this._db.getCount(
-          function(count) {
-            mm.sendAsyncMessage("Contacts:Count", {
-              requestID: msg.requestID,
-              count: count
-            });
-          },
-          function(aErrorMsg) {
-            mm.sendAsyncMessage("Contacts:Count:Return:KO", { requestID: msg.requestID, errorMsg: aErrorMsg });
-          }.bind(this)
-        );
-        break;
-      case "Contacts:RegisterForMessages":
-        if (!aMessage.target.assertPermission("contacts-read")) {
-          return null;
-        }
-        if (DEBUG) debug("Register!");
-        if (this._children.indexOf(mm) == -1) {
-          this._children.push(mm);
-        }
-        break;
-      case "child-process-shutdown":
-        if (DEBUG) debug("Unregister");
-        let index = this._children.indexOf(mm);
-        if (index != -1) {
-          if (DEBUG) debug("Unregister index: " + index);
-          this._children.splice(index, 1);
-        }
-        cursorList = this._cursors.get(mm);
-        if (cursorList) {
-          for (let id of cursorList) {
-            this._db.clearDispatcher(id);
-          }
-          this._cursors.delete(mm);
-        }
-        break;
-      default:
-        if (DEBUG) debug("WRONG MESSAGE NAME: " + aMessage.name);
-    }
-  }
-}
-
-ContactService.init();
deleted file mode 100644
--- a/dom/contacts/moz.build
+++ /dev/null
@@ -1,20 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-# Disable the tests on Android for now (bug 927869)
-if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
-    MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
-    MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
-
-EXTRA_COMPONENTS += [
-    'ContactManager.js',
-    'ContactManager.manifest',
-]
-
-EXTRA_JS_MODULES += [
-    'fallback/ContactDB.jsm',
-    'fallback/ContactService.jsm'
-]
deleted file mode 100644
--- a/dom/contacts/tests/chrome.ini
+++ /dev/null
@@ -1,44 +0,0 @@
-[DEFAULT]
-skip-if = toolkit == 'android' # Bug 1287455: takes too long to complete on Android
-support-files =
-  shared.js
-  file_contacts_basics.html
-  file_contacts_basics2.html
-  file_contacts_blobs.html
-  file_contacts_events.html
-  file_contacts_getall.html
-  file_contacts_getall2.html
-  file_contacts_international.html
-  file_contacts_substringmatching.html
-  file_contacts_substringmatchingVE.html
-  file_contacts_substringmatchingCL.html
-  test_migration_chrome.js
-  file_migration.html
-
-# renaming with "_a_" to execure before others, since we hardcode open of 
-# database and this messes up with mozContacts when done after mozContacts
-# did opened the database. those should really be xpcshell and not chrome
-# mochitests maybe ...
-[test_contacts_a_shutdown.xul]
-skip-if = buildapp == 'b2g'
-[test_contacts_a_upgrade.xul]
-skip-if = buildapp == 'b2g'
-[test_contacts_a_cache.xul]
-skip-if = buildapp == 'b2g'
-[test_contacts_basics.html]
-skip-if = (toolkit == 'gonk' && debug) #debug-only failure
-[test_contacts_basics2.html]
-skip-if = (toolkit == 'gonk' && debug) || (os == 'win' && os_version == '5.1') #debug-only failure, bug 967258 on XP
-[test_contacts_blobs.html]
-skip-if = (toolkit == 'gonk' && debug) #debug-only failure
-[test_contacts_events.html]
-[test_contacts_getall.html]
-skip-if = (toolkit == 'gonk' && debug) #debug-only failure
-[test_contacts_getall2.html]
-skip-if = (toolkit == 'gonk' && debug) #debug-only failure
-[test_contacts_international.html]
-[test_contacts_substringmatching.html]
-[test_contacts_substringmatchingVE.html]
-[test_contacts_substringmatchingCL.html]
-[test_migration.html]
-  support-files +=
deleted file mode 100644
--- a/dom/contacts/tests/file_contacts_basics.html
+++ /dev/null
@@ -1,787 +0,0 @@
-<!DOCTYPE html>
-<html>
-<!--
-https://bugzilla.mozilla.org/show_bug.cgi?id=674720
--->
-<head>
-  <title>Test for Bug 674720 WebContacts</title>
-  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
-  <script type="text/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
-</head>
-<body>
-
-<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=674720">Mozilla Bug 674720</a>
-<p id="display"></p>
-<div id="content" style="display: none">
-
-</div>
-<pre id="test">
-<script type="text/javascript;version=1.8" src="http://mochi.test:8888/tests/dom/contacts/tests/shared.js"></script>
-<script class="testbody" type="text/javascript">
-"use strict";
-
-var ok = parent.ok;
-var is = parent.is;
-
-var initialRev;
-
-function checkRevision(revision, msg, then) {
-  var revReq = mozContacts.getRevision();
-  revReq.onsuccess = function(e) {
-    is(e.target.result, initialRev+revision, msg);
-    then();
-  };
-  // The revision function isn't supported on Android so treat on failure as success
-  if (isAndroid) {
-    revReq.onerror = function(e) {
-      then();
-    };
-  } else {
-    revReq.onerror = onFailure;
-  }
-}
-
-var req;
-
-var steps = [
-  function() {
-    req = mozContacts.getRevision();
-    req.onsuccess = function(e) {
-      initialRev = e.target.result;
-      next();
-    };
-
-    // Android does not support the revision function. Treat errors as success.
-    if (isAndroid) {
-      req.onerror = function(e) {
-        initialRev = 0;
-        next();
-      };
-    } else {
-      req.onerror = onFailure;
-    }
-  },
-  function () {
-    ok(true, "Deleting database");
-    checkRevision(0, "Initial revision is 0", function() {
-      req = mozContacts.clear();
-      req.onsuccess = function () {
-        ok(true, "Deleted the database");
-        checkCount(0, "No contacts after clear", function() {
-          checkRevision(1, "Revision was incremented on clear", next);
-        });
-      };
-      req.onerror = onFailure;
-    });
-  },
-  function () {
-    ok(true, "Retrieving all contacts");
-    req = mozContacts.find(defaultOptions);
-    req.onsuccess = function () {
-      is(req.result.length, 0, "Empty database.");
-      checkRevision(1, "Revision was not incremented on find", next);
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Adding empty contact");
-    createResult1 = new mozContact({});
-    req = navigator.mozContacts.save(createResult1);
-    req.onsuccess = function () {
-      ok(createResult1.id, "The contact now has an ID.");
-      sample_id1 = createResult1.id;
-      checkCount(1, "1 contact after adding empty contact", function() {
-        checkRevision(2, "Revision was incremented on save", next);
-      });
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving all contacts");
-    req = mozContacts.find(defaultOptions);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "One contact.");
-      findResult1 = req.result[0];
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Deleting empty contact");
-    req = navigator.mozContacts.remove(findResult1);
-    req.onsuccess = function () {
-      var req2 = mozContacts.find(defaultOptions);
-      req2.onsuccess = function () {
-        is(req2.result.length, 0, "Empty Database.");
-        clearTemps();
-        checkRevision(3, "Revision was incremented on remove", next);
-      }
-      req2.onerror = onFailure;
-    }
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Adding a new contact1");
-    createResult1 = new mozContact(properties1);
-
-    mozContacts.oncontactchange = function(event) {
-      is(event.contactID, createResult1.id, "Same contactID");
-      is(event.reason, "create", "Same reason");
-      next();
-    }
-
-    req = navigator.mozContacts.save(createResult1);
-    req.onsuccess = function () {
-      ok(createResult1.id, "The contact now has an ID.");
-      sample_id1 = createResult1.id;
-      checkContacts(createResult1, properties1);
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring 1");
-    var options = {filterBy: ["givenName"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.givenName[1].substring(0,3)};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      // Some manual testing. Testint the testfunctions
-      // tel: [{type: ["work"], value: "123456", carrier: "testCarrier"} , {type: ["home", "fax"], value: "+55 (31) 9876-3456"}],
-      is(findResult1.tel[0].carrier, "testCarrier", "Same Carrier");
-      is(String(findResult1.tel[0].type), "work", "Same type");
-      is(findResult1.tel[0].value, "123456", "Same Value");
-      is(findResult1.tel[1].type[1], "fax", "Same type");
-      is(findResult1.tel[1].value, "+55 (31) 9876-3456", "Same Value");
-
-      is(findResult1.adr[0].countryName, "country 1", "Same country");
-
-      // email: [{type: ["work"], value: "x@y.com"}]
-      is(String(findResult1.email[0].type), "work", "Same Type");
-      is(findResult1.email[0].value, "x@y.com", "Same Value");
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Searching for exact email");
-    var options = {filterBy: ["email"],
-                   filterOp: "equals",
-                   filterValue: properties1.email[0].value};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(findResult1, createResult1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring and update");
-    mozContacts.oncontactchange = function(event) {
-       is(event.contactID, findResult1.id, "Same contactID");
-       is(event.reason, "update", "Same reason");
-     }
-    var options = {filterBy: ["givenName"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.givenName[0].substring(0,3)};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      findResult1.jobTitle = ["new Job"];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Adding a new contact");
-    mozContacts.oncontactchange = function(event) {
-       is(event.contactID, createResult2.id, "Same contactID");
-       is(event.reason, "create", "Same reason");
-     }
-    createResult2 = new mozContact({name: ["newName"]});
-    req = navigator.mozContacts.save(createResult2);
-    req.onsuccess = function () {
-      ok(createResult2.id, "The contact now has an ID.");
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring 2");
-    var options = {filterBy: ["givenName"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.givenName[0].substring(0,3)};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      checkContacts(createResult1, findResult1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function() {
-    ok(true, "Retrieving by name equality 1");
-    var options = {filterBy: ["name"],
-                   filterOp: "equals",
-                   filterValue: properties1.name[0]};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      checkContacts(createResult1, findResult1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function() {
-    ok(true, "Retrieving by name equality 2");
-    var options = {filterBy: ["name"],
-                   filterOp: "equals",
-                   filterValue: properties1.name[1]};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      checkContacts(createResult1, findResult1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function() {
-    ok(true, "Retrieving by name substring 1");
-    var options = {filterBy: ["name"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.name[0].substring(0,3).toLowerCase()};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      checkContacts(createResult1, findResult1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function() {
-    ok(true, "Retrieving by name substring 2");
-    var options = {filterBy: ["name"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.name[1].substring(0,3).toLowerCase()};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      checkContacts(createResult1, findResult1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Remove contact1");
-    mozContacts.oncontactchange = function(event) {
-      is(event.contactID, createResult1.id, "Same contactID");
-      is(event.reason, "remove", "Same reason");
-    }
-    req = navigator.mozContacts.remove(createResult1);
-    req.onsuccess = function () {
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring 3");
-    var options = {filterBy: ["givenName"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.givenName[1].substring(0,3)};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 0, "Found no contact.");
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Remove contact2");
-    mozContacts.oncontactchange = function(event) {
-      is(event.contactID, createResult2.id, "Same contactID");
-      is(event.reason, "remove", "Same reason");
-    }
-    req = navigator.mozContacts.remove(createResult2);
-    req.onsuccess = function () {
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring 4");
-    var options = {filterBy: ["givenName"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.givenName[1].substring(0,3)};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 0, "Found no contact.");
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Deleting database");
-    mozContacts.oncontactchange = function(event) {
-      is(event.contactID, "undefined", "Same contactID");
-      is(event.reason, "remove", "Same reason");
-    }
-    req = mozContacts.clear();
-    req.onsuccess = function () {
-      ok(true, "Deleted the database");
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Adding a new contact with properties1");
-    createResult1 = new mozContact(properties1);
-    mozContacts.oncontactchange = null;
-    req = navigator.mozContacts.save(createResult1);
-    req.onsuccess = function () {
-      ok(createResult1.id, "The contact now has an ID.");
-      sample_id1 = createResult1.id;
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring tel1");
-    var options = {filterBy: ["tel"],
-                   filterOp: "contains",
-                   filterValue: properties1.tel[1].value.substring(2,5)};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by tel exact");
-    var options = {filterBy: ["tel"],
-                   filterOp: "equals",
-                   filterValue: "+55 319 8 7 6 3456"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by tel exact with substring");
-    var options = {filterBy: ["tel"],
-                   filterOp: "equals",
-                   filterValue: "3456"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 0, "Found no contacts.");
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by tel exact with substring");
-    var options = {filterBy: ["tel"],
-                   filterOp: "equals",
-                   filterValue: "+55 (31)"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 0, "Found no contacts.");
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by tel match national number");
-    var options = {filterBy: ["tel"],
-                   filterOp: "match",
-                   filterValue: "3198763456"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by tel match national format");
-    var options = {filterBy: ["tel"],
-                   filterOp: "match",
-                   filterValue: "0451 491934"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by tel match entered number");
-    var options = {filterBy: ["tel"],
-                   filterOp: "match",
-                   filterValue: "123456"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by tel match international number");
-    var options = {filterBy: ["tel"],
-                   filterOp: "match",
-                   filterValue: "+55 31 98763456"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by match with field other than tel");
-    var options = {filterBy: ["givenName"],
-                   filterOp: "match",
-                   filterValue: "my friends call me 555-4040"};
-    req = mozContacts.find(options);
-    req.onsuccess = onUnwantedSuccess;
-    req.onerror = function() {
-      ok(true, "Failed");
-      next();
-    }
-  },
-  function () {
-    ok(true, "Retrieving by substring tel2");
-    var options = {filterBy: ["tel"],
-                   filterOp: "startsWith",
-                   filterValue: "9876"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring tel3");
-    var options = {filterBy: ["tel"],
-                   filterOp: "startsWith",
-                   filterValue: "98763456"};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring 5");
-    var options = {filterBy: ["givenName"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.givenName[0].substring(0,3)};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {
-    ok(true, "Retrieving by substring 6");
-    var options = {filterBy: ["familyName", "givenName"],
-                   filterOp: "startsWith",
-                   filterValue: properties1.givenName[0].substring(0,3)};
-    req = mozContacts.find(options);
-    req.onsuccess = function () {
-      is(req.result.length, 1, "Found exactly 1 contact.");
-      findResult1 = req.result[0];
-      ok(findResult1.id == sample_id1, "Same ID");
-      checkContacts(createResult1, properties1);
-      next();
-    };
-    req.onerror = onFailure;
-  },
-  function () {