Merge b2g-inbound to m-c on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Thu, 14 Nov 2013 20:57:32 -0500
changeset 154783 319c3d822ae4707f699b71bc3914170d251a1516
parent 154662 7b014f0f3b031ad57e2995d1f9ee04095c82bda5 (current diff)
parent 154782 e75b1e1185b29ed6b0922cf59eb8f6fcd6d821aa (diff)
child 154840 1e1b514a0f4b4c3193999302e22cebbf950c26f8
push id25653
push userryanvm@gmail.com
push dateFri, 15 Nov 2013 01:57:38 +0000
treeherdermozilla-central@319c3d822ae4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge b2g-inbound to m-c on a CLOSED TREE.
configure.in
gfx/layers/ipc/AsyncPanZoomController.cpp
mobile/android/base/sync/CredentialsSource.java
netwerk/test/TestUDPServerSocket.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -13,9 +13,9 @@
 #          |               |
 #          O <-- Clobber   O  <-- Clobber
 #
 # Note: The description below will be part of the error message shown to users.
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
-Another Windows WebIDL clobber needed due to bug 928195
+Another Windows WebIDL clobber needed due to bug 674741
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "f6f928dc9106402f7101dc55f9401cd136622faf", 
+    "revision": "88cc9854d6daff8c577e3867b95a1e523e429112", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -184,16 +184,19 @@
 @BINPATH@/components/dom_core.xpt
 @BINPATH@/components/dom_css.xpt
 @BINPATH@/components/dom_devicestorage.xpt
 @BINPATH@/components/dom_events.xpt
 @BINPATH@/components/dom_file.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_media.xpt
 @BINPATH@/components/dom_network.xpt
+#ifdef MOZ_NFC
+@BINPATH@/components/dom_nfc.xpt
+#endif
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_indexeddb.xpt
 @BINPATH@/components/dom_inputmethod.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_payment.xpt
 @BINPATH@/components/dom_json.xpt
 @BINPATH@/components/dom_messages.xpt
@@ -489,16 +492,23 @@
 @BINPATH@/components/messageWakeupService.manifest
 @BINPATH@/components/SettingsManager.js
 @BINPATH@/components/SettingsManager.manifest
 @BINPATH@/components/SettingsService.js
 @BINPATH@/components/SettingsService.manifest
 @BINPATH@/components/webvtt.xpt
 @BINPATH@/components/WebVTT.manifest
 @BINPATH@/components/WebVTTParserWrapper.js
+#ifdef MOZ_NFC
+@BINPATH@/components/nsNfc.manifest
+@BINPATH@/components/nsNfc.js
+@BINPATH@/components/Nfc.manifest
+@BINPATH@/components/Nfc.js
+@BINPATH@/components/NfcContentHelper.js
+#endif
 #ifdef MOZ_ENABLE_DBUS
 @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
 #endif
 @BINPATH@/components/nsINIProcessor.manifest
 @BINPATH@/components/nsINIProcessor.js
 @BINPATH@/components/nsPrompter.manifest
 @BINPATH@/components/nsPrompter.js
 #ifdef MOZ_SERVICES_SYNC
--- a/build/annotationProcessors/moz.build
+++ b/build/annotationProcessors/moz.build
@@ -2,16 +2,16 @@
 # 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/.
 
 jar = add_java_jar('annotationProcessors')
 jar.sources += [
     'AnnotationProcessor.java',
+    'classloader/IterableJarLoadingURLClassLoader.java',
+    'classloader/JarClassIterator.java',
     'CodeGenerator.java',
     'MethodWithAnnotationInfo.java',
-    'classloader/IterableJarLoadingURLClassLoader.java',
-    'classloader/JarClassIterator.java',
     'utils/AlphabeticMethodComparator.java',
     'utils/GeneratableEntryPointIterator.java',
     'utils/Utils.java',
 ]
--- a/configure.in
+++ b/configure.in
@@ -218,32 +218,34 @@ if test -n "$gonkdir" ; then
         ;;
     esac
 
     case "$ANDROID_VERSION" in
     15)
         GONK_INCLUDES="-I$gonkdir/frameworks/base/opengl/include -I$gonkdir/frameworks/base/native/include -I$gonkdir/frameworks/base/include -I$gonkdir/frameworks/base/services/camera -I$gonkdir/frameworks/base/include/media/stagefright -I$gonkdir/frameworks/base/include/media/stagefright/openmax -I$gonkdir/frameworks/base/media/libstagefright/rtsp -I$gonkdir/frameworks/base/media/libstagefright/include -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib -I$gonkdir/dalvik/libnativehelper/include/nativehelper"
         MOZ_B2G_BT=1
         MOZ_B2G_BT_BLUEZ=1
+        MOZ_NFC=1
         MOZ_B2G_CAMERA=1
         MOZ_OMX_DECODER=1
         AC_SUBST(MOZ_OMX_DECODER)
         MOZ_RTSP=1
         ;;
     17|18)
         GONK_INCLUDES="-I$gonkdir/frameworks/native/include -I$gonkdir/frameworks/av/include -I$gonkdir/frameworks/av/include/media -I$gonkdir/frameworks/av/include/camera -I$gonkdir/frameworks/native/include/media/openmax -I$gonkdir/frameworks/av/media/libstagefright/include"
         if test -d "$gonkdir/external/bluetooth/bluez"; then
           GONK_INCLUDES="$GONK_INCLUDES -I$gonkdir/external/dbus -I$gonkdir/external/bluetooth/bluez/lib"
             MOZ_B2G_BT=1
             MOZ_B2G_BT_BLUEZ=1
         elif test -d "$gonkdir/external/bluetooth/bluedroid"; then
             MOZ_B2G_BT=1
             MOZ_B2G_BT_BLUEDROID=1
         fi
 
+        MOZ_NFC=1
         MOZ_B2G_CAMERA=1
         MOZ_OMX_DECODER=1
         AC_SUBST(MOZ_OMX_DECODER)
         ;;
     *)
         AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])
         ;;
     esac
@@ -7302,16 +7304,28 @@ MOZ_ARG_ENABLE_BOOL(b2g-bt,
 if test -n "$MOZ_B2G_BT"; then
     AC_DEFINE(MOZ_B2G_BT)
 fi
 AC_SUBST(MOZ_B2G_BT)
 AC_SUBST(MOZ_B2G_BT_BLUEZ)
 AC_SUBST(MOZ_B2G_BT_BLUEDROID)
 
 dnl ========================================================
+dnl = Enable NFC Interface for B2G (Gonk usually)
+dnl ========================================================
+MOZ_ARG_ENABLE_BOOL(b2g-nfc,
+[  --enable-nfc         Set compile flags necessary for compiling NFC API ],
+    MOZ_NFC=1,
+    MOZ_NFC= )
+if test -n "$MOZ_NFC"; then
+   AC_DEFINE(MOZ_NFC)
+fi
+AC_SUBST(MOZ_NFC)
+
+dnl ========================================================
 dnl = Enable Pico Speech Synthesis (Gonk usually)
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(synth-pico,
 [  --enable-synth-pico  Set compile flags necessary for compiling Pico Web Speech API ],
     MOZ_SYNTH_PICO=1,
     MOZ_SYNTH_PICO= )
 if test -n "$MOZ_SYNTH_PICO"; then
     AC_DEFINE(MOZ_SYNTH_PICO)
@@ -8878,17 +8892,17 @@ dnl so that regeneration via dependencie
       	GYP_MOZMAKE_OPTIONS="-G os=win"
         ;;
       *-darwin*)
         GYP_MOZMAKE_OPTIONS="-G os=mac"
         if test "$MACOS_SDK_DIR"; then
            GYP_MOZMAKE_OPTIONS="${GYP_MOZMAKE_OPTIONS} -D mac_sdk_path=$MACOS_SDK_DIR"
         fi
         ;;
-      *-android*)
+      *-*linux*)
         GYP_MOZMAKE_OPTIONS="-G os=linux"
         ;;
       *)
         AC_MSG_ERROR([Don't know what options to give to WebRTC for cross-compilation])
     	;;
       esac
    fi
 
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -713,16 +713,17 @@ GK_ATOM(onfocus, "onfocus")
 GK_ATOM(onfrequencychange, "onfrequencychange")
 GK_ATOM(onget, "onget")
 GK_ATOM(ongroupchange, "ongroupchange")
 GK_ATOM(onhashchange, "onhashchange")
 GK_ATOM(onheadphoneschange, "onheadphoneschange")
 GK_ATOM(onheld, "onheld")
 GK_ATOM(onhfpstatuschanged, "onhfpstatuschanged")
 GK_ATOM(onholding, "onholding")
+GK_ATOM(oniccchange, "oniccchange")
 GK_ATOM(oniccinfochange, "oniccinfochange")
 GK_ATOM(onincoming, "onincoming")
 GK_ATOM(oninput, "oninput")
 GK_ATOM(oninvalid, "oninvalid")
 GK_ATOM(onkeydown, "onkeydown")
 GK_ATOM(onkeypress, "onkeypress")
 GK_ATOM(onkeyup, "onkeyup")
 GK_ATOM(onlevelchange, "onlevelchange")
--- a/dom/apps/src/PermissionsTable.jsm
+++ b/dom/apps/src/PermissionsTable.jsm
@@ -297,16 +297,27 @@ this.PermissionsTable =  { geolocation: 
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
                            "audio-capture": {
                              app: PROMPT_ACTION,
                              privileged: PROMPT_ACTION,
                              certified: PROMPT_ACTION
                            },
+                           "nfc": {
+                             app: DENY_ACTION,
+                             privileged: DENY_ACTION,
+                             certified: ALLOW_ACTION,
+                             access: ["read", "write"]
+                           },
+                           "nfc-manager": {
+                             app: DENY_ACTION,
+                             privileged: DENY_ACTION,
+                             certified: ALLOW_ACTION
+                           },
                          };
 
 /**
  * Append access modes to the permission name as suffixes.
  *   e.g. permission name 'contacts' with ['read', 'write'] =
  *   ['contacts-read', contacts-write']
  * @param string aPermName
  * @param array aAccess
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -35,17 +35,17 @@
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/StaticPtr.h"
 #include "Connection.h"
 #include "nsDOMEvent.h"
 #include "nsGlobalWindow.h"
 #ifdef MOZ_B2G_RIL
 #include "mozilla/dom/IccManager.h"
 #include "mozilla/dom/CellBroadcast.h"
-#include "mozilla/dom/network/MobileConnection.h"
+#include "mozilla/dom/network/MobileConnectionArray.h"
 #include "mozilla/dom/Voicemail.h"
 #endif
 #include "nsIIdleObserver.h"
 #include "nsIPermissionManager.h"
 #include "nsNetUtil.h"
 #include "nsIHttpChannel.h"
 #include "TimeManager.h"
 #include "DeviceStorage.h"
@@ -136,17 +136,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mGeolocation)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
 #ifdef MOZ_B2G_RIL
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnection)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
 #endif
 #ifdef MOZ_B2G_BT
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBluetooth)
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
@@ -214,19 +214,18 @@ Navigator::Invalidate()
   }
 
   if (mConnection) {
     mConnection->Shutdown();
     mConnection = nullptr;
   }
 
 #ifdef MOZ_B2G_RIL
-  if (mMobileConnection) {
-    mMobileConnection->Shutdown();
-    mMobileConnection = nullptr;
+  if (mMobileConnections) {
+    mMobileConnections = nullptr;
   }
 
   if (mCellBroadcast) {
     mCellBroadcast = nullptr;
   }
 
   if (mIccManager) {
     mIccManager->Shutdown();
@@ -1176,16 +1175,30 @@ Navigator::GetMozTelephony(ErrorResult& 
     mTelephony = Telephony::Create(mWindow, aRv);
   }
 
   return mTelephony;
 }
 
 #ifdef MOZ_B2G_RIL
 
+network::MobileConnectionArray*
+Navigator::GetMozMobileConnections(ErrorResult& aRv)
+{
+  if (!mMobileConnections) {
+    if (!mWindow) {
+      aRv.Throw(NS_ERROR_UNEXPECTED);
+      return nullptr;
+    }
+    mMobileConnections = new network::MobileConnectionArray(mWindow);
+  }
+
+  return mMobileConnections;
+}
+
 CellBroadcast*
 Navigator::GetMozCellBroadcast(ErrorResult& aRv)
 {
   if (!mCellBroadcast) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
@@ -1267,33 +1280,16 @@ Navigator::GetMozConnection()
 
     mConnection = new network::Connection();
     mConnection->Init(mWindow);
   }
 
   return mConnection;
 }
 
-#ifdef MOZ_B2G_RIL
-nsIDOMMozMobileConnection*
-Navigator::GetMozMobileConnection(ErrorResult& aRv)
-{
-  if (!mMobileConnection) {
-    if (!mWindow) {
-      aRv.Throw(NS_ERROR_UNEXPECTED);
-      return nullptr;
-    }
-    mMobileConnection = new network::MobileConnection();
-    mMobileConnection->Init(mWindow);
-  }
-
-  return mMobileConnection;
-}
-#endif // MOZ_B2G_RIL
-
 #ifdef MOZ_B2G_BT
 bluetooth::BluetoothManager*
 Navigator::GetMozBluetooth(ErrorResult& aRv)
 {
   if (!mBluetooth) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
@@ -1792,16 +1788,28 @@ Navigator::HasBluetoothSupport(JSContext
 bool
 Navigator::HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
   return win && CheckPermission(win, "fmradio");
 }
 #endif // MOZ_B2G_FM
 
+#ifdef MOZ_NFC
+/* static */
+bool
+Navigator::HasNfcSupport(JSContext* /* unused */, JSObject* aGlobal)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
+  return win && (CheckPermission(win, "nfc-read") ||
+                 CheckPermission(win, "nfc-write"));
+}
+#endif // MOZ_NFC
+
+
 #ifdef MOZ_TIME_MANAGER
 /* static */
 bool
 Navigator::HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
   return win && CheckPermission(win, "time");
 }
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -30,17 +30,16 @@ namespace dom {
 class Geolocation;
 class systemMessageCallback;
 class MediaStreamConstraints;
 class MediaStreamConstraintsInternal;
 }
 }
 
 #ifdef MOZ_B2G_RIL
-class nsIDOMMozMobileConnection;
 class nsIDOMMozIccManager;
 #endif // MOZ_B2G_RIL
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
 void NS_GetNavigatorAppName(nsAString& aAppName);
@@ -68,17 +67,17 @@ class Gamepad;
 class NavigatorUserMediaSuccessCallback;
 class NavigatorUserMediaErrorCallback;
 class MozGetUserMediaDevicesSuccessCallback;
 #endif // MOZ_MEDIA_NAVIGATOR
 
 namespace network {
 class Connection;
 #ifdef MOZ_B2G_RIL
-class MobileConnection;
+class MobileConnectionArray;
 #endif
 } // namespace Connection;
 
 #ifdef MOZ_B2G_BT
 namespace bluetooth {
 class BluetoothManager;
 } // namespace bluetooth
 #endif // MOZ_B2G_BT
@@ -214,17 +213,17 @@ public:
   Telephony* GetMozTelephony(ErrorResult& aRv);
   nsIDOMMozConnection* GetMozConnection();
   nsDOMCameraManager* GetMozCameras(ErrorResult& aRv);
   void MozSetMessageHandler(const nsAString& aType,
                             systemMessageCallback* aCallback,
                             ErrorResult& aRv);
   bool MozHasPendingMessage(const nsAString& aType, ErrorResult& aRv);
 #ifdef MOZ_B2G_RIL
-  nsIDOMMozMobileConnection* GetMozMobileConnection(ErrorResult& aRv);
+  network::MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
   CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
   Voicemail* GetMozVoicemail(ErrorResult& aRv);
   nsIDOMMozIccManager* GetMozIccManager(ErrorResult& aRv);
 #endif // MOZ_B2G_RIL
 #ifdef MOZ_GAMEPAD
   void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
 #endif // MOZ_GAMEPAD
 #ifdef MOZ_B2G_FM
@@ -283,16 +282,19 @@ public:
                                    JSObject* aGlobal);
 #endif // MOZ_B2G_RIL
 #ifdef MOZ_B2G_BT
   static bool HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal);
 #endif // MOZ_B2G_BT
 #ifdef MOZ_B2G_FM
   static bool HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal);
 #endif // MOZ_B2G_FM
+#ifdef MOZ_NFC
+  static bool HasNfcSupport(JSContext* /* unused */, JSObject* aGlobal);
+#endif // MOZ_NFC
 #ifdef MOZ_TIME_MANAGER
   static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
 #endif // MOZ_TIME_MANAGER
 #ifdef MOZ_MEDIA_NAVIGATOR
   static bool HasUserMediaSupport(JSContext* /* unused */,
                                   JSObject* /* unused */);
 #endif // MOZ_MEDIA_NAVIGATOR
 
@@ -324,17 +326,17 @@ private:
 #ifdef MOZ_B2G_FM
   nsRefPtr<FMRadio> mFMRadio;
 #endif
   nsRefPtr<PowerManager> mPowerManager;
   nsRefPtr<MobileMessageManager> mMobileMessageManager;
   nsRefPtr<Telephony> mTelephony;
   nsRefPtr<network::Connection> mConnection;
 #ifdef MOZ_B2G_RIL
-  nsRefPtr<network::MobileConnection> mMobileConnection;
+  nsRefPtr<network::MobileConnectionArray> mMobileConnections;
   nsRefPtr<CellBroadcast> mCellBroadcast;
   nsRefPtr<IccManager> mIccManager;
   nsRefPtr<Voicemail> mVoicemail;
 #endif
 #ifdef MOZ_B2G_BT
   nsCOMPtr<bluetooth::BluetoothManager> mBluetooth;
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7954,19 +7954,22 @@ nsGlobalWindow::Close(ErrorResult& aErro
   if (mBlockScriptedClosingFlag)
   {
     // A script's popup has been blocked and we don't want
     // the window to be closed directly after this event,
     // so the user can see that there was a blocked popup.
     return;
   }
 
-  // Don't allow scripts from content to close non-app windows that were not
-  // opened by script.
+  // Don't allow scripts from content to close non-app or non-neterror
+  // windows that were not opened by script.
+  nsAutoString url;
+  mDoc->GetURL(url);
   if (!mDocShell->GetIsApp() &&
+      !StringBeginsWith(url, NS_LITERAL_STRING("about:neterror")) &&
       !mHadOriginalOpener && !nsContentUtils::IsCallerChrome()) {
     bool allowClose = mAllowScriptsToClose ||
       Preferences::GetBool("dom.allow_scripts_to_close_windows", true);
     if (!allowClose) {
       // We're blocking the close operation
       // report localized error msg in JS console
       nsContentUtils::ReportToConsole(
           nsIScriptError::warningFlag,
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -784,16 +784,21 @@ DOMInterfaces = {
 {
     'workers': True,
 }],
 
 'MozCellBroadcast': {
     'nativeType': 'mozilla::dom::CellBroadcast',
 },
 
+'MozMobileConnectionArray': {
+    'nativeType': 'mozilla::dom::network::MobileConnectionArray',
+    'resultNotAddRefed': [ 'item' ]
+},
+
 'MozNamedAttrMap': {
     'nativeType': 'nsDOMAttributeMap',
 },
 
 'MozPowerManager': {
     'nativeType': 'mozilla::dom::PowerManager',
 },
 
--- a/dom/bluetooth/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/BluetoothServiceBluedroid.cpp
@@ -244,17 +244,24 @@ AdapterPropertiesChangeCallback(bt_statu
     } else if (p.type == BT_PROPERTY_BDNAME) {
       // Construct nsCString here because Bd name returned from bluedroid
       // is missing a null terminated character after SetProperty.
       propertyValue = sAdapterBdName = NS_ConvertUTF8toUTF16(
         nsCString((char*)p.val, p.len));
       propertiesArray.AppendElement(
         BluetoothNamedValue(NS_LITERAL_STRING("Name"), propertyValue));
     } else if (p.type == BT_PROPERTY_ADAPTER_SCAN_MODE) {
-      propertyValue = sAdapterDiscoverable = *(uint32_t*)p.val;
+      bt_scan_mode_t newMode = *(bt_scan_mode_t*)p.val;
+
+      if (newMode == BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+        propertyValue = sAdapterDiscoverable = true;
+      } else {
+        propertyValue = sAdapterDiscoverable = false;
+      }
+
       propertiesArray.AppendElement(
         BluetoothNamedValue(NS_LITERAL_STRING("Discoverable"), propertyValue));
     } else if (p.type == BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT) {
       propertyValue = sAdapterDiscoverableTimeout = *(uint32_t*)p.val;
       propertiesArray.AppendElement(
         BluetoothNamedValue(NS_LITERAL_STRING("DiscoverableTimeout"),
                             propertyValue));
     } else if (p.type == BT_PROPERTY_ADAPTER_BONDED_DEVICES) {
@@ -632,19 +639,22 @@ StartStopGonkBluetooth(bool aShouldEnabl
   return (ret == BT_STATUS_SUCCESS) ? NS_OK : NS_ERROR_FAILURE;
 }
 
 static void
 ReplyStatusError(BluetoothReplyRunnable* aBluetoothReplyRunnable,
                  int aStatusCode, const nsAString& aCustomMsg)
 {
   MOZ_ASSERT(aBluetoothReplyRunnable, "Reply runnable is nullptr");
-  nsAutoString replyError;
+
+  BT_LOGR("%s: error code(%d)", __FUNCTION__, aStatusCode);
 
+  nsAutoString replyError;
   replyError.Assign(aCustomMsg);
+
   if (aStatusCode == BT_STATUS_BUSY) {
     replyError.AppendLiteral(":BT_STATUS_BUSY");
   } else if (aStatusCode == BT_STATUS_NOT_READY) {
     replyError.AppendLiteral(":BT_STATUS_NOT_READY");
   } else if (aStatusCode == BT_STATUS_DONE) {
     replyError.AppendLiteral(":BT_STATUS_DONE");
   } else if (aStatusCode == BT_STATUS_AUTH_FAILURE) {
     replyError.AppendLiteral(":BT_STATUS_AUTH_FAILURE");
@@ -835,16 +845,17 @@ BluetoothServiceBluedroid::SetProperty(B
     NS_NAMED_LITERAL_STRING(errorStr, "Bluetooth service is not ready yet!");
     DispatchBluetoothReply(aRunnable, BluetoothValue(), errorStr);
 
     return NS_OK;
   }
 
   const nsString propName = aValue.name();
   bt_property_t prop;
+  bt_scan_mode_t scanMode;
   nsString str;
 
   // For Bluedroid, it's necessary to check property name for SetProperty
   if (propName.EqualsLiteral("Name")) {
     prop.type = BT_PROPERTY_BDNAME;
   } else if (propName.EqualsLiteral("Discoverable")) {
     prop.type = BT_PROPERTY_ADAPTER_SCAN_MODE;
   } else if (propName.EqualsLiteral("DiscoverableTimeout")) {
@@ -858,32 +869,33 @@ BluetoothServiceBluedroid::SetProperty(B
     prop.val = (void*)aValue.value().get_uint32_t();
   } else if (aValue.value().type() == BluetoothValue::TnsString) {
     // Set name
     str = aValue.value().get_nsString();
     const char* name = NS_ConvertUTF16toUTF8(str).get();
     prop.val = (void*)name;
     prop.len = strlen(name);
   } else if (aValue.value().type() == BluetoothValue::Tbool) {
-    bt_scan_mode_t mode = aValue.value().get_bool() ?
-                            BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE :
-                            BT_SCAN_MODE_CONNECTABLE;
-    bt_scan_mode_t* sss = &mode;
-    prop.val = (void*)sss;
-    prop.len = sizeof(sss);
+    scanMode = aValue.value().get_bool() ?
+                 BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE :
+                 BT_SCAN_MODE_CONNECTABLE;
+
+    prop.val = (void*)&scanMode;
+    prop.len = sizeof(scanMode);
   } else {
     BT_LOGR("SetProperty but the property cannot be recognized correctly.");
     return NS_OK;
   }
 
   sSetPropertyRunnableArray.AppendElement(aRunnable);
+
   int ret = sBtInterface->set_adapter_property(&prop);
-
-  if (ret != BT_STATUS_SUCCESS)
+  if (ret != BT_STATUS_SUCCESS) {
     ReplyStatusError(aRunnable, ret, NS_LITERAL_STRING("SetProperty"));
+  }
 
   return NS_OK;
 }
 
 bool
 BluetoothServiceBluedroid::GetDevicePath(const nsAString& aAdapterPath,
                                          const nsAString& aDeviceAddress,
                                          nsAString& aDevicePath)
--- a/dom/browser-element/mochitest/browserElementTestHelpers.js
+++ b/dom/browser-element/mochitest/browserElementTestHelpers.js
@@ -24,34 +24,41 @@ const browserElementTestHelpers = {
     this.lockTestReady();
     if (value !== undefined && value !== null) {
       SpecialPowers.pushPrefEnv({'set': [[pref, value]]}, this.unlockTestReady.bind(this));
     } else {
       SpecialPowers.pushPrefEnv({'clear': [[pref]]}, this.unlockTestReady.bind(this));
     }
   },
 
+  _setPrefs: function() {
+    this.lockTestReady();
+    SpecialPowers.pushPrefEnv({'set': Array.slice(arguments)}, this.unlockTestReady.bind(this));
+  },
+
   _testReadyLockCount: 0,
   _firedTestReady: false,
   lockTestReady: function() {
     this._testReadyLockCount++;
   },
 
   unlockTestReady: function() {
     this._testReadyLockCount--;
     if (this._testReadyLockCount == 0 && !this._firedTestReady) {
       this._firedTestReady = true;
       dispatchEvent(new Event("testready"));
     }
   },
 
   enableProcessPriorityManager: function() {
-    this._setPref('dom.ipc.processPriorityManager.testMode', true);
-    this._setPref('dom.ipc.processPriorityManager.enabled', true);
-    this._setPref('dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2);
+    this._setPrefs(
+      ['dom.ipc.processPriorityManager.testMode', true],
+      ['dom.ipc.processPriorityManager.enabled', true],
+      ['dom.ipc.processPriorityManager.backgroundLRUPoolLevels', 2]
+    );
   },
 
   setEnabledPref: function(value) {
     this._setPref('dom.mozBrowserFramesEnabled', value);
   },
 
   getOOPByDefaultPref: function() {
     return this._getBoolPref("dom.ipc.browser_frames.oop_by_default");
--- a/dom/camera/GonkCameraControl.cpp
+++ b/dom/camera/GonkCameraControl.cpp
@@ -636,17 +636,20 @@ nsGonkCameraControl::SetParameter(uint32
   if (!key) {
     return;
   }
 
   uint32_t length = aRegions.Length();
 
   if (!length) {
     // This tells the camera driver to revert to automatic regioning.
-    mParams.set(key, "(0,0,0,0,0)");
+    {
+      RwAutoLockWrite lock(mRwLock);
+      mParams.set(key, "(0,0,0,0,0)");
+    }
     PushParameters();
     return;
   }
 
   nsCString s;
 
   for (uint32_t i = 0; i < length; ++i) {
     const idl::CameraRegion* r = &aRegions[i];
@@ -1225,17 +1228,20 @@ nsGonkCameraControl::SetPreviewSize(uint
 {
   android::Vector<Size> previewSizes;
   uint32_t bestWidth = aWidth;
   uint32_t bestHeight = aHeight;
   uint32_t minSizeDelta = UINT32_MAX;
   uint32_t delta;
   Size size;
 
-  mParams.getSupportedPreviewSizes(previewSizes);
+  {
+    RwAutoLockRead lock(mRwLock);
+    mParams.getSupportedPreviewSizes(previewSizes);
+  }
 
   if (!aWidth && !aHeight) {
     // no size specified, take the first supported size
     size = previewSizes[0];
     bestWidth = size.width;
     bestHeight = size.height;
   } else if (aWidth && aHeight) {
     // both height and width specified, find the supported size closest to requested size
@@ -1269,17 +1275,20 @@ nsGonkCameraControl::SetPreviewSize(uint
         bestWidth = size.width;
         bestHeight = size.height;
       }
     }
   }
 
   mWidth = bestWidth;
   mHeight = bestHeight;
-  mParams.setPreviewSize(mWidth, mHeight);
+  {
+    RwAutoLockWrite lock(mRwLock);
+    mParams.setPreviewSize(mWidth, mHeight);
+  }
   PushParameters();
 }
 
 nsresult
 nsGonkCameraControl::SetupVideoMode(const nsAString& aProfile)
 {
   // read preferences for camcorder
   mMediaProfiles = MediaProfiles::getInstance();
@@ -1301,26 +1310,29 @@ nsGonkCameraControl::SetupVideoMode(cons
   }
 
   PullParametersImpl();
 
   // configure camera video recording parameters
   const size_t SIZE = 256;
   char buffer[SIZE];
 
-  mParams.setPreviewSize(width, height);
-  mParams.setPreviewFrameRate(fps);
+  {
+    RwAutoLockWrite lock(mRwLock);
+    mParams.setPreviewSize(width, height);
+    mParams.setPreviewFrameRate(fps);
 
-  /**
-   * "record-size" is probably deprecated in later ICS;
-   * might need to set "video-size" instead of "record-size".
-   * See bug 795332.
-   */
-  snprintf(buffer, SIZE, "%dx%d", width, height);
-  mParams.set("record-size", buffer);
+    /**
+     * "record-size" is probably deprecated in later ICS;
+     * might need to set "video-size" instead of "record-size".
+     * See bug 795332.
+     */
+    snprintf(buffer, SIZE, "%dx%d", width, height);
+    mParams.set("record-size", buffer);
+  }
 
   // push the updated camera configuration immediately
   PushParameters();
   return NS_OK;
 }
 
 class GonkRecorderListener : public IMediaRecorderClient
 {
@@ -1602,20 +1614,24 @@ nsGonkCameraControl::GetRecorderProfileM
 }
 
 nsresult
 nsGonkCameraControl::GetVideoSizes(nsTArray<idl::CameraSize>& aVideoSizes)
 {
   aVideoSizes.Clear();
 
   android::Vector<Size> sizes;
-  mParams.getSupportedVideoSizes(sizes);
-  if (sizes.size() == 0) {
-    DOM_CAMERA_LOGI("Camera doesn't support video independent of the preview\n");
-    mParams.getSupportedPreviewSizes(sizes);
+  {
+    RwAutoLockRead lock(mRwLock);
+
+    mParams.getSupportedVideoSizes(sizes);
+    if (sizes.size() == 0) {
+      DOM_CAMERA_LOGI("Camera doesn't support video independent of the preview\n");
+      mParams.getSupportedPreviewSizes(sizes);
+    }
   }
 
   if (sizes.size() == 0) {
     DOM_CAMERA_LOGW("Camera doesn't report any supported video sizes at all\n");
     return NS_OK;
   }
 
   for (size_t i = 0; i < sizes.size(); ++i) {
--- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_etws.js
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_etws.js
@@ -258,11 +258,11 @@ function cleanUp() {
 
   SpecialPowers.removePermission("mobileconnection", document);
   SpecialPowers.removePermission("cellbroadcast", true, document);
 
   finish();
 }
 
 waitFor(testEtwsMessageAttributes, function () {
-  return navigator.mozMobileConnection.voice.connected;
+  return navigator.mozMobileConnections[0].voice.connected;
 });
 
--- a/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js
+++ b/dom/cellbroadcast/tests/marionette/test_cellbroadcast_gsm.js
@@ -471,11 +471,11 @@ function cleanUp() {
 
   SpecialPowers.removePermission("mobileconnection", document);
   SpecialPowers.removePermission("cellbroadcast", true, document);
 
   finish();
 }
 
 waitFor(testGsmMessageAttributes, function () {
-  return navigator.mozMobileConnection.voice.connected;
+  return navigator.mozMobileConnections[0].voice.connected;
 });
 
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -18,16 +18,17 @@ include JavaScriptTypes;
 include URIParams;
 
 
 using class IPC::Principal from "mozilla/dom/PermissionMessageUtils.h";
 using struct gfxMatrix from "gfxMatrix.h";
 using struct gfxSize from "gfxPoint.h";
 using CSSRect from "Units.h";
 using struct mozilla::layers::FrameMetrics from "FrameMetrics.h";
+using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h";
 using FrameMetrics::ViewID from "FrameMetrics.h";
 using mozilla::layout::ScrollingBehavior from "mozilla/layout/RenderFrameUtils.h";
 using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
 using mozilla::WindowsHandle from "ipc/IPCMessageUtils.h";
 using nscolor from "nsColor.h";
 using class mozilla::WidgetCompositionEvent from "ipc/nsGUIEventIPC.h";
 using struct nsIMEUpdatePreference from "nsIWidget.h";
 using struct nsIntPoint from "nsPoint.h";
@@ -271,32 +272,34 @@ parent:
     sync BrowserFrameOpenWindow(PBrowser opener, nsString aURL,
                                 nsString aName, nsString aFeatures)
       returns (bool windowOpened);
 
     /**
      * Instructs the TabParent to forward a request to zoom to a rect given in
      * CSS pixels. This rect is relative to the document.
      */
-    ZoomToRect(CSSRect aRect);
+    ZoomToRect(uint32_t aPresShellId, ViewID aViewId, CSSRect aRect);
 
     /**
      * We know for sure that content has either preventDefaulted or not
      * preventDefaulted. This applies to an entire batch of touch events. It is
      * expected that, if there are any DOM touch listeners, touch events will be
      * batched and only processed for panning and zooming if content does not
      * preventDefault.
      */
-    ContentReceivedTouch(bool aPreventDefault);
+    ContentReceivedTouch(ScrollableLayerGuid aGuid, bool aPreventDefault);
 
     /**
-     * Updates any zoom constraints on the parent and anything tied to it. This
-     * is useful for control logic that resides outside of the remote browser.
+     * Updates the zoom constraints for a scrollable frame in this tab.
+     * The zoom controller code lives on the parent side and so this allows it to
+     * have up-to-date zoom constraints.
      */
-    UpdateZoomConstraints(bool aAllowZoom, CSSToScreenScale aMinZoom, CSSToScreenScale aMaxZoom);
+    UpdateZoomConstraints(uint32_t aPresShellId, ViewID aViewId,
+                          bool aAllowZoom, CSSToScreenScale aMinZoom, CSSToScreenScale aMaxZoom);
 
     /**
      * Notifies the parent about a scroll event. The pres shell ID and
      * view ID identify which scrollable (sub-)frame was scrolled, and
      * the new scroll offset for that frame is sent.
      */
     UpdateScrollOffset(uint32_t aPresShellId, ViewID aViewId, CSSIntPoint aScrollOffset);
 
@@ -367,20 +370,20 @@ child:
                int32_t aButton,
                int32_t aClickCount,
                int32_t aModifiers,
                bool aIgnoreRootScrollFrame);
 
     RealMouseEvent(WidgetMouseEvent event);
     RealKeyEvent(WidgetKeyboardEvent event);
     MouseWheelEvent(WidgetWheelEvent event);
-    RealTouchEvent(WidgetTouchEvent event);
+    RealTouchEvent(WidgetTouchEvent aEvent, ScrollableLayerGuid aGuid);
     // We use a separate message for touchmove events only to apply
     // compression to them.
-    RealTouchMoveEvent(WidgetTouchEvent event) compress;
+    RealTouchMoveEvent(WidgetTouchEvent aEvent, ScrollableLayerGuid aGuid) compress;
 
     /**
      * @see nsIDOMWindowUtils sendKeyEvent.
      */
     KeyEvent(nsString aType,
              int32_t aKeyCode,
              int32_t aCharCode,
              int32_t aModifiers,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -357,28 +357,32 @@ NS_IMETHODIMP
 TabChild::Observe(nsISupports *aSubject,
                   const char *aTopic,
                   const PRUnichar *aData)
 {
   if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
     nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
     nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
     if (tabChild == this) {
-      CSSRect rect;
-      sscanf(NS_ConvertUTF16toUTF8(aData).get(),
-             "{\"x\":%f,\"y\":%f,\"w\":%f,\"h\":%f}",
-             &rect.x, &rect.y, &rect.width, &rect.height);
-      SendZoomToRect(rect);
+      nsCOMPtr<nsIDocument> doc(GetDocument());
+      uint32_t presShellId;
+      ViewID viewId;
+      if (APZCCallbackHelper::GetScrollIdentifiers(doc->GetDocumentElement(),
+                                                    &presShellId, &viewId)) {
+        CSSRect rect;
+        sscanf(NS_ConvertUTF16toUTF8(aData).get(),
+               "{\"x\":%f,\"y\":%f,\"w\":%f,\"h\":%f}",
+               &rect.x, &rect.y, &rect.width, &rect.height);
+        SendZoomToRect(presShellId, viewId, rect);
+      }
     }
   } else if (!strcmp(aTopic, BEFORE_FIRST_PAINT)) {
     if (IsAsyncPanZoomEnabled()) {
       nsCOMPtr<nsIDocument> subject(do_QueryInterface(aSubject));
-      nsCOMPtr<nsIDOMDocument> domDoc;
-      mWebNav->GetDocument(getter_AddRefs(domDoc));
-      nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
+      nsCOMPtr<nsIDocument> doc(GetDocument());
 
       if (SameCOMIdentity(subject, doc)) {
         nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
 
         mContentDocumentIsDisplayed = true;
 
         // Reset CSS viewport and zoom to default on new page, then
         // calculate them properly using the actual metadata from the
@@ -528,18 +532,27 @@ TabChild::HandlePossibleViewportChange()
   }
 
   nsCOMPtr<nsIDOMDocument> domDoc;
   mWebNav->GetDocument(getter_AddRefs(domDoc));
   nsCOMPtr<nsIDocument> document(do_QueryInterface(domDoc));
 
   nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
 
+  uint32_t presShellId;
+  ViewID viewId;
+  if (!APZCCallbackHelper::GetScrollIdentifiers(document->GetDocumentElement(),
+                                                &presShellId, &viewId)) {
+    return;
+  }
+
   nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize);
-  SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(),
+  SendUpdateZoomConstraints(presShellId,
+                            viewId,
+                            viewportInfo.IsZoomAllowed(),
                             viewportInfo.GetMinZoom(),
                             viewportInfo.GetMaxZoom());
 
   float screenW = mInnerSize.width;
   float screenH = mInnerSize.height;
   CSSSize viewport(viewportInfo.GetSize());
 
   // We're not being displayed in any way; don't bother doing anything because
@@ -1063,16 +1076,25 @@ TabChild::BrowserFrameProvideWindow(nsID
 already_AddRefed<nsIDOMWindowUtils>
 TabChild::GetDOMWindowUtils()
 {
   nsCOMPtr<nsPIDOMWindow> window = do_GetInterface(mWebNav);
   nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(window);
   return utils.forget();
 }
 
+already_AddRefed<nsIDocument>
+TabChild::GetDocument()
+{
+  nsCOMPtr<nsIDOMDocument> domDoc;
+  mWebNav->GetDocument(getter_AddRefs(domDoc));
+  nsCOMPtr<nsIDocument> doc(do_QueryInterface(domDoc));
+  return doc.forget();
+}
+
 static nsInterfaceHashtable<nsPtrHashKey<PContentDialogChild>, nsIDialogParamBlock>* gActiveDialogs;
 
 NS_IMETHODIMP
 TabChild::OpenDialog(uint32_t aType, const nsACString& aName,
                      const nsACString& aFeatures,
                      nsIDialogParamBlock* aArguments,
                      nsIDOMElement* aFrameElement)
 {
@@ -1849,39 +1871,41 @@ TabChild::CancelTapTracking()
   mActivePointerId = -1;
   if (mTapHoldTimer) {
     mTapHoldTimer->Cancel();
   }
   mTapHoldTimer = nullptr;
 }
 
 bool
-TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent)
+TabChild::RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
+                             const ScrollableLayerGuid& aGuid)
 {
   WidgetTouchEvent localEvent(aEvent);
   nsEventStatus status = DispatchWidgetEvent(localEvent);
 
   if (IsAsyncPanZoomEnabled()) {
     nsCOMPtr<nsPIDOMWindow> outerWindow = do_GetInterface(mWebNav);
     nsCOMPtr<nsPIDOMWindow> innerWindow = outerWindow->GetCurrentInnerWindow();
 
     if (innerWindow && innerWindow->HasTouchEventListeners()) {
-      SendContentReceivedTouch(nsIPresShell::gPreventMouseEvents);
+      SendContentReceivedTouch(aGuid, nsIPresShell::gPreventMouseEvents);
     }
   } else {
     UpdateTapState(aEvent, status);
   }
 
   return true;
 }
 
 bool
-TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent)
+TabChild::RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent,
+                                 const ScrollableLayerGuid& aGuid)
 {
-  return RecvRealTouchEvent(aEvent);
+  return RecvRealTouchEvent(aEvent, aGuid);
 }
 
 bool
 TabChild::RecvRealKeyEvent(const WidgetKeyboardEvent& event)
 {
   WidgetKeyboardEvent localEvent(event);
   DispatchWidgetEvent(localEvent);
   return true;
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -224,18 +224,20 @@ public:
                                 const float&    aY,
                                 const int32_t&  aButton,
                                 const int32_t&  aClickCount,
                                 const int32_t&  aModifiers,
                                 const bool&     aIgnoreRootScrollFrame);
     virtual bool RecvRealMouseEvent(const mozilla::WidgetMouseEvent& event);
     virtual bool RecvRealKeyEvent(const mozilla::WidgetKeyboardEvent& event);
     virtual bool RecvMouseWheelEvent(const mozilla::WidgetWheelEvent& event);
-    virtual bool RecvRealTouchEvent(const WidgetTouchEvent& event);
-    virtual bool RecvRealTouchMoveEvent(const WidgetTouchEvent& event);
+    virtual bool RecvRealTouchEvent(const WidgetTouchEvent& aEvent,
+                                    const ScrollableLayerGuid& aGuid);
+    virtual bool RecvRealTouchMoveEvent(const WidgetTouchEvent& aEvent,
+                                        const ScrollableLayerGuid& aGuid);
     virtual bool RecvKeyEvent(const nsString& aType,
                               const int32_t&  aKeyCode,
                               const int32_t&  aCharCode,
                               const int32_t&  aModifiers,
                               const bool&     aPreventDefault);
     virtual bool RecvCompositionEvent(const mozilla::WidgetCompositionEvent& event);
     virtual bool RecvTextEvent(const mozilla::WidgetTextEvent& event);
     virtual bool RecvSelectionEvent(const mozilla::WidgetSelectionEvent& event);
@@ -446,16 +448,18 @@ private:
                               nsIURI* aURI,
                               const nsAString& aName,
                               const nsACString& aFeatures,
                               bool* aWindowIsNew,
                               nsIDOMWindow** aReturn);
 
     // Get the DOMWindowUtils for the top-level window in this tab.
     already_AddRefed<nsIDOMWindowUtils> GetDOMWindowUtils();
+    // Get the Document for the top-level window in this tab.
+    already_AddRefed<nsIDocument> GetDocument();
 
     class CachedFileDescriptorInfo;
     class CachedFileDescriptorCallbackRunnable;
 
     TextureFactoryIdentifier mTextureFactoryIdentifier;
     nsCOMPtr<nsIWebNavigation> mWebNav;
     nsCOMPtr<nsIWidget> mWidget;
     nsCOMPtr<nsIURI> mLastURI;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -644,43 +644,43 @@ TabParent::MapEventCoordinatesForChildPr
 }
 
 bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event)
 {
   if (mIsDestroyed) {
     return false;
   }
   WidgetMouseEvent e(event);
-  MaybeForwardEventToRenderFrame(event, &e);
+  MaybeForwardEventToRenderFrame(event, nullptr, &e);
   if (!MapEventCoordinatesForChildProcess(&e)) {
     return false;
   }
   return PBrowserParent::SendRealMouseEvent(e);
 }
 
 bool TabParent::SendMouseWheelEvent(WidgetWheelEvent& event)
 {
   if (mIsDestroyed) {
     return false;
   }
   WidgetWheelEvent e(event);
-  MaybeForwardEventToRenderFrame(event, &e);
+  MaybeForwardEventToRenderFrame(event, nullptr, &e);
   if (!MapEventCoordinatesForChildProcess(&e)) {
     return false;
   }
   return PBrowserParent::SendMouseWheelEvent(event);
 }
 
 bool TabParent::SendRealKeyEvent(WidgetKeyboardEvent& event)
 {
   if (mIsDestroyed) {
     return false;
   }
   WidgetKeyboardEvent e(event);
-  MaybeForwardEventToRenderFrame(event, &e);
+  MaybeForwardEventToRenderFrame(event, nullptr, &e);
   if (!MapEventCoordinatesForChildProcess(&e)) {
     return false;
   }
   return PBrowserParent::SendRealKeyEvent(e);
 }
 
 bool TabParent::SendRealTouchEvent(WidgetTouchEvent& event)
 {
@@ -715,23 +715,24 @@ bool TabParent::SendRealTouchEvent(Widge
   if (event.message == NS_TOUCH_END || event.message == NS_TOUCH_CANCEL) {
     for (int i = e.touches.Length() - 1; i >= 0; i--) {
       if (!e.touches[i]->mChanged) {
         e.touches.RemoveElementAt(i);
       }
     }
   }
 
-  MaybeForwardEventToRenderFrame(event, &e);
+  ScrollableLayerGuid guid;
+  MaybeForwardEventToRenderFrame(event, &guid, &e);
 
   MapEventCoordinatesForChildProcess(mChildProcessOffsetAtTouchStart, &e);
 
   return (e.message == NS_TOUCH_MOVE) ?
-    PBrowserParent::SendRealTouchMoveEvent(e) :
-    PBrowserParent::SendRealTouchEvent(e);
+    PBrowserParent::SendRealTouchMoveEvent(e, guid) :
+    PBrowserParent::SendRealTouchEvent(e, guid);
 }
 
 /*static*/ TabParent*
 TabParent::GetEventCapturer()
 {
   return sEventCapturer;
 }
 
@@ -1571,20 +1572,21 @@ TabParent::UseAsyncPanZoom()
   bool asyncPanZoomEnabled =
     Preferences::GetBool("layers.async-pan-zoom.enabled", false);
   return (usingOffMainThreadCompositing && asyncPanZoomEnabled &&
           GetScrollingBehavior() == ASYNC_PAN_ZOOM);
 }
 
 void
 TabParent::MaybeForwardEventToRenderFrame(const WidgetInputEvent& aEvent,
+                                          ScrollableLayerGuid* aOutTargetGuid,
                                           WidgetInputEvent* aOutEvent)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->NotifyInputEvent(aEvent, aOutEvent);
+    rfp->NotifyInputEvent(aEvent, aOutTargetGuid, aOutEvent);
   }
 }
 
 bool
 TabParent::RecvBrowserFrameOpenWindow(PBrowserParent* aOpener,
                                       const nsString& aURL,
                                       const nsString& aName,
                                       const nsString& aFeatures,
@@ -1608,51 +1610,56 @@ TabParent::RecvPRenderFrameConstructor(P
     rfp->NotifyDimensionsChanged(ScreenIntSize::FromUnknownSize(
       gfx::IntSize(mDimensions.width, mDimensions.height)));
   }
 
   return true;
 }
 
 bool
-TabParent::RecvZoomToRect(const CSSRect& aRect)
+TabParent::RecvZoomToRect(const uint32_t& aPresShellId,
+                          const ViewID& aViewId,
+                          const CSSRect& aRect)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->ZoomToRect(aRect);
+    rfp->ZoomToRect(aPresShellId, aViewId, aRect);
   }
   return true;
 }
 
 bool
-TabParent::RecvUpdateZoomConstraints(const bool& aAllowZoom,
+TabParent::RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
+                                     const ViewID& aViewId,
+                                     const bool& aAllowZoom,
                                      const CSSToScreenScale& aMinZoom,
                                      const CSSToScreenScale& aMaxZoom)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->UpdateZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
+    rfp->UpdateZoomConstraints(aPresShellId, aViewId, aAllowZoom, aMinZoom, aMaxZoom);
   }
   return true;
 }
 
 bool
 TabParent::RecvUpdateScrollOffset(const uint32_t& aPresShellId,
                                   const ViewID& aViewId,
                                   const CSSIntPoint& aScrollOffset)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
     rfp->UpdateScrollOffset(aPresShellId, aViewId, aScrollOffset);
   }
   return true;
 }
 
 bool
-TabParent::RecvContentReceivedTouch(const bool& aPreventDefault)
+TabParent::RecvContentReceivedTouch(const ScrollableLayerGuid& aGuid,
+                                    const bool& aPreventDefault)
 {
   if (RenderFrameParent* rfp = GetRenderFrame()) {
-    rfp->ContentReceivedTouch(aPreventDefault);
+    rfp->ContentReceivedTouch(aGuid, aPreventDefault);
   }
   return true;
 }
 
 bool
 TabParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
                                      const bool& aIsAudio,
                                      const bool& aIsVideo)
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -157,22 +157,27 @@ public:
                                      const int32_t& aFocusChange);
     virtual bool RecvRequestFocus(const bool& aCanRaise);
     virtual bool RecvSetCursor(const uint32_t& aValue);
     virtual bool RecvSetBackgroundColor(const nscolor& aValue);
     virtual bool RecvSetStatus(const uint32_t& aType, const nsString& aStatus);
     virtual bool RecvGetDPI(float* aValue);
     virtual bool RecvGetDefaultScale(double* aValue);
     virtual bool RecvGetWidgetNativeData(WindowsHandle* aValue);
-    virtual bool RecvZoomToRect(const CSSRect& aRect);
-    virtual bool RecvUpdateZoomConstraints(const bool& aAllowZoom,
+    virtual bool RecvZoomToRect(const uint32_t& aPresShellId,
+                                const ViewID& aViewId,
+                                const CSSRect& aRect);
+    virtual bool RecvUpdateZoomConstraints(const uint32_t& aPresShellId,
+                                           const ViewID& aViewId,
+                                           const bool& aAllowZoom,
                                            const CSSToScreenScale& aMinZoom,
                                            const CSSToScreenScale& aMaxZoom);
     virtual bool RecvUpdateScrollOffset(const uint32_t& aPresShellId, const ViewID& aViewId, const CSSIntPoint& aScrollOffset);
-    virtual bool RecvContentReceivedTouch(const bool& aPreventDefault);
+    virtual bool RecvContentReceivedTouch(const ScrollableLayerGuid& aGuid,
+                                          const bool& aPreventDefault);
     virtual bool RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
                                            const bool& aIsAudio,
                                            const bool& aIsVideo);
     virtual PContentDialogParent* AllocPContentDialogParent(const uint32_t& aType,
                                                             const nsCString& aName,
                                                             const nsCString& aFeatures,
                                                             const InfallibleTArray<int>& aIntParams,
                                                             const InfallibleTArray<nsString>& aStringParams);
@@ -338,18 +343,21 @@ private:
     void TryCacheDPIAndScale();
 
     // When true, we create a pan/zoom controller for our frame and
     // notify it of input events targeting us.
     bool UseAsyncPanZoom();
     // If we have a render frame currently, notify it that we're about
     // to dispatch |aEvent| to our child.  If there's a relevant
     // transform in place, |aOutEvent| is the transformed |aEvent| to
-    // dispatch to content.
+    // dispatch to content. |aOutTargetGuid| will contain the identifier
+    // of the APZC instance that handled the event. aOutTargetGuid may be
+    // null but aOutEvent must not be.
     void MaybeForwardEventToRenderFrame(const WidgetInputEvent& aEvent,
+                                        ScrollableLayerGuid* aOutTargetGuid,
                                         WidgetInputEvent* aOutEvent);
     // The offset for the child process which is sampled at touch start. This
     // means that the touch events are relative to where the frame was at the
     // start of the touch. We need to look for a better solution to this
     // problem see bug 872911.
     LayoutDeviceIntPoint mChildProcessOffsetAtTouchStart;
     // When true, we've initiated normal shutdown and notified our
     // managing PContent.
--- a/dom/messages/SystemMessagePermissionsChecker.jsm
+++ b/dom/messages/SystemMessagePermissionsChecker.jsm
@@ -90,16 +90,25 @@ this.SystemMessagePermissionsTable = {
     "mobileconnection": []
   },
   "wappush-received": {
     "wappush": []
   },
   "cdma-info-rec-received": {
     "mobileconnection": []
   },
+  "nfc-manager-tech-discovered": {
+    "nfc-manager": []
+  },
+  "nfc-manager-tech-lost": {
+    "nfc-manager": []
+  },
+  "nfc-powerlevel-change": {
+    "settings": ["read", "write"]
+  }
 };
 
 this.SystemMessagePermissionsChecker = {
   /**
    * Return all the needed permission names for the given system message.
    * @param string aSysMsgName
    *        The system messsage name.
    * @returns object
--- a/dom/mobilemessage/src/gonk/MmsService.js
+++ b/dom/mobilemessage/src/gonk/MmsService.js
@@ -32,19 +32,16 @@ const kSmsReceivedObserverTopic         
 const kSmsRetrievingObserverTopic        = "sms-retrieving";
 const kSmsDeliverySuccessObserverTopic   = "sms-delivery-success";
 const kSmsDeliveryErrorObserverTopic     = "sms-delivery-error";
 
 const NS_XPCOM_SHUTDOWN_OBSERVER_ID      = "xpcom-shutdown";
 const kNetworkInterfaceStateChangedTopic = "network-interface-state-changed";
 const kMobileMessageDeletedObserverTopic = "mobile-message-deleted";
 
-const kPrefRilMmsc                       = "ril.mms.mmsc";
-const kPrefRilMmsProxy                   = "ril.mms.mmsproxy";
-const kPrefRilMmsPort                    = "ril.mms.mmsport";
 const kPrefRilRadioDisabled              = "ril.radio.disabled";
 
 // HTTP status codes:
 // @see http://tools.ietf.org/html/rfc2616#page-39
 const HTTP_STATUS_OK = 200;
 
 // Non-standard HTTP status for internal use.
 const _HTTP_STATUS_ACQUIRE_CONNECTION_SUCCESS  =  0;
@@ -169,33 +166,34 @@ MmsConnection.prototype = {
 
   get proxyInfo() {
     if (!this.mmsProxy) {
       if (DEBUG) debug("getProxyInfo: MMS proxy is not available.");
       return null;
     }
 
     let port = this.mmsPort;
-    if (port == -1) {
+
+    if (port <= 0) {
       port = 80;
       if (DEBUG) debug("getProxyInfo: port is not valid. Set to defult (80).");
     }
 
     let proxyInfo =
       gpps.newProxyInfo("http", this.mmsProxy, port,
                         Ci.nsIProxyInfo.TRANSPARENT_PROXY_RESOLVES_HOST,
                         -1, null);
     if (DEBUG) debug("getProxyInfo: " + JSON.stringify(proxyInfo));
 
     return proxyInfo;
   },
 
   // For keeping track of the radio status.
   radioDisabled: false,
-  settings: ["ril.radio.disabled"],
+  settings: [kPrefRilRadioDisabled],
   connected: false,
 
   //A queue to buffer the MMS HTTP requests when the MMS network
   //is not yet connected. The buffered requests will be cleared
   //if the MMS network fails to be connected within a timer.
   pendingCallbacks: [],
 
   /** MMS network connection reference count. */
@@ -1167,16 +1165,17 @@ SendTransaction.prototype = Object.creat
    */
   run: {
     value: function run(callback) {
       this.registerRunCallback(callback);
 
       if (!this.istreamComposed) {
         this.loadBlobs(this.msg.parts, (function () {
           this.istream = MMS.PduHelper.compose(null, this.msg);
+          this.istreamSize = this.istream.available();
           this.istreamComposed = true;
           if (this.isCancelled) {
             this.runCallbackIfValid(_MMS_ERROR_MESSAGE_DELETED, null);
           } else {
             this.run(callback);
           }
         }).bind(this));
         return;
@@ -1197,16 +1196,23 @@ SendTransaction.prototype = Object.creat
           }
 
           if (this.timer == null) {
             this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
           }
 
           this.retryCount++;
 
+          // the input stream may be read in the previous failure request so
+          // we have to re-compose it.
+          if (this.istreamSize == null ||
+              this.istreamSize != this.istream.available()) {
+            this.istream = MMS.PduHelper.compose(null, this.msg);
+          }
+
           this.timer.initWithCallback(this.send.bind(this, retryCallback),
                                       PREF_SEND_RETRY_INTERVAL,
                                       Ci.nsITimer.TYPE_ONE_SHOT);
           return;
         }
 
         this.runCallbackIfValid(mmsStatus, msg);
       }).bind(this);
--- a/dom/mobilemessage/src/gonk/WspPduHelper.jsm
+++ b/dom/mobilemessage/src/gonk/WspPduHelper.jsm
@@ -2441,41 +2441,42 @@ this.PduHelper = {
         }
 
         // Restore Content-Type back
         part.headers["content-type"] = contentType;
       }
 
       // Encode headersLen, DataLen
       let headersLen = data.offset;
+      let content = part.content;
       UintVar.encode(data, headersLen);
-      if (typeof part.content === "string") {
+      if (typeof content === "string") {
         let charset;
         if (contentType && contentType.params && contentType.params.charset &&
           contentType.params.charset.charset) {
           charset = contentType.params.charset.charset;
         }
-        part.content = this.encodeStringContent(part.content, charset);
-        UintVar.encode(data, part.content.length);
+        content = this.encodeStringContent(content, charset);
+        UintVar.encode(data, content.length);
       } else if (part.content instanceof Uint8Array) {
-        UintVar.encode(data, part.content.length);
+        UintVar.encode(data, content.length);
       } else {
         throw new TypeError();
       }
 
       // Move them to the beginning of encoded octet array.
       let slice1 = data.array.slice(headersLen);
       let slice2 = data.array.slice(0, headersLen);
       data.array = slice1.concat(slice2);
       debug("Encoded per-part header: " + JSON.stringify(data.array));
 
       // Append per-part header
       this.appendArrayToMultiStream(multiStream, data.array, data.offset);
       // Append part content
-      this.appendArrayToMultiStream(multiStream, part.content, part.content.length);
+      this.appendArrayToMultiStream(multiStream, content, content.length);
     }
   },
 };
 
 // WSP Header Field Name Assignments
 // Note: Items commented out are either deprecated or not implemented.
 //       Deprecated items should only be supported for backward compatibility
 //       purpose.
--- a/dom/mobilemessage/tests/header_helpers.js
+++ b/dom/mobilemessage/tests/header_helpers.js
@@ -48,19 +48,17 @@ function do_check_throws(func, result, s
  * @param data
  *        Input data for `func`.
  * @param expect
  *        Expected result.
  */
 function wsp_test_func(func, data, expect) {
   let result_str = JSON.stringify(func(data));
   let expect_str = JSON.stringify(expect);
-  if (result_str !== expect_str) {
-    do_throw("expect value: '" + expect_str + "', got '" + result_str + "'");
-  }
+  do_check_eq(result_str, expect_str);
 }
 
 /**
  * Test customized WSP PDU decoding.
  *
  * @param func
  *        Decoding func under test. It should return a decoded value if invoked.
  * @param input
--- a/dom/mobilemessage/tests/test_wsp_pdu_helper.js
+++ b/dom/mobilemessage/tests/test_wsp_pdu_helper.js
@@ -1309,8 +1309,49 @@ add_test(function StringContent_decode()
     let octetArray = WSP.Octet.decodeMultiple(data, data.array.length);
     wsp_decode_test_ex(function (data) {
         return WSP.PduHelper.decodeStringContent(data.array, "utf-16");
       }, raw, str);
   }
 
   run_next_test();
 });
+
+//// PduHelper.composeMultiPart ////
+
+add_test(function test_PduHelper_composeMultiPart() {
+  let multiStream = Components.classes["@mozilla.org/io/multiplex-input-stream;1"]
+                    .createInstance(Ci.nsIMultiplexInputStream);
+  let uint8Array = new Uint8Array(5);
+  uint8Array[0] = 0x00;
+  uint8Array[1] = 0x01;
+  uint8Array[2] = 0x02;
+  uint8Array[3] = 0x03;
+  uint8Array[4] = 0x04;
+
+  let parts = [
+      {
+        content: "content",
+        headers: {
+            "content-type": {
+                media: "text/plain",
+                params: {}
+            }
+        }
+      },
+      {
+        content: uint8Array,
+        headers: {
+            "content-type": {
+                media: "text/plain",
+                params: {}
+            }
+        }
+      }
+    ];
+
+  let beforeCompose = JSON.stringify(parts);
+  WSP.PduHelper.composeMultiPart(multiStream, parts);
+  let afterCompose = JSON.stringify(parts);
+
+  do_check_eq(beforeCompose, afterCompose);
+  run_next_test();
+});
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -92,16 +92,19 @@ if CONFIG['MOZ_B2G_RIL']:
     ]
 
 if CONFIG['MOZ_PAY']:
     PARALLEL_DIRS += ['payment']
 
 if CONFIG['MOZ_GAMEPAD']:
     PARALLEL_DIRS += ['gamepad']
 
+if CONFIG['MOZ_NFC']:
+    PARALLEL_DIRS += ['nfc']
+
 # bindings/test is here, because it needs to build after bindings/, and
 # we build subdirectories before ourselves.
 TEST_DIRS += [
     'tests',
     'imptests',
     'bindings/test',
 ]
 
--- a/dom/network/interfaces/nsIDOMMobileConnection.idl
+++ b/dom/network/interfaces/nsIDOMMobileConnection.idl
@@ -6,17 +6,17 @@
 
 interface nsIDOMEventListener;
 interface nsIDOMDOMRequest;
 interface nsIDOMMozMobileConnectionInfo;
 interface nsIDOMMozMobileNetworkInfo;
 interface nsIDOMMozMobileCellInfo;
 interface nsIDOMMozMobileCFInfo;
 
-[scriptable, builtinclass, uuid(095b3720-058c-11e3-8ffd-0800200c9a66)]
+[scriptable, builtinclass, uuid(052550e3-7466-4941-80d7-405c169652f9)]
 interface nsIDOMMozMobileConnection : nsIDOMEventTarget
 {
   const long ICC_SERVICE_CLASS_VOICE = (1 << 0);
   const long ICC_SERVICE_CLASS_DATA = (1 << 1);
   const long ICC_SERVICE_CLASS_FAX = (1 << 2);
   const long ICC_SERVICE_CLASS_SMS = (1 << 3);
   const long ICC_SERVICE_CLASS_DATA_SYNC = (1 << 4);
   const long ICC_SERVICE_CLASS_DATA_ASYNC = (1 << 5);
@@ -65,16 +65,22 @@ interface nsIDOMMozMobileConnection : ns
   readonly attribute nsIDOMMozMobileConnectionInfo voice;
 
   /**
    * Information about the data connection.
    */
   readonly attribute nsIDOMMozMobileConnectionInfo data;
 
   /**
+   * Integrated Circuit Card Identifier of the SIM this
+   * mobile connection corresponds to.
+   */
+  readonly attribute DOMString iccId;
+
+  /**
    * The selection mode of the voice and data networks.
    *
    * Possible values: null (unknown), 'automatic', 'manual'
    */
   readonly attribute DOMString networkSelectionMode;
 
   /**
    * Search for available networks.
@@ -378,16 +384,22 @@ interface nsIDOMMozMobileConnection : ns
    */
   [implicit_jscontext] attribute jsval onemergencycbmodechange;
 
   /**
    * The 'onotastatuschange' event is notified whenever the ota provision status
    * changes.
    */
   [implicit_jscontext] attribute jsval onotastatuschange;
+
+  /**
+   * The 'oniccchange' event is notified whenever the iccid value
+   * changes.
+   */
+  [implicit_jscontext] attribute jsval oniccchange;
 };
 
 [scriptable, uuid(49706beb-a160-40b7-b745-50f62e389a2c)]
 interface nsIDOMMozMobileConnectionInfo : nsISupports
 {
   /**
    * State of the connection.
    *
--- a/dom/network/interfaces/nsIDOMTCPSocket.idl
+++ b/dom/network/interfaces/nsIDOMTCPSocket.idl
@@ -206,36 +206,49 @@ interface nsIDOMTCPSocket : nsISupports
    *
    * If onerror was not called before onclose, then either side cleanly
    * closed the connection.
    */
   attribute jsval onclose;
 };
 
 /*
- * Internal interfaces for use in cross-process socket implementation.
+ * This interface is implemented in TCPSocket.js as an internal interfaces
+ * for use in cross-process socket implementation.
  * Needed to account for multiple possible types that can be provided to
  * the socket callbacks as arguments.
  */
-[scriptable, uuid(234c664c-3d6c-4859-b45c-4e9a98cb5bdc)]
+[scriptable, uuid(017f130f-2477-4215-8783-57eada957699)]
 interface nsITCPSocketInternal : nsISupports {
   // Trigger the callback for |type| and provide a DOMError() object with the given data
   void callListenerError(in DOMString type, in DOMString name);
 
   // Trigger the callback for |type| and provide a string argument
   void callListenerData(in DOMString type, in DOMString data);
 
   // Trigger the callback for |type| and provide an ArrayBuffer argument
   void callListenerArrayBuffer(in DOMString type, in jsval data);
 
   // Trigger the callback for |type| with no argument
   void callListenerVoid(in DOMString type);
 
-  // Update the DOM object's readyState and bufferedAmount values with the provided data
-  void updateReadyStateAndBuffered(in DOMString readyState, in uint32_t bufferedAmount);
+  // Update the DOM object's readyState.
+  // @param readyState
+  //        new ready state to be set to TCPSocket.
+  void updateReadyState(in DOMString readyState);
+
+  // Update the DOM object's bufferedAmount value with a tracking number to
+  // ensure the update request is sent after child's send() invocation.
+  // @param bufferedAmount
+  //        TCPSocket parent's bufferedAmount.
+  // @param trackingNumber
+  //        A number to ensure the bufferedAmount is updated after data
+  //        from child are sent to parent.
+  void updateBufferedAmount(in uint32_t bufferedAmount,
+                            in uint32_t trackingNumber);
 
   // Create a socket object on the parent side.
   // This is called in accepting any open request on the parent side.
   // 
   // @param transport
   //        The accepted socket transport.
   // @param binaryType
   //        "arraybuffer" to use ArrayBuffer instances 
@@ -254,16 +267,28 @@ interface nsITCPSocketInternal : nsISupp
   // @param window
   //        An object to create ArrayBuffer for this window. See Bug 831107.
   nsIDOMTCPSocket createAcceptedChild(in nsITCPSocketChild socketChild,
                                       in DOMString binaryType,
                                       in nsIDOMWindow window);
 
   // Set App ID.
   void setAppId(in unsigned long appId);
+
+  // Set a callback that handles the request from a TCP socket parent when that
+  // socket parent wants to notify that its bufferedAmount is updated.
+  void setOnUpdateBufferedAmountHandler(in jsval handler);
+
+  // Providing child process with ability to pass more arguments to parent's
+  // send() function.
+  // @param trackingNumber
+  //        To ensure the request to update bufferedAmount in child is after
+  //        lastest send() invocation from child.
+  void onRecvSendFromChild(in jsval data, in unsigned long byteOffset,
+                           in unsigned long byteLength, in unsigned long trackingNumber);
 };
 
 /**
  * nsITCPSocketEvent is the event object which is passed as the
  * first argument to all the event handler callbacks. It contains
  * the socket that was associated with the event, the type of event,
  * and the data associated with the event (if any).
  */
--- a/dom/network/interfaces/nsITCPSocketChild.idl
+++ b/dom/network/interfaces/nsITCPSocketChild.idl
@@ -3,32 +3,36 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "domstubs.idl"
 
 interface nsITCPSocketInternal;
 interface nsIDOMWindow;
 
 // Interface to allow the content process socket to reach the IPC bridge.
-[scriptable, uuid(ada5342d-6d45-4ff1-a7d3-6a4b150d0385)]
+// Implemented in C++ as TCPSocketChild, referenced as _socketBridge in TCPSocket.js
+[scriptable, uuid(292ebb3a-beac-4e06-88b0-b5b4e88ebd1c)]
 interface nsITCPSocketChild : nsISupports
 {
   // Tell the chrome process to open a corresponding connection with the given parameters
   [implicit_jscontext]
-  void open(in nsITCPSocketInternal socket, in DOMString host,
-            in unsigned short port, in boolean ssl, in DOMString binaryType,
-            in nsIDOMWindow window, in jsval windowVal);
+  void sendOpen(in nsITCPSocketInternal socket, in DOMString host,
+                in unsigned short port, in boolean ssl, in DOMString binaryType,
+                in nsIDOMWindow window, in jsval windowVal);
+
+  // Tell the chrome process to perform send and update the tracking number.
+  [implicit_jscontext] 
+  void sendSend(in jsval data, in unsigned long byteOffset,
+                in unsigned long byteLength, in unsigned long trackingNumber);
 
   // Tell the chrome process to perform equivalent operations to all following methods
-  [implicit_jscontext] 
-  void send(in jsval data, in unsigned long byteOffset, in unsigned long byteLength);
-  void resume();
-  void suspend();
-  void close();
-  void startTLS();
+  void sendResume();
+  void sendSuspend();
+  void sendClose();
+  void sendStartTLS();
 
   /**
    * Initialize the TCP socket on the child side for IPC. It is called from the child side,
    * which is generated in receiving a notification of accepting any open request
    * on the parent side. We use single implementation that works on a child process 
    * as well as in the single process model.
    *
    * @param socket
--- a/dom/network/interfaces/nsITCPSocketParent.idl
+++ b/dom/network/interfaces/nsITCPSocketParent.idl
@@ -4,56 +4,80 @@
 
 #include "domstubs.idl"
 
 interface nsIDOMTCPSocket;
 interface nsIDOMTCPServerSocket;
 interface nsITCPServerSocketParent;
 interface nsITCPSocketIntermediary;
 
-// Interface required to allow the TCP socket object in the parent process
-// to talk to the parent IPC actor
-[scriptable, uuid(123f654b-4435-43c8-8447-db1b5420a1c2)]
+// Interface required to allow the TCP socket object (TCPSocket.js) in the
+// parent process to talk to the parent IPC actor, TCPSocketParent, which
+// is written in C++.
+[scriptable, uuid(868662a4-681c-4b89-9f02-6fe5b7ace265)]
 interface nsITCPSocketParent : nsISupports
 {
   [implicit_jscontext] void initJS(in jsval intermediary);
 
   // Trigger a callback in the content process for |type|, providing a serialized
-  // argument of |data|, and update the child's readyState and bufferedAmount values
-  // with the given values.
-  [implicit_jscontext] void sendCallback(in DOMString type,
-                                         in jsval data,
-                                         in DOMString readyState,
-                                         in uint32_t bufferedAmount);
+  // argument of |data|, and update the child's readyState value with the given
+  // values.
+  //
+  // @param type
+  //        Event type: 'onopen', 'ondata', 'onerror' or 'onclose'. 'odrain' is
+  //        controlled by child.
+  // @param data
+  //        Serialized data that is passed to event handler.
+  // @param readyState
+  //        Current ready state.
+  [implicit_jscontext] void sendEvent(in DOMString type,
+                                      in jsval data,
+                                      in DOMString readyState);
 
   // Initialize a parent socket object. It is called from the parent side socket,
   // which is generated in accepting any open request on the parent side.
   // The socket after being initialized will be established.
   //
   // @param socket
   //        The socket on the parent side.
   // @param intermediary
   //        Intermediate class object. See nsITCPSocketIntermediary.
   [implicit_jscontext] void setSocketAndIntermediary(in nsIDOMTCPSocket socket,
                                                      in nsITCPSocketIntermediary intermediary);
+
+  // When parent's buffered amount is updated and it wants to inform child to
+  // update the bufferedAmount as well.
+  //
+  // @param bufferedAmount
+  //        The new value of bufferedAmount that is going to be set to child's
+  //        bufferedAmount.
+  // @param trackingNumber
+  //        Parent's current tracking number, reflecting the number of calls to
+  //        send() on the child process. This number is sent back to the child
+  //        to make sure the bufferedAmount updated on the child will correspond
+  //        to the latest call of send().
+  void sendUpdateBufferedAmount(in uint32_t bufferedAmount, in uint32_t trackingNumber);
 };
 
 // Intermediate class to handle sending multiple possible data types
 // and kicking off the chrome process socket object's connection.
-[scriptable, uuid(be67b1b8-03b0-4171-a791-d004458021b6)]
+// This interface is the bridge of TCPSocketParent, which is written in C++,
+// and TCPSocket, which is written in Javascript. TCPSocketParentIntermediary
+// implements nsITCPSocketIntermediary in Javascript.
+[scriptable, uuid(c434224a-dbb7-4869-8b2b-e49cee990e85)]
 interface nsITCPSocketIntermediary : nsISupports {
   // Open the connection to the server with the given parameters
   nsIDOMTCPSocket open(in nsITCPSocketParent parent,
                        in DOMString host, in unsigned short port,
                        in boolean useSSL, in DOMString binaryType,
                        in unsigned long appId);
 
   // Listen on a port
   nsIDOMTCPServerSocket listen(in nsITCPServerSocketParent parent,
                                in unsigned short port, in unsigned short backlog,
                                in DOMString binaryType);
 
-  // Send a basic string along the connection
-  void sendString(in DOMString data);
+  // Called when received a child request to send a string.
+  void onRecvSendString(in DOMString data, in uint32_t trackingNumber);
 
-  // Send a typed array
-  void sendArrayBuffer(in jsval data);
+  // Called when received a child request to send an array buffer.
+  void onRecvSendArrayBuffer(in jsval data, in uint32_t trackingNumber);
 };
--- a/dom/network/src/MobileConnection.cpp
+++ b/dom/network/src/MobileConnection.cpp
@@ -72,25 +72,24 @@ NS_IMPL_RELEASE_INHERITED(MobileConnecti
 
 NS_IMPL_EVENT_HANDLER(MobileConnection, voicechange)
 NS_IMPL_EVENT_HANDLER(MobileConnection, datachange)
 NS_IMPL_EVENT_HANDLER(MobileConnection, ussdreceived)
 NS_IMPL_EVENT_HANDLER(MobileConnection, dataerror)
 NS_IMPL_EVENT_HANDLER(MobileConnection, cfstatechange)
 NS_IMPL_EVENT_HANDLER(MobileConnection, emergencycbmodechange)
 NS_IMPL_EVENT_HANDLER(MobileConnection, otastatuschange)
+NS_IMPL_EVENT_HANDLER(MobileConnection, iccchange)
 
-MobileConnection::MobileConnection()
+MobileConnection::MobileConnection(uint32_t aClientId)
+: mClientId(aClientId)
 {
   mProvider = do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
   mWindow = nullptr;
 
-  // TODO: Bug 814629 - WebMobileConnection API: support multiple sim cards
-  mClientId = 0;
-
   // Not being able to acquire the provider isn't fatal since we check
   // for it explicitly below.
   if (!mProvider) {
     NS_WARNING("Could not acquire nsIMobileConnectionProvider!");
     return;
   }
 }
 
@@ -121,137 +120,148 @@ MobileConnection::Shutdown()
     mProvider = nullptr;
     mListener = nullptr;
   }
 }
 
 // nsIDOMMozMobileConnection
 
 NS_IMETHODIMP
-MobileConnection::GetLastKnownNetwork(nsAString& network)
+MobileConnection::GetLastKnownNetwork(nsAString& aNetwork)
 {
-  network.SetIsVoid(true);
+  aNetwork.SetIsVoid(true);
 
   if (!CheckPermission("mobilenetwork")) {
     return NS_OK;
   }
 
-  network = mozilla::Preferences::GetString("ril.lastKnownNetwork");
+  aNetwork = mozilla::Preferences::GetString("ril.lastKnownNetwork");
   return NS_OK;
 }
 
 NS_IMETHODIMP
-MobileConnection::GetLastKnownHomeNetwork(nsAString& network)
+MobileConnection::GetLastKnownHomeNetwork(nsAString& aNetwork)
 {
-  network.SetIsVoid(true);
+  aNetwork.SetIsVoid(true);
 
   if (!CheckPermission("mobilenetwork")) {
     return NS_OK;
   }
 
-  network = mozilla::Preferences::GetString("ril.lastKnownHomeNetwork");
+  aNetwork = mozilla::Preferences::GetString("ril.lastKnownHomeNetwork");
   return NS_OK;
 }
 
 // All fields below require the "mobileconnection" permission.
 
 bool
-MobileConnection::CheckPermission(const char* type)
+MobileConnection::CheckPermission(const char* aType)
 {
   nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, false);
 
   nsCOMPtr<nsIPermissionManager> permMgr =
     do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
   NS_ENSURE_TRUE(permMgr, false);
 
   uint32_t permission = nsIPermissionManager::DENY_ACTION;
-  permMgr->TestPermissionFromWindow(window, type, &permission);
+  permMgr->TestPermissionFromWindow(window, aType, &permission);
   return permission == nsIPermissionManager::ALLOW_ACTION;
 }
 
 NS_IMETHODIMP
-MobileConnection::GetVoice(nsIDOMMozMobileConnectionInfo** voice)
+MobileConnection::GetVoice(nsIDOMMozMobileConnectionInfo** aVoice)
 {
-  *voice = nullptr;
+  *aVoice = nullptr;
+
+  if (!mProvider || !CheckPermission("mobileconnection")) {
+    return NS_OK;
+  }
+  return mProvider->GetVoiceConnectionInfo(mClientId, aVoice);
+}
+
+NS_IMETHODIMP
+MobileConnection::GetData(nsIDOMMozMobileConnectionInfo** aData)
+{
+  *aData = nullptr;
 
   if (!mProvider || !CheckPermission("mobileconnection")) {
     return NS_OK;
   }
-  return mProvider->GetVoiceConnectionInfo(mClientId, voice);
+  return mProvider->GetDataConnectionInfo(mClientId, aData);
 }
 
 NS_IMETHODIMP
-MobileConnection::GetData(nsIDOMMozMobileConnectionInfo** data)
+MobileConnection::GetIccId(nsAString& aIccId)
 {
-  *data = nullptr;
-
-  if (!mProvider || !CheckPermission("mobileconnection")) {
-    return NS_OK;
-  }
-  return mProvider->GetDataConnectionInfo(mClientId, data);
-}
-
-NS_IMETHODIMP
-MobileConnection::GetNetworkSelectionMode(nsAString& networkSelectionMode)
-{
-  networkSelectionMode.SetIsVoid(true);
+  aIccId.SetIsVoid(true);
 
   if (!mProvider || !CheckPermission("mobileconnection")) {
      return NS_OK;
   }
-  return mProvider->GetNetworkSelectionMode(mClientId, networkSelectionMode);
+  return mProvider->GetIccId(mClientId, aIccId);
 }
 
 NS_IMETHODIMP
-MobileConnection::GetNetworks(nsIDOMDOMRequest** request)
+MobileConnection::GetNetworkSelectionMode(nsAString& aNetworkSelectionMode)
 {
-  *request = nullptr;
+  aNetworkSelectionMode.SetIsVoid(true);
+
+  if (!mProvider || !CheckPermission("mobileconnection")) {
+     return NS_OK;
+  }
+  return mProvider->GetNetworkSelectionMode(mClientId, aNetworkSelectionMode);
+}
+
+NS_IMETHODIMP
+MobileConnection::GetNetworks(nsIDOMDOMRequest** aRequest)
+{
+  *aRequest = nullptr;
 
   if (!CheckPermission("mobileconnection")) {
     return NS_OK;
   }
 
   if (!mProvider) {
     return NS_ERROR_FAILURE;
   }
 
-  return mProvider->GetNetworks(mClientId, GetOwner(), request);
+  return mProvider->GetNetworks(mClientId, GetOwner(), aRequest);
 }
 
 NS_IMETHODIMP
-MobileConnection::SelectNetwork(nsIDOMMozMobileNetworkInfo* network, nsIDOMDOMRequest** request)
+MobileConnection::SelectNetwork(nsIDOMMozMobileNetworkInfo* aNetwork, nsIDOMDOMRequest** aRequest)
 {
-  *request = nullptr;
+  *aRequest = nullptr;
 
   if (!CheckPermission("mobileconnection")) {
     return NS_OK;
   }
 
   if (!mProvider) {
     return NS_ERROR_FAILURE;
   }
 
-  return mProvider->SelectNetwork(mClientId, GetOwner(), network, request);
+  return mProvider->SelectNetwork(mClientId, GetOwner(), aNetwork, aRequest);
 }
 
 NS_IMETHODIMP
-MobileConnection::SelectNetworkAutomatically(nsIDOMDOMRequest** request)
+MobileConnection::SelectNetworkAutomatically(nsIDOMDOMRequest** aRequest)
 {
-  *request = nullptr;
+  *aRequest = nullptr;
 
   if (!CheckPermission("mobileconnection")) {
     return NS_OK;
   }
 
   if (!mProvider) {
     return NS_ERROR_FAILURE;
   }
 
-  return mProvider->SelectNetworkAutomatically(mClientId, GetOwner(), request);
+  return mProvider->SelectNetworkAutomatically(mClientId, GetOwner(), aRequest);
 }
 
 NS_IMETHODIMP
 MobileConnection::SetRoamingPreference(const nsAString& aMode, nsIDOMDOMRequest** aDomRequest)
 {
   *aDomRequest = nullptr;
 
   if (!CheckPermission("mobileconnection")) {
@@ -633,12 +643,14 @@ MobileConnection::NotifyOtaStatusChanged
   NS_ENSURE_SUCCESS(rv, rv);
 
   return DispatchTrustedEvent(ce);
 }
 
 NS_IMETHODIMP
 MobileConnection::NotifyIccChanged()
 {
-  // TODO: Bug 814629 - WebMobileConnection API: support multiple sim cards
-  // Return NS_OK for now, will be implemented in Bug 814629.
-  return NS_OK;
-}
\ No newline at end of file
+  if (!CheckPermission("mobileconnection")) {
+    return NS_OK;
+  }
+
+  return DispatchTrustedEvent(NS_LITERAL_STRING("iccchange"));
+}
--- a/dom/network/src/MobileConnection.h
+++ b/dom/network/src/MobileConnection.h
@@ -30,31 +30,31 @@ class MobileConnection : public nsDOMEve
 
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIDOMMOZMOBILECONNECTION
   NS_DECL_NSIMOBILECONNECTIONLISTENER
 
   NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
 
-  MobileConnection();
+  MobileConnection(uint32_t aClientId);
 
   void Init(nsPIDOMWindow *aWindow);
   void Shutdown();
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MobileConnection,
                                            nsDOMEventTargetHelper)
 
 private:
   nsCOMPtr<nsIMobileConnectionProvider> mProvider;
   nsRefPtr<Listener> mListener;
   nsWeakPtr mWindow;
 
   uint32_t mClientId;
 
-  bool CheckPermission(const char* type);
+  bool CheckPermission(const char* aType);
 };
 
 } // namespace network
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_network_MobileConnection_h
new file mode 100644
--- /dev/null
+++ b/dom/network/src/MobileConnectionArray.cpp
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+#include "MobileConnectionArray.h"
+#include "mozilla/dom/MozMobileConnectionArrayBinding.h"
+#include "mozilla/Preferences.h"
+
+using namespace mozilla::dom::network;
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(MobileConnectionArray,
+                                        mWindow,
+                                        mMobileConnections)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(MobileConnectionArray)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(MobileConnectionArray)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MobileConnectionArray)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+MobileConnectionArray::MobileConnectionArray(nsPIDOMWindow* aWindow)
+: mWindow(aWindow)
+{
+  int32_t numRil = mozilla::Preferences::GetInt("ril.numRadioInterfaces", 1);
+  MOZ_ASSERT(numRil > 0);
+
+  for (int32_t id = 0; id < numRil; id++) {
+    nsRefPtr<MobileConnection> mobileConnection = new MobileConnection(id);
+    mobileConnection->Init(aWindow);
+    mMobileConnections.AppendElement(mobileConnection);
+  }
+
+  SetIsDOMBinding();
+}
+
+MobileConnectionArray::~MobileConnectionArray()
+{
+  for (uint32_t i = 0; i < mMobileConnections.Length(); i++) {
+    mMobileConnections[i]->Shutdown();
+  }
+  mMobileConnections.Clear();
+}
+
+nsPIDOMWindow*
+MobileConnectionArray::GetParentObject() const
+{
+  MOZ_ASSERT(mWindow);
+  return mWindow;
+}
+
+JSObject*
+MobileConnectionArray::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return MozMobileConnectionArrayBinding::Wrap(aCx, aScope, this);
+}
+
+nsIDOMMozMobileConnection*
+MobileConnectionArray::Item(uint32_t aIndex) const
+{
+  bool unused;
+  return IndexedGetter(aIndex, unused);
+}
+
+uint32_t
+MobileConnectionArray::Length() const
+{
+  return mMobileConnections.Length();
+}
+
+nsIDOMMozMobileConnection*
+MobileConnectionArray::IndexedGetter(uint32_t aIndex, bool& aFound) const
+{
+  aFound = false;
+  aFound = aIndex < mMobileConnections.Length();
+
+  return aFound ? mMobileConnections[aIndex] : nullptr;
+}
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/network/src/MobileConnectionArray.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=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/. */
+
+#ifndef mozilla_dom_network_MobileConnectionArray_h__
+#define mozilla_dom_network_MobileConnectionArray_h__
+
+#include "nsWrapperCache.h"
+#include "mozilla/dom/network/MobileConnection.h"
+
+class nsIDOMMozMobileConnection;
+
+namespace mozilla {
+namespace dom {
+namespace network {
+
+class MobileConnectionArray MOZ_FINAL : public nsISupports,
+                                        public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MobileConnectionArray)
+
+  MobileConnectionArray(nsPIDOMWindow* aWindow);
+
+  nsPIDOMWindow*
+  GetParentObject() const;
+
+  // WrapperCache
+  virtual JSObject*
+  WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  //  WebIDL
+  nsIDOMMozMobileConnection*
+  Item(uint32_t aIndex) const;
+
+  uint32_t
+  Length() const;
+
+  nsIDOMMozMobileConnection*
+  IndexedGetter(uint32_t aIndex, bool& aFound) const;
+
+private:
+  ~MobileConnectionArray();
+
+  nsCOMPtr<nsPIDOMWindow> mWindow;
+  nsTArray<nsRefPtr<MobileConnection>> mMobileConnections;
+};
+
+} // namespace network
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_network_MobileConnectionArray_h__
\ No newline at end of file
--- a/dom/network/src/NetworkStatsService.jsm
+++ b/dom/network/src/NetworkStatsService.jsm
@@ -357,16 +357,17 @@ this.NetworkStatsService = {
   updateStats: function updateStats(aNetId, aCallback) {
     // Check if the connection is in the main queue, push a new element
     // if it is not being processed or add a callback if it is.
     let index = this.updateQueueIndex(aNetId);
     if (index == -1) {
       this.updateQueue.push({netId: aNetId, callbacks: [aCallback]});
     } else {
       this.updateQueue[index].callbacks.push(aCallback);
+      return;
     }
 
     // Call the function that process the elements of the queue.
     this.processQueue();
   },
 
   /*
    * Find if a connection is in the main queue array and return its
--- a/dom/network/src/PTCPSocket.ipdl
+++ b/dom/network/src/PTCPSocket.ipdl
@@ -30,26 +30,45 @@ namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
 protocol PTCPSocket
 {
   manager PNecko;
 
 parent:
+  // Forward calling to child's open() method to parent, expect TCPOptions
+  // is expanded to |useSSL| (from TCPOptions.useSecureTransport) and
+  // |binaryType| (from TCPOption.binaryType).
   Open(nsString host, uint16_t port, bool useSSL, nsString binaryType);
-  Data(SendableData data);
+
+  // When child's send() is called, this message requrests parent to send
+  // data and update it's trackingNumber.
+  Data(SendableData data, uint32_t trackingNumber);
+
+  // Forward calling to child's upgradeToSecure() method to parent.
   StartTLS();
+
+  // Forward calling to child's send() method to parent.
   Suspend();
+
+  // Forward calling to child's resume() method to parent.
   Resume();
+
+  // Forward calling to child's close() method to parent.
   Close();
 
 child:
-  Callback(nsString type, CallbackData data,
-           nsString readyState, uint32_t bufferedAmount);
+  // Forward events that are dispatched by parent.
+  Callback(nsString type, CallbackData data, nsString readyState);
+
+  // Update child's bufferedAmount when parent's bufferedAmount is updated.
+  // trackingNumber is also passed back to child to ensure the bufferedAmount
+  // is corresponding the last call to send().
+  UpdateBufferedAmount(uint32_t bufferedAmount, uint32_t trackingNumber);
 
 both:
   RequestDelete();
   __delete__();
 };
 
 
 } // namespace net
--- a/dom/network/src/TCPSocket.js
+++ b/dom/network/src/TCPSocket.js
@@ -157,16 +157,20 @@ TCPSocket.prototype = {
 
   // IPC socket actor
   _socketBridge: null,
 
   // StartTLS
   _waitingForStartTLS: false,
   _pendingDataAfterStartTLS: [],
 
+  // Used to notify when update bufferedAmount is updated.
+  _onUpdateBufferedAmount: null,
+  _trackingNumber: 0,
+
 #ifdef MOZ_WIDGET_GONK
   // Network statistics (Gonk-specific feature)
   _txBytes: 0,
   _rxBytes: 0,
   _appId: Ci.nsIScriptSecurityManager.NO_APP_ID,
   _activeNetwork: null,
 #endif
 
@@ -237,28 +241,35 @@ TCPSocket.prototype = {
     } else {
       options = ['starttls'];
     }
     return Cc["@mozilla.org/network/socket-transport-service;1"]
              .getService(Ci.nsISocketTransportService)
              .createTransport(options, 1, host, port, null);
   },
 
+  _sendBufferedAmount: function ts_sendBufferedAmount() {
+    if (this._onUpdateBufferedAmount) {
+      this._onUpdateBufferedAmount(this.bufferedAmount, this._trackingNumber);
+    }
+  },
+
   _ensureCopying: function ts_ensureCopying() {
     let self = this;
     if (this._asyncCopierActive) {
       return;
     }
     this._asyncCopierActive = true;
     this._multiplexStreamCopier.asyncCopy({
       onStartRequest: function ts_output_onStartRequest() {
       },
       onStopRequest: function ts_output_onStopRequest(request, context, status) {
         self._asyncCopierActive = false;
         self._multiplexStream.removeStream(0);
+        self._sendBufferedAmount();
 
         if (!Components.isSuccessCode(status)) {
           // Note that we can/will get an error here as well as in the
           // onStopRequest for inbound data.
           self._maybeReportErrorAndCloseIfOpen(status);
           return;
         }
 
@@ -275,17 +286,19 @@ TCPSocket.prototype = {
             if (self._pendingDataAfterStartTLS.length > 0) {
               while (self._pendingDataAfterStartTLS.length)
                 self._multiplexStream.appendStream(self._pendingDataAfterStartTLS.shift());
               self._ensureCopying();
               return;
             }
           }
 
-          if (self._waitingForDrain) {
+          // If we have a callback to update bufferedAmount, we let child to
+          // decide whether ondrain should be dispatched.
+          if (self._waitingForDrain && !self._onUpdateBufferedAmount) {
             self._waitingForDrain = false;
             self.callListener("drain");
           }
           if (self._readyState === kCLOSING) {
             self._socketOutputStream.close();
             self._readyState = kCLOSED;
             self.callListener("close");
           }
@@ -377,19 +390,46 @@ TCPSocket.prototype = {
   callListenerArrayBuffer: function ts_callListenerArrayBuffer(type, data) {
     this.callListener(type, data);
   },
 
   callListenerVoid: function ts_callListenerVoid(type) {
     this.callListener(type);
   },
 
-  updateReadyStateAndBuffered: function ts_setReadyState(readyState, bufferedAmount) {
+  /**
+   * This method is expected to be called by TCPSocketChild to update child's
+   * readyState.
+   */
+  updateReadyState: function ts_updateReadyState(readyState) {
+    if (!this._inChild) {
+      LOG("Calling updateReadyState in parent, which should only be called " +
+          "in child");
+      return;
+    }
     this._readyState = readyState;
+  },
+
+  updateBufferedAmount: function ts_updateBufferedAmount(bufferedAmount, trackingNumber) {
+    if (trackingNumber != this._trackingNumber) {
+      LOG("updateBufferedAmount is called but trackingNumber is not matched " +
+          "parent's trackingNumber: " + trackingNumber + ", child's trackingNumber: " +
+          this._trackingNumber);
+      return;
+    }
     this._bufferedAmount = bufferedAmount;
+    if (bufferedAmount == 0) {
+      if (this._waitingForDrain) {
+        this._waitingForDrain = false;
+        this.callListener("drain");
+      }
+    } else {
+      LOG("bufferedAmount is updated but haven't reaches zero. bufferedAmount: " +
+          bufferedAmount);
+    }
   },
 
   createAcceptedParent: function ts_createAcceptedParent(transport, binaryType) {
     let that = new TCPSocket();
     that._transport = transport;
     that._initStream(binaryType);
 
     // ReadyState is kOpen since accepted transport stream has already been connected
@@ -415,16 +455,35 @@ TCPSocket.prototype = {
   setAppId: function ts_setAppId(appId) {
 #ifdef MOZ_WIDGET_GONK
     this._appId = appId;
 #else
     // Do nothing because _appId only exists on Gonk-specific platform.
 #endif
   },
 
+  setOnUpdateBufferedAmountHandler: function(aFunction) {
+    if (typeof(aFunction) == 'function') {
+      this._onUpdateBufferedAmount = aFunction;
+    } else {
+      throw new Error("only function can be passed to " +
+                      "setOnUpdateBufferedAmountHandler");
+    }
+  },
+
+  /**
+   * Handle the requst of sending data and update trackingNumber from
+   * child.
+   * This function is expected to be called by TCPSocketChild.
+   */
+  onRecvSendFromChild: function(data, byteOffset, byteLength, trackingNumber) {
+    this._trackingNumber = trackingNumber;
+    this.send(data, byteOffset, byteLength);
+  },
+
   /* end nsITCPSocketInternal methods */
 
   initWindowless: function ts_initWindowless() {
     try {
       return Services.prefs.getBoolPref("dom.mozTCPSocket.enabled");
     } catch (e) {
       // no pref means return false
       return false;
@@ -512,18 +571,18 @@ TCPSocket.prototype = {
       that._binaryType = options.binaryType || that._binaryType;
     }
 
     LOG("SSL: " + that.ssl);
 
     if (this._inChild) {
       that._socketBridge = Cc["@mozilla.org/tcp-socket-child;1"]
                              .createInstance(Ci.nsITCPSocketChild);
-      that._socketBridge.open(that, host, port, !!that._ssl,
-                              that._binaryType, this.useWin, this.useWin || this);
+      that._socketBridge.sendOpen(that, host, port, !!that._ssl,
+                                  that._binaryType, this.useWin, this.useWin || this);
       return that;
     }
 
     let transport = that._transport = this._createTransport(host, port, that._ssl);
     transport.setEventSink(that, Services.tm.currentThread);
     that._initStream(that._binaryType);
 
 #ifdef MOZ_WIDGET_GONK
@@ -546,17 +605,17 @@ TCPSocket.prototype = {
     if (this._ssl == 'ssl') {
       // Already SSL
       return;
     }
 
     this._ssl = 'ssl';
 
     if (this._inChild) {
-      this._socketBridge.startTLS();
+      this._socketBridge.sendStartTLS();
       return;
     }
 
     if (this._multiplexStream.count == 0) {
       this._activateTLS();
     } else {
       this._waitingForStartTLS = true;
     }
@@ -580,17 +639,17 @@ TCPSocket.prototype = {
   close: function ts_close() {
     if (this._readyState === kCLOSED || this._readyState === kCLOSING)
       return;
 
     LOG("close called");
     this._readyState = kCLOSING;
 
     if (this._inChild) {
-      this._socketBridge.close();
+      this._socketBridge.sendClose();
       return;
     }
 
     if (!this._multiplexStream.count) {
       this._socketOutputStream.close();
     }
     this._socketInputStream.close();
   },
@@ -600,25 +659,37 @@ TCPSocket.prototype = {
       throw new Error("Socket not open.");
     }
 
     if (this._binaryType === "arraybuffer") {
       byteLength = byteLength || data.byteLength;
     }
 
     if (this._inChild) {
-      this._socketBridge.send(data, byteOffset, byteLength);
+      this._socketBridge.sendSend(data, byteOffset, byteLength, ++this._trackingNumber);
     }
 
     let length = this._binaryType === "arraybuffer" ? byteLength : data.length;
+    let newBufferedAmount = this.bufferedAmount + length;
+    let bufferFull = newBufferedAmount >= BUFFER_SIZE;
 
-    var newBufferedAmount = this.bufferedAmount + length;
-    var bufferNotFull = newBufferedAmount < BUFFER_SIZE;
+    if (bufferFull) {
+      // If we buffered more than some arbitrary amount of data,
+      // (65535 right now) we should tell the caller so they can
+      // wait until ondrain is called if they so desire. Once all the
+      // buffered data has been written to the socket, ondrain is
+      // called.
+      this._waitingForDrain = true;
+    }
+
     if (this._inChild) {
-      return bufferNotFull;
+      // In child, we just add buffer length to our bufferedAmount and let
+      // parent to update our bufferedAmount when data have been sent.
+      this._bufferedAmount = newBufferedAmount;
+      return !bufferFull;
     }
 
     let new_stream;
     if (this._binaryType === "arraybuffer") {
       new_stream = new ArrayBufferInputStream();
       new_stream.setData(data, byteOffset, byteLength);
     } else {
       new_stream = new StringInputStream();
@@ -628,52 +699,43 @@ TCPSocket.prototype = {
     if (this._waitingForStartTLS) {
       // When we are waiting for starttls, new_stream is added to pendingData
       // and will be appended to multiplexStream after tls had been set up.
       this._pendingDataAfterStartTLS.push(new_stream);
     } else {
       this._multiplexStream.appendStream(new_stream);
     }
 
-    if (newBufferedAmount >= BUFFER_SIZE) {
-      // If we buffered more than some arbitrary amount of data,
-      // (65535 right now) we should tell the caller so they can
-      // wait until ondrain is called if they so desire. Once all the
-      //buffered data has been written to the socket, ondrain is
-      // called.
-      this._waitingForDrain = true;
-    }
-
     this._ensureCopying();
 
 #ifdef MOZ_WIDGET_GONK
     // Collect transmitted amount for network statistics.
     this._txBytes += length;
     this._saveNetworkStats(false);
 #endif
 
-    return bufferNotFull;
+    return !bufferFull;
   },
 
   suspend: function ts_suspend() {
     if (this._inChild) {
-      this._socketBridge.suspend();
+      this._socketBridge.sendSuspend();
       return;
     }
 
     if (this._inputStreamPump) {
       this._inputStreamPump.suspend();
     } else {
       ++this._suspendCount;
     }
   },
 
   resume: function ts_resume() {
     if (this._inChild) {
-      this._socketBridge.resume();
+      this._socketBridge.sendResume();
       return;
     }
 
     if (this._inputStreamPump) {
       this._inputStreamPump.resume();
     } else if (this._suspendCount < 1) {
       throw new Error(kRESUME_ERROR);
     } else {
--- a/dom/network/src/TCPSocketChild.cpp
+++ b/dom/network/src/TCPSocketChild.cpp
@@ -72,31 +72,33 @@ NS_IMETHODIMP_(nsrefcnt) TCPSocketChild:
 }
 
 TCPSocketChild::TCPSocketChild()
 : mWindowObj(nullptr)
 {
 }
 
 NS_IMETHODIMP
-TCPSocketChild::Open(nsITCPSocketInternal* aSocket, const nsAString& aHost,
-                     uint16_t aPort, bool aUseSSL, const nsAString& aBinaryType,
-                     nsIDOMWindow* aWindow, const JS::Value& aWindowObj,
-                     JSContext* aCx)
+TCPSocketChild::SendOpen(nsITCPSocketInternal* aSocket,
+                         const nsAString& aHost, uint16_t aPort,
+                         bool aUseSSL, const nsAString& aBinaryType,
+                         nsIDOMWindow* aWindow, const JS::Value& aWindowObj,
+                         JSContext* aCx)
 {
   mSocket = aSocket;
 
   MOZ_ASSERT(aWindowObj.isObject());
   mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
   if (!mWindowObj) {
     return NS_ERROR_FAILURE;
   }
   AddIPDLReference();
   gNeckoChild->SendPTCPSocketConstructor(this);
-  SendOpen(nsString(aHost), aPort, aUseSSL, nsString(aBinaryType));
+  PTCPSocketChild::SendOpen(nsString(aHost), aPort,
+                            aUseSSL, nsString(aBinaryType));
   return NS_OK;
 }
 
 void
 TCPSocketChildBase::ReleaseIPDLReference()
 {
   MOZ_ASSERT(mIPCOpen);
   mIPCOpen = false;
@@ -111,22 +113,31 @@ TCPSocketChildBase::AddIPDLReference()
   this->AddRef();
 }
 
 TCPSocketChild::~TCPSocketChild()
 {
 }
 
 bool
+TCPSocketChild::RecvUpdateBufferedAmount(const uint32_t& aBuffered,
+                                         const uint32_t& aTrackingNumber)
+{
+  if (NS_FAILED(mSocket->UpdateBufferedAmount(aBuffered, aTrackingNumber))) {
+    NS_ERROR("Shouldn't fail!");
+  }
+  return true;
+}
+
+bool
 TCPSocketChild::RecvCallback(const nsString& aType,
                              const CallbackData& aData,
-                             const nsString& aReadyState,
-                             const uint32_t& aBuffered)
+                             const nsString& aReadyState)
 {
-  if (NS_FAILED(mSocket->UpdateReadyStateAndBuffered(aReadyState, aBuffered)))
+  if (NS_FAILED(mSocket->UpdateReadyState(aReadyState)))
     NS_ERROR("Shouldn't fail!");
 
   nsresult rv = NS_ERROR_FAILURE;
   if (aData.type() == CallbackData::Tvoid_t) {
     rv = mSocket->CallListenerVoid(aType);
 
   } else if (aData.type() == CallbackData::TTCPError) {
     const TCPError& err(aData.get_TCPError());
@@ -154,56 +165,56 @@ TCPSocketChild::RecvCallback(const nsStr
   } else {
     MOZ_CRASH("Invalid callback type!");
   }
   NS_ENSURE_SUCCESS(rv, true);
   return true;
 }
 
 NS_IMETHODIMP
-TCPSocketChild::StartTLS()
+TCPSocketChild::SendStartTLS()
 {
-  SendStartTLS();
+  PTCPSocketChild::SendStartTLS();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TCPSocketChild::Suspend()
+TCPSocketChild::SendSuspend()
 {
-  SendSuspend();
+  PTCPSocketChild::SendSuspend();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TCPSocketChild::Resume()
+TCPSocketChild::SendResume()
 {
-  SendResume();
+  PTCPSocketChild::SendResume();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TCPSocketChild::Close()
+TCPSocketChild::SendClose()
 {
-  SendClose();
+  PTCPSocketChild::SendClose();
   return NS_OK;
 }
 
 NS_IMETHODIMP
-TCPSocketChild::Send(const JS::Value& aData,
-                     uint32_t aByteOffset,
-                     uint32_t aByteLength,
-                     JSContext* aCx)
+TCPSocketChild::SendSend(const JS::Value& aData,
+                         uint32_t aByteOffset,
+                         uint32_t aByteLength,
+                         uint32_t aTrackingNumber,
+                         JSContext* aCx)
 {
   if (aData.isString()) {
     JSString* jsstr = aData.toString();
     nsDependentJSString str;
     bool ok = str.init(aCx, jsstr);
     NS_ENSURE_TRUE(ok, NS_ERROR_FAILURE);
-    SendData(str);
-
+    SendData(str, aTrackingNumber);
   } else {
     NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_FAILURE);
     JS::Rooted<JSObject*> obj(aCx, &aData.toObject());
     NS_ENSURE_TRUE(JS_IsArrayBufferObject(obj), NS_ERROR_FAILURE);
     uint32_t buflen = JS_GetArrayBufferByteLength(obj);
     aByteOffset = std::min(buflen, aByteOffset);
     uint32_t nbytes = std::min(buflen - aByteOffset, aByteLength);
     uint8_t* data = JS_GetArrayBufferData(obj);
@@ -211,25 +222,25 @@ TCPSocketChild::Send(const JS::Value& aD
       return NS_ERROR_OUT_OF_MEMORY;
     }
     FallibleTArray<uint8_t> fallibleArr;
     if (!fallibleArr.InsertElementsAt(0, data, nbytes)) {
       return NS_ERROR_OUT_OF_MEMORY;
     }
     InfallibleTArray<uint8_t> arr;
     arr.SwapElements(fallibleArr);
-    SendData(arr);
+    SendData(arr, aTrackingNumber);
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TCPSocketChild::SetSocketAndWindow(nsITCPSocketInternal *aSocket,
-                          const JS::Value& aWindowObj,
-                          JSContext* aCx)
+                                   const JS::Value& aWindowObj,
+                                   JSContext* aCx)
 {
   mSocket = aSocket;
   MOZ_ASSERT(aWindowObj.isObject());
   mWindowObj = js::CheckedUnwrap(&aWindowObj.toObject());
   if (!mWindowObj) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
--- a/dom/network/src/TCPSocketChild.h
+++ b/dom/network/src/TCPSocketChild.h
@@ -39,17 +39,18 @@ public:
   NS_DECL_NSITCPSOCKETCHILD
   NS_IMETHOD_(nsrefcnt) Release() MOZ_OVERRIDE;
 
   TCPSocketChild();
   ~TCPSocketChild();
 
   virtual bool RecvCallback(const nsString& aType,
                             const CallbackData& aData,
-                            const nsString& aReadyState,
-                            const uint32_t& aBuffered) MOZ_OVERRIDE;
+                            const nsString& aReadyState) MOZ_OVERRIDE;
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
+  virtual bool RecvUpdateBufferedAmount(const uint32_t& aBufferred,
+                                        const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
 private:
   JSObject* mWindowObj;
 };
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/network/src/TCPSocketParent.cpp
+++ b/dom/network/src/TCPSocketParent.cpp
@@ -30,17 +30,17 @@ namespace mozilla {
 namespace dom {
 
 static void
 FireInteralError(mozilla::net::PTCPSocketParent* aActor, uint32_t aLineNo)
 {
   mozilla::unused <<
       aActor->SendCallback(NS_LITERAL_STRING("onerror"),
                            TCPError(NS_LITERAL_STRING("InvalidStateError")),
-                           NS_LITERAL_STRING("connecting"), 0);
+                           NS_LITERAL_STRING("connecting"));
 }
 
 NS_IMPL_CYCLE_COLLECTION_2(TCPSocketParentBase, mSocket, mIntermediary)
 NS_IMPL_CYCLE_COLLECTING_ADDREF(TCPSocketParentBase)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(TCPSocketParentBase)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TCPSocketParentBase)
   NS_INTERFACE_MAP_ENTRY(nsITCPSocketParent)
@@ -151,35 +151,36 @@ TCPSocketParent::RecvResume()
 {
   NS_ENSURE_TRUE(mSocket, true);
   nsresult rv = mSocket->Resume();
   NS_ENSURE_SUCCESS(rv, true);
   return true;
 }
 
 bool
-TCPSocketParent::RecvData(const SendableData& aData)
+TCPSocketParent::RecvData(const SendableData& aData,
+                          const uint32_t& aTrackingNumber)
 {
   NS_ENSURE_TRUE(mIntermediary, true);
 
   nsresult rv;
   switch (aData.type()) {
     case SendableData::TArrayOfuint8_t: {
       AutoSafeJSContext cx;
       JSAutoRequest ar(cx);
       JS::Rooted<JS::Value> val(cx);
       JS::Rooted<JSObject*> obj(cx, mIntermediaryObj);
       IPC::DeserializeArrayBuffer(obj, aData.get_ArrayOfuint8_t(), &val);
-      rv = mIntermediary->SendArrayBuffer(val);
+      rv = mIntermediary->OnRecvSendArrayBuffer(val, aTrackingNumber);
       NS_ENSURE_SUCCESS(rv, true);
       break;
     }
 
     case SendableData::TnsString:
-      rv = mIntermediary->SendString(aData.get_nsString());
+      rv = mIntermediary->OnRecvSendString(aData.get_nsString(), aTrackingNumber);
       NS_ENSURE_SUCCESS(rv, true);
       break;
 
     default:
       MOZ_CRASH("unexpected SendableData type");
   }
   return true;
 }
@@ -189,19 +190,18 @@ TCPSocketParent::RecvClose()
 {
   NS_ENSURE_TRUE(mSocket, true);
   nsresult rv = mSocket->Close();
   NS_ENSURE_SUCCESS(rv, true);
   return true;
 }
 
 NS_IMETHODIMP
-TCPSocketParent::SendCallback(const nsAString& aType, const JS::Value& aDataVal,
-                              const nsAString& aReadyState, uint32_t aBuffered,
-                              JSContext* aCx)
+TCPSocketParent::SendEvent(const nsAString& aType, const JS::Value& aDataVal,
+                           const nsAString& aReadyState, JSContext* aCx)
 {
   if (!mIPCOpen) {
     NS_WARNING("Dropping callback due to no IPC connection");
     return NS_OK;
   }
 
   CallbackData data;
   if (aDataVal.isString()) {
@@ -250,30 +250,39 @@ TCPSocketParent::SendCallback(const nsAS
     }
   } else {
     NS_ERROR("Unexpected JS value encountered");
     FireInteralError(this, __LINE__);
     return NS_ERROR_FAILURE;
   }
   mozilla::unused <<
       PTCPSocketParent::SendCallback(nsString(aType), data,
-                                     nsString(aReadyState), aBuffered);
+                                     nsString(aReadyState));
   return NS_OK;
 }
 
 NS_IMETHODIMP
 TCPSocketParent::SetSocketAndIntermediary(nsIDOMTCPSocket *socket,
                                           nsITCPSocketIntermediary *intermediary,
                                           JSContext* cx)
 {
   mSocket = socket;
   mIntermediary = intermediary;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+TCPSocketParent::SendUpdateBufferedAmount(uint32_t aBufferedAmount,
+                                          uint32_t aTrackingNumber)
+{
+  mozilla::unused << PTCPSocketParent::SendUpdateBufferedAmount(aBufferedAmount,
+                                                                aTrackingNumber);
+  return NS_OK;
+}
+
 void
 TCPSocketParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mSocket) {
     mSocket->Close();
   }
   mSocket = nullptr;
   mIntermediaryObj = nullptr;
--- a/dom/network/src/TCPSocketParent.h
+++ b/dom/network/src/TCPSocketParent.h
@@ -46,17 +46,18 @@ public:
 
   virtual bool RecvOpen(const nsString& aHost, const uint16_t& aPort,
                         const bool& useSSL, const nsString& aBinaryType);
 
   virtual bool RecvStartTLS() MOZ_OVERRIDE;
   virtual bool RecvSuspend() MOZ_OVERRIDE;
   virtual bool RecvResume() MOZ_OVERRIDE;
   virtual bool RecvClose() MOZ_OVERRIDE;
-  virtual bool RecvData(const SendableData& aData) MOZ_OVERRIDE;
+  virtual bool RecvData(const SendableData& aData,
+                        const uint32_t& aTrackingNumber) MOZ_OVERRIDE;
   virtual bool RecvRequestDelete() MOZ_OVERRIDE;
 
 private:
   virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
   JSObject* mIntermediaryObj;
 };
 
--- a/dom/network/src/TCPSocketParentIntermediary.js
+++ b/dom/network/src/TCPSocketParentIntermediary.js
@@ -15,37 +15,47 @@ function TCPSocketParentIntermediary() {
 
 TCPSocketParentIntermediary.prototype = {
   _setCallbacks: function(aParentSide, socket) {
     aParentSide.initJS(this);
     this._socket = socket;
 
     // Create handlers for every possible callback that attempt to trigger
     // corresponding callbacks on the child object.
-    ["open", "drain", "data", "error", "close"].forEach(
+    // ondrain event is not forwarded, since the decision of firing ondrain
+    // is made in child.
+    ["open", "data", "error", "close"].forEach(
       function(p) {
         socket["on" + p] = function(data) {
-          aParentSide.sendCallback(p, data.data, socket.readyState,
-                                   socket.bufferedAmount);
+          aParentSide.sendEvent(p, data.data, socket.readyState,
+                                socket.bufferedAmount);
         };
       }
     );
- },
+  },
+
+  _onUpdateBufferedAmountHandler: function(aParentSide, aBufferedAmount, aTrackingNumber) {
+    aParentSide.sendUpdateBufferedAmount(aBufferedAmount, aTrackingNumber);
+  },
 
   open: function(aParentSide, aHost, aPort, aUseSSL, aBinaryType, aAppId) {
     let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
     let socket = baseSocket.open(aHost, aPort, {useSecureTransport: aUseSSL, binaryType: aBinaryType});
     if (!socket)
       return null;
 
     let socketInternal = socket.QueryInterface(Ci.nsITCPSocketInternal);
     if (socketInternal) {
       socketInternal.setAppId(aAppId);
     }
 
+    // Handle parent's request to update buffered amount.
+    socketInternal.setOnUpdateBufferedAmountHandler(
+      this._onUpdateBufferedAmountHandler.bind(this, aParentSide));
+
     // Handlers are set to the JS-implemented socket object on the parent side.
     this._setCallbacks(aParentSide, socket);
     return socket;
   },
 
   listen: function(aTCPServerSocketParent, aLocalPort, aBacklog, aBinaryType) {
     let baseSocket = Cc["@mozilla.org/tcp-socket;1"].createInstance(Ci.nsIDOMTCPSocket);
     let serverSocket = baseSocket.listen(aLocalPort, { binaryType: aBinaryType }, aBacklog);
@@ -74,22 +84,25 @@ TCPSocketParentIntermediary.prototype = 
 
         aTCPServerSocketParent.sendCallbackError(error.message, error.filename,
                                                  error.lineNumber, error.columnNumber);
     };
 
     return serverSocket;
   },
 
-  sendString: function(aData) {
-    return this._socket.send(aData);
+  onRecvSendString: function(aData, aTrackingNumber) {
+    let socketInternal = this._socket.QueryInterface(Ci.nsITCPSocketInternal);
+    return socketInternal.onRecvSendFromChild(aData, 0, 0, aTrackingNumber);
   },
 
-  sendArrayBuffer: function(aData) {
-    return this._socket.send(aData, 0, aData.byteLength);
+  onRecvSendArrayBuffer: function(aData, aTrackingNumber) {
+    let socketInternal = this._socket.QueryInterface(Ci.nsITCPSocketInternal);
+    return socketInternal.onRecvSendFromChild(aData, 0, aData.byteLength,
+                                              aTrackingNumber);
   },
 
   classID: Components.ID("{afa42841-a6cb-4a91-912f-93099f6a3d18}"),
   QueryInterface: XPCOMUtils.generateQI([
     Ci.nsITCPSocketIntermediary
   ])
 };
 
--- a/dom/network/src/moz.build
+++ b/dom/network/src/moz.build
@@ -23,19 +23,21 @@ SOURCES += [
     'TCPSocketParent.cpp',
     'UDPSocketChild.cpp',
     'UDPSocketParent.cpp',
 ]
 
 if CONFIG['MOZ_B2G_RIL']:
     EXPORTS.mozilla.dom.network += [
         'MobileConnection.h',
+        'MobileConnectionArray.h',
     ]
     SOURCES += [
         'MobileConnection.cpp',
+        'MobileConnectionArray.cpp',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     EXTRA_JS_MODULES = [
         'NetworkStatsDB.jsm',
         'NetworkStatsService.jsm',
     ]
 
--- a/dom/network/tests/marionette/test_call_barring_change_password.js
+++ b/dom/network/tests/marionette/test_call_barring_change_password.js
@@ -5,17 +5,17 @@ MARIONETTE_TIMEOUT = 60000;
 
 SpecialPowers.addPermission("mobileconnection", true, document);
 
 // Permission changes can't change existing Navigator.prototype
 // objects, so grab our objects from a new Navigator
 let ifr = document.createElement("iframe");
 let connection;
 ifr.onload = function() {
-  connection = ifr.contentWindow.navigator.mozMobileConnection;
+  connection = ifr.contentWindow.navigator.mozMobileConnections[0];
 
   ok(connection instanceof ifr.contentWindow.MozMobileConnection,
      "connection is instanceof " + connection.constructor);
 
   setTimeout(testChangeCallBarringPasswordWithFailure, 0);
 };
 document.body.appendChild(ifr);
 
--- a/dom/network/tests/marionette/test_call_barring_get_option.js
+++ b/dom/network/tests/marionette/test_call_barring_get_option.js
@@ -5,17 +5,17 @@ MARIONETTE_TIMEOUT = 60000;
 
 SpecialPowers.addPermission("mobileconnection", true, document);
 
 // Permission changes can't change existing Navigator.prototype
 // objects, so grab our objects from a new Navigator
 let ifr = document.createElement("iframe");
 let connection;
 ifr.onload = function() {
-  connection = ifr.contentWindow.navigator.mozMobileConnection;
+  connection = ifr.contentWindow.navigator.mozMobileConnections[0];
 
   ok(connection instanceof ifr.contentWindow.MozMobileConnection,
      "connection is instanceof " + connection.constructor);
 
   testGetCallBarringOption();
 };
 document.body.appendChild(ifr);
 
--- a/dom/network/tests/marionette/test_call_barring_set_error.js
+++ b/dom/network/tests/marionette/test_call_barring_set_error.js
@@ -5,17 +5,17 @@ MARIONETTE_TIMEOUT = 60000;
 
 SpecialPowers.addPermission("mobileconnection", true, document);
 
 // Permission changes can't change existing Navigator.prototype
 // objects, so grab our objects from a new Navigator
 let ifr = document.createElement("iframe");
 let connection;
 ifr.onload = function() {
-  connection = ifr.contentWindow.navigator.mozMobileConnection;
+  connection = ifr.contentWindow.navigator.mozMobileConnections[0];
 
   ok(connection instanceof ifr.contentWindow.MozMobileConnection,
      "connection is instanceof " + connection.constructor);
 
   nextTest();
 };
 document.body.appendChild(ifr);
 
--- a/dom/network/tests/marionette/test_mobile_data_connection.js
+++ b/dom/network/tests/marionette/test_mobile_data_connection.js
@@ -8,17 +8,17 @@ const DATA_ROAMING_KEY = "ril.data.roami
 const APN_KEY = "ril.data.apnSettings";
 
 SpecialPowers.setBoolPref("dom.mozSettings.enabled", true);
 SpecialPowers.addPermission("mobileconnection", true, document);
 SpecialPowers.addPermission("settings-read", true, document);
 SpecialPowers.addPermission("settings-write", true, document);
 
 let settings = window.navigator.mozSettings;
-let connection = window.navigator.mozMobileConnection;
+let connection = window.navigator.mozMobileConnections[0];
 ok(connection instanceof MozMobileConnection,
    "connection is instanceof " + connection.constructor);
 
 
 let pendingEmulatorCmdCount = 0;
 function sendCmdToEmulator(cmd, callback) {
   ++pendingEmulatorCmdCount;
 
--- a/dom/network/tests/marionette/test_mobile_data_location.js
+++ b/dom/network/tests/marionette/test_mobile_data_location.js
@@ -5,17 +5,17 @@ MARIONETTE_TIMEOUT = 20000;
 
 SpecialPowers.addPermission("mobileconnection", true, document);
 
 // Permission changes can't change existing Navigator.prototype
 // objects, so grab our objects from a new Navigator
 let ifr = document.createElement("iframe");
 let mobileConnection;
 ifr.onload = function() {
-  mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
+  mobileConnection = ifr.contentWindow.navigator.mozMobileConnections[0];
 
   // Start the test
   verifyInitialState();
 };
 document.body.appendChild(ifr);
 
 let emulatorStartLac = 0;
 let emulatorStartCid = 0;
--- a/dom/network/tests/marionette/test_mobile_data_state.js
+++ b/dom/network/tests/marionette/test_mobile_data_state.js
@@ -5,17 +5,17 @@ MARIONETTE_TIMEOUT = 30000;
 
 SpecialPowers.addPermission("mobileconnection", true, document);
 
 // Permission changes can't change existing Navigator.prototype
 // objects, so grab our objects from a new Navigator
 let ifr = document.createElement("iframe");
 let mobileConnection;
 ifr.onload = function() {
-  mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
+  mobileConnection = ifr.contentWindow.navigator.mozMobileConnections[0];
 
   // Start the test
   verifyInitialState();
 };
 document.body.appendChild(ifr);
 
 function verifyInitialState() {
   log("Verifying initial state.");
--- a/dom/network/tests/marionette/test_mobile_mmi.js
+++ b/dom/network/tests/marionette/test_mobile_mmi.js
@@ -5,17 +5,17 @@ MARIONETTE_TIMEOUT = 20000;
 
 SpecialPowers.addPermission("mobileconnection", true, document);
 
 // Permission changes can't change existing Navigator.prototype
 // objects, so grab our objects from a new Navigator
 let ifr = document.createElement("iframe");
 let mobileConnection;
 ifr.onload = function() {
-  mobileConnection = ifr.contentWindow.navigator.mozMobileConnection;
+  mobileConnection = ifr.contentWindow.navigator.mozMobileConnections[0];
 
   tasks.run();
 };
 document.body.appendChild(ifr);
 
 let tasks = {
   // List of test functions. Each of them should call |tasks.next()| when
   // completed or |tasks.abort()| to jump to the last one.
--- a/dom/network/tests/marionette/test_mobile_networks.js
+++ b/dom/network/tests/marionette/test_mobile_networks.js
@@ -1,17 +1,17 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // getNetworks() can take some time..
 MARIONETTE_TIMEOUT = 60000;
  
 SpecialPowers.addPermission("mobileconnection", true, document);
 
-let connection = navigator.mozMobileConnection;
+let connection = navigator.mozMobileConnections[0];
 ok(connection instanceof MozMobileConnection,
    "connection is instanceof " + connection.constructor);
 
 is(connection.networkSelectionMode, "automatic");
 
 let androidNetwork = null;
 let telkilaNetwork = null;
 
--- a/dom/network/tests/marionette/test_mobile_operator_names.js
+++ b/dom/network/tests/marionette/test_mobile_operator_names.js
@@ -10,17 +10,17 @@ const OPERATOR_ROAMING = 1;
 
 // Permission changes can't change existing Navigator.prototype
 // objects, so grab our objects from a new Navigator
 let ifr = document.createElement("iframe");
 let connection;
 let voice;
 let network;
 ifr.onload = function() {
-  connection = ifr.contentWindow.navigator.mozMobileConnection;
+  connection = ifr.contentWindow.navigator.mozMobileConnections[0];
   ok(connection instanceof ifr.contentWindow.MozMobileConnection,
      "connection is instanceof " + connection.constructor);
 
   voice = connection.voice;
   ok(voice, "voice connection valid");
 
   network = voice.network;
   ok(network, "voice network info valid");
--- a/dom/network/tests/marionette/test_mobile_preferred_network_type.js
+++ b/dom/network/tests/marionette/test_mobile_preferred_network_type.js
@@ -55,11 +55,11 @@ function cleanUp() {
   SpecialPowers.removePermission("mobileconnection", document);
   SpecialPowers.removePermission("settings-write", document);
   SpecialPowers.removePermission("settings-read", document);
 
   finish();
 }
 
 waitFor(test_revert_previous_setting_on_invalid_value, function () {
-  return navigator.mozMobileConnection.voice.connected;
+  return navigator.mozMobileConnections[0].voice.connected;
 });
 
--- a/dom/network/tests/marionette/test_mobile_roaming_preference.js
+++ b/dom/network/tests/marionette/test_mobile_roaming_preference.js
@@ -1,16 +1,16 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 MARIONETTE_TIMEOUT = 60000;
 
 SpecialPowers.addPermission("mobileconnection", true, document);
 
-let connection = navigator.mozMobileConnection;
+let connection = navigator.mozMobileConnections[0];
 ok(connection instanceof MozMobileConnection,
    "connection is instanceof " + connection.constructor);
 
 function failedToSetRoamingPreference(mode, expectedErrorMessage, callback) {
   let request = connection.setRoamingPreference(mode);
 
   ok(request instanceof DOMRequest,
      "request instanceof " + request.constructor);
--- a/dom/network/tests/marionette/test_mobile_voice_state.js
+++ b/dom/network/tests/marionette/test_mobile_voice_state.js
@@ -5,17 +5,17 @@ MARIONETTE_TIMEOUT = 30000;
 
 SpecialPowers.addPermission("mobileconnection", true, document);
 
 // Permission changes can't change existing Navigator.prototype
 // objects, so grab our objects from a new Navigator
 let ifr = document.createElement("iframe");
 let connection;
 ifr.onload = function() {
-  connection = ifr.contentWindow.navigator.mozMobileConnection;
+  connection = ifr.contentWindow.navigator.mozMobileConnections[0];
   ok(connection instanceof ifr.contentWindow.MozMobileConnection,
      "connection is instanceof " + connection.constructor);
   testConnectionInfo();
 };
 document.body.appendChild(ifr);
 
 let emulatorCmdPendingCount = 0;
 function setEmulatorVoiceState(state) {
--- a/dom/network/tests/unit/test_tcpsocket.js
+++ b/dom/network/tests/unit/test_tcpsocket.js
@@ -75,16 +75,21 @@ Cu.import("resource://gre/modules/Servic
  */
 
 function get_platform() {
   var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
                               .getService(Components.interfaces.nsIXULRuntime);
   return xulRuntime.OS;
 }
 
+function is_content() {
+  return this._inChild = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
+                            .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+}
+
 /**
  * Spin up a listening socket and associate at most one live, accepted socket
  * with ourselves.
  */
 function TestServer() {
   this.listener = ServerSocket(-1, true, -1);
   do_print('server: listening on', this.listener.port);
   this.listener.asyncListen(this);
@@ -413,37 +418,55 @@ function badConnect() {
  * and buffering again causes ondrain to be fired again.
  */
 
 function drainTwice() {
   let yays = makeJointSuccess(
     ['ondrain', 'ondrain2',
     'ondata', 'ondata2',
     'serverclose', 'clientclose']);
+  let ondrainCalled = false,
+      ondataCalled = false;
 
-  function serverSideCallback() {
-    yays.ondata();
+  function maybeSendNextData() {
+    if (!ondrainCalled || !ondataCalled) {
+      // make sure server got data and client got ondrain.
+      return;
+    }
+
     server.ondata = makeExpectData(
       "ondata2", BIG_TYPED_ARRAY_2, false, yays.ondata2);
 
     sock.ondrain = yays.ondrain2;
 
     if (sock.send(BIG_ARRAY_BUFFER_2)) {
       do_throw("sock.send(BIG_TYPED_ARRAY_2) did not return false to indicate buffering");
     }
 
     sock.close();
   }
 
+  function clientOndrain() {
+    yays.ondrain();
+    ondrainCalled = true;
+    maybeSendNextData();
+  }
+
+  function serverSideCallback() {
+    yays.ondata();
+    ondataCalled = true;
+    maybeSendNextData();
+  }
+
   server.onclose = yays.serverclose;
   server.ondata = makeExpectData(
     "ondata", BIG_TYPED_ARRAY, false, serverSideCallback);
 
   sock.onclose = yays.clientclose;
-  sock.ondrain = yays.ondrain;
+  sock.ondrain = clientOndrain;
 
   if (sock.send(BIG_ARRAY_BUFFER)) {
     throw new Error("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
   }
 }
 
 function cleanup() {
   do_print("Cleaning up");
@@ -477,16 +500,72 @@ function bufferTwice() {
   if (sock.send(BIG_ARRAY_BUFFER)) {
     throw new Error("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
   }
   if (sock.send(BIG_ARRAY_BUFFER_2)) {
     throw new Error("sock.send(BIG_TYPED_ARRAY_2) did not return false to indicate buffering on second synchronous call to send");
   }
 }
 
+// Test child behavior when child thinks it's buffering but parent doesn't
+// buffer.
+// 1. set bufferedAmount of content socket to a value that will make next
+//    send() call return false.
+// 2. send a small data to make send() return false, but it won't make
+//    parent buffer.
+// 3. we should get a ondrain.
+function childbuffered() {
+  let yays = makeJointSuccess(['ondrain', 'serverdata',
+                               'clientclose', 'serverclose']);
+  sock.ondrain = function() {
+    yays.ondrain();
+    sock.close();
+  };
+
+  server.ondata = makeExpectData(
+    'ondata', DATA_ARRAY, false, yays.serverdata);
+
+  let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
+  internalSocket.updateBufferedAmount(65535, // almost reach buffering threshold
+                                      0);
+  if (sock.send(DATA_ARRAY_BUFFER)) {
+    do_throw("expected sock.send to return false.");
+  }
+
+  sock.onclose = yays.clientclose;
+  server.onclose = yays.serverclose;
+}
+
+// Test child's behavior when send() of child return true but parent buffers
+// data.
+// 1. send BIG_ARRAY to make parent buffer. This would make child wait for
+//    drain as well.
+// 2. set child's bufferedAmount to zero, so child will no longer wait for
+//    drain but parent will dispatch a drain event.
+// 3. wait for 1 second, to make sure there's no ondrain event dispatched in
+//    child.
+function childnotbuffered() {
+  let yays = makeJointSuccess(['serverdata', 'clientclose', 'serverclose']);
+  server.ondata = makeExpectData('ondata', BIG_ARRAY, false, yays.serverdata);
+  if (sock.send(BIG_ARRAY_BUFFER)) {
+    do_throw("sock.send(BIG_TYPED_ARRAY) did not return false to indicate buffering");
+  }
+  let internalSocket = sock.QueryInterface(Ci.nsITCPSocketInternal);
+  internalSocket.updateBufferedAmount(0, // setting zero will clear waitForDrain in sock.
+                                      1);
+
+  // shouldn't get ondrain, even after parent have cleared its buffer.
+  sock.ondrain = makeFailureCase('drain');
+  sock.onclose = yays.clientclose;
+  server.onclose = yays.serverclose;
+  do_timeout(1000, function() {
+    sock.close();
+  });
+};
+
 // - connect, data and events work both ways
 add_test(connectSock);
 add_test(sendData);
 add_test(sendBig);
 add_test(receiveData);
 // - server closes on us
 add_test(serverCloses);
 
@@ -508,16 +587,24 @@ if (get_platform() !== "Darwin") {
 // send a buffer, get a drain, send a buffer, get a drain
 add_test(connectSock);
 add_test(drainTwice);
 
 // send a buffer, get a drain, send a buffer, get a drain
 add_test(connectSock);
 add_test(bufferTwice);
 
+if (is_content()) {
+  add_test(connectSock);
+  add_test(childnotbuffered);
+
+  add_test(connectSock);
+  add_test(childbuffered);
+}
+
 // clean up
 add_test(cleanup);
 
 function run_test() {
   if (!gInChild)
     Services.prefs.setBoolPref('dom.mozTCPSocket.enabled', true);
 
   server = new TestServer();
new file mode 100644
--- /dev/null
+++ b/dom/nfc/MozNdefRecord.cpp
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+/* Copyright © 2013 Deutsche Telekom, Inc. */
+
+#include "MozNdefRecord.h"
+#include "mozilla/dom/MozNdefRecordBinding.h"
+#include "nsContentUtils.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_1(MozNdefRecord, mWindow)
+NS_IMPL_CYCLE_COLLECTING_ADDREF(MozNdefRecord)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(MozNdefRecord)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozNdefRecord)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/* static */
+already_AddRefed<MozNdefRecord>
+MozNdefRecord::Constructor(const GlobalObject& aGlobal,
+                           uint8_t aTnf, const nsAString& aType,
+                           const nsAString& aId, const nsAString& aPayload,
+                           ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  nsRefPtr<MozNdefRecord> ndefrecord =
+    new MozNdefRecord(win, aTnf, aType, aId, aPayload);
+  return ndefrecord.forget();
+}
+
+MozNdefRecord::MozNdefRecord(nsPIDOMWindow* aWindow,
+                             uint8_t aTnf, const nsAString& aType,
+                             const nsAString& aId, const nsAString& aPayload)
+  : mTnf(aTnf)
+  , mType(aType)
+  , mId(aId)
+  , mPayload(aPayload)
+{
+  mWindow = aWindow;
+  SetIsDOMBinding();
+}
+
+MozNdefRecord::~MozNdefRecord()
+{
+}
+
+JSObject*
+MozNdefRecord::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return MozNdefRecordBinding::Wrap(aCx, aScope, this);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/nfc/MozNdefRecord.h
@@ -0,0 +1,88 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+/* Copyright © 2013 Deutsche Telekom, Inc. */
+
+#ifndef mozilla_dom_MozNdefRecord_h__
+#define mozilla_dom_MozNdefRecord_h__
+
+#include "mozilla/Attributes.h"
+#include "mozilla/ErrorResult.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
+#include "jsapi.h"
+
+#include "nsIDocument.h"
+
+struct JSContext;
+
+namespace mozilla {
+namespace dom {
+
+class MozNdefRecord MOZ_FINAL : public nsISupports,
+                                public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MozNdefRecord)
+
+public:
+
+  MozNdefRecord(nsPIDOMWindow* aWindow,
+                uint8_t aTnf, const nsAString& aType,
+                const nsAString& aId, const nsAString& aPlayload);
+
+  ~MozNdefRecord();
+
+  nsIDOMWindow* GetParentObject() const
+  {
+    return mWindow;
+  }
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
+  static already_AddRefed<MozNdefRecord> Constructor(
+                                           const GlobalObject& aGlobal,
+                                           uint8_t aTnf, const nsAString& aType,
+                                           const nsAString& aId,
+                                           const nsAString& aPayload,
+                                           ErrorResult& aRv);
+
+  uint8_t Tnf() const
+  {
+    return mTnf;
+  }
+
+  void GetType(nsString& aType) const
+  {
+    aType = mType;
+  }
+
+  void GetId(nsString& aId) const
+  {
+    aId = mId;
+  }
+
+  void GetPayload(nsString& aPayload) const
+  {
+    aPayload = mPayload;
+  }
+
+private:
+  MozNdefRecord() MOZ_DELETE;
+  nsRefPtr<nsPIDOMWindow> mWindow;
+
+  uint8_t mTnf;
+  nsString mType;
+  nsString mId;
+  nsString mPayload;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_MozNdefRecord_h__
new file mode 100644
--- /dev/null
+++ b/dom/nfc/moz.build
@@ -0,0 +1,25 @@
+# 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/.
+#
+# Copyright © 2013 Deutsche Telekom, Inc.
+
+if CONFIG['MOZ_NFC']:
+    MODULE = 'dom'
+    EXPORTS.mozilla.dom += [
+        'MozNdefRecord.h',
+    ]
+    SOURCES += [
+        'MozNdefRecord.cpp',
+    ]
+    EXTRA_COMPONENTS += [
+      'nsNfc.js',
+      'nsNfc.manifest',
+    ]
+
+FAIL_ON_WARNINGS = True
+
+LIBRARY_NAME = 'dom_nfc_s'
+
+LIBXUL_LIBRARY = True
new file mode 100644
--- /dev/null
+++ b/dom/nfc/nsNfc.js
@@ -0,0 +1,178 @@
+/* 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/. */
+
+/* Copyright © 2013, Deutsche Telekom, Inc. */
+
+"use strict";
+
+const DEBUG = false;
+function debug(s) {
+  if (DEBUG) dump("-*- Nfc DOM: " + 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/ObjectWrapper.jsm");
+
+/**
+ * NFCTag
+ */
+function MozNFCTag() {
+  debug("In MozNFCTag Constructor");
+  this._nfcContentHelper = Cc["@mozilla.org/nfc/content-helper;1"]
+                             .getService(Ci.nsINfcContentHelper);
+  this.session = null;
+  // Map WebIDL declared enum map names to integer
+  this._techTypesMap = [];
+  this._techTypesMap['NFC_A'] = 0;
+  this._techTypesMap['NFC_B'] = 1;
+  this._techTypesMap['NFC_ISO_DEP'] = 2;
+  this._techTypesMap['NFC_F'] = 3;
+  this._techTypesMap['NFC_V'] = 4;
+  this._techTypesMap['NDEF'] = 5;
+  this._techTypesMap['NDEF_FORMATABLE'] = 6;
+  this._techTypesMap['MIFARE_CLASSIC'] = 7;
+  this._techTypesMap['MIFARE_ULTRALIGHT'] = 8;
+  this._techTypesMap['NFC_BARCODE'] = 9;
+  this._techTypesMap['P2P'] = 10;
+}
+MozNFCTag.prototype = {
+  _nfcContentHelper: null,
+  _window: null,
+
+  initialize: function(aWindow, aSessionToken) {
+    this._window = aWindow;
+    this.setSessionToken(aSessionToken);
+  },
+
+  // ChromeOnly interface
+  setSessionToken: function setSessionToken(aSessionToken) {
+    debug("Setting session token.");
+    this.session = aSessionToken;
+    // report to NFC worker:
+    this._nfcContentHelper.setSessionToken(aSessionToken);
+  },
+
+  _techTypesMap: null,
+
+  // NFCTag interface:
+  getDetailsNDEF: function getDetailsNDEF() {
+    return this._nfcContentHelper.getDetailsNDEF(this._window, this.session);
+  },
+  readNDEF: function readNDEF() {
+    return this._nfcContentHelper.readNDEF(this._window, this.session);
+  },
+  writeNDEF: function writeNDEF(records) {
+    return this._nfcContentHelper.writeNDEF(this._window, records, this.session);
+  },
+  makeReadOnlyNDEF: function makeReadOnlyNDEF() {
+    return this._nfcContentHelper.makeReadOnlyNDEF(this._window, this.session);
+  },
+  connect: function connect(enum_tech_type) {
+    let int_tech_type = this._techTypesMap[enum_tech_type];
+    return this._nfcContentHelper.connect(this._window, int_tech_type, this.session);
+  },
+  close: function close() {
+    return this._nfcContentHelper.close(this._window, this.session);
+  },
+
+  classID: Components.ID("{4e1e2e90-3137-11e3-aa6e-0800200c9a66}"),
+  contractID: "@mozilla.org/nfc/NFCTag;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
+                                         Ci.nsIDOMGlobalPropertyInitializer]),
+};
+
+/**
+ * NFCPeer
+ */
+function MozNFCPeer() {
+  debug("In MozNFCPeer Constructor");
+  this._nfcContentHelper = Cc["@mozilla.org/nfc/content-helper;1"]
+                             .getService(Ci.nsINfcContentHelper);
+  this.session = null;
+}
+MozNFCPeer.prototype = {
+  _nfcContentHelper: null,
+  _window: null,
+
+  initialize: function(aWindow, aSessionToken) {
+    this._window = aWindow;
+    this.setSessionToken(aSessionToken);
+  },
+
+  // ChromeOnly interface
+  setSessionToken: function setSessionToken(aSessionToken) {
+    debug("Setting session token.");
+    this.session = aSessionToken;
+    // report to NFC worker:
+    return this._nfcContentHelper.setSessionToken(aSessionToken);
+  },
+
+  // NFCPeer interface:
+  sendNDEF: function sendNDEF(records) {
+    // Just forward sendNDEF to writeNDEF
+    return this._nfcContentHelper.writeNDEF(this._window, records);
+  },
+
+  classID: Components.ID("{c1b2bcf0-35eb-11e3-aa6e-0800200c9a66}"),
+  contractID: "@mozilla.org/nfc/NFCPeer;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
+                                         Ci.nsIDOMGlobalPropertyInitializer]),
+};
+
+/**
+ * Navigator NFC object
+ */
+function mozNfc() {
+  debug("In mozNfc Constructor");
+}
+mozNfc.prototype = {
+  _nfcContentHelper: null,
+  _window: null,
+  _wrap: function _wrap(obj) {
+    return ObjectWrapper.wrap(obj, this._window);
+  },
+
+  init: function init(aWindow) {
+    debug("mozNfc init called");
+    this._window = aWindow;
+  },
+
+  getNFCTag: function getNFCTag(sessionToken) {
+    let obj = new MozNFCTag();
+    let nfcTag = this._window.MozNFCTag._create(this._window, obj);
+    if (nfcTag) {
+      obj.initialize(this._window, sessionToken);
+      return nfcTag;
+    } else {
+      debug("Error: Unable to create NFCTag");
+      return null;
+    }
+  },
+
+  getNFCPeer: function getNFCPeer(sessionToken) {
+    let obj = new MozNFCPeer();
+    let nfcPeer = this._window.MozNFCTag._create(this._window, obj);
+    if (nfcPeer) {
+      obj.initialize(this._window, sessionToken);
+      return nfcPeer;
+    } else {
+      debug("Error: Unable to create NFCPeer");
+      return null;
+    }
+  },
+
+  // get/set onpeerfound/lost onforegrounddispatch
+
+  classID: Components.ID("{6ff2b290-2573-11e3-8224-0800200c9a66}"),
+  contractID: "@mozilla.org/navigatorNfc;1",
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
+                                         Ci.nsIDOMGlobalPropertyInitializer]),
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozNFCTag, MozNFCPeer, mozNfc]);
new file mode 100644
--- /dev/null
+++ b/dom/nfc/nsNfc.manifest
@@ -0,0 +1,8 @@
+component {6ff2b290-2573-11e3-8224-0800200c9a66} nsNfc.js
+contract @mozilla.org/navigatorNfc;1 {6ff2b290-2573-11e3-8224-0800200c9a66}
+
+component {4e1e2e90-3137-11e3-aa6e-0800200c9a66} nsNfc.js
+contract @mozilla.org/nfc/NFCTag;1 {4e1e2e90-3137-11e3-aa6e-0800200c9a66}
+
+component {c1b2bcf0-35eb-11e3-aa6e-0800200c9a66} nsNfc.js
+contract @mozilla.org/nfc/NFCPeer;1 {c1b2bcf0-35eb-11e3-aa6e-0800200c9a66}
--- a/dom/permission/tests/test_mobileconnection.html
+++ b/dom/permission/tests/test_mobileconnection.html
@@ -14,17 +14,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <p id="display"></p>
 <div id="content" style="display: none"></div>
 <pre id="test">
 <script type="application/javascript;version=1.8" src="file_framework.js"></script>
 <script type="application/javascript;version=1.8">
 var gData = [
   {
     perm: ["mobileconnection"],
-    obj: "mozMobileConnection",
-    idl: "nsIDOMMozMobileConnection",
+    obj: "mozMobileConnections",
+    webidl: "MozMobileConnectionArray",
   },
 ]
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/phonenumberutils/PhoneNumberMetaData.jsm
+++ b/dom/phonenumberutils/PhoneNumberMetaData.jsm
@@ -1,99 +1,99 @@
 /* Automatically generated. Do not edit. */
 // Please use https://github.com/andreasgal/PhoneNumber.js
 
 this.EXPORTED_SYMBOLS = ["PHONE_NUMBER_META_DATA"];
 
 this.PHONE_NUMBER_META_DATA = {
-"46": '["SE","00","0",,,"$NP$FG","\\d{5,10}","[1-9]\\d{6,9}",[["(8)(\\d{2,3})(\\d{2,3})(\\d{2})","$1-$2 $3 $4","8",,"$1 $2 $3 $4"],["([1-69]\\d)(\\d{2,3})(\\d{2})(\\d{2})","$1-$2 $3 $4","1[013689]|2[0136]|3[1356]|4[0246]|54|6[03]|90",,"$1 $2 $3 $4"],["([1-69]\\d)(\\d{3})(\\d{2})","$1-$2 $3","1[13689]|2[136]|3[1356]|4[0246]|54|6[03]|90",,"$1 $2 $3"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1-$2 $3 $4","1[2457]|2[2457-9]|3[0247-9]|4[1357-9]|5[0-35-9]|6[124-9]|9(?:[125-8]|3[0-5]|4[0-3])",,"$1 $2 $3 $4"],["(\\d{3})(\\d{2,3})(\\d{2})","$1-$2 $3","1[2457]|2[2457-9]|3[0247-9]|4[1357-9]|5[0-35-9]|6[124-9]|9(?:[125-8]|3[0-5]|4[0-3])",,"$1 $2 $3"],["(7\\d)(\\d{3})(\\d{2})(\\d{2})","$1-$2 $3 $4","7",,"$1 $2 $3 $4"],["(20)(\\d{2,3})(\\d{2})","$1-$2 $3","20",,"$1 $2 $3"],["(9[034]\\d)(\\d{2})(\\d{2})(\\d{3})","$1-$2 $3 $4","9[034]",,"$1 $2 $3 $4"]]]',
+"46": '["SE","00","0",,,"$NP$FG","\\d{5,10}","[1-9]\\d{5,9}",[["(8)(\\d{2,3})(\\d{2,3})(\\d{2})","$1-$2 $3 $4","8",,"$1 $2 $3 $4"],["([1-69]\\d)(\\d{2,3})(\\d{2})(\\d{2})","$1-$2 $3 $4","1[013689]|2[0136]|3[1356]|4[0246]|54|6[03]|90",,"$1 $2 $3 $4"],["([1-69]\\d)(\\d{3})(\\d{2})","$1-$2 $3","1[13689]|2[136]|3[1356]|4[0246]|54|6[03]|90",,"$1 $2 $3"],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1-$2 $3 $4","1[2457]|2[2457-9]|3[0247-9]|4[1357-9]|5[0-35-9]|6[124-9]|9(?:[125-8]|3[0-5]|4[0-3])",,"$1 $2 $3 $4"],["(\\d{3})(\\d{2,3})(\\d{2})","$1-$2 $3","1[2457]|2[2457-9]|3[0247-9]|4[1357-9]|5[0-35-9]|6[124-9]|9(?:[125-8]|3[0-5]|4[0-3])",,"$1 $2 $3"],["(7\\d)(\\d{3})(\\d{2})(\\d{2})","$1-$2 $3 $4","7",,"$1 $2 $3 $4"],["(77)(\\d{2})(\\d{2})","$1-$2$3","7",,"$1 $2 $3"],["(20)(\\d{2,3})(\\d{2})","$1-$2 $3","20",,"$1 $2 $3"],["(9[034]\\d)(\\d{2})(\\d{2})(\\d{3})","$1-$2 $3 $4","9[034]",,"$1 $2 $3 $4"],["(9[034]\\d)(\\d{4})","$1-$2","9[034]",,"$1 $2"]]]',
 "299": '["GL","00",,,,,"\\d{6}","[1-689]\\d{5}",[["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3",,,]]]',
 "385": '["HR","00","0",,,"$NP$FG","\\d{6,12}","[1-7]\\d{5,8}|[89]\\d{6,11}",[["(1)(\\d{4})(\\d{3})","$1 $2 $3","1",,],["(6[09])(\\d{4})(\\d{3})","$1 $2 $3","6[09]",,],["(62)(\\d{3})(\\d{3,4})","$1 $2 $3","62",,],["([2-5]\\d)(\\d{3})(\\d{3})","$1 $2 $3","[2-5]",,],["(9\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","9",,],["(9\\d)(\\d{4})(\\d{4})","$1 $2 $3","9",,],["(9\\d)(\\d{3,4})(\\d{3})(\\d{3})","$1 $2 $3 $4","9",,],["(\\d{2})(\\d{2})(\\d{2,3})","$1 $2 $3","6[145]|7",,],["(\\d{2})(\\d{3,4})(\\d{3})","$1 $2 $3","6[145]|7",,],["(80[01])(\\d{2})(\\d{2,3})","$1 $2 $3","8",,],["(80[01])(\\d{3,4})(\\d{3})","$1 $2 $3","8",,]]]',
 "670": '["TL","00",,,,,"\\d{7,8}","[2-489]\\d{6}|7\\d{6,7}",[["(\\d{3})(\\d{4})","$1 $2","[2-489]",,],["(\\d{4})(\\d{4})","$1 $2","7",,]]]',
 "258": '["MZ","00",,,,,"\\d{8,9}","[28]\\d{7,8}",[["([28]\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","2|8[246]",,],["(80\\d)(\\d{3})(\\d{3})","$1 $2 $3","80",,]]]',
 "359": '["BG","00","0",,,"$NP$FG","\\d{5,9}","[23567]\\d{5,7}|[489]\\d{6,8}",[["(2)(\\d{5})","$1 $2","29",,],["(2)(\\d{3})(\\d{3,4})","$1 $2 $3","2",,],["(\\d{3})(\\d{4})","$1 $2","43[124-7]|70[1-9]",,],["(\\d{3})(\\d{3})(\\d{2})","$1 $2 $3","43[124-7]|70[1-9]",,],["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3","[78]00",,],["(\\d{2})(\\d{3})(\\d{2,3})","$1 $2 $3","[356]|4[124-7]|7[1-9]|8[1-6]|9[1-7]",,],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3","48|8[7-9]|9[08]",,]]]',
 "682": '["CK","00",,,,,"\\d{5}","[2-57]\\d{4}",[["(\\d{2})(\\d{3})","$1 $2",,,]]]',
 "852": '["HK","00",,,,,"\\d{5,11}","[235-7]\\d{7}|8\\d{7,8}|9\\d{4,10}",[["(\\d{4})(\\d{4})","$1 $2","[235-7]|[89](?:0[1-9]|[1-9])",,],["(800)(\\d{3})(\\d{3})","$1 $2 $3","800",,],["(900)(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3 $4","900",,],["(900)(\\d{2,5})","$1 $2","900",,]]]',
 "998": '["UZ","810","8",,,"$NP $FG","\\d{7,9}","[679]\\d{8}",[["([679]\\d)(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "291": '["ER","00","0",,,"$NP$FG","\\d{6,7}","[178]\\d{6}",[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3",,,]]]',
-"95": '["MM","00","0",,,"$NP$FG","\\d{5,10}","[14578]\\d{5,7}|[26]\\d{5,8}|9(?:[258]|3\\d|4\\d{1,2}|[679]\\d?)\\d{6}",[["(\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","1|2[45]",,],["(2)(\\d{4})(\\d{4})","$1 $2 $3","251",,],["(\\d)(\\d{2})(\\d{3})","$1 $2 $3","16|2",,],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3","67|81",,],["(\\d{2})(\\d{2})(\\d{3,4})","$1 $2 $3","[4-8]",,],["(9)(\\d{3})(\\d{4,5})","$1 $2 $3","9(?:[235-9]|4[13789])",,],["(9)(4\\d{4})(\\d{4})","$1 $2 $3","94[0245]",,]]]',
+"95": '["MM","00","0",,,"$NP$FG","\\d{5,10}","[14578]\\d{5,7}|[26]\\d{5,8}|9(?:2\\d{0,2}|[58]|3\\d|4\\d{1,2}|[679]\\d?)\\d{6}",[["(\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","1|2[45]",,],["(2)(\\d{4})(\\d{4})","$1 $2 $3","251",,],["(\\d)(\\d{2})(\\d{3})","$1 $2 $3","16|2",,],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3","67|81",,],["(\\d{2})(\\d{2})(\\d{3,4})","$1 $2 $3","[4-8]",,],["(9)(\\d{3})(\\d{4,5})","$1 $2 $3","9(?:2[0-4]|[35-9]|4[13789])",,],["(9)(4\\d{4})(\\d{4})","$1 $2 $3","94[0245]",,],["(9)(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4","925",,]]]',
 "266": '["LS","00",,,,,"\\d{8}","[2568]\\d{7}",[["(\\d{4})(\\d{4})","$1 $2",,,]]]',
 "245": '["GW","00",,,,,"\\d{7}","[3-79]\\d{6}",[["(\\d{3})(\\d{4})","$1 $2",,,]]]',
 "374": '["AM","00","0",,,"($NP$FG)","\\d{5,8}","[1-9]\\d{7}",[["(\\d{2})(\\d{6})","$1 $2","1|47",,],["(\\d{2})(\\d{6})","$1 $2","[5-7]|9[1-9]","$NP$FG",],["(\\d{3})(\\d{5})","$1 $2","[23]",,],["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3","8|90","$NP $FG",]]]',
 "379": '["VA","00",,,,,"\\d{10}","06\\d{8}",[["(06)(\\d{4})(\\d{4})","$1 $2 $3",,,]]]',
 "61": ['["AU","(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]","0",,,,"\\d{6,10}","[1-578]\\d{5,9}",[["([2378])(\\d{4})(\\d{4})","$1 $2 $3","[2378]","($NP$FG)",],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3","[45]|14","$NP$FG",],["(16)(\\d{3})(\\d{2,4})","$1 $2 $3","16","$NP$FG",],["(1[389]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","1(?:[38]0|90)","$FG",],["(180)(2\\d{3})","$1 $2","180","$FG",],["(19\\d)(\\d{3})","$1 $2","19[13]","$FG",],["(19\\d{2})(\\d{4})","$1 $2","19[67]","$FG",],["(13)(\\d{2})(\\d{2})","$1 $2 $3","13[1-9]","$FG",]]]','["CC","(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]","0",,,,"\\d{6,10}","[1458]\\d{5,9}",]','["CX","(?:14(?:1[14]|34|4[17]|[56]6|7[47]|88))?001[14-689]","0",,,,"\\d{6,10}","[1458]\\d{5,9}",]'],
 "500": '["FK","00",,,,,"\\d{5}","[2-7]\\d{4}",]',
 "261": '["MG","00","0",,,"$NP$FG","\\d{7,9}","[23]\\d{8}",[["([23]\\d)(\\d{2})(\\d{3})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "92": '["PK","00","0",,,"($NP$FG)","\\d{6,12}","1\\d{8}|[2-8]\\d{5,11}|9(?:[013-9]\\d{4,9}|2\\d(?:111\\d{6}|\\d{3,7}))",[["(\\d{2})(111)(\\d{3})(\\d{3})","$1 $2 $3 $4","(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)1",,],["(\\d{3})(111)(\\d{3})(\\d{3})","$1 $2 $3 $4","2[349]|45|54|60|72|8[2-5]|9[2-9]",,],["(\\d{2})(\\d{7,8})","$1 $2","(?:2[125]|4[0-246-9]|5[1-35-7]|6[1-8]|7[14]|8[16]|91)[2-9]",,],["(\\d{3})(\\d{6,7})","$1 $2","2[349]|45|54|60|72|8[2-5]|9[2-9]",,],["(3\\d{2})(\\d{7})","$1 $2","3","$NP$FG",],["([15]\\d{3})(\\d{5,6})","$1 $2","58[12]|1",,],["(586\\d{2})(\\d{5})","$1 $2","586",,],["([89]00)(\\d{3})(\\d{2})","$1 $2 $3","[89]00","$NP$FG",]]]',
 "234": '["NG","009","0",,,"$NP$FG","\\d{5,14}","[1-69]\\d{5,8}|[78]\\d{5,13}",[["([129])(\\d{3})(\\d{3,4})","$1 $2 $3","[129]",,],["([3-8]\\d)(\\d{3})(\\d{2,3})","$1 $2 $3","[3-6]|7(?:[1-79]|0[1-9])|8[2-9]",,],["([78]\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3","70|8[01]",,],["([78]00)(\\d{4})(\\d{4,5})","$1 $2 $3","[78]00",,],["([78]00)(\\d{5})(\\d{5,6})","$1 $2 $3","[78]00",,],["(78)(\\d{2})(\\d{3})","$1 $2 $3","78",,]]]',
-"350": '["GI","00",,,,,"\\d{8}","[2568]\\d{7}",]',
+"350": '["GI","00",,,,,"\\d{8}","[2568]\\d{7}",[["(\\d{3})(\\d{5})","$1 $2","2",,]]]',
 "45": '["DK","00",,,,,"\\d{8}","[2-9]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "963": '["SY","00","0",,,"$NP$FG","\\d{6,9}","[1-59]\\d{7,8}",[["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3","[1-5]",,],["(9\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","9",,]]]',
 "226": '["BF","00",,,,,"\\d{8}","[24-7]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "974": '["QA","00",,,,,"\\d{7,8}","[2-8]\\d{6,7}",[["([28]\\d{2})(\\d{4})","$1 $2","[28]",,],["([3-7]\\d{3})(\\d{4})","$1 $2","[3-7]",,]]]',
 "218": '["LY","00","0",,,"$NP$FG","\\d{7,9}","[25679]\\d{8}",[["([25679]\\d)(\\d{7})","$1-$2",,,]]]',
 "51": '["PE","19(?:1[124]|77|90)00","0",,,"($NP$FG)","\\d{6,9}","[14-9]\\d{7,8}",[["(1)(\\d{7})","$1 $2","1",,],["([4-8]\\d)(\\d{6})","$1 $2","[4-7]|8[2-4]",,],["(\\d{3})(\\d{5})","$1 $2","80",,],["(9\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","9","$FG",]]]',
 "62": '["ID","0(?:0[1789]|10(?:00|1[67]))","0",,,"$NP$FG","\\d{5,11}","[1-9]\\d{6,10}",[["(\\d{2})(\\d{7,8})","$1 $2","2[124]|[36]1","($NP$FG)",],["(\\d{3})(\\d{5,7})","$1 $2","[4579]|2[035-9]|[36][02-9]","($NP$FG)",],["(8\\d{2})(\\d{3,4})(\\d{3,4})","$1-$2-$3","8[1-35-9]",,],["(177)(\\d{6,8})","$1 $2","1",,],["(800)(\\d{5,7})","$1 $2","800",,],["(809)(\\d)(\\d{3})(\\d{3})","$1 $2 $3 $4","809",,]]]',
 "298": '["FO","00",,"(10(?:01|[12]0|88))",,,"\\d{6}","[2-9]\\d{5}",[["(\\d{6})","$1",,,]]]',
 "381": '["RS","00","0",,,"$NP$FG","\\d{5,12}","[126-9]\\d{4,11}|3(?:[0-79]\\d{3,10}|8[2-9]\\d{2,9})",[["([23]\\d{2})(\\d{4,9})","$1 $2","(?:2[389]|39)0",,],["([1-3]\\d)(\\d{5,10})","$1 $2","1|2(?:[0-24-7]|[389][1-9])|3(?:[0-8]|9[1-9])",,],["(6\\d)(\\d{6,8})","$1 $2","6",,],["([89]\\d{2})(\\d{3,9})","$1 $2","[89]",,],["(7[26])(\\d{4,9})","$1 $2","7[26]",,],["(7[08]\\d)(\\d{4,9})","$1 $2","7[08]",,]]]',
 "975": '["BT","00",,,,,"\\d{6,8}","[1-8]\\d{6,7}",[["([17]7)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","1|77",,],["([2-8])(\\d{3})(\\d{3})","$1 $2 $3","[2-68]|7[246]",,]]]',
-"34": '["ES","00",,,,,"\\d{9}","[5-9]\\d{8}",[["([5-9]\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
+"34": '["ES","00",,,,,"\\d{9}","[5-9]\\d{8}",[["([5-9]\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[568]|[79][0-8]",,]]]',
 "881": '["001",,,,,,"\\d{9}","[67]\\d{8}",[["(\\d)(\\d{3})(\\d{5})","$1 $2 $3","[67]",,]]]',
 "855": '["KH","00[14-9]","0",,,,"\\d{6,10}","[1-9]\\d{7,9}",[["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3","1\\d[1-9]|[2-9]","$NP$FG",],["(1[89]00)(\\d{3})(\\d{3})","$1 $2 $3","1[89]0",,]]]',
 "420": '["CZ","00",,,,,"\\d{9,12}","[2-8]\\d{8}|9\\d{8,11}",[["([2-9]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","[2-8]|9[015-7]",,],["(96\\d)(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4","96",,],["(9\\d)(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4","9[36]",,]]]',
 "216": '["TN","00",,,,,"\\d{8}","[2-57-9]\\d{7}",[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3",,,]]]',
 "673": '["BN","00",,,,,"\\d{7}","[2-578]\\d{6}",[["([2-578]\\d{2})(\\d{4})","$1 $2",,,]]]',
 "290": ['["SH","00",,,,,"\\d{4,5}","[2-79]\\d{3,4}",]','["TA","00",,,,,"\\d{4}","8\\d{3}",]'],
 "882": '["001",,,,,,"\\d{7,12}","[13]\\d{6,11}",[["(\\d{2})(\\d{4})(\\d{3})","$1 $2 $3","3[23]",,],["(\\d{2})(\\d{5})","$1 $2","16|342",,],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","34[57]",,],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3","348",,],["(\\d{2})(\\d{2})(\\d{4})","$1 $2 $3","1",,],["(\\d{2})(\\d{3,4})(\\d{4})","$1 $2 $3","16",,],["(\\d{2})(\\d{4,5})(\\d{5})","$1 $2 $3","16",,]]]',
 "267": '["BW","00",,,,,"\\d{7,8}","[2-79]\\d{6,7}",[["(\\d{3})(\\d{4})","$1 $2","[2-6]",,],["(7\\d)(\\d{3})(\\d{3})","$1 $2 $3","7",,],["(90)(\\d{5})","$1 $2","9",,]]]',
 "94": '["LK","00","0",,,"$NP$FG","\\d{7,9}","[1-9]\\d{8}",[["(\\d{2})(\\d{1})(\\d{6})","$1 $2 $3","[1-689]",,],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","7",,]]]',
 "356": '["MT","00",,,,,"\\d{8}","[2357-9]\\d{7}",[["(\\d{4})(\\d{4})","$1 $2",,,]]]',
-"375": '["BY","810","8","8?0?",,,"\\d{7,11}","[1-4]\\d{8}|[89]\\d{9,10}",[["([1-4]\\d)(\\d{3})(\\d{4})","$1 $2 $3","[1-4]","$NP 0$FG",],["([89]\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","8[01]|9","$NP $FG",],["(8\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","82","$NP $FG",]]]',
+"375": '["BY","810","8","8?0?",,,"\\d{7,11}","[1-4]\\d{8}|[89]\\d{9,10}",[["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2-$3-$4","17[0-3589]|2[4-9]|[34]","$NP 0$FG",],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2-$3-$4","1(?:5[24]|6[235]|7[467])|2(?:1[246]|2[25]|3[26])","$NP 0$FG",],["(\\d{4})(\\d{2})(\\d{3})","$1 $2-$3","1(?:5[169]|6[3-5]|7[179])|2(?:1[35]|2[34]|3[3-5])","$NP 0$FG",],["([89]\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","8[01]|9","$NP $FG",],["(8\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","82","$NP $FG",]]]',
 "690": '["TK","00",,,,,"\\d{4}","[2-9]\\d{3}",]',
 "507": '["PA","00",,,,,"\\d{7,8}","[1-9]\\d{6,7}",[["(\\d{3})(\\d{4})","$1-$2","[1-57-9]",,],["(\\d{4})(\\d{4})","$1-$2","6",,]]]',
 "692": '["MH","011","1",,,,"\\d{7}","[2-6]\\d{6}",[["(\\d{3})(\\d{4})","$1-$2",,,]]]',
 "250": '["RW","00","0",,,,"\\d{8,9}","[027-9]\\d{7,8}",[["(2\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","2","$FG",],["([7-9]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","[7-9]","$NP$FG",],["(0\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","0",,]]]',
 "81": '["JP","010","0",,,"$NP$FG","\\d{7,16}","[1-9]\\d{8,9}|0(?:[36]\\d{7,14}|7\\d{5,7}|8\\d{7})",[["(\\d{3})(\\d{3})(\\d{3})","$1-$2-$3","(?:12|57|99)0",,],["(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3","800",,],["(\\d{3})(\\d{4})","$1-$2","077",,],["(\\d{3})(\\d{2})(\\d{3,4})","$1-$2-$3","077",,],["(\\d{3})(\\d{2})(\\d{4})","$1-$2-$3","088",,],["(\\d{3})(\\d{3})(\\d{3,4})","$1-$2-$3","0(?:37|66)",,],["(\\d{3})(\\d{4})(\\d{4,5})","$1-$2-$3","0(?:37|66)",,],["(\\d{3})(\\d{5})(\\d{5,6})","$1-$2-$3","0(?:37|66)",,],["(\\d{3})(\\d{6})(\\d{6,7})","$1-$2-$3","0(?:37|66)",,],["(\\d{2})(\\d{4})(\\d{4})","$1-$2-$3","[2579]0|80[1-9]",,],["(\\d{4})(\\d)(\\d{4})","$1-$2-$3","1(?:26|3[79]|4[56]|5[4-68]|6[3-5])|5(?:76|97)|499|746|8(?:3[89]|63|47|51)|9(?:49|80|9[16])",,],["(\\d{3})(\\d{2})(\\d{4})","$1-$2-$3","1(?:2[3-6]|3[3-9]|4[2-6]|5[2-8]|[68][2-7]|7[2-689]|9[1-578])|2(?:2[03-689]|3[3-58]|4[0-468]|5[04-8]|6[013-8]|7[06-9]|8[02-57-9]|9[13])|4(?:2[28]|3[689]|6[035-7]|7[05689]|80|9[3-5])|5(?:3[1-36-9]|4[4578]|5[013-8]|6[1-9]|7[2-8]|8[14-7]|9[4-9])|7(?:2[15]|3[5-9]|4[02-9]|6[135-8]|7[0-4689]|9[014-9])|8(?:2[49]|3[3-8]|4[5-8]|5[2-9]|6[35-9]|7[579]|8[03-579]|9[2-8])|9(?:[23]0|4[02-46-9]|5[024-79]|6[4-9]|7[2-47-9]|8[02-7]|9[3-7])",,],["(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3","1|2(?:2[37]|5[5-9]|64|78|8[39]|91)|4(?:2[2689]|64|7[347])|5(?:[2-589]|39)|60|8(?:[46-9]|3[279]|2[124589])|9(?:[235-8]|93)",,],["(\\d{3})(\\d{2})(\\d{4})","$1-$2-$3","2(?:9[14-79]|74|[34]7|[56]9)|82|993",,],["(\\d)(\\d{4})(\\d{4})","$1-$2-$3","3|4(?:2[09]|7[01])|6[1-9]",,],["(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3","[2479][1-9]",,]]]',
 "237": '["CM","00",,,,,"\\d{8}","[2357-9]\\d{7}",[["([2357-9]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[23579]|88",,],["(800)(\\d{2})(\\d{3})","$1 $2 $3","80",,]]]',
 "351": '["PT","00",,,,,"\\d{9}","[2-46-9]\\d{8}",[["(2\\d)(\\d{3})(\\d{4})","$1 $2 $3","2[12]",,],["([2-46-9]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","2[3-9]|[346-9]",,]]]',
 "246": '["IO","00",,,,,"\\d{7}","3\\d{6}",[["(\\d{3})(\\d{4})","$1 $2",,,]]]',
 "227": '["NE","00",,,,,"\\d{8}","[0289]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[289]|09",,],["(08)(\\d{3})(\\d{3})","$1 $2 $3","08",,]]]',
 "27": '["ZA","00","0",,,"$NP$FG","\\d{5,9}","[1-79]\\d{8}|8(?:[067]\\d{7}|[1-4]\\d{3,7})",[["(860)(\\d{3})(\\d{3})","$1 $2 $3","860",,],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","[1-79]|8(?:[0-47]|6[1-9])",,],["(\\d{2})(\\d{3,4})","$1 $2","8[1-4]",,],["(\\d{2})(\\d{3})(\\d{2,3})","$1 $2 $3","8[1-4]",,]]]',
 "962": '["JO","00","0",,,"$NP$FG","\\d{7,9}","[235-9]\\d{7,8}",[["(\\d)(\\d{3})(\\d{4})","$1 $2 $3","[2356]|87","($NP$FG)",],["(7)(\\d{4})(\\d{4})","$1 $2 $3","7[457-9]",,],["(\\d{3})(\\d{5,6})","$1 $2","70|8[0158]|9",,]]]',
 "387": '["BA","00","0",,,"$NP$FG","\\d{6,9}","[3-9]\\d{7,8}",[["(\\d{2})(\\d{3})(\\d{3})","$1 $2-$3","[3-5]",,],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","6[1-356]|[7-9]",,],["(\\d{2})(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3 $4","6[047]",,]]]',
-"33": '["FR","[04579]0","0",,,"$NP$FG","\\d{4}(?:\\d{5})?","[124-9]\\d{8}|3\\d{3}(?:\\d{5})?",[["([1-79])(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5","[1-79]",,],["(8\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","8","$NP $FG",]]]',
+"33": '["FR","00","0",,,"$NP$FG","\\d{9}","[1-9]\\d{8}",[["([1-79])(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5","[1-79]",,],["(1\\d{2})(\\d{3})","$1 $2","11","$FG","NA"],["(8\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","8","$NP $FG",]]]',
 "972": '["IL","0(?:0|1[2-9])","0",,,"$FG","\\d{4,10}","[17]\\d{6,9}|[2-589]\\d{3}(?:\\d{3,6})?|6\\d{3}",[["([2-489])(\\d{3})(\\d{4})","$1-$2-$3","[2-489]","$NP$FG",],["([57]\\d)(\\d{3})(\\d{4})","$1-$2-$3","[57]","$NP$FG",],["(1)([7-9]\\d{2})(\\d{3})(\\d{3})","$1-$2-$3-$4","1[7-9]",,],["(1255)(\\d{3})","$1-$2","125",,],["(1200)(\\d{3})(\\d{3})","$1-$2-$3","120",,],["(1212)(\\d{2})(\\d{2})","$1-$2-$3","121",,],["(1599)(\\d{6})","$1-$2","15",,],["(\\d{4})","*$1","[2-689]",,]]]',
 "248": '["SC","0[0-2]",,,,,"\\d{6,7}","[24689]\\d{5,6}",[["(\\d{3})(\\d{3})","$1 $2","[89]",,],["(\\d)(\\d{3})(\\d{3})","$1 $2 $3","[246]",,]]]',
 "297": '["AW","00",,,,,"\\d{7}","[25-9]\\d{6}",[["(\\d{3})(\\d{4})","$1 $2",,,]]]',
 "421": '["SK","00","0",,,"$NP$FG","\\d{9}","[2-689]\\d{8}",[["(2)(\\d{3})(\\d{3})(\\d{2})","$1/$2 $3 $4","2",,],["([3-5]\\d)(\\d{3})(\\d{2})(\\d{2})","$1/$2 $3 $4","[3-5]",,],["([689]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","[689]",,]]]',
 "672": '["NF","00",,,,,"\\d{5,6}","[13]\\d{5}",[["(\\d{2})(\\d{4})","$1 $2","1",,],["(\\d)(\\d{5})","$1 $2","3",,]]]',
 "870": '["001",,,,,,"\\d{9}","[35-7]\\d{8}",[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",,,]]]',
 "883": '["001",,,,,,"\\d{9}(?:\\d{3})?","51\\d{7}(?:\\d{3})?",[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",,,],["(\\d{3})(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3 $4",,,]]]',
 "264": '["NA","00","0",,,"$NP$FG","\\d{8,9}","[68]\\d{7,8}",[["(8\\d)(\\d{3})(\\d{4})","$1 $2 $3","8[1235]",,],["(6\\d)(\\d{2,3})(\\d{4})","$1 $2 $3","6",,],["(88)(\\d{3})(\\d{3})","$1 $2 $3","88",,],["(870)(\\d{3})(\\d{3})","$1 $2 $3","870",,]]]',
 "878": '["001",,,,,,"\\d{12}","1\\d{11}",[["(\\d{2})(\\d{5})(\\d{5})","$1 $2 $3",,,]]]',
 "239": '["ST","00",,,,,"\\d{7}","[29]\\d{6}",[["(\\d{3})(\\d{4})","$1 $2",,,]]]',
 "357": '["CY","00",,,,,"\\d{8}","[257-9]\\d{7}",[["(\\d{2})(\\d{6})","$1 $2",,,]]]',
 "240": '["GQ","00",,,,,"\\d{9}","[23589]\\d{8}",[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3","[235]",,],["(\\d{3})(\\d{6})","$1 $2","[89]",,]]]',
-"506": '["CR","00",,"(19(?:0[0-2468]|19|20|66|77))",,,"\\d{8,10}","[24-9]\\d{7,9}",[["(\\d{4})(\\d{4})","$1 $2","[24-7]|8[3-9]",,],["(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3","[89]0",,]]]',
-"86": '["CN","(1[1279]\\d{3})?00","0","(1[1279]\\d{3})|0",,,"\\d{4,12}","[1-7]\\d{6,11}|8[0-357-9]\\d{6,9}|9(?:5\\d{3,4}|\\d{9})",[["(80\\d{2})(\\d{4})","$1 $2","80[2678]","$NP$FG",],["([48]00)(\\d{3})(\\d{4})","$1 $2 $3","[48]00",,],["(\\d{5})","$1","95",,],["(\\d{2})(\\d{5,6})","$1 $2","(?:10|2\\d)9","$NP$FG",],["(\\d{3})(\\d{5,6})","$1 $2","[3-9]","$NP$FG",],["(\\d{3,4})(\\d{4})","$1 $2","[2-9]",,"NA"],["(21)(\\d{4})(\\d{4,6})","$1 $2 $3","21","$NP$FG",],["([12]\\d)(\\d{4})(\\d{4})","$1 $2 $3","10[1-9]|2[02-9]","$NP$FG",],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3","3(?:11|7[179])|4(?:[15]1|3[12])|5(?:1|2[37]|3[12]|51|7[13-79]|9[15])|7(?:31|5[457]|6[09]|91)|8(?:71|98)","$NP$FG",],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","3(?:1[02-9]|35|49|5|7[02-68]|9[1-68])|4(?:1[02-9]|2[179]|[35][2-9]|6[4789]|7\\d|8[23])|5(?:3[03-9]|4[36]|5[02-9]|6[1-46]|7[028]|80|9[2-46-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]|2[248]|3[04-9]|4[3-6]|6[2368])|8(?:1[236-8]|2[5-7]|3|5[1-9]|7[02-9]|8[3678]|9[1-7])|9(?:0[1-3689]|1[1-79]|[379]|4[13]|5[1-5])","$NP$FG",],["(1[3-58]\\d)(\\d{4})(\\d{4})","$1 $2 $3","1[3-58]",,],["(10800)(\\d{3})(\\d{4})","$1 $2 $3","108",,]]]',
+"506": '["CR","00",,"(19(?:0[01468]|19|20|66|77))",,,"\\d{8,10}","[24-9]\\d{7,9}",[["(\\d{4})(\\d{4})","$1 $2","[24-7]|8[3-9]",,],["(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3","[89]0",,]]]',
+"86": '["CN","(1[1279]\\d{3})?00","0","(1[1279]\\d{3})|0",,,"\\d{4,12}","1(?:00\\d{2}|\\d{6,11})|[2-7]\\d{6,11}|8[0-357-9]\\d{6,9}|9(?:5\\d{3,4}|\\d{9})",[["(80\\d{2})(\\d{4})","$1 $2","80[2678]","$NP$FG",],["([48]00)(\\d{3})(\\d{4})","$1 $2 $3","[48]00",,],["(\\d{5,6})","$1","100|95",,"NA"],["(\\d{2})(\\d{5,6})","$1 $2","(?:10|2\\d)[19]","$NP$FG",],["(\\d{3})(\\d{5,6})","$1 $2","[3-9]","$NP$FG",],["(\\d{3,4})(\\d{4})","$1 $2","[2-9]",,"NA"],["(21)(\\d{4})(\\d{4,6})","$1 $2 $3","21","$NP$FG",],["([12]\\d)(\\d{4})(\\d{4})","$1 $2 $3","10[1-9]|2[02-9]","$NP$FG",],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3","3(?:11|7[179])|4(?:[15]1|3[12])|5(?:1|2[37]|3[12]|51|7[13-79]|9[15])|7(?:31|5[457]|6[09]|91)|8(?:71|98)","$NP$FG",],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","3(?:1[02-9]|35|49|5|7[02-68]|9[1-68])|4(?:1[02-9]|2[179]|[35][2-9]|6[4789]|7\\d|8[23])|5(?:3[03-9]|4[36]|5[02-9]|6[1-46]|7[028]|80|9[2-46-9])|6(?:3[1-5]|6[0238]|9[12])|7(?:01|[1579]|2[248]|3[04-9]|4[3-6]|6[2368])|8(?:1[236-8]|2[5-7]|3|5[1-9]|7[02-9]|8[3678]|9[1-7])|9(?:0[1-3689]|1[1-79]|[379]|4[13]|5[1-5])","$NP$FG",],["(1[3-58]\\d)(\\d{4})(\\d{4})","$1 $2 $3","1[3-58]",,],["(10800)(\\d{3})(\\d{4})","$1 $2 $3","108",,]]]',
 "257": '["BI","00",,,,,"\\d{8}","[27]\\d{7}",[["([27]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "683": '["NU","00",,,,,"\\d{4}","[1-5]\\d{3}",]',
-"43": '["AT","00","0",,,"$NP$FG","\\d{3,13}","[1-9]\\d{3,12}",[["(1)(\\d{3,12})","$1 $2","1",,],["(5\\d)(\\d{3,5})","$1 $2","5[079]",,],["(5\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","5[079]",,],["(5\\d)(\\d{4})(\\d{4,7})","$1 $2 $3","5[079]",,],["(\\d{3})(\\d{3,10})","$1 $2","316|46|51|732|6(?:44|5[0-3579]|[6-9])|7(?:1|[28]0)|[89]",,],["(\\d{4})(\\d{3,9})","$1 $2","2|3(?:1[1-578]|[3-8])|4[2378]|5[2-6]|6(?:[12]|4[1-35-9]|5[468])|7(?:2[1-8]|35|4[1-8]|[57-9])",,]]]',
+"43": '["AT","00","0",,,"$NP$FG","\\d{3,13}","[1-9]\\d{3,12}",[["(1)(\\d{3,12})","$1 $2","1",,],["(5\\d)(\\d{3,5})","$1 $2","5[079]",,],["(5\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","5[079]",,],["(5\\d)(\\d{4})(\\d{4,7})","$1 $2 $3","5[079]",,],["(\\d{3})(\\d{3,10})","$1 $2","316|46|51|732|6(?:44|5[0-3579]|[6-9])|7(?:1|[28]0)|[89]",,],["(\\d{4})(\\d{3,9})","$1 $2","2|3(?:1[1-578]|[3-8])|4[2378]|5[2-6]|6(?:[12]|4[1-35-9]|5[468])|7(?:2[1-8]|35|4[1-8]|[5-79])",,]]]',
 "247": '["AC","00",,,,,"\\d{4}","[2-467]\\d{3}",]',
-"675": '["PG","00",,,,,"\\d{7,8}","[1-9]\\d{6,7}",[["(\\d{3})(\\d{4})","$1 $2","[1-689]",,],["(7\\d{2})(\\d{2})(\\d{3})","$1 $2 $3","7",,]]]',
+"675": '["PG","00",,,,,"\\d{7,8}","[1-9]\\d{6,7}",[["(\\d{3})(\\d{4})","$1 $2","[1-689]",,],["(7\\d{3})(\\d{4})","$1 $2","7",,]]]',
 "376": '["AD","00",,,,,"\\d{6,8}","(?:[346-9]|180)\\d{5}",[["(\\d{3})(\\d{3})","$1 $2","[346-9]",,],["(180[02])(\\d{4})","$1 $2","1",,]]]',
 "63": '["PH","00","0",,,,"\\d{5,13}","2\\d{5,7}|[3-9]\\d{7,9}|1800\\d{7,9}",[["(2)(\\d{3})(\\d{4})","$1 $2 $3","2","($NP$FG)",],["(2)(\\d{5})","$1 $2","2","($NP$FG)",],["(\\d{4})(\\d{4,6})","$1 $2","3(?:23|39|46)|4(?:2[3-6]|[35]9|4[26]|76)|5(?:22|44)|642|8(?:62|8[245])","($NP$FG)",],["(\\d{5})(\\d{4})","$1 $2","346|4(?:27|9[35])|883","($NP$FG)",],["([3-8]\\d)(\\d{3})(\\d{4})","$1 $2 $3","[3-8]","($NP$FG)",],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","81|9","$NP$FG",],["(1800)(\\d{3})(\\d{4})","$1 $2 $3","1",,],["(1800)(\\d{1,2})(\\d{3})(\\d{4})","$1 $2 $3 $4","1",,]]]',
 "236": '["CF","00",,,,,"\\d{8}","[278]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "590": ['["GP","00","0",,,"$NP$FG","\\d{9}","[56]\\d{8}",[["([56]90)(\\d{2})(\\d{4})","$1 $2-$3",,,]]]','["BL","00","0",,,,"\\d{9}","[56]\\d{8}",]','["MF","00","0",,,,"\\d{9}","[56]\\d{8}",]'],
 "53": '["CU","119","0",,,"($NP$FG)","\\d{4,8}","[2-57]\\d{5,7}",[["(\\d)(\\d{6,7})","$1 $2","7",,],["(\\d{2})(\\d{4,6})","$1 $2","[2-4]",,],["(\\d)(\\d{7})","$1 $2","5","$NP$FG",]]]',
 "64": '["NZ","0(?:0|161)","0",,,"$NP$FG","\\d{7,11}","6[235-9]\\d{6}|[2-57-9]\\d{7,10}",[["([34679])(\\d{3})(\\d{4})","$1-$2 $3","[3467]|9[1-9]",,],["(24099)(\\d{3})","$1 $2","240",,],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","21",,],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3","2(?:1[1-9]|[69]|7[0-35-9])|86",,],["(2\\d)(\\d{3,4})(\\d{4})","$1 $2 $3","2[028]",,],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3","2(?:10|74)|5|[89]0",,]]]',
 "965": '["KW","00",,,,,"\\d{7,8}","[12569]\\d{6,7}",[["(\\d{4})(\\d{3,4})","$1 $2","[1269]",,],["(5[015]\\d)(\\d{5})","$1 $2","5",,]]]',
 "224": '["GN","00",,,,,"\\d{8,9}","[367]\\d{7,8}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","3",,],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[67]",,]]]',
 "973": '["BH","00",,,,,"\\d{8}","[136-9]\\d{7}",[["(\\d{4})(\\d{4})","$1 $2",,,]]]',
-"32": '["BE","00","0",,,"$NP$FG","\\d{8,9}","[1-9]\\d{7,8}",[["(4[6-9]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","4[6-9]",,],["([2-49])(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4","[23]|[49][23]",,],["([15-8]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[156]|7[0178]|8(?:0[1-9]|[1-79])",,],["([89]\\d{2})(\\d{2})(\\d{3})","$1 $2 $3","(?:80|9)0",,]]]',
+"32": '["BE","00","0",,,"$NP$FG","\\d{8,9}","[1-9]\\d{7,8}",[["(4[6-9]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","4[6-9]",,],["([2-49])(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4","[23]|[49][23]",,],["([15-8]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[156]|7[018]|8(?:0[1-9]|[1-79])",,],["([89]\\d{2})(\\d{2})(\\d{3})","$1 $2 $3","(?:80|9)0",,]]]',
 "249": '["SD","00","0",,,"$NP$FG","\\d{9}","[19]\\d{8}",[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3",,,]]]',
 "678": '["VU","00",,,,,"\\d{5,7}","[2-57-9]\\d{4,6}",[["(\\d{3})(\\d{4})","$1 $2","[579]",,]]]',
 "52": '["MX","0[09]","01","0[12]|04[45](\\d{10})","1$1","$NP $FG","\\d{7,11}","[1-9]\\d{9,10}",[["([358]\\d)(\\d{4})(\\d{4})","$1 $2 $3","33|55|81",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","[2467]|3[12457-9]|5[89]|8[02-9]|9[0-35-9]",,],["(1)([358]\\d)(\\d{4})(\\d{4})","044 $2 $3 $4","1(?:33|55|81)","$FG","$1 $2 $3 $4"],["(1)(\\d{3})(\\d{3})(\\d{4})","044 $2 $3 $4","1(?:[2467]|3[12457-9]|5[89]|8[2-9]|9[1-35-9])","$FG","$1 $2 $3 $4"]]]',
 "968": '["OM","00",,,,,"\\d{7,9}","(?:2[2-6]|5|9[1-9])\\d{6}|800\\d{5,6}",[["(2\\d)(\\d{6})","$1 $2","2",,],["(9\\d{3})(\\d{4})","$1 $2","9",,],["([58]00)(\\d{4,6})","$1 $2","[58]",,]]]',
 "599": ['["CW","00",,,,,"\\d{7,8}","[169]\\d{6,7}",[["(\\d{3})(\\d{4})","$1 $2","[13-7]",,],["(9)(\\d{3})(\\d{4})","$1 $2 $3","9",,]]]','["BQ","00",,,,,"\\d{7}","[347]\\d{6}",]'],
 "800": '["001",,,,,,"\\d{8}","\\d{8}",[["(\\d{4})(\\d{4})","$1 $2",,,]]]',
 "386": '["SI","00","0",,,"$NP$FG","\\d{5,8}","[1-7]\\d{6,7}|[89]\\d{4,7}",[["(\\d)(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4","[12]|3[4-8]|4[24-8]|5[2-8]|7[3-8]","($NP$FG)",],["([3-7]\\d)(\\d{3})(\\d{3})","$1 $2 $3","[37][01]|4[019]|51|6",,],["([89][09])(\\d{3,6})","$1 $2","[89][09]",,],["([58]\\d{2})(\\d{5})","$1 $2","59|8[1-3]",,]]]',
 "679": '["FJ","0(?:0|52)",,,,,"\\d{7}(?:\\d{4})?","[36-9]\\d{6}|0\\d{10}",[["(\\d{3})(\\d{4})","$1 $2","[36-9]",,],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3","0",,]]]',
@@ -105,25 +105,25 @@ this.PHONE_NUMBER_META_DATA = {
 "256": '["UG","00[057]","0",,,"$NP$FG","\\d{5,9}","\\d{9}",[["(\\d{3})(\\d{6})","$1 $2","[7-9]|20(?:[013-8]|2[5-9])|4(?:6[45]|[7-9])",,],["(\\d{2})(\\d{7})","$1 $2","3|4(?:[1-5]|6[0-36-9])",,],["(2024)(\\d{5})","$1 $2","2024",,]]]',
 "677": '["SB","0[01]",,,,,"\\d{5,7}","[1-9]\\d{4,6}",[["(\\d{3})(\\d{4})","$1 $2","[7-9]",,]]]',
 "377": '["MC","00","0",,,"$NP$FG","\\d{8,9}","[4689]\\d{7,8}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[89]","$FG",],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","4",,],["(6)(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5","6",,]]]',
 "382": '["ME","00","0",,,"$NP$FG","\\d{6,9}","[2-9]\\d{7,8}",[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","[2-57-9]|6[3789]",,],["(67)(9)(\\d{3})(\\d{3})","$1 $2 $3 $4","679",,]]]',
 "231": '["LR","00","0",,,"$NP$FG","\\d{7,9}","(?:[29]\\d|[4-6]|7\\d{1,2}|[38]\\d{2})\\d{6}",[["([279]\\d)(\\d{3})(\\d{3})","$1 $2 $3","[279]",,],["(7\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","7",,],["([4-6])(\\d{3})(\\d{3})","$1 $2 $3","[4-6]",,],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","[38]",,]]]',
 "591": '["BO","00(1\\d)?","0","0(1\\d)?",,,"\\d{7,8}","[23467]\\d{7}",[["([234])(\\d{7})","$1 $2","[234]",,],["([67]\\d{7})","$1","[67]",,]]]',
 "808": '["001",,,,,,"\\d{8}","\\d{8}",[["(\\d{4})(\\d{4})","$1 $2",,,]]]',
 "964": '["IQ","00","0",,,"$NP$FG","\\d{6,10}","[1-7]\\d{7,9}",[["(1)(\\d{3})(\\d{4})","$1 $2 $3","1",,],["([2-6]\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","[2-6]",,],["(7\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","7",,]]]',
-"225": '["CI","00",,,,,"\\d{8}","[02-6]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
+"225": '["CI","00",,,,,"\\d{8}","[02-7]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "992": '["TJ","810","8",,,"($NP) $FG","\\d{3,9}","[3-59]\\d{8}",[["([349]\\d{2})(\\d{2})(\\d{4})","$1 $2 $3","[34]7|91[78]",,],["([459]\\d)(\\d{3})(\\d{4})","$1 $2 $3","4[48]|5|9(?:1[59]|[0235-9])",,],["(331700)(\\d)(\\d{2})","$1 $2 $3","331",,],["(\\d{4})(\\d)(\\d{4})","$1 $2 $3","3[1-5]",,]]]',
 "55": '["BR","00(?:1[45]|2[135]|[34]1|43)","0","(?:0|90)(?:(1[245]|2[135]|[34]1)(\\d{10,11}))?","$2",,"\\d{8,11}","[1-46-9]\\d{7,10}|5\\d{8,9}",[["(\\d{4})(\\d{4})","$1-$2","[2-9](?:[1-9]|0[1-9])","$FG","NA"],["(\\d{5})(\\d{4})","$1-$2","9(?:[1-9]|0[1-9])","$FG","NA"],["(\\d{3,5})","$1","1[125689]","$FG","NA"],["(\\d{2})(\\d{5})(\\d{4})","$1 $2-$3","(?:1[1-9]|2[12478])9","($FG)",],["(\\d{2})(\\d{4})(\\d{4})","$1 $2-$3","[1-9][1-9]","($FG)",],["([34]00\\d)(\\d{4})","$1-$2","[34]00",,],["([3589]00)(\\d{2,3})(\\d{4})","$1 $2 $3","[3589]00","$NP$FG",]]]',
 "674": '["NR","00",,,,,"\\d{7}","[458]\\d{6}",[["(\\d{3})(\\d{4})","$1 $2",,,]]]',
 "967": '["YE","00","0",,,"$NP$FG","\\d{6,9}","[1-7]\\d{6,8}",[["([1-7])(\\d{3})(\\d{3,4})","$1 $2 $3","[1-6]|7[24-68]",,],["(7\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","7[0137]",,]]]',
-"49": '["DE","00","0",,,"$NP$FG","\\d{2,15}","[1-35-9]\\d{3,14}|4(?:[0-8]\\d{4,12}|9(?:[0-37]\\d|4(?:[1-35-8]|4\\d?)|5\\d{1,2}|6[1-8]\\d?)\\d{2,7})",[["(1\\d{2})(\\d{7,8})","$1 $2","1[67]",,],["(1\\d{3})(\\d{7})","$1 $2","15",,],["(\\d{2})(\\d{4,11})","$1 $2","3[02]|40|[68]9",,],["(\\d{3})(\\d{3,11})","$1 $2","2(?:\\d1|0[2389]|1[24]|28|34)|3(?:[3-9][15]|40)|[4-8][1-9]1|9(?:06|[1-9]1)",,],["(\\d{4})(\\d{2,11})","$1 $2","[24-6]|[7-9](?:\\d[1-9]|[1-9]\\d)|3(?:[3569][02-46-9]|4[2-4679]|7[2-467]|8[2-46-8])",,],["(3\\d{4})(\\d{1,10})","$1 $2","3",,],["(800)(\\d{7,12})","$1 $2","800",,],["(177)(99)(\\d{7,8})","$1 $2 $3","177",,],["(\\d{3})(\\d)(\\d{4,10})","$1 $2 $3","(?:18|90)0",,],["(1\\d{2})(\\d{5,11})","$1 $2","181",,],["(18\\d{3})(\\d{6})","$1 $2","185",,],["(18\\d{2})(\\d{7})","$1 $2","18[68]",,],["(18\\d)(\\d{8})","$1 $2","18[2-579]",,],["(700)(\\d{4})(\\d{4})","$1 $2 $3","700",,]]]',
+"49": '["DE","00","0",,,"$NP$FG","\\d{2,15}","[1-35-9]\\d{3,14}|4(?:[0-8]\\d{4,12}|9(?:[0-37]\\d|4(?:[1-35-8]|4\\d?)|5\\d{1,2}|6[1-8]\\d?)\\d{2,7})",[["(1\\d{2})(\\d{7,8})","$1 $2","1[67]",,],["(1\\d{3})(\\d{7})","$1 $2","15",,],["(\\d{2})(\\d{3,11})","$1 $2","3[02]|40|[68]9",,],["(\\d{3})(\\d{3,11})","$1 $2","2(?:\\d1|0[2389]|1[24]|28|34)|3(?:[3-9][15]|40)|[4-8][1-9]1|9(?:06|[1-9]1)",,],["(\\d{4})(\\d{2,11})","$1 $2","[24-6]|[7-9](?:\\d[1-9]|[1-9]\\d)|3(?:[3569][02-46-9]|4[2-4679]|7[2-467]|8[2-46-8])",,],["(3\\d{4})(\\d{1,10})","$1 $2","3",,],["(800)(\\d{7,12})","$1 $2","800",,],["(177)(99)(\\d{7,8})","$1 $2 $3","177",,],["(\\d{3})(\\d)(\\d{4,10})","$1 $2 $3","(?:18|90)0",,],["(1\\d{2})(\\d{5,11})","$1 $2","181",,],["(18\\d{3})(\\d{6})","$1 $2","185",,],["(18\\d{2})(\\d{7})","$1 $2","18[68]",,],["(18\\d)(\\d{8})","$1 $2","18[2-579]",,],["(700)(\\d{4})(\\d{4})","$1 $2 $3","700",,]]]',
 "31": '["NL","00","0",,,"$NP$FG","\\d{5,10}","1\\d{4,8}|[2-7]\\d{8}|[89]\\d{6,9}",[["([1-578]\\d)(\\d{3})(\\d{4})","$1 $2 $3","1[035]|2[0346]|3[03568]|4[0356]|5[0358]|7|8[4578]",,],["([1-5]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","1[16-8]|2[259]|3[124]|4[17-9]|5[124679]",,],["(6)(\\d{8})","$1 $2","6[0-57-9]",,],["(66)(\\d{7})","$1 $2","66",,],["(14)(\\d{3,4})","$1 $2","14","$FG",],["([89]0\\d)(\\d{4,7})","$1 $2","80|9",,]]]',
 "970": '["PS","00","0",,,"$NP$FG","\\d{4,10}","[24589]\\d{7,8}|1(?:[78]\\d{8}|[49]\\d{2,3})",[["([2489])(2\\d{2})(\\d{4})","$1 $2 $3","[2489]",,],["(5[69]\\d)(\\d{3})(\\d{3})","$1 $2 $3","5",,],["(1[78]00)(\\d{3})(\\d{3})","$1 $2 $3","1[78]","$FG",]]]',
-"58": '["VE","00","0","(1\\d{2})|0",,"$NP$FG","\\d{7,10}","[24589]\\d{9}",[["(\\d{3})(\\d{7})","$1-$2",,,]]]',
+"58": '["VE","00","0",,,"$NP$FG","\\d{7,10}","[24589]\\d{9}",[["(\\d{3})(\\d{7})","$1-$2",,,]]]',
 "856": '["LA","00","0",,,"$NP$FG","\\d{6,10}","[2-8]\\d{7,9}",[["(20)(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3 $4","20",,],["([2-8]\\d)(\\d{3})(\\d{3})","$1 $2 $3","2[13]|[3-8]",,]]]',
 "354": '["IS","00",,,,,"\\d{7,9}","[4-9]\\d{6}|38\\d{7}",[["(\\d{3})(\\d{4})","$1 $2","[4-9]",,],["(3\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","3",,]]]',
 "242": '["CG","00",,,,,"\\d{9}","[028]\\d{8}",[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","[02]",,],["(\\d)(\\d{4})(\\d{4})","$1 $2 $3","8",,]]]',
 "423": '["LI","00","0",,,,"\\d{7,9}","6\\d{8}|[23789]\\d{6}",[["(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3","[23]|7[3-57-9]|87",,],["(6\\d)(\\d{3})(\\d{3})","$1 $2 $3","6",,],["(6[567]\\d)(\\d{3})(\\d{3})","$1 $2 $3","6[567]",,],["(69)(7\\d{2})(\\d{4})","$1 $2 $3","697",,],["([7-9]0\\d)(\\d{2})(\\d{2})","$1 $2 $3","[7-9]0",,],["([89]0\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[89]0","$NP$FG",]]]',
 "213": '["DZ","00","0",,,"$NP$FG","\\d{8,9}","(?:[1-4]|[5-9]\\d)\\d{7}",[["([1-4]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[1-4]",,],["([5-8]\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[5-8]",,],["(9\\d)(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4","9",,]]]',
 "371": '["LV","00",,,,,"\\d{8}","[2689]\\d{7}",[["([2689]\\d)(\\d{3})(\\d{3})","$1 $2 $3",,,]]]',
 "503": '["SV","00",,,,,"\\d{7,8}|\\d{11}","[267]\\d{7}|[89]\\d{6}(?:\\d{4})?",[["(\\d{4})(\\d{4})","$1 $2","[267]",,],["(\\d{3})(\\d{4})","$1 $2","[89]",,],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3","[89]",,]]]',
 "685": '["WS","0",,,,,"\\d{5,7}","[2-8]\\d{4,6}",[["(8\\d{2})(\\d{3,4})","$1 $2","8",,],["(7\\d)(\\d{5})","$1 $2","7",,]]]',
@@ -137,76 +137,76 @@ this.PHONE_NUMBER_META_DATA = {
 "222": '["MR","00",,,,,"\\d{8}","[2-48]\\d{7}",[["([2-48]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "230": '["MU","0(?:0|[2-7]0|33)",,,,,"\\d{7,8}","[2-9]\\d{6,7}",[["([2-46-9]\\d{2})(\\d{4})","$1 $2","[2-46-9]",,],["(5\\d{3})(\\d{4})","$1 $2","5",,]]]',
 "592": '["GY","001",,,,,"\\d{7}","[2-4679]\\d{6}",[["(\\d{3})(\\d{4})","$1 $2",,,]]]',
 "41": '["CH","00","0",,,"$NP$FG","\\d{9}(?:\\d{3})?","[2-9]\\d{8}|860\\d{9}",[["([2-9]\\d)(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4","[2-7]|[89]1",,],["([89]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","8[047]|90",,],["(\\d{3})(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4 $5","860",,]]]',
 "39": '["IT","00",,,,,"\\d{6,11}","[01589]\\d{5,10}|3(?:[12457-9]\\d{8}|[36]\\d{7,9})",[["(\\d{2})(\\d{3,4})(\\d{4})","$1 $2 $3","0[26]|55",,],["(0[26])(\\d{4})(\\d{5})","$1 $2 $3","0[26]",,],["(0[26])(\\d{4,6})","$1 $2","0[26]",,],["(0\\d{2})(\\d{3,4})(\\d{4})","$1 $2 $3","0[13-57-9][0159]",,],["(\\d{3})(\\d{3,6})","$1 $2","0[13-57-9][0159]|8(?:03|4[17]|9[245])",,],["(0\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","0[13-57-9][2-46-8]",,],["(0\\d{3})(\\d{2,6})","$1 $2","0[13-57-9][2-46-8]",,],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3","[13]|8(?:00|4[08]|9[59])",,],["(\\d{4})(\\d{4})","$1 $2","894",,],["(\\d{3})(\\d{4})(\\d{4})","$1 $2 $3","3",,]]]',
 "993": '["TM","810","8",,,"($NP $FG)","\\d{8}","[1-6]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2-$3-$4","12",,],["(\\d{2})(\\d{6})","$1 $2","6","$NP $FG",],["(\\d{3})(\\d)(\\d{2})(\\d{2})","$1 $2-$3-$4","13|[2-5]",,]]]',
 "888": '["001",,,,,,"\\d{11}","\\d{11}",[["(\\d{3})(\\d{3})(\\d{5})","$1 $2 $3",,,]]]',
 "353": '["IE","00","0",,,"($NP$FG)","\\d{5,10}","[124-9]\\d{6,9}",[["(1)(\\d{3,4})(\\d{4})","$1 $2 $3","1",,],["(\\d{2})(\\d{5})","$1 $2","2[24-9]|47|58|6[237-9]|9[35-9]",,],["(\\d{3})(\\d{5})","$1 $2","40[24]|50[45]",,],["(48)(\\d{4})(\\d{4})","$1 $2 $3","48",,],["(818)(\\d{3})(\\d{3})","$1 $2 $3","81",,],["(\\d{2})(\\d{3})(\\d{3,4})","$1 $2 $3","[24-69]|7[14]",,],["([78]\\d)(\\d{3,4})(\\d{4})","$1 $2 $3","76|8[35-9]","$NP$FG",],["(700)(\\d{3})(\\d{3})","$1 $2 $3","70","$NP$FG",],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3","1(?:8[059]|5)","$FG",]]]',
-"966": '["SA","00","0",,,"$NP$FG","\\d{7,10}","1\\d{7,8}|(?:[2-467]|92)\\d{7}|5\\d{8}|8\\d{9}",[["([1-467])(\\d{3})(\\d{4})","$1 $2 $3","[1-467]",,],["(1\\d)(\\d{3})(\\d{4})","$1 $2 $3","1[1-467]",,],["(5\\d)(\\d{3})(\\d{4})","$1 $2 $3","5",,],["(92\\d{2})(\\d{5})","$1 $2","9","$FG",],["(800)(\\d{3})(\\d{4})","$1 $2 $3","80","$FG",],["(811)(\\d{3})(\\d{3,4})","$1 $2 $3","81",,]]]',
+"966": '["SA","00","0",,,"$NP$FG","\\d{7,10}","1\\d{7,8}|(?:[2-467]|92)\\d{7}|5\\d{8}|8\\d{9}",[["([1-467])(\\d{3})(\\d{4})","$1 $2 $3","[1-467]",,],["(1\\d)(\\d{3})(\\d{4})","$1 $2 $3","1[1-467]",,],["(5\\d)(\\d{3})(\\d{4})","$1 $2 $3","5",,],["(92\\d{2})(\\d{5})","$1 $2","92","$FG",],["(800)(\\d{3})(\\d{4})","$1 $2 $3","80","$FG",],["(811)(\\d{3})(\\d{3,4})","$1 $2 $3","81",,]]]',
 "380": '["UA","00","0",,,"$NP$FG","\\d{5,9}","[3-689]\\d{8}",[["([3-689]\\d)(\\d{3})(\\d{4})","$1 $2 $3","[38]9|4(?:[45][0-5]|87)|5(?:0|6[37]|7[37])|6[36-8]|9[1-9]",,],["([3-689]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","3[1-8]2|4[13678]2|5(?:[12457]2|6[24])|6(?:[49]2|[12][29]|5[24])|8[0-8]|90",,],["([3-6]\\d{3})(\\d{5})","$1 $2","3(?:5[013-9]|[1-46-8])|4(?:[137][013-9]|6|[45][6-9]|8[4-6])|5(?:[1245][013-9]|6[0135-9]|3|7[4-6])|6(?:[49][013-9]|5[0135-9]|[12][13-8])",,]]]',
 "98": '["IR","00","0",,,"$NP$FG","\\d{4,10}","[14-8]\\d{6,9}|[23]\\d{4,9}|9(?:[1-4]\\d{8}|9\\d{2,8})",[["(2[15])(\\d{3,5})","$1 $2","2(?:1|5[0-47-9])",,],["(2[15])(\\d{3})(\\d{3,4})","$1 $2 $3","2(?:1|5[0-47-9])",,],["(2\\d)(\\d{4})(\\d{4})","$1 $2 $3","2(?:[16]|5[0-47-9])",,],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3","[13-9]|2[02-57-9]",,],["(\\d{3})(\\d{2})(\\d{2,3})","$1 $2 $3","[13-9]|2[02-57-9]",,],["(\\d{3})(\\d{3})","$1 $2","[13-9]|2[02-57-9]",,]]]',
 "971": '["AE","00","0",,,"$NP$FG","\\d{5,12}","[2-79]\\d{7,8}|800\\d{2,9}",[["([2-4679])(\\d{3})(\\d{4})","$1 $2 $3","[2-4679][2-8]",,],["(5[0256])(\\d{3})(\\d{4})","$1 $2 $3","5",,],["([479]00)(\\d)(\\d{5})","$1 $2 $3","[479]0","$FG",],["([68]00)(\\d{2,9})","$1 $2","60|8","$FG",]]]',
 "30": '["GR","00",,,,,"\\d{10}","[26-9]\\d{9}",[["([27]\\d)(\\d{4})(\\d{4})","$1 $2 $3","21|7",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","2[2-9]1|[689]",,],["(2\\d{3})(\\d{6})","$1 $2","2[2-9][02-9]",,]]]',
 "228": '["TG","00",,,,,"\\d{8}","[29]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "48": '["PL","00",,,,,"\\d{6,9}","[1-58]\\d{6,8}|9\\d{8}|[67]\\d{5,8}",[["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4","[124]|3[2-4]|5[24-689]|6[1-3578]|7[14-7]|8[1-79]|9[145]",,],["(\\d{2})(\\d{4,6})","$1 $2","[124]|3[2-4]|5[24-689]|6[1-3578]|7[14-7]|8[1-7]",,],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3","39|5[013]|6[0469]|7[02389]|8[08]",,],["(\\d{3})(\\d{2})(\\d{2,3})","$1 $2 $3","64",,],["(\\d{3})(\\d{3})","$1 $2","64",,]]]',
 "886": '["TW","0(?:0[25679]|19)","0",,,"$NP$FG","\\d{8,9}","[2-9]\\d{7,8}",[["([2-8])(\\d{3,4})(\\d{4})","$1 $2 $3","[2-7]|8[1-9]",,],["([89]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","80|9",,]]]',
 "212": ['["MA","00","0",,,"$NP$FG","\\d{9}","[5689]\\d{8}",[["([56]\\d{2})(\\d{6})","$1-$2","5(?:2[015-7]|3[0-4])|6",,],["([58]\\d{3})(\\d{5})","$1-$2","5(?:2[2-489]|3[5-9])|892",,],["(5\\d{4})(\\d{4})","$1-$2","5(?:29|38)",,],["(8[09])(\\d{7})","$1-$2","8(?:0|9[013-9])",,]]]','["EH","00","0",,,"$NP$FG","\\d{9}","[5689]\\d{8}",]'],
 "372": '["EE","00",,,,,"\\d{4,10}","1\\d{3,4}|[3-9]\\d{6,7}|800\\d{6,7}",[["([3-79]\\d{2})(\\d{4})","$1 $2","[369]|4[3-8]|5(?:[0-2]|5[0-478]|6[45])|7[1-9]",,],["(70)(\\d{2})(\\d{4})","$1 $2 $3","70",,],["(8000)(\\d{3})(\\d{3})","$1 $2 $3","800",,],["([458]\\d{3})(\\d{3,4})","$1 $2","40|5|8(?:00|[1-5])",,]]]',
 "598": '["UY","0(?:1[3-9]\\d|0)","0",,,,"\\d{7,8}","[2489]\\d{6,7}",[["(\\d{4})(\\d{4})","$1 $2","[24]",,],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","9[1-9]","$NP$FG",],["(\\d{3})(\\d{4})","$1 $2","[89]0","$NP$FG",]]]',
 "502": '["GT","00",,,,,"\\d{8}(?:\\d{3})?","[2-7]\\d{7}|1[89]\\d{9}",[["(\\d{4})(\\d{4})","$1 $2","[2-7]",,],["(\\d{4})(\\d{3})(\\d{4})","$1 $2 $3","1",,]]]',
 "82": '["KR","00(?:[124-68]|[37]\\d{2})","0","0(8[1-46-8]|85\\d{2})?",,"$NP$FG","\\d{4,10}","[1-7]\\d{3,9}|8\\d{8}",[["(\\d{2})(\\d{4})(\\d{4})","$1-$2-$3","1(?:0|1[19]|[69]9|5[458])|[57]0",,],["(\\d{2})(\\d{3,4})(\\d{4})","$1-$2-$3","1(?:[169][2-8]|[78]|5[1-4])|[68]0|[3-6][1-9][1-9]",,],["(\\d{3})(\\d)(\\d{4})","$1-$2-$3","131",,],["(\\d{3})(\\d{2})(\\d{4})","$1-$2-$3","131",,],["(\\d{3})(\\d{3})(\\d{4})","$1-$2-$3","13[2-9]",,],["(\\d{2})(\\d{2})(\\d{3})(\\d{4})","$1-$2-$3-$4","30",,],["(\\d)(\\d{3,4})(\\d{4})","$1-$2-$3","2[1-9]",,],["(\\d)(\\d{3,4})","$1-$2","21[0-46-9]",,],["(\\d{2})(\\d{3,4})","$1-$2","[3-6][1-9]1",,],["(\\d{4})(\\d{4})","$1-$2","1(?:5[46-9]|6[04678])","$FG",]]]',
 "253": '["DJ","00",,,,,"\\d{8}","[27]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
-"91": '["IN","00","0",,,"$NP$FG","\\d{6,13}","1\\d{7,12}|[2-9]\\d{9,10}",[["(\\d{2})(\\d{2})(\\d{6})","$1 $2 $3","7(?:2[0579]|3[057-9]|4[0-389]|5[024-9]|6[0-35-9]|7|8[0-79])|8(?:0[015689]|1[0-57-9]|2[2356-9]|3[0-57-9]|[45]|6[0245789]|7[1-69]|8[0124-9]|9[02-9])|9",,],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","11|2[02]|33|4[04]|79|80[2-46]",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","1(?:2[0-249]|3[0-25]|4[145]|[569][14]|7[1257]|8[1346]|[68][1-9])|2(?:1[257]|3[013]|4[01]|5[0137]|6[0158]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[126-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:[136][25]|22|4[28]|5[12]|[78]1|9[15])|6(?:12|[2345]1|57|6[13]|7[14]|80)",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","7(?:12|2[14]|3[134]|4[47]|5[15]|[67]1|88)",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","8(?:16|2[014]|3[126]|6[136]|7[078]|8[34]|91)",,],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3","1(?:[2-579]|[68][1-9])|[2-8]",,],["(1600)(\\d{2})(\\d{4})","$1 $2 $3","160","$FG",],["(1800)(\\d{4,5})","$1 $2","180","$FG",],["(18[06]0)(\\d{2,4})(\\d{4})","$1 $2 $3","18[06]","$FG",],["(\\d{4})(\\d{3})(\\d{4})(\\d{2})","$1 $2 $3 $4","18[06]","$FG",]]]',
+"91": '["IN","00","0",,,"$NP$FG","\\d{6,13}","1\\d{7,12}|[2-9]\\d{9,10}",[["(\\d{2})(\\d{2})(\\d{6})","$1 $2 $3","7(?:2[0579]|3[057-9]|4[0-389]|6[0-35-9]|[57]|8[0-79])|8(?:0[015689]|1[0-57-9]|2[2356-9]|3[0-57-9]|[45]|6[02457-9]|7[1-69]|8[0124-9]|9[02-9])|9",,],["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","11|2[02]|33|4[04]|79|80[2-46]",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","1(?:2[0-249]|3[0-25]|4[145]|[569][14]|7[1257]|8[1346]|[68][1-9])|2(?:1[257]|3[013]|4[01]|5[0137]|6[0158]|78|8[1568]|9[14])|3(?:26|4[1-3]|5[34]|6[01489]|7[02-46]|8[159])|4(?:1[36]|2[1-47]|3[15]|5[12]|6[126-9]|7[0-24-9]|8[013-57]|9[014-7])|5(?:[136][25]|22|4[28]|5[12]|[78]1|9[15])|6(?:12|[2345]1|57|6[13]|7[14]|80)",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","7(?:12|2[14]|3[134]|4[47]|5[15]|[67]1|88)",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","8(?:16|2[014]|3[126]|6[136]|7[078]|8[34]|91)",,],["(\\d{4})(\\d{3})(\\d{3})","$1 $2 $3","1(?:[2-579]|[68][1-9])|[2-8]",,],["(1600)(\\d{2})(\\d{4})","$1 $2 $3","160","$FG",],["(1800)(\\d{4,5})","$1 $2","180","$FG",],["(18[06]0)(\\d{2,4})(\\d{4})","$1 $2 $3","18[06]","$FG",],["(\\d{4})(\\d{3})(\\d{4})(\\d{2})","$1 $2 $3 $4","18[06]","$FG",]]]',
 "389": '["MK","00","0",,,"$NP$FG","\\d{8}","[2-578]\\d{7}",[["(2)(\\d{3})(\\d{4})","$1 $2 $3","2",,],["([347]\\d)(\\d{3})(\\d{3})","$1 $2 $3","[347]",,],["([58]\\d{2})(\\d)(\\d{2})(\\d{2})","$1 $2 $3 $4","[58]",,]]]',
 "1": ['["US","011","1",,,,"\\d{7}(?:\\d{3})?","[2-9]\\d{9}",[["(\\d{3})(\\d{4})","$1-$2",,,"NA"],["(\\d{3})(\\d{3})(\\d{4})","($1) $2-$3",,,"$1-$2-$3"]]]','["AI","011","1",,,,"\\d{7}(?:\\d{3})?","[2589]\\d{9}",]','["AS","011","1",,,,"\\d{7}(?:\\d{3})?","[5689]\\d{9}",]','["BB","011","1",,,,"\\d{7}(?:\\d{3})?","[2589]\\d{9}",]','["BM","011","1",,,,"\\d{7}(?:\\d{3})?","[4589]\\d{9}",]','["BS","011","1",,,,"\\d{7}(?:\\d{3})?","[2589]\\d{9}",]','["CA","011","1",,,,"\\d{7}(?:\\d{3})?","[2-9]\\d{9}|3\\d{6}",]','["DM","011","1",,,,"\\d{7}(?:\\d{3})?","[57-9]\\d{9}",]','["DO","011","1",,,,"\\d{7}(?:\\d{3})?","[589]\\d{9}",]','["GD","011","1",,,,"\\d{7}(?:\\d{3})?","[4589]\\d{9}",]','["GU","011","1",,,,"\\d{7}(?:\\d{3})?","[5689]\\d{9}",]','["JM","011","1",,,,"\\d{7}(?:\\d{3})?","[589]\\d{9}",]','["KN","011","1",,,,"\\d{7}(?:\\d{3})?","[589]\\d{9}",]','["KY","011","1",,,,"\\d{7}(?:\\d{3})?","[3589]\\d{9}",]','["LC","011","1",,,,"\\d{7}(?:\\d{3})?","[5789]\\d{9}",]','["MP","011","1",,,,"\\d{7}(?:\\d{3})?","[5689]\\d{9}",]','["MS","011","1",,,,"\\d{7}(?:\\d{3})?","[5689]\\d{9}",]','["PR","011","1",,,,"\\d{7}(?:\\d{3})?","[5789]\\d{9}",]','["SX","011","1",,,,"\\d{7}(?:\\d{3})?","[5789]\\d{9}",]','["TC","011","1",,,,"\\d{7}(?:\\d{3})?","[5689]\\d{9}",]','["TT","011","1",,,,"\\d{7}(?:\\d{3})?","[589]\\d{9}",]','["AG","011","1",,,,"\\d{7}(?:\\d{3})?","[2589]\\d{9}",]','["VC","011","1",,,,"\\d{7}(?:\\d{3})?","[5789]\\d{9}",]','["VG","011","1",,,,"\\d{7}(?:\\d{3})?","[2589]\\d{9}",]','["VI","011","1",,,,"\\d{7}(?:\\d{3})?","[3589]\\d{9}",]'],
 "60": '["MY","00","0",,,,"\\d{6,10}","[13-9]\\d{7,9}",[["([4-79])(\\d{3})(\\d{4})","$1-$2 $3","[4-79]","$NP$FG",],["(3)(\\d{4})(\\d{4})","$1-$2 $3","3","$NP$FG",],["([18]\\d)(\\d{3})(\\d{3,4})","$1-$2 $3","1[02-46-9][1-9]|8","$NP$FG",],["(1)([36-8]00)(\\d{2})(\\d{4})","$1-$2-$3-$4","1[36-8]0",,],["(11)(\\d{4})(\\d{4})","$1-$2 $3","11","$NP$FG",],["(15[49])(\\d{3})(\\d{4})","$1-$2 $3","15","$NP$FG",]]]',
 "355": '["AL","00","0",,,"$NP$FG","\\d{5,9}","[2-57]\\d{7}|6\\d{8}|8\\d{5,7}|9\\d{5}",[["(4)(\\d{3})(\\d{4})","$1 $2 $3","4[0-6]",,],["(6[6-9])(\\d{3})(\\d{4})","$1 $2 $3","6",,],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","[2358][2-5]|4[7-9]",,],["(\\d{3})(\\d{3,5})","$1 $2","[235][16-9]|8[016-9]|[79]",,]]]',
 "254": '["KE","000","0",,,"$NP$FG","\\d{5,10}","20\\d{6,7}|[4-9]\\d{6,9}",[["(\\d{2})(\\d{4,7})","$1 $2","[24-6]",,],["(\\d{3})(\\d{6,7})","$1 $2","7",,],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3","[89]",,]]]',
-"223": '["ML","00",,,,,"\\d{8}","[246-8]\\d{7}",[["([246-8]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
-"686": '["KI","00",,"0",,,"\\d{5}","[2-689]\\d{4}",]',
+"223": '["ML","00",,,,,"\\d{8}","[246-9]\\d{7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[246-9]",,],["(\\d{4})","$1","67|74",,"NA"]]]',
+"686": '["KI","00",,"0",,,"\\d{5,8}","[2-689]\\d{4}|7\\d{7}",]',
 "994": '["AZ","00","0",,,"($NP$FG)","\\d{7,9}","[1-9]\\d{8}",[["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4","(?:1[28]|2(?:[45]2|[0-36])|365)",,],["(\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3 $4","[4-8]","$NP$FG",],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","9","$NP$FG",]]]',
 "979": '["001",,,,,,"\\d{9}","\\d{9}",[["(\\d)(\\d{4})(\\d{4})","$1 $2 $3",,,]]]',
 "66": '["TH","00","0",,,"$NP$FG","\\d{4}|\\d{8,10}","[2-9]\\d{7,8}|1\\d{3}(?:\\d{6})?",[["(2)(\\d{3})(\\d{4})","$1 $2 $3","2",,],["([3-9]\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","[3-9]",,],["(1[89]00)(\\d{3})(\\d{3})","$1 $2 $3","1","$FG",]]]',
 "233": '["GH","00","0",,,"$NP$FG","\\d{7,9}","[235]\\d{8}|8\\d{7}",[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","[235]",,],["(\\d{3})(\\d{5})","$1 $2","8",,]]]',
 "593": '["EC","00","0",,,"($NP$FG)","\\d{7,11}","1\\d{9,10}|[2-8]\\d{7}|9\\d{8}",[["(\\d)(\\d{3})(\\d{4})","$1 $2-$3","[247]|[356][2-8]",,"$1-$2-$3"],["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","9","$NP$FG",],["(1800)(\\d{3})(\\d{3,4})","$1 $2 $3","1","$FG",]]]',
 "509": '["HT","00",,,,,"\\d{8}","[2-489]\\d{7}",[["(\\d{2})(\\d{2})(\\d{4})","$1 $2 $3",,,]]]',
-"54": '["AR","00","0","0?(?:(11|2(?:2(?:02?|[13]|2[13-79]|4[1-6]|5[2457]|6[124-8]|7[1-4]|8[13-6]|9[1267])|3(?:02?|1[467]|2[03-6]|3[13-8]|[49][2-6]|5[2-8]|[67])|4(?:7[3-578]|9)|6(?:[0136]|2[24-6]|4[6-8]?|5[15-8])|80|9(?:0[1-3]|[19]|2\\d|3[1-6]|4[02568]?|5[2-4]|6[2-46]|72?|8[23]?))|3(?:3(?:2[79]|6|8[2578])|4(?:0[124-9]|[12]|3[5-8]?|4[24-7]|5[4-68]?|6[02-9]|7[126]|8[2379]?|9[1-36-8])|5(?:1|2[1245]|3[237]?|4[1-46-9]|6[2-4]|7[1-6]|8[2-5]?)|6[24]|7(?:1[1568]|2[15]|3[145]|4[13]|5[14-8]|[069]|7[2-57]|8[126])|8(?:[01]|2[15-7]|3[2578]?|4[13-6]|5[4-8]?|6[1-357-9]|7[36-8]?|8[5-8]?|9[124])))15)?","9$1","$NP$FG","\\d{6,11}","[1-368]\\d{9}|9\\d{10}",[["([68]\\d{2})(\\d{3})(\\d{4})","$1-$2-$3","[68]",,],["(9)(11)(\\d{4})(\\d{4})","$2 15-$3-$4","911",,"$1 $2 $3-$4"],["(9)(\\d{3})(\\d{3})(\\d{4})","$2 15-$3-$4","9(?:2[234689]|3[3-8])",,"$1 $2 $3-$4"],["(9)(\\d{4})(\\d{3})(\\d{3})","$2 15-$3-$4","93[58]",,"$1 $2 $3-$4"],["(9)(\\d{4})(\\d{2})(\\d{4})","$2 15-$3-$4","9[23]",,"$1 $2 $3-$4"],["(11)(\\d{4})(\\d{4})","$1 $2-$3","1",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2-$3","2(?:2[013]|3[067]|49|6[01346]|80|9[147-9])|3(?:36|4[12358]|5[138]|6[24]|7[069]|8[013578])",,],["(\\d{4})(\\d{3})(\\d{3})","$1 $2-$3","3(?:53|8[78])",,],["(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3","[23]",,]]]',
-"57": '["CO","00[579]|#555|#999","0","0([3579]|4(?:44|56))?",,,"\\d{7,11}","(?:[13]\\d{0,3}|[24-8])\\d{7}",[["(\\d)(\\d{7})","$1 $2","1(?:8[2-9]|9[0-3]|[2-7])|[24-8]","($FG)",],["(\\d{3})(\\d{7})","$1 $2","3",,],["(1)(\\d{3})(\\d{7})","$1-$2-$3","1(?:80|9[04])","$NP$FG","$1 $2 $3"]]]',
+"54": '["AR","00","0","0?(?:(11|2(?:2(?:02?|[13]|2[13-79]|4[1-6]|5[2457]|6[124-8]|7[1-4]|8[13-6]|9[1267])|3(?:02?|1[467]|2[03-6]|3[13-8]|[49][2-6]|5[2-8]|[67])|4(?:7[3-578]|9)|6(?:[0136]|2[24-6]|4[6-8]?|5[15-8])|80|9(?:0[1-3]|[19]|2\\d|3[1-6]|4[02568]?|5[2-4]|6[2-46]|72?|8[23]?))|3(?:3(?:2[79]|6|8[2578])|4(?:0[124-9]|[12]|3[5-8]?|4[24-7]|5[4-68]?|6[02-9]|7[126]|8[2379]?|9[1-36-8])|5(?:1|2[1245]|3[237]?|4[1-46-9]|6[2-4]|7[1-6]|8[2-5]?)|6[24]|7(?:1[1568]|2[15]|3[145]|4[13]|5[14-8]|[069]|7[2-57]|8[126])|8(?:[01]|2[15-7]|3[2578]?|4[13-6]|5[4-8]?|6[1-357-9]|7[36-8]?|8[5-8]?|9[124])))15)?","9$1","$NP$FG","\\d{6,11}","[1-368]\\d{9}|9\\d{10}",[["([68]\\d{2})(\\d{3})(\\d{4})","$1-$2-$3","[68]",,],["(9)(11)(\\d{4})(\\d{4})","$2 15-$3-$4","911",,"$1 $2 $3-$4"],["(9)(\\d{3})(\\d{3})(\\d{4})","$2 15-$3-$4","9(?:2[234689]|3[3-8])",,"$1 $2 $3-$4"],["(9)(\\d{4})(\\d{3})(\\d{3})","$2 15-$3-$4","93[58]",,"$1 $2 $3-$4"],["(9)(\\d{4})(\\d{2})(\\d{4})","$2 15-$3-$4","9[23]",,"$1 $2 $3-$4"],["(11)(\\d{4})(\\d{4})","$1 $2-$3","1",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2-$3","2(?:2[013]|3[067]|49|6[01346]|80|9[147-9])|3(?:36|4[12358]|5[138]|6[24]|7[069]|8[013578])",,],["(\\d{4})(\\d{3})(\\d{3})","$1 $2-$3","3(?:53|8[78])",,],["(\\d{4})(\\d{2})(\\d{4})","$1 $2-$3","[23]",,],["(\\d{3})","$1","1[012]|911","$FG","NA"]]]',
+"57": '["CO","00(?:4(?:[14]4|56)|[579])","0","0([3579]|4(?:44|56))?",,,"\\d{7,11}","(?:[13]\\d{0,3}|[24-8])\\d{7}",[["(\\d)(\\d{7})","$1 $2","1(?:8[2-9]|9[0-3]|[2-7])|[24-8]","($FG)",],["(\\d{3})(\\d{7})","$1 $2","3",,],["(1)(\\d{3})(\\d{7})","$1-$2-$3","1(?:80|9[04])","$NP$FG","$1 $2 $3"]]]',
 "597": '["SR","00",,,,,"\\d{6,7}","[2-8]\\d{5,6}",[["(\\d{3})(\\d{3})","$1-$2","[2-4]|5[2-58]",,],["(\\d{2})(\\d{2})(\\d{2})","$1-$2-$3","56",,],["(\\d{3})(\\d{4})","$1-$2","[6-8]",,]]]',
 "676": '["TO","00",,,,,"\\d{5,7}","[02-8]\\d{4,6}",[["(\\d{2})(\\d{3})","$1-$2","[1-6]|7[0-4]|8[05]",,],["(\\d{3})(\\d{4})","$1 $2","7[5-9]|8[7-9]",,],["(\\d{4})(\\d{3})","$1 $2","0",,]]]',
-"505": '["NI","00",,,,,"\\d{8}","[128]\\d{7}",[["(\\d{4})(\\d{4})","$1 $2",,,]]]',
+"505": '["NI","00",,,,,"\\d{8}","[1258]\\d{7}",[["(\\d{4})(\\d{4})","$1 $2",,,]]]',
 "850": '["KP","00|99","0",,,"$NP$FG","\\d{6,8}|\\d{10}","1\\d{9}|[28]\\d{7}",[["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","1",,],["(\\d)(\\d{3})(\\d{4})","$1 $2 $3","2",,],["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","8",,]]]',
 "7": ['["RU","810","8",,,"$NP ($FG)","\\d{10}","[3489]\\d{9}",[["(\\d{3})(\\d{2})(\\d{2})","$1-$2-$3","[1-79]","$FG","NA"],["([3489]\\d{2})(\\d{3})(\\d{2})(\\d{2})","$1 $2-$3-$4","[34689]",,],["(7\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","7",,]]]','["KZ","810","8",,,,"\\d{10}","(?:33\\d|7\\d{2}|80[09])\\d{7}",]'],
 "268": '["SZ","00",,,,,"\\d{8}","[027]\\d{7}",[["(\\d{4})(\\d{4})","$1 $2","[027]",,]]]',
 "501": '["BZ","00",,,,,"\\d{7}(?:\\d{4})?","[2-8]\\d{6}|0\\d{10}",[["(\\d{3})(\\d{4})","$1-$2","[2-8]",,],["(0)(800)(\\d{4})(\\d{3})","$1-$2-$3-$4","0",,]]]',
 "252": '["SO","00","0",,,,"\\d{7,9}","[1-79]\\d{6,8}",[["(\\d)(\\d{6})","$1 $2","2[0-79]|[13-5]",,],["(\\d)(\\d{7})","$1 $2","24|[67]",,],["(\\d{2})(\\d{5,7})","$1 $2","15|28|6[1378]|9",,],["(69\\d)(\\d{6})","$1 $2","69",,]]]',
 "229": '["BJ","00",,,,,"\\d{4,8}","[2689]\\d{7}|7\\d{3}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "680": '["PW","01[12]",,,,,"\\d{7}","[2-8]\\d{6}",[["(\\d{3})(\\d{4})","$1 $2",,,]]]',
 "263": '["ZW","00","0",,,"$NP$FG","\\d{3,10}","2(?:[012457-9]\\d{3,8}|6\\d{3,6})|[13-79]\\d{4,8}|8[06]\\d{8}",[["([49])(\\d{3})(\\d{2,5})","$1 $2 $3","4|9[2-9]",,],["([179]\\d)(\\d{3})(\\d{3,4})","$1 $2 $3","[19]1|7",,],["(86\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","86[24]",,],["([2356]\\d{2})(\\d{3,5})","$1 $2","2(?:[278]|0[45]|[49]8)|3(?:08|17|3[78]|[78])|5[15][78]|6(?:[29]8|37|[68][78])",,],["(\\d{3})(\\d{3})(\\d{3,4})","$1 $2 $3","2(?:[278]|0[45]|48)|3(?:08|17|3[78]|[78])|5[15][78]|6(?:[29]8|37|[68][78])|80",,],["([1-356]\\d)(\\d{3,5})","$1 $2","1[3-9]|2(?:[1-469]|0[0-35-9]|[45][0-79])|3(?:0[0-79]|1[0-689]|[24-69]|3[0-69])|5(?:[02-46-9]|[15][0-69])|6(?:[0145]|[29][0-79]|3[0-689]|[68][0-69])",,],["([1-356]\\d)(\\d{3})(\\d{3})","$1 $2 $3","1[3-9]|2(?:[1-469]|0[0-35-9]|[45][0-79])|3(?:0[0-79]|1[0-689]|[24-69]|3[0-69])|5(?:[02-46-9]|[15][0-69])|6(?:[0145]|[29][0-79]|3[0-689]|[68][0-69])",,],["([25]\\d{3})(\\d{3,5})","$1 $2","(?:25|54)8",,],["([25]\\d{3})(\\d{3})(\\d{3})","$1 $2 $3","(?:25|54)8",,],["(8\\d{3})(\\d{6})","$1 $2","86",,]]]',
 "90": '["TR","00","0",,,,"\\d{7,10}","[2-589]\\d{9}|444\\d{4}",[["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","[23]|4(?:[0-35-9]|4[0-35-9])","($NP$FG)",],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","[589]","$NP$FG",],["(444)(\\d{1})(\\d{3})","$1 $2 $3","444",,]]]',
 "352": '["LU","00",,"(15(?:0[06]|1[12]|35|4[04]|55|6[26]|77|88|99)\\d)",,,"\\d{4,11}","[24-9]\\d{3,10}|3(?:[0-46-9]\\d{2,9}|5[013-9]\\d{1,8})",[["(\\d{2})(\\d{3})","$1 $2","[2-5]|7[1-9]|[89](?:[1-9]|0[2-9])",,],["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3","[2-5]|7[1-9]|[89](?:[1-9]|0[2-9])",,],["(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3","20",,],["(\\d{2})(\\d{2})(\\d{2})(\\d{1,2})","$1 $2 $3 $4","2(?:[0367]|4[3-8])",,],["(\\d{2})(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3 $4","20",,],["(\\d{2})(\\d{2})(\\d{2})(\\d{2})(\\d{1,2})","$1 $2 $3 $4 $5","2(?:[0367]|4[3-8])",,],["(\\d{2})(\\d{2})(\\d{2})(\\d{1,4})","$1 $2 $3 $4","2(?:[12589]|4[12])|[3-5]|7[1-9]|[89](?:[1-9]|0[2-9])",,],["(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3","[89]0[01]|70",,],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3","6",,]]]',
 "47": ['["NO","00",,,,,"\\d{5}(?:\\d{3})?","0\\d{4}|[2-9]\\d{7}",[["([489]\\d{2})(\\d{2})(\\d{3})","$1 $2 $3","[489]",,],["([235-7]\\d)(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[235-7]",,]]]','["SJ","00",,,,,"\\d{5}(?:\\d{3})?","0\\d{4}|[4789]\\d{7}",]'],
 "243": '["CD","00","0",,,"$NP$FG","\\d{7,9}","[2-6]\\d{6}|[18]\\d{6,8}|9\\d{8}",[["(\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","12",,],["([89]\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","8[0-2459]|9",,],["(\\d{2})(\\d{2})(\\d{3})","$1 $2 $3","88",,],["(\\d{2})(\\d{5})","$1 $2","[1-6]",,]]]',
 "220": '["GM","00",,,,,"\\d{7}","[2-9]\\d{6}",[["(\\d{3})(\\d{4})","$1 $2",,,]]]',
-"687": '["NC","00",,,,,"\\d{6}","[2-47-9]\\d{5}",[["(\\d{2})(\\d{2})(\\d{2})","$1.$2.$3",,,]]]',
+"687": '["NC","00",,,,,"\\d{6}","[2-57-9]\\d{5}",[["(\\d{2})(\\d{2})(\\d{2})","$1.$2.$3","[2-46-9]|5[0-4]",,]]]',
 "995": '["GE","00","0",,,,"\\d{6,9}","[34578]\\d{8}",[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","[348]","$NP$FG",],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3","7","$NP$FG",],["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","5","$FG",]]]',
 "961": '["LB","00","0",,,,"\\d{7,8}","[13-9]\\d{6,7}",[["(\\d)(\\d{3})(\\d{3})","$1 $2 $3","[13-6]|7(?:[2-579]|62|8[0-7])|[89][2-9]","$NP$FG",],["([7-9]\\d)(\\d{3})(\\d{3})","$1 $2 $3","[89][01]|7(?:[01]|6[013-9]|8[89]|91)",,]]]',
 "40": '["RO","00","0",,,"$NP$FG","\\d{6,9}","2\\d{5,8}|[37-9]\\d{8}",[["([237]\\d)(\\d{3})(\\d{4})","$1 $2 $3","[23]1",,],["(21)(\\d{4})","$1 $2","21",,],["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3","[23][3-7]|[7-9]",,],["(2\\d{2})(\\d{3})","$1 $2","2[3-6]",,]]]',
 "232": '["SL","00","0",,,"($NP$FG)","\\d{6,8}","[2-578]\\d{7}",[["(\\d{2})(\\d{6})","$1 $2",,,]]]',
 "594": '["GF","00","0",,,"$NP$FG","\\d{9}","[56]\\d{8}",[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "976": '["MN","001","0",,,"$NP$FG","\\d{6,10}","[12]\\d{7,9}|[57-9]\\d{7}",[["([12]\\d)(\\d{2})(\\d{4})","$1 $2 $3","[12]1",,],["([12]2\\d)(\\d{5,6})","$1 $2","[12]2[1-3]",,],["([12]\\d{3})(\\d{5})","$1 $2","[12](?:27|[3-5])",,],["(\\d{4})(\\d{4})","$1 $2","[57-9]","$FG",],["([12]\\d{4})(\\d{4,5})","$1 $2","[12](?:27|[3-5])",,]]]',
 "20": '["EG","00","0",,,"$NP$FG","\\d{5,10}","1\\d{4,9}|[2456]\\d{8}|3\\d{7}|[89]\\d{8,9}",[["(\\d)(\\d{7,8})","$1 $2","[23]",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","1[012]|[89]00",,],["(\\d{2})(\\d{6,7})","$1 $2","1(?:3|5[23])|[4-6]|[89][2-9]",,]]]',
 "689": '["PF","00",,,,,"\\d{6}(?:\\d{2})?","[2-79]\\d{5}|8\\d{5,7}",[["(\\d{2})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4","89",,],["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3",,,]]]',
-"56": '["CL","(?:0|1(?:1[0-69]|2[0-57]|5[13-58]|69|7[0167]|8[018]))0","0","0|(1(?:1[0-69]|2[0-57]|5[13-58]|69|7[0167]|8[018]))",,"$NP$FG","\\d{6,11}","(?:[2-9]|600|123)\\d{7,8}",[["(2)(\\d{3,4})(\\d{4})","$1 $2 $3","2","($FG)",],["(\\d{2})(\\d{2,3})(\\d{4})","$1 $2 $3","[357]|4[1-35]|6[13-57]","($FG)",],["(9)([5-9]\\d{3})(\\d{4})","$1 $2 $3","9",,],["(44)(\\d{3})(\\d{4})","$1 $2 $3","44",,],["([68]00)(\\d{3})(\\d{3,4})","$1 $2 $3","60|8","$FG",],["(600)(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3 $4","60","$FG",],["(1230)(\\d{3})(\\d{4})","$1 $2 $3","1","$FG",]]]',
+"56": '["CL","(?:0|1(?:1[0-69]|2[0-57]|5[13-58]|69|7[0167]|8[018]))0","0","0|(1(?:1[0-69]|2[0-57]|5[13-58]|69|7[0167]|8[018]))",,"$NP$FG","\\d{6,11}","(?:[2-9]|600|123)\\d{7,8}",[["(2)(\\d{3,4})(\\d{4})","$1 $2 $3","2","($FG)",],["(\\d{2})(\\d{2,3})(\\d{4})","$1 $2 $3","[357]|4[1-35]|6[13-57]","($FG)",],["(9)([5-9]\\d{3})(\\d{4})","$1 $2 $3","9",,],["(44)(\\d{3})(\\d{4})","$1 $2 $3","44",,],["([68]00)(\\d{3})(\\d{3,4})","$1 $2 $3","60|8","$FG",],["(600)(\\d{3})(\\d{2})(\\d{3})","$1 $2 $3 $4","60","$FG",],["(1230)(\\d{3})(\\d{4})","$1 $2 $3","1","$FG",],["(\\d{4,5})","$1","[1-9]","$FG","NA"]]]',
 "596": '["MQ","00","0",,,"$NP$FG","\\d{9}","[56]\\d{8}",[["(\\d{3})(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3 $4",,,]]]',
 "508": '["PM","00","0",,,"$NP$FG","\\d{6}","[45]\\d{5}",[["([45]\\d)(\\d{2})(\\d{2})","$1 $2 $3",,,]]]',
 "269": '["KM","00",,,,,"\\d{7}","[379]\\d{6}",[["(\\d{3})(\\d{2})(\\d{2})","$1 $2 $3",,,]]]',
-"358": ['["FI","00|99[049]","0",,,"$NP$FG","\\d{5,12}","1\\d{4,11}|[2-9]\\d{4,10}",[["(\\d{3})(\\d{3,7})","$1 $2","(?:[1-3]00|[6-8]0)",,],["(\\d{2})(\\d{4,10})","$1 $2","2[09]|[14]|50|7[135]",,],["(\\d)(\\d{4,11})","$1 $2","[25689][1-8]|3",,]]]','["AX","00|99[049]","0",,,"$NP$FG","\\d{5,12}","[135]\\d{5,9}|[27]\\d{4,9}|4\\d{5,10}|6\\d{7,8}|8\\d{6,9}",]'],
+"358": ['["FI","00|99[049]","0",,,"$NP$FG","\\d{5,12}","1\\d{4,11}|[2-9]\\d{4,10}",[["(\\d{3})(\\d{3,7})","$1 $2","(?:[1-3]00|[6-8]0)",,],["(\\d{2})(\\d{4,10})","$1 $2","[14]|2[09]|50|7[135]",,],["(\\d)(\\d{4,11})","$1 $2","[25689][1-8]|3",,]]]','["AX","00|99[049]","0",,,"$NP$FG","\\d{5,12}","[135]\\d{5,9}|[27]\\d{4,9}|4\\d{5,10}|6\\d{7,8}|8\\d{6,9}",]'],
 "251": '["ET","00","0",,,"$NP$FG","\\d{7,9}","[1-59]\\d{8}",[["([1-59]\\d)(\\d{3})(\\d{4})","$1 $2 $3",,,]]]',
 "681": '["WF","00",,,,,"\\d{6}","[5-7]\\d{5}",[["(\\d{2})(\\d{2})(\\d{2})","$1 $2 $3",,,]]]',
 "853": '["MO","00",,,,,"\\d{8}","[268]\\d{7}",[["([268]\\d{3})(\\d{4})","$1 $2",,,]]]',
 "44": ['["GB","00","0",,,"$NP$FG","\\d{4,10}","\\d{7,10}",[["(\\d{2})(\\d{4})(\\d{4})","$1 $2 $3","2|5[56]|7(?:0|6[013-9])",,],["(\\d{3})(\\d{3})(\\d{4})","$1 $2 $3","1(?:1|\\d1)|3|9[018]",,],["(\\d{5})(\\d{4,5})","$1 $2","1(?:38|5[23]|69|76|94)",,],["(1\\d{3})(\\d{5,6})","$1 $2","1",,],["(7\\d{3})(\\d{6})","$1 $2","7(?:[1-5789]|62)",,],["(800)(\\d{4})","$1 $2","800",,],["(845)(46)(4\\d)","$1 $2 $3","845",,],["(8\\d{2})(\\d{3})(\\d{4})","$1 $2 $3","8(?:4[2-5]|7[0-3])",,],["(80\\d)(\\d{3})(\\d{4})","$1 $2 $3","80",,],["([58]00)(\\d{6})","$1 $2","[58]00",,]]]','["GG","00","0",,,"$NP$FG","\\d{6,10}","[135789]\\d{6,9}",]','["IM","00","0",,,"$NP$FG","\\d{6,10}","[135789]\\d{6,9}",]','["JE","00","0",,,"$NP$FG","\\d{6,10}","[135789]\\d{6,9}",]'],
 "244": '["AO","00",,,,,"\\d{9}","[29]\\d{8}",[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",,,]]]',
 "211": '["SS","00","0",,,,"\\d{9}","[19]\\d{8}",[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3",,"$NP$FG",]]]',
 "373": '["MD","00","0",,,"$NP$FG","\\d{8}","[235-9]\\d{7}",[["(\\d{2})(\\d{3})(\\d{3})","$1 $2 $3","22|3",,],["([25-7]\\d{2})(\\d{2})(\\d{3})","$1 $2 $3","2[13-79]|[5-7]",,],["([89]\\d{2})(\\d{5})","$1 $2","[89]",,]]]',
 "996": '["KG","00","0",,,"$NP$FG","\\d{5,10}","[35-8]\\d{8,9}",[["(\\d{3})(\\d{3})(\\d{3})","$1 $2 $3","31[25]|[5-7]",,],["(\\d{4})(\\d{5})","$1 $2","3(?:1[36]|[2-9])",,],["(\\d{3})(\\d{3})(\\d)(\\d{3})","$1 $2 $3 $4","8",,]]]',
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -1429,18 +1429,18 @@ this.PushService = {
       return;
     }
 
     if (!prefs.get("udp.wakeupEnabled")) {
       debug("UDP support disabled");
       return;
     }
 
-    this._udpServer = Cc["@mozilla.org/network/socket-udp;1"]
-                        .createInstance(Ci.nsIUDPServerSocket);
+    this._udpServer = Cc["@mozilla.org/network/udp-socket;1"]
+                        .createInstance(Ci.nsIUDPSocket);
     this._udpServer.init(-1, false);
     this._udpServer.asyncListen(this);
     debug("listenForUDPWakeup listening on " + this._udpPort);
 
     return this._udpServer.port;
   },
 
   /**
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/Nfc.js
@@ -0,0 +1,486 @@
+/* Copyright 2012 Mozilla Foundation and Mozilla contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Copyright © 2013, Deutsche Telekom, Inc. */
+
+"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");
+
+let NFC = {};
+Cu.import("resource://gre/modules/nfc_consts.js", NFC);
+
+// set to true in nfc_consts.js to see debug messages
+let DEBUG = NFC.DEBUG_NFC;
+
+let debug;
+if (DEBUG) {
+  debug = function (s) {
+    dump("-*- Nfc: " + s + "\n");
+  };
+} else {
+  debug = function (s) {};
+}
+
+const NFC_CONTRACTID = "@mozilla.org/nfc;1";
+const NFC_CID =
+  Components.ID("{2ff24790-5e74-11e1-b86c-0800200c9a66}");
+
+const NFC_IPC_MSG_NAMES = [
+  "NFC:SetSessionToken",
+  "NFC:ReadNDEF",
+  "NFC:WriteNDEF",
+  "NFC:GetDetailsNDEF",
+  "NFC:MakeReadOnlyNDEF",
+  "NFC:Connect",
+  "NFC:Close"
+];
+
+XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
+                                   "@mozilla.org/parentprocessmessagemanager;1",
+                                   "nsIMessageBroadcaster");
+XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
+                                   "@mozilla.org/system-message-internal;1",
+                                   "nsISystemMessagesInternal");
+XPCOMUtils.defineLazyServiceGetter(this, "gSystemWorkerManager",
+                                   "@mozilla.org/telephony/system-worker-manager;1",
+                                   "nsISystemWorkerManager");
+XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
+                                   "@mozilla.org/settingsService;1",
+                                   "nsISettingsService");
+XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator",
+                                    "@mozilla.org/uuid-generator;1",
+                                    "nsIUUIDGenerator");
+XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
+  return {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIMessageListener,
+                                           Ci.nsIObserver]),
+
+    nfc: null,
+
+    // Manage message targets in terms of sessionToken. Only the authorized and
+    // registered contents can receive related messages.
+    targetsBySessionTokens: {},
+    sessionTokens: [],
+
+    init: function init(nfc) {
+      this.nfc = nfc;
+
+      Services.obs.addObserver(this, "xpcom-shutdown", false);
+      this._registerMessageListeners();
+    },
+
+    _shutdown: function _shutdown() {
+      this.nfc = null;
+
+      Services.obs.removeObserver(this, "xpcom-shutdown");
+      this._unregisterMessageListeners();
+    },
+
+    _registerMessageListeners: function _registerMessageListeners() {
+      ppmm.addMessageListener("child-process-shutdown", this);
+      for (let msgname of NFC_IPC_MSG_NAMES) {
+        ppmm.addMessageListener(msgname, this);
+      }
+    },
+
+    _unregisterMessageListeners: function _unregisterMessageListeners() {
+      ppmm.removeMessageListener("child-process-shutdown", this);
+      for (let msgname of NFC_IPC_MSG_NAMES) {
+        ppmm.removeMessageListener(msgname, this);
+      }
+      ppmm = null;
+    },
+
+    _registerMessageTarget: function _registerMessageTarget(sessionToken, target) {
+      let targets = this.targetsBySessionTokens[sessionToken];
+      if (!targets) {
+        targets = this.targetsBySessionTokens[sessionToken] = [];
+        let list = this.sessionTokens;
+        if (list.indexOf(sessionToken) == -1) {
+          list.push(sessionToken);
+        }
+      }
+
+      if (targets.indexOf(target) != -1) {
+        debug("Already registered this target!");
+        return;
+      }
+
+      targets.push(target);
+      debug("Registered :" + sessionToken + " target: " + target);
+    },
+
+    _unregisterMessageTarget: function _unregisterMessageTarget(sessionToken, target) {
+      if (sessionToken == null) {
+        // Unregister the target for every sessionToken when no sessionToken is specified.
+        for (let session of this.sessionTokens) {
+          this._unregisterMessageTarget(session, target);
+        }
+        return;
+      }
+
+      // Unregister the target for a specified sessionToken.
+      let targets = this.targetsBySessionTokens[sessionToken];
+      if (!targets) {
+        return;
+      }
+
+      if (target == null) {
+        debug("Unregistered all targets for the " + sessionToken + " targets: " + targets);
+        targets = [];
+        let list = this.sessionTokens;
+        if (sessionToken !== null) {
+          let index = list.indexOf(sessionToken);
+          if (index > -1) {
+            list.splice(index, 1);
+          }
+        }
+        return;
+      }
+
+      let index = targets.indexOf(target);
+      if (index != -1) {
+        targets.splice(index, 1);
+      }
+    },
+
+    _sendTargetMessage: function _sendTargetMessage(sessionToken, message, options) {
+      let targets = this.targetsBySessionTokens[sessionToken];
+      if (!targets) {
+        return;
+      }
+
+      for (let target of targets) {
+        target.sendAsyncMessage(message, options);
+      }
+    },
+
+    /**
+     * nsIMessageListener interface methods.
+     */
+
+    receiveMessage: function receiveMessage(msg) {
+      debug("Received '" + msg.name + "' message from content process");
+      if (msg.name == "child-process-shutdown") {
+        // By the time we receive child-process-shutdown, the child process has
+        // already forgotten its permissions so we need to unregister the target
+        // for every permission.
+        this._unregisterMessageTarget(null, msg.target);
+        return null;
+      }
+
+      if (NFC_IPC_MSG_NAMES.indexOf(msg.name) != -1) {
+        if (!msg.target.assertPermission("nfc-read")) {
+          debug("Nfc message " + msg.name +
+                " from a content process with no 'nfc-read' privileges.");
+          return null;
+        }
+      } else {
+        debug("Ignoring unknown message type: " + msg.name);
+        return null;
+      }
+
+      switch (msg.name) {
+        case "NFC:SetSessionToken":
+          this._registerMessageTarget(this.nfc.sessionTokenMap[this.nfc._currentSessionId], msg.target);
+          debug("Registering target for this SessionToken : " +
+                this.nfc.sessionTokenMap[this.nfc._currentSessionId]);
+          return null;
+      }
+
+      return null;
+    },
+
+    /**
+     * nsIObserver interface methods.
+     */
+
+    observe: function observe(subject, topic, data) {
+      switch (topic) {
+        case "xpcom-shutdown":
+          this._shutdown();
+          break;
+      }
+    },
+
+    sendNfcResponseMessage: function sendNfcResponseMessage(message, data) {
+      this._sendTargetMessage(this.nfc.sessionTokenMap[this.nfc._currentSessionId], message, data);
+    },
+  };
+});
+
+function Nfc() {
+  debug("Starting Worker");
+  this.worker = new ChromeWorker("resource://gre/modules/nfc_worker.js");
+  this.worker.onerror = this.onerror.bind(this);
+  this.worker.onmessage = this.onmessage.bind(this);
+
+  for each (let msgname in NFC_IPC_MSG_NAMES) {
+    ppmm.addMessageListener(msgname, this);
+  }
+
+  Services.obs.addObserver(this, NFC.TOPIC_MOZSETTINGS_CHANGED, false);
+  Services.obs.addObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN, false);
+
+  gMessageManager.init(this);
+  let lock = gSettingsService.createLock();
+  lock.get(NFC.SETTING_NFC_POWER_LEVEL, this);
+  lock.get(NFC.SETTING_NFC_ENABLED, this);
+  // Maps sessionId (that are generated from nfcd) with a unique guid : 'SessionToken'
+  this.sessionTokenMap = {};
+
+  gSystemWorkerManager.registerNfcWorker(this.worker);
+}
+
+Nfc.prototype = {
+
+  classID:   NFC_CID,
+  classInfo: XPCOMUtils.generateCI({classID: NFC_CID,
+                                    classDescription: "Nfc",
+                                    interfaces: [Ci.nsIWorkerHolder]}),
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsIWorkerHolder,
+                                         Ci.nsIObserver,
+                                         Ci.nsISettingsServiceCallback]),
+
+  _currentSessionId: null,
+  _enabled: false,
+
+  onerror: function onerror(event) {
+    debug("Got an error: " + event.filename + ":" +
+          event.lineno + ": " + event.message + "\n");
+    event.preventDefault();
+  },
+
+  /**
+   * Send arbitrary message to worker.
+   *
+   * @param nfcMessageType
+   *        A text message type.
+   * @param message [optional]
+   *        An optional message object to send.
+   */
+  sendToWorker: function sendToWorker(nfcMessageType, message) {
+    message = message || {};
+    message.type = nfcMessageType;
+    this.worker.postMessage(message);
+  },
+
+  /**
+   * Send Error response to content.
+   *
+   * @param message
+   *        An nsIMessageListener's message parameter.
+   */
+  sendNfcErrorResponse: function sendNfcErrorResponse(message) {
+    if (!message.target) {
+      return;
+    }
+
+    let nfcMsgType = message.name + "Response";
+    message.target.sendAsyncMessage(nfcMsgType, {
+      sessionId: message.json.sessionToken,
+      requestId: message.json.requestId,
+      status: NFC.GECKO_NFC_ERROR_GENERIC_FAILURE
+    });
+  },
+
+  /**
+   * Process the incoming message from the NFC worker
+   */
+  onmessage: function onmessage(event) {
+    let message = event.data;
+    debug("Received message from NFC worker: " + JSON.stringify(message));
+
+    switch (message.type) {
+      case "techDiscovered":
+        this._currentSessionId = message.sessionId;
+        // Check if the session token already exists. If exists, continue to use the same one.
+        // If not, generate a new token.
+        if (!this.sessionTokenMap[this._currentSessionId]) {
+          this.sessionTokenMap[this._currentSessionId] = UUIDGenerator.generateUUID().toString();
+        }
+        // Update the upper layers with a session token (alias)
+        message.sessionToken = this.sessionTokenMap[this._currentSessionId];
+        // Do not expose the actual session to the content
+        delete message.sessionId;
+        gSystemMessenger.broadcastMessage("nfc-manager-tech-discovered", message);
+        break;
+      case "techLost":
+        gMessageManager._unregisterMessageTarget(this.sessionTokenMap[this._currentSessionId], null);
+        // Update the upper layers with a session token (alias)
+        message.sessionToken = this.sessionTokenMap[this._currentSessionId];
+        // Do not expose the actual session to the content
+        delete message.sessionId;
+        gSystemMessenger.broadcastMessage("nfc-manager-tech-lost", message);
+        delete this.sessionTokenMap[this._currentSessionId];
+        this._currentSessionId = null;
+        break;
+     case "ConfigResponse":
+        gSystemMessenger.broadcastMessage("nfc-powerlevel-change", message);
+        break;
+      case "ConnectResponse": // Fall through.
+      case "CloseResponse":
+      case "GetDetailsNDEFResponse":
+      case "ReadNDEFResponse":
+      case "MakeReadOnlyNDEFResponse":
+      case "WriteNDEFResponse":
+        message.sessionToken = this.sessionTokenMap[this._currentSessionId];
+        // Do not expose the actual session to the content
+        delete message.sessionId;
+        gMessageManager.sendNfcResponseMessage("NFC:" + message.type, message);
+        break;
+      default:
+        throw new Error("Don't know about this message type: " + message.type);
+    }
+  },
+
+  // nsINfcWorker
+  worker: null,
+
+  powerLevel: NFC.NFC_POWER_LEVEL_DISABLED,
+
+  sessionTokenMap: null,
+
+  /**
+   * Process a message from the content process.
+   */
+  receiveMessage: function receiveMessage(message) {
+    debug("Received '" + JSON.stringify(message) + "' message from content process");
+
+    if (!this._enabled) {
+      debug("NFC is not enabled.");
+      this.sendNfcErrorResponse(message);
+      return null;
+    }
+
+    // Enforce bare minimums for NFC permissions
+    switch (message.name) {
+      case "NFC:Connect": // Fall through
+      case "NFC:Close":
+      case "NFC:GetDetailsNDEF":
+      case "NFC:ReadNDEF":
+        if (!message.target.assertPermission("nfc-read")) {
+          debug("NFC message " + message.name +
+                " from a content process with no 'nfc-read' privileges.");
+          this.sendNfcErrorResponse(message);
+          return null;
+        }
+        break;
+      case "NFC:WriteNDEF": // Fall through
+      case "NFC:MakeReadOnlyNDEF":
+        if (!message.target.assertPermission("nfc-write")) {
+          debug("NFC message " + message.name +
+                " from a content process with no 'nfc-write' privileges.");
+          this.sendNfcErrorResponse(message);
+          return null;
+        }
+        break;
+      case "NFC:SetSessionToken":
+        //Do nothing here. No need to process this message further
+        return null;
+    }
+
+    // Sanity check on sessionId
+    if (message.json.sessionToken !== this.sessionTokenMap[this._currentSessionId]) {
+      debug("Invalid Session Token: " + message.json.sessionToken +
+            " Expected Session Token: " + this.sessionTokenMap[this._currentSessionId]);
+      this.sendNfcErrorResponse(message);
+      return null;
+    }
+
+    // Update the current sessionId before sending to the worker
+    message.sessionId = this._currentSessionId;
+
+    switch (message.name) {
+      case "NFC:GetDetailsNDEF":
+        this.sendToWorker("getDetailsNDEF", message.json);
+        break;
+      case "NFC:ReadNDEF":
+        this.sendToWorker("readNDEF", message.json);
+        break;
+      case "NFC:WriteNDEF":
+        this.sendToWorker("writeNDEF", message.json);
+        break;
+      case "NFC:MakeReadOnlyNDEF":
+        this.sendToWorker("makeReadOnlyNDEF", message.json);
+        break;
+      case "NFC:Connect":
+        this.sendToWorker("connect", message.json);
+        break;
+      case "NFC:Close":
+        this.sendToWorker("close", message.json);
+        break;
+      default:
+        debug("UnSupported : Message Name " + message.name);
+        return null;
+    }
+  },
+
+  /**
+   * nsISettingsServiceCallback
+   */
+
+  handle: function handle(aName, aResult) {
+    switch(aName) {
+      case NFC.SETTING_NFC_ENABLED:
+        debug("'nfc.enabled' is now " + aResult);
+        this._enabled = aResult;
+        // General power setting
+        let powerLevel = this._enabled ? NFC.NFC_POWER_LEVEL_ENABLED :
+                                         NFC.NFC_POWER_LEVEL_DISABLED;
+        // Only if the value changes, set the power config and persist
+        if (powerLevel !== this.powerLevel) {
+          debug("New Power Level " + powerLevel);
+          this.setConfig({powerLevel: powerLevel});
+          this.powerLevel = powerLevel;
+        }
+        break;
+    }
+  },
+
+  /**
+   * nsIObserver
+   */
+
+  observe: function observe(subject, topic, data) {
+    switch (topic) {
+      case NFC.TOPIC_XPCOM_SHUTDOWN:
+        for each (let msgname in NFC_IPC_MSG_NAMES) {
+          ppmm.removeMessageListener(msgname, this);
+        }
+        ppmm = null;
+        Services.obs.removeObserver(this, NFC.TOPIC_XPCOM_SHUTDOWN);
+        break;
+      case NFC.TOPIC_MOZSETTINGS_CHANGED:
+        let setting = JSON.parse(data);
+        if (setting) {
+          let setting = JSON.parse(data);
+          this.handle(setting.key, setting.value);
+        }
+        break;
+    }
+  },
+
+  setConfig: function setConfig(prop) {
+    this.sendToWorker("config", prop);
+  }
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Nfc]);
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/Nfc.manifest
@@ -0,0 +1,15 @@
+# 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/.
+#
+# Copyright © 2013 Deutsche Telekom, Inc.
+
+# Nfc.js
+component {2ff24790-5e74-11e1-b86c-0800200c9a66} Nfc.js
+contract @mozilla.org/nfc;1 {2ff24790-5e74-11e1-b86c-0800200c9a66}
+category profile-after-change Nfc @mozilla.org/nfc;1
+
+# NfcContentHelper.js
+component {4d72c120-da5f-11e1-9b23-0800200c9a66} NfcContentHelper.js
+contract @mozilla.org/nfc/content-helper;1 {4d72c120-da5f-11e1-9b23-0800200c9a66}
+category profile-after-change NfcContentHelper @mozilla.org/nfc/content-helper;1
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/NfcContentHelper.js
@@ -0,0 +1,314 @@
+/* Copyright 2012 Mozilla Foundation and Mozilla contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Copyright © 2013, Deutsche Telekom, Inc. */
+
+"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/DOMRequestHelper.jsm");
+
+let NFC = {};
+Cu.import("resource://gre/modules/nfc_consts.js", NFC);
+
+// set to true to in nfc_consts.js to see debug messages
+let DEBUG = NFC.DEBUG_CONTENT_HELPER;
+
+let debug;
+if (DEBUG) {
+  debug = function (s) {
+    dump("-*- NfcContentHelper: " + s + "\n");
+  };
+} else {
+  debug = function (s) {};
+}
+
+const NFCCONTENTHELPER_CID =
+  Components.ID("{4d72c120-da5f-11e1-9b23-0800200c9a66}");
+
+const NFC_IPC_MSG_NAMES = [
+  "NFC:ReadNDEFResponse",
+  "NFC:WriteNDEFResponse",
+  "NFC:GetDetailsNDEFResponse",
+  "NFC:MakeReadOnlyNDEFResponse",
+  "NFC:ConnectResponse",
+  "NFC:CloseResponse"
+];
+
+XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
+                                   "@mozilla.org/childprocessmessagemanager;1",
+                                   "nsISyncMessageSender");
+
+function NfcContentHelper() {
+  this.initDOMRequestHelper(/* aWindow */ null, NFC_IPC_MSG_NAMES);
+  Services.obs.addObserver(this, "xpcom-shutdown", false);
+
+  this._requestMap = [];
+}
+
+NfcContentHelper.prototype = {
+  __proto__: DOMRequestIpcHelper.prototype,
+
+  QueryInterface: XPCOMUtils.generateQI([Ci.nsINfcContentHelper,
+                                         Ci.nsISupportsWeakReference,
+                                         Ci.nsIObserver]),
+  classID:   NFCCONTENTHELPER_CID,
+  classInfo: XPCOMUtils.generateCI({
+    classID:          NFCCONTENTHELPER_CID,
+    classDescription: "NfcContentHelper",
+    interfaces:       [Ci.nsINfcContentHelper]
+  }),
+
+  _requestMap: null,
+
+  /* TODO: Bug 815526: This is a limitation when a DOMString is used in sequences of Moz DOM Objects.
+   *       Strings such as 'type', 'id' 'payload' will not be acccessible to NfcWorker.
+   *       Therefore this function exists till the bug is addressed.
+   */
+  encodeNdefRecords: function encodeNdefRecords(records) {
+    let encodedRecords = [];
+    for (let i = 0; i < records.length; i++) {
+      let record = records[i];
+      encodedRecords.push({
+        tnf: record.tnf,
+        type: record.type,
+        id: record.id,
+        payload: record.payload,
+      });
+    }
+    return encodedRecords;
+  },
+
+  // NFC interface:
+  setSessionToken: function setSessionToken(sessionToken) {
+    if (sessionToken == null) {
+      throw Components.Exception("No session token!",
+                                  Cr.NS_ERROR_UNEXPECTED);
+      return;
+    }
+    // Report session to Nfc.js only.
+    cpmm.sendAsyncMessage("NFC:SetSessionToken", {
+      sessionToken: sessionToken,
+    });
+  },
+
+  // NFCTag interface
+  getDetailsNDEF: function getDetailsNDEF(window, sessionToken) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = btoa(this.getRequestId(request));
+    this._requestMap[requestId] = window;
+
+    cpmm.sendAsyncMessage("NFC:GetDetailsNDEF", {
+      requestId: requestId,
+      sessionToken: sessionToken
+    });
+    return request;
+  },
+
+  readNDEF: function readNDEF(window, sessionToken) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = btoa(this.getRequestId(request));
+    this._requestMap[requestId] = window;
+
+    cpmm.sendAsyncMessage("NFC:ReadNDEF", {
+      requestId: requestId,
+      sessionToken: sessionToken
+    });
+    return request;
+  },
+
+  writeNDEF: function writeNDEF(window, records, sessionToken) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = btoa(this.getRequestId(request));
+    this._requestMap[requestId] = window;
+
+    let encodedRecords = this.encodeNdefRecords(records);
+
+    cpmm.sendAsyncMessage("NFC:WriteNDEF", {
+      requestId: requestId,
+      sessionToken: sessionToken,
+      records: encodedRecords
+    });
+    return request;
+  },
+
+  makeReadOnlyNDEF: function makeReadOnlyNDEF(window, sessionToken) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = btoa(this.getRequestId(request));
+    this._requestMap[requestId] = window;
+
+    cpmm.sendAsyncMessage("NFC:MakeReadOnlyNDEF", {
+      requestId: requestId,
+      sessionToken: sessionToken
+    });
+    return request;
+  },
+
+  connect: function connect(window, techType, sessionToken) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = btoa(this.getRequestId(request));
+    this._requestMap[requestId] = window;
+
+    cpmm.sendAsyncMessage("NFC:Connect", {
+      requestId: requestId,
+      sessionToken: sessionToken,
+      techType: techType
+    });
+    return request;
+  },
+
+  close: function close(window, sessionToken) {
+    if (window == null) {
+      throw Components.Exception("Can't get window object",
+                                  Cr.NS_ERROR_UNEXPECTED);
+    }
+    let request = Services.DOMRequest.createRequest(window);
+    let requestId = btoa(this.getRequestId(request));
+    this._requestMap[requestId] = window;
+
+    cpmm.sendAsyncMessage("NFC:Close", {
+      requestId: requestId,
+      sessionToken: sessionToken
+    });
+    return request;
+  },
+
+  // nsIObserver
+
+  observe: function observe(subject, topic, data) {
+    if (topic == "xpcom-shutdown") {
+      this.removeMessageListener();
+      Services.obs.removeObserver(this, "xpcom-shutdown");
+      cpmm = null;
+    }
+  },
+
+  // nsIMessageListener
+
+  fireRequestSuccess: function fireRequestSuccess(requestId, result) {
+    let request = this.takeRequest(requestId);
+    if (!request) {
+      debug("not firing success for id: " + requestId +
+            ", result: " + JSON.stringify(result));
+      return;
+    }
+
+    debug("fire request success, id: " + requestId +
+          ", result: " + JSON.stringify(result));
+    Services.DOMRequest.fireSuccess(request, result);
+  },
+
+  fireRequestError: function fireRequestError(requestId, error) {
+    let request = this.takeRequest(requestId);
+    if (!request) {
+      debug("not firing error for id: " + requestId +
+            ", error: " + JSON.stringify(error));
+      return;
+    }
+
+    debug("fire request error, id: " + requestId +
+          ", result: " + JSON.stringify(error));
+    Services.DOMRequest.fireError(request, error);
+  },
+
+  receiveMessage: function receiveMessage(message) {
+    debug("Message received: " + JSON.stringify(message));
+    switch (message.name) {
+      case "NFC:ReadNDEFResponse":
+        this.handleReadNDEFResponse(message.json);
+        break;
+      case "NFC:ConnectResponse": // Fall through.
+      case "NFC:CloseResponse":
+      case "NFC:WriteNDEFResponse":
+      case "NFC:MakeReadOnlyNDEFResponse":
+      case "NFC:GetDetailsNDEFResponse":
+        this.handleResponse(message.json);
+        break;
+    }
+  },
+
+  handleReadNDEFResponse: function handleReadNDEFResponse(message) {
+    debug("ReadNDEFResponse(" + JSON.stringify(message) + ")");
+    let requester = this._requestMap[message.requestId];
+    if (!requester) {
+       debug("ReadNDEFResponse Invalid requester=" + requester +
+             " message.sessionToken=" + message.sessionToken);
+       return; // Nothing to do in this instance.
+    }
+    delete this._requestMap[message.requestId];
+    let records = message.records;
+    let requestId = atob(message.requestId);
+
+    if (message.status !== NFC.GECKO_NFC_ERROR_SUCCESS) {
+      this.fireRequestError(requestId, message.status);
+    } else {
+      let ndefMsg = [];
+      for (let i = 0; i < records.length; i++) {
+        let record = records[i];
+        ndefMsg.push(new requester.MozNdefRecord(record.tnf,
+                                                 record.type,
+                                                 record.id,
+                                                 record.payload));
+      }
+      this.fireRequestSuccess(requestId, ndefMsg);
+    }
+  },
+
+  handleResponse: function handleResponse(message) {
+    debug("Response(" + JSON.stringify(message) + ")");
+    let requester = this._requestMap[message.requestId];
+    if (!requester) {
+       debug("Response Invalid requester=" + requester +
+             " message.sessionToken=" + message.sessionToken);
+       return; // Nothing to do in this instance.
+    }
+    delete this._requestMap[message.requestId];
+    let result = message;
+    let requestId = atob(message.requestId);
+
+    if (message.status !== NFC.GECKO_NFC_ERROR_SUCCESS) {
+      this.fireRequestError(requestId, result.status);
+    } else {
+      this.fireRequestSuccess(requestId, result);
+    }
+  },
+};
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NfcContentHelper]);
--- a/dom/system/gonk/moz.build
+++ b/dom/system/gonk/moz.build
@@ -80,24 +80,39 @@ if CONFIG['MOZ_B2G_RIL']:
         'RadioInterfaceLayer.manifest',
         'RILContentHelper.js',
     ]
     EXTRA_JS_MODULES += [
         'ril_consts.js',
         'ril_worker.js',
     ]
 
+if CONFIG['MOZ_NFC']:
+    XPIDL_SOURCES += [
+        'nsINfcContentHelper.idl',
+    ]
+    EXTRA_COMPONENTS += [
+        'Nfc.js',
+        'Nfc.manifest',
+        'NfcContentHelper.js',
+    ]
+    EXTRA_JS_MODULES += [
+    'nfc_consts.js',
+    'nfc_worker.js',
+    ]
+
 FAIL_ON_WARNINGS = True
 
 LIBXUL_LIBRARY = True
 
 LIBRARY_NAME = 'domsystemgonk_s'
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/content/events/src',
     '/dom/base',
     '/dom/bluetooth',
+    '/dom/nfc',
     '/dom/src/geolocation',
     '/dom/wifi',
 ]
 
--- a/dom/system/gonk/net_worker.js
+++ b/dom/system/gonk/net_worker.js
@@ -550,26 +550,18 @@ function setDnsForwarders(params, callba
 
 function enableNat(params, callback) {
   let command = "nat enable " + params.internalIfname + " " +
                 params.externalIfname + " " + "0";
   return doCommand(command, callback);
 }
 
 function disableNat(params, callback) {
-  let command;
-
-  // Don't disable nat because others interface still need it.
-  // Send the dummy command to continue the function chain.
-  if ("interfaceList" in params && params.interfaceList.length > 1) {
-    command = DUMMY_COMMAND;
-  } else {
-    command = "nat disable " + params.internalIfname + " " +
-              params.externalIfname + " " + "0";
-  }
+  let command = "nat disable " + params.internalIfname + " " +
+                 params.externalIfname + " " + "0";
   return doCommand(command, callback);
 }
 
 function wifiFirmwareReload(params, callback) {
   let command = "softap fwreload " + params.ifname + " " + params.mode;
   return doCommand(command, callback);
 }
 
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/nfc_consts.js
@@ -0,0 +1,71 @@
+/* Copyright 2012 Mozilla Foundation and Mozilla contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Copyright © 2013, Deutsche Telekom, Inc. */
+
+// Set to true to debug all NFC layers
+this.DEBUG_ALL = false;
+
+// Set individually to debug specific layers
+this.DEBUG_WORKER = false || DEBUG_ALL;
+this.DEBUG_CONTENT_HELPER = false || DEBUG_ALL;
+this.DEBUG_NFC = false || DEBUG_ALL;
+
+// Current version
+this.NFC_MAJOR_VERSION = 1;
+this.NFC_MINOR_VERSION = 7;
+
+this.NFC_REQUEST_CONFIG = 0;
+this.NFC_REQUEST_CONNECT = 1;
+this.NFC_REQUEST_CLOSE = 2;
+this.NFC_REQUEST_GET_DETAILS = 3;
+this.NFC_REQUEST_READ_NDEF = 4;
+this.NFC_REQUEST_WRITE_NDEF = 5;
+this.NFC_REQUEST_MAKE_NDEF_READ_ONLY = 6;
+
+this.NFC_RESPONSE_GENERAL = 1000;
+this.NFC_RESPONSE_CONFIG = 1001;
+this.NFC_RESPONSE_READ_NDEF_DETAILS = 1002;
+this.NFC_RESPONSE_READ_NDEF = 1003;
+
+this.NFC_NOTIFICATION_INITIALIZED = 2000;
+this.NFC_NOTIFICATION_TECH_DISCOVERED = 2001;
+this.NFC_NOTIFICATION_TECH_LOST = 2002;
+
+this.NFC_TECHS = {
+  0:'NDEF',
+  1:'NDEF_WRITEABLE',
+  2:'NDEF_FORMATABLE',
+  3:'P2P',
+  4:'NFC_A'
+};
+
+// TODO: Bug 933595. Fill-in all error codes for Gonk/nfcd protocol
+this.GECKO_NFC_ERROR_SUCCESS             = 0;
+this.GECKO_NFC_ERROR_GENERIC_FAILURE     = 1;
+
+// NFC powerlevels must match config PDUs.
+this.NFC_POWER_LEVEL_UNKNOWN        = -1;
+this.NFC_POWER_LEVEL_DISABLED       = 0;
+this.NFC_POWER_LEVEL_LOW            = 1;
+this.NFC_POWER_LEVEL_ENABLED        = 2;
+
+this.TOPIC_MOZSETTINGS_CHANGED      = "mozsettings-changed";
+this.TOPIC_XPCOM_SHUTDOWN           = "xpcom-shutdown";
+this.SETTING_NFC_ENABLED            = "nfc.enabled";
+this.SETTING_NFC_POWER_LEVEL        = "nfc.powerlevel";
+
+// Allow this file to be imported via Components.utils.import().
+this.EXPORTED_SYMBOLS = Object.keys(this);
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/nfc_worker.js
@@ -0,0 +1,440 @@
+/* Copyright 2012 Mozilla Foundation and Mozilla contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Copyright © 2013, Deutsche Telekom, Inc. */
+
+"use strict";
+
+importScripts("systemlibs.js", "nfc_consts.js");
+importScripts("resource://gre/modules/workers/require.js");
+
+// set to true in nfc_consts.js to see debug messages
+let DEBUG = DEBUG_WORKER;
+
+function getPaddingLen(len) {
+  return (len % 4) ? (4 - len % 4) : 0;
+}
+
+let Buf = {
+  __proto__: (function(){
+    return require("resource://gre/modules/workers/worker_buf.js").Buf;
+  })(),
+
+  init: function init() {
+    this._init();
+  },
+
+  /**
+   * Process one parcel.
+   */
+  processParcel: function processParcel() {
+    let pduType = this.readInt32();
+    if (DEBUG) debug("Number of bytes available in Parcel : " + this.readAvailable);
+    NfcWorker.handleParcel(pduType, this.mCallback);
+  },
+
+  /**
+   * Start a new outgoing parcel.
+   *
+   * @param type
+   *        Integer specifying the request type.
+   * @param callback
+   */
+  newParcel: function newParcel(type, callback) {
+    if (DEBUG) debug("New outgoing parcel of type " + type);
+    this.mCallback = callback;
+    // We're going to leave room for the parcel size at the beginning.
+    this.outgoingIndex = this.PARCEL_SIZE_SIZE;
+    this.writeInt32(type);
+  },
+
+  simpleRequest: function simpleRequest(type) {
+    this.newParcel(type);
+    this.sendParcel();
+  },
+
+  onSendParcel: function onSendParcel(parcel) {
+    postNfcMessage(parcel);
+  },
+
+  /**
+   * TODO: Bug 933593. Callback map of NFC_RESPONSE_XXX and RequestID
+   *       needs to be maintained
+   */
+  mCallback: null,
+};
+
+/**
+ * Provide a high-level API representing NFC capabilities.
+ * Rensponsible for converting NFC requests from Content process to binary data
+ * and NFC Responses from binary data to dictionary objects.
+ */
+let NfcWorker = {
+  /**
+   * Handle incoming messages from the main UI thread.
+   *
+   * @param message
+   *        Object containing the message. Messages are supposed
+   */
+  handleDOMMessage: function handleMessage(message) {
+    if (DEBUG) debug("Received DOM message " + JSON.stringify(message));
+    let method = this[message.type];
+    if (typeof method != "function") {
+      if (DEBUG) {
+        debug("Don't know what to do with message " + JSON.stringify(message));
+      }
+      return;
+    }
+    method.call(this, message);
+  },
+
+  /**
+   * Unmarshals a NDEF message
+   */
+  unMarshallNdefMessage: function unMarshallNdefMessage() {
+    let numOfRecords = Buf.readInt32();
+    debug("numOfRecords = " + numOfRecords);
+    if (numOfRecords <= 0) {
+      return null;
+    }
+    let records = [];
+
+    for (let i = 0; i < numOfRecords; i++) {
+      let tnf        = Buf.readInt32();
+      let typeLength = Buf.readInt32();
+      let type = [];
+      for (let i = 0; i < typeLength; i++) {
+        type.push(Buf.readUint8());
+      }
+      let padding    = getPaddingLen(typeLength);
+      for (let i = 0; i < padding; i++) {
+        Buf.readUint8();
+      }
+
+      let idLength = Buf.readInt32();
+      let id = [];
+      for (let i = 0; i < idLength; i++) {
+        id.push(Buf.readUint8());
+      }
+      padding      = getPaddingLen(idLength);
+      for (let i = 0; i < padding; i++) {
+        Buf.readUint8();
+      }
+
+      let payloadLength = Buf.readInt32();
+      let payload = [];
+      for (let i = 0; i < payloadLength; i++) {
+        payload.push(Buf.readUint8());
+      }
+      padding = getPaddingLen(payloadLength);
+      for (let i = 0; i < padding; i++) {
+        Buf.readUint8();
+      }
+      records.push({tnf: tnf,
+                    type: type,
+                    id: id,
+                    payload: payload});
+    }
+    return records;
+  },
+
+  /**
+   * Read and return NDEF data, if present.
+   */
+  readNDEF: function readNDEF(message) {
+    let cb = function callback() {
+      let error        = Buf.readInt32();
+      let sessionId    = Buf.readInt32();
+      let records      = this.unMarshallNdefMessage();
+
+      message.type      = "ReadNDEFResponse";
+      message.sessionId = sessionId;
+      message.records   = records;
+      message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
+                                       GECKO_NFC_ERROR_GENERIC_FAILURE;
+      this.sendDOMMessage(message);
+    }
+
+    Buf.newParcel(NFC_REQUEST_READ_NDEF, cb);
+    Buf.writeInt32(message.sessionId);
+    Buf.sendParcel();
+  },
+
+  /**
+   * Write to a target that accepts NDEF formattable data
+   */
+  writeNDEF: function writeNDEF(message) {
+    let cb = function callback() {
+      let error         = Buf.readInt32();
+      let sessionId     = Buf.readInt32();
+
+      message.type      = "WriteNDEFResponse";
+      message.sessionId = sessionId;
+      message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
+                                       GECKO_NFC_ERROR_GENERIC_FAILURE;
+      this.sendDOMMessage(message);
+    };
+
+    Buf.newParcel(NFC_REQUEST_WRITE_NDEF, cb);
+    Buf.writeInt32(message.sessionId);
+    let records    = message.records;
+    let numRecords = records.length;
+    Buf.writeInt32(numRecords);
+    for (let i = 0; i < numRecords; i++) {
+      let record = records[i];
+      Buf.writeInt32(record.tnf);
+
+      let typeLength = record.type.length;
+      Buf.writeInt32(typeLength);
+      for (let j = 0; j < typeLength; j++) {
+        Buf.writeUint8(record.type.charCodeAt(j));
+      }
+      let padding = getPaddingLen(typeLength);
+      for (let i = 0; i < padding; i++) {
+        Buf.writeUint8(0x00);
+      }
+
+      let idLength = record.id.length;
+      Buf.writeInt32(idLength);
+      for (let j = 0; j < idLength; j++) {
+        Buf.writeUint8(record.id.charCodeAt(j));
+      }
+      padding = getPaddingLen(idLength);
+      for (let i = 0; i < padding; i++) {
+        Buf.writeUint8(0x00);
+      }
+
+      let payloadLength = record.payload && record.payload.length;
+      Buf.writeInt32(payloadLength);
+      for (let j = 0; j < payloadLength; j++) {
+        Buf.writeUint8(record.payload.charCodeAt(j));
+      }
+      padding = getPaddingLen(payloadLength);
+      for (let i = 0; i < padding; i++) {
+        Buf.writeUint8(0x00);
+      }
+    }
+
+    Buf.sendParcel();
+  },
+
+  /**
+   * Make the NFC NDEF tag permanently read only
+   */
+  makeReadOnlyNDEF: function makeReadOnlyNDEF(message) {
+    let cb = function callback() {
+      let error         = Buf.readInt32();
+      let sessionId     = Buf.readInt32();
+
+      message.type      = "MakeReadOnlyNDEFResponse";
+      message.sessionId = sessionId;
+      message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
+                                       GECKO_NFC_ERROR_GENERIC_FAILURE;
+      this.sendDOMMessage(message);
+    };
+
+    Buf.newParcel(NFC_REQUEST_MAKE_NDEF_READ_ONLY, cb);
+    Buf.writeInt32(message.sessionId);
+    Buf.sendParcel();
+  },
+
+  /**
+   * Retrieve metadata describing the NDEF formatted data, if present.
+   */
+  getDetailsNDEF: function getDetailsNDEF(message) {
+    let cb = function callback() {
+      let error                  = Buf.readInt32();
+      let sessionId              = Buf.readInt32();
+      let isReadOnly             = Buf.readUint8();
+      let canBeMadeReadOnly      = Buf.readUint8();
+      // Ensure that padding is taken care here after reading two successive uint8's
+      Buf.readUint8();
+      Buf.readUint8();
+      let maxSupportedLength     = Buf.readInt32();
+
+      message.type               = "GetDetailsNDEFResponse";
+      message.sessionId          = sessionId;
+      message.isReadOnly         = isReadOnly;
+      message.canBeMadeReadOnly  = canBeMadeReadOnly;
+      message.maxSupportedLength = maxSupportedLength;
+      message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
+                                       GECKO_NFC_ERROR_GENERIC_FAILURE;
+      this.sendDOMMessage(message);
+    };
+    Buf.newParcel(NFC_REQUEST_GET_DETAILS, cb);
+    Buf.writeInt32(message.sessionId);
+    Buf.sendParcel();
+  },
+
+
+  /**
+   * Open a connection to the NFC target.
+   */
+  connect: function connect(message) {
+    let cb = function callback() {
+      let error         = Buf.readInt32();
+      let sessionId     = Buf.readInt32();
+
+      message.type      = "ConnectResponse";
+      message.sessionId = sessionId;
+      message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
+                                       GECKO_NFC_ERROR_GENERIC_FAILURE;
+      this.sendDOMMessage(message);
+    };
+
+    Buf.newParcel(NFC_REQUEST_CONNECT, cb);
+    Buf.writeInt32(message.sessionId);
+    Buf.writeInt32(message.techType);
+    Buf.sendParcel();
+  },
+
+  /**
+   * NFC Configuration
+   */
+  config: function config(message) {
+    let cb = function callback() {
+      let error         = Buf.readInt32();
+
+      message.type      = "ConfigResponse";
+      message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
+                                       GECKO_NFC_ERROR_GENERIC_FAILURE;
+      this.sendDOMMessage(message);
+    };
+
+    Buf.newParcel(NFC_REQUEST_CONFIG , cb);
+    Buf.writeInt32(message.powerLevel);
+    Buf.sendParcel();
+  },
+
+  /**
+   * Close connection to the NFC target.
+   */
+  close: function close(message) {
+    let cb = function callback() {
+      let error         = Buf.readInt32();
+      let sessionId     = Buf.readInt32();
+
+      message.type      = "CloseResponse";
+      message.sessionId = sessionId;
+      message.status = (error === 0) ? GECKO_NFC_ERROR_SUCCESS :
+                                       GECKO_NFC_ERROR_GENERIC_FAILURE;
+      this.sendDOMMessage(message);
+    };
+
+    Buf.newParcel(NFC_REQUEST_CLOSE , cb);
+    Buf.writeInt32(message.sessionId);
+    Buf.sendParcel();
+  },
+
+  handleParcel: function handleParcel(request_type, callback) {
+    let method = this[request_type];
+    if (typeof method == "function") {
+      if (DEBUG) debug("Handling parcel as " + method.name);
+      method.call(this);
+    } else if (typeof callback == "function") {
+      callback.call(this, request_type);
+      this.mCallback = null;
+    } else {
+      debug("Unable to handle ReqType:"+request_type);
+    }
+  },
+
+  /**
+   * Send messages to the main UI thread.
+   */
+  sendDOMMessage: function sendDOMMessage(message) {
+    postMessage(message);
+  }
+};
+
+/**
+ * Notification Handlers
+ */
+NfcWorker[NFC_NOTIFICATION_INITIALIZED] = function NFC_NOTIFICATION_INITIALIZED () {
+  let status       = Buf.readInt32();
+  let majorVersion = Buf.readInt32();
+  let minorVersion = Buf.readInt32();
+  debug("NFC_NOTIFICATION_INITIALIZED status:" + status);
+  if ((majorVersion != NFC_MAJOR_VERSION) || (minorVersion != NFC_MINOR_VERSION)) {
+    debug("Version Mismatch! Current Supported Version : " +
+            NFC_MAJOR_VERSION + "." + NFC_MINOR_VERSION  +
+           " Received Version : " + majorVersion + "." + minorVersion);
+  }
+};
+
+NfcWorker[NFC_NOTIFICATION_TECH_DISCOVERED] = function NFC_NOTIFICATION_TECH_DISCOVERED() {
+  debug("NFC_NOTIFICATION_TECH_DISCOVERED");
+  let techs     = [];
+  let ndefMsgs  = [];
+
+  let sessionId = Buf.readInt32();
+  let techCount = Buf.readInt32();
+  for (let count = 0; count < techCount; count++) {
+    techs.push(NFC_TECHS[Buf.readUint8()]);
+  }
+
+  let padding   = getPaddingLen(techCount);
+  for (let i = 0; i < padding; i++) {
+    Buf.readUint8();
+  }
+
+  let ndefMsgCount = Buf.readInt32();
+  for (let count = 0; count < ndefMsgCount; count++) {
+    ndefMsgs.push(this.unMarshallNdefMessage());
+  }
+  this.sendDOMMessage({type: "techDiscovered",
+                       sessionId: sessionId,
+                       tech: techs,
+                       ndef: ndefMsgs
+                       });
+};
+
+NfcWorker[NFC_NOTIFICATION_TECH_LOST] = function NFC_NOTIFICATION_TECH_LOST() {
+  debug("NFC_NOTIFICATION_TECH_LOST");
+  let sessionId = Buf.readInt32();
+  debug("sessionId = " + sessionId);
+  this.sendDOMMessage({type: "techLost",
+                       sessionId: sessionId,
+                       });
+};
+
+/**
+ * Global stuff.
+ */
+
+if (!this.debug) {
+  // Debugging stub that goes nowhere.
+  this.debug = function debug(message) {
+    dump("Nfc Worker: " + message + "\n");
+  };
+}
+
+// Initialize buffers. This is a separate function so that unit tests can
+// re-initialize the buffers at will.
+Buf.init();
+
+function onNfcMessage(data) {
+  Buf.processIncoming(data);
+};
+
+onmessage = function onmessage(event) {
+  NfcWorker.handleDOMMessage(event.data);
+};
+
+onerror = function onerror(event) {
+  debug("OnError: event: " + JSON.stringify(event));
+  debug("NFC Worker error " + event.message + " " + event.filename + ":" +
+        event.lineno + ":\n");
+};
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/nsINfcContentHelper.idl
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+#include "nsIDOMDOMRequest.idl"
+
+interface nsIVariant;
+
+[scriptable, uuid(28c8f240-da8c-11e1-9b23-0800200c9a66)]
+interface nsINfcContentHelper : nsISupports
+{
+  void setSessionToken(in DOMString sessionToken);
+
+  nsIDOMDOMRequest getDetailsNDEF(in nsIDOMWindow window, in DOMString sessionToken);
+  nsIDOMDOMRequest readNDEF(in nsIDOMWindow window, in DOMString sessionToken);
+  nsIDOMDOMRequest writeNDEF(in nsIDOMWindow window, in nsIVariant records, in DOMString sessionToken);
+  nsIDOMDOMRequest makeReadOnlyNDEF(in nsIDOMWindow window, in DOMString sessionToken);
+
+  nsIDOMDOMRequest connect(in nsIDOMWindow window, in unsigned long techType, in DOMString sessionToken);
+  nsIDOMDOMRequest close(in nsIDOMWindow window, in DOMString sessionToken);
+};
--- a/dom/telephony/test/marionette/test_outgoing_radio_off.js
+++ b/dom/telephony/test/marionette/test_outgoing_radio_off.js
@@ -76,17 +76,17 @@ function cleanUp() {
 }
 
 let permissions = [
   "mobileconnection",
   "settings-write"
 ];
 
 startTestWithPermissions(permissions, function() {
-  connection = navigator.mozMobileConnection;
+  connection = navigator.mozMobileConnections[0];
   ok(connection instanceof MozMobileConnection,
      "connection is instanceof " + connection.constructor);
 
   icc = navigator.mozIccManager;
   ok(icc instanceof MozIccManager, "icc is instanceof " + icc.constructor);
 
   setRadioEnabled(false, function() {
     dial("0912345678");
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -346,19 +346,24 @@ var interfaceNamesInGlobalScope =
     "MozCSSKeyframesRule",
     {name: "MozEmergencyCbModeEvent", b2g: true, pref: "dom.mobileconnection.enabled"},
     {name: "MozIccManager", b2g: true, pref: "dom.icc.enabled"},
     {name: "MozInputContext", b2g: true},
     {name: "MozInputMethodManager", b2g: true},
     "MozMmsEvent",
     "MozMmsMessage",
     {name: "MozMobileConnection", b2g: true, pref: "dom.mobileconnection.enabled"},
+    {name: "MozMobileConnectionArray", b2g: true, pref: "dom.mobileconnection.enabled"},
     "MozMobileMessageManager",
     "MozMobileMessageThread",
     "MozNamedAttrMap",
+    {name: "MozNdefRecord", b2g: true},
+    {name: "MozNfc", b2g: true},
+    {name: "MozNFCPeer", b2g: true},
+    {name: "MozNFCTag", b2g: true},
     {name: "MozOtaStatusEvent", b2g: true, pref: "dom.mobileconnection.enabled"},
     "MozPowerManager",
     "mozRTCIceCandidate",
     "mozRTCPeerConnection",
     "mozRTCSessionDescription",
     "MozSettingsEvent",
     "MozSmsEvent",
     "MozSmsFilter",
--- a/dom/voicemail/test/marionette/test_voicemail_statuschanged.js
+++ b/dom/voicemail/test/marionette/test_voicemail_statuschanged.js
@@ -106,17 +106,17 @@ const MWI_LEVEL2_DISCARD_ACTIVE_PDU =
 
 function testLevel2DiscardActive() {
 
   function onLevel2Active(event) {
     let status = event.status;
     // TODO: bug 905228 - MozVoicemailStatus is not defined.
     //ok(status instanceof MozVoicemailStatus);
     is(status.hasMessages, true);
-    is(status.messageCount, status.MESSAGE_COUNT_UNKNOWN);
+    is(status.messageCount, -1);
     is(status.returnNumber, MWI_LEVEL2_SENDER);
     is(status.returnMessage, MWI_DEFAULT_BODY);
     isVoicemailStatus(status);
   }
 
   sendIndicatorPDU(MWI_LEVEL2_DISCARD_ACTIVE_PDU,
                    onLevel2Active,
                    testLevel2DiscardInactive);
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozMobileConnectionArray.webidl
@@ -0,0 +1,12 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+interface MozMobileConnection;
+
+interface MozMobileConnectionArray {
+  getter MozMobileConnection? item(unsigned long index);
+  readonly attribute unsigned long length;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozNFCPeer.webidl
@@ -0,0 +1,22 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Part of this IDL file is from:
+ * http://w3c.github.io/nfc/proposals/common/nfc.html#idl-def-NFCPeer
+ *
+ * Copyright © 2013 Deutsche Telekom, Inc.
+ */
+
+[JSImplementation="@mozilla.org/nfc/NFCPeer;1"]
+interface MozNFCPeer {
+  DOMRequest sendNDEF(sequence<MozNdefRecord> records);
+};
+
+// Mozilla Only
+partial interface MozNFCPeer {
+  [ChromeOnly]
+  attribute DOMString session;
+  [ChromeOnly]
+  void setSessionToken(DOMString sessionToken);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozNFCTag.webidl
@@ -0,0 +1,43 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Part of this idl is from:
+ * http://w3c.github.io/nfc/proposals/common/nfc.html#nfctag-interface
+ *
+ * Copyright © 2013 Deutsche Telekom, Inc.
+ */
+
+enum NFCTechType {
+  "NFC_A",
+  "NFC_B",
+  "NFC_ISO_DEP",
+  "NFC_F",
+  "NFC_V",
+  "NDEF",
+  "NDEF_FORMATABLE",
+  "MIFARE_CLASSIC",
+  "MIFARE_ULTRALIGHT",
+  "NFC_BARCODE",
+  "P2P",
+  "UNKNOWN_TECH"
+};
+
+[JSImplementation="@mozilla.org/nfc/NFCTag;1"]
+interface MozNFCTag {
+  DOMRequest getDetailsNDEF();
+  DOMRequest readNDEF();
+  DOMRequest writeNDEF(sequence<MozNdefRecord> records);
+  DOMRequest makeReadOnlyNDEF();
+
+  DOMRequest connect(NFCTechType techType);
+  DOMRequest close();
+};
+
+// Mozilla Only
+partial interface MozNFCTag {
+  [ChromeOnly]
+  attribute DOMString session;
+  [ChromeOnly]
+  void setSessionToken(DOMString sessionToken);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozNdefRecord.webidl
@@ -0,0 +1,38 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+/* Copyright © 2013 Deutsche Telekom, Inc. */
+
+[Constructor(octet tnf, DOMString type, DOMString id, DOMString payload)]
+interface MozNdefRecord
+{
+  /**
+   * Type Name Field (3-bits) - Specifies the NDEF record type in general.
+   *   tnf_empty: 0x00
+   *   tnf_well_known: 0x01
+   *   tnf_mime_media: 0x02
+   *   tnf_absolute_uri: 0x03
+   *   tnf_external type: 0x04
+   *   tnf_unknown: 0x05
+   *   tnf_unchanged: 0x06
+   *   tnf_reserved: 0x07
+   */
+  readonly attribute octet tnf;
+
+  /**
+   * type - Describes the content of the payload. This can be a mime type.
+   */
+  readonly attribute DOMString type;
+
+  /**
+   * id - Identifer is application dependent.
+   */
+  readonly attribute DOMString id;
+
+  /**
+   * payload - Binary data blob. The meaning of this field is application dependent.
+   */
+  readonly attribute DOMString payload;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozNfc.webidl
@@ -0,0 +1,16 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ /* Copyright © 2013 Deutsche Telekom, Inc. */
+
+[JSImplementation="@mozilla.org/navigatorNfc;1",
+ NavigatorProperty="mozNfc"]
+interface MozNfc : EventTarget {
+   MozNFCTag getNFCTag(DOMString sessionId);
+   MozNFCPeer getNFCPeer(DOMString sessionId);
+
+   /*attribute EventHandler onpeerfound;
+   attribute EventHandler onpeerlost;
+   attribute EventHandler onforegrounddispatch;*/
+};
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -250,21 +250,19 @@ callback systemMessageCallback = void (o
 partial interface Navigator {
   [Throws, Pref="dom.sysmsg.enabled"]
   void    mozSetMessageHandler (DOMString type, systemMessageCallback? callback);
   [Throws, Pref="dom.sysmsg.enabled"]
   boolean mozHasPendingMessage (DOMString type);
 };
 
 #ifdef MOZ_B2G_RIL
-// nsIMozNavigatorMobileConnection
-interface MozMobileConnection;
 partial interface Navigator {
   [Throws, Func="Navigator::HasMobileConnectionSupport"]
-  readonly attribute MozMobileConnection mozMobileConnection;
+  readonly attribute MozMobileConnectionArray mozMobileConnections;
 };
 
 partial interface Navigator {
   [Throws, Func="Navigator::HasCellBroadcastSupport"]
   readonly attribute MozCellBroadcast mozCellBroadcast;
 };
 
 partial interface Navigator {
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -510,22 +510,31 @@ if CONFIG['MOZ_B2G_BT']:
 if CONFIG['MOZ_B2G_RIL']:
     WEBIDL_FILES += [
         'CFStateChangeEvent.webidl',
         'DataErrorEvent.webidl',
         'IccCardLockError.webidl',
         'MozCellBroadcast.webidl',
         'MozCellBroadcastEvent.webidl',
         'MozEmergencyCbModeEvent.webidl',
+        'MozMobileConnectionArray.webidl',
         'MozOtaStatusEvent.webidl',
         'MozVoicemail.webidl',
         'MozVoicemailEvent.webidl',
         'USSDReceivedEvent.webidl',
     ]
 
+if CONFIG['MOZ_NFC']:
+    WEBIDL_FILES += [
+         'MozNdefRecord.webidl',
+         'MozNfc.webidl',
+         'MozNFCPeer.webidl',
+         'MozNFCTag.webidl',
+    ]
+
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     WEBIDL_FILES += [
         'MozWifiConnectionInfoEvent.webidl',
         'MozWifiStatusChangeEvent.webidl',
     ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     WEBIDL_FILES += [
--- a/gfx/2d/DrawTargetCairo.cpp
+++ b/gfx/2d/DrawTargetCairo.cpp
@@ -847,18 +847,20 @@ DrawTargetCairo::Fill(const Path *aPath,
 
   DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL);
 }
 
 void
 DrawTargetCairo::SetPermitSubpixelAA(bool aPermitSubpixelAA)
 {
   DrawTarget::SetPermitSubpixelAA(aPermitSubpixelAA);
+#ifdef MOZ_TREE_CAIRO
   cairo_surface_set_subpixel_antialiasing(mSurface,
     aPermitSubpixelAA ? CAIRO_SUBPIXEL_ANTIALIASING_ENABLED : CAIRO_SUBPIXEL_ANTIALIASING_DISABLED);
+#endif
 }
 
 void
 DrawTargetCairo::FillGlyphs(ScaledFont *aFont,
                             const GlyphBuffer &aBuffer,
                             const Pattern &aPattern,
                             const DrawOptions &aOptions,
                             const GlyphRenderingOptions*)
--- a/gfx/2d/Rect.h
+++ b/gfx/2d/Rect.h
@@ -54,17 +54,17 @@ IntMarginTyped<units> RoundedToInt(const
 
 template<class units>
 struct IntRectTyped :
     public BaseRect<int32_t, IntRectTyped<units>, IntPointTyped<units>, IntSizeTyped<units>, IntMarginTyped<units> >,
     public units {
     typedef BaseRect<int32_t, IntRectTyped<units>, IntPointTyped<units>, IntSizeTyped<units>, IntMarginTyped<units> > Super;
 
     IntRectTyped() : Super() {}
-    IntRectTyped(IntPointTyped<units> aPos, IntSizeTyped<units> aSize) :
+    IntRectTyped(const IntPointTyped<units>& aPos, const IntSizeTyped<units>& aSize) :
         Super(aPos, aSize) {}
     IntRectTyped(int32_t _x, int32_t _y, int32_t _width, int32_t _height) :
         Super(_x, _y, _width, _height) {}
 
     // Rounding isn't meaningful on an integer rectangle.
     void Round() {}
     void RoundIn() {}
     void RoundOut() {}
@@ -84,17 +84,17 @@ typedef IntRectTyped<UnknownUnits> IntRe
 
 template<class units>
 struct RectTyped :
     public BaseRect<Float, RectTyped<units>, PointTyped<units>, SizeTyped<units>, MarginTyped<units> >,
     public units {
     typedef BaseRect<Float, RectTyped<units>, PointTyped<units>, SizeTyped<units>, MarginTyped<units> > Super;
 
     RectTyped() : Super() {}
-    RectTyped(PointTyped<units> aPos, SizeTyped<units> aSize) :
+    RectTyped(const PointTyped<units>& aPos, const SizeTyped<units>& aSize) :
         Super(aPos, aSize) {}
     RectTyped(Float _x, Float _y, Float _width, Float _height) :
         Super(_x, _y, _width, _height) {}
     explicit RectTyped(const IntRectTyped<units>& rect) :
         Super(float(rect.x), float(rect.y),
               float(rect.width), float(rect.height)) {}
 
     GFX2D_API void NudgeToIntegers()
--- a/gfx/2d/unittest/Main.cpp
+++ b/gfx/2d/unittest/Main.cpp
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * 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/. */
 
 #include "SanityChecks.h"
 #include "TestPoint.h"
 #include "TestScaling.h"
+#include "TestBugs.h"
 #ifdef WIN32
 #include "TestDrawTargetD2D.h"
 #endif
 
 #include <string>
 #include <sstream>
 
 struct TestObject {
@@ -27,16 +28,17 @@ main()
   TestObject tests[] = 
   {
     { new SanityChecks(), "Sanity Checks" },
   #ifdef WIN32
     { new TestDrawTargetD2D(), "DrawTarget (D2D)" },
   #endif
     { new TestPoint(), "Point Tests" },
     { new TestScaling(), "Scaling Tests" }
+    { new TestBugs(), "Bug Tests" }
   };
 
   int totalFailures = 0;
   int totalTests = 0;
   stringstream message;
   printf("------ STARTING RUNNING TESTS ------\n");
   for (int i = 0; i < sizeof(tests) / sizeof(TestObject); i++) {
     message << "--- RUNNING TESTS: " << tests[i].name << " ---\n";
new file mode 100644
--- /dev/null
+++ b/gfx/2d/unittest/TestBugs.cpp
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#include "TestBugs.h"
+#include "2D.h"
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+
+TestBugs::TestBugs()
+{
+  REGISTER_TEST(TestBugs, CairoClip918671);
+}
+
+void
+TestBugs::CairoClip918671()
+{
+  RefPtr<DrawTarget> dt = Factory::CreateDrawTarget(BACKEND_CAIRO,
+                                                    IntSize(100, 100),
+                                                    FORMAT_B8G8R8A8);
+  RefPtr<DrawTarget> ref = Factory::CreateDrawTarget(BACKEND_CAIRO,
+                                                     IntSize(100, 100),
+                                                     FORMAT_B8G8R8A8);
+  // Create a path that extends around the center rect but doesn't intersect it.
+  RefPtr<PathBuilder> pb1 = dt->CreatePathBuilder();
+  pb1->MoveTo(Point(10, 10));
+  pb1->LineTo(Point(90, 10));
+  pb1->LineTo(Point(90, 20));
+  pb1->LineTo(Point(10, 20));
+  pb1->Close();
+  pb1->MoveTo(Point(90, 90));
+  pb1->LineTo(Point(91, 90));
+  pb1->LineTo(Point(91, 91));
+  pb1->LineTo(Point(91, 90));
+  pb1->Close();
+
+  RefPtr<Path> path1 = pb1->Finish();
+  dt->PushClip(path1);
+
+  // This center rect must NOT be rectilinear!
+  RefPtr<PathBuilder> pb2 = dt->CreatePathBuilder();
+  pb2->MoveTo(Point(50, 50));
+  pb2->LineTo(Point(55, 51));
+  pb2->LineTo(Point(54, 55));
+  pb2->LineTo(Point(50, 56));
+  pb2->Close();
+
+  RefPtr<Path> path2 = pb2->Finish();
+  dt->PushClip(path2);
+
+  dt->FillRect(Rect(0, 0, 100, 100), ColorPattern(Color(1,0,0)));
+
+  RefPtr<SourceSurface> surf1 = dt->Snapshot();
+  RefPtr<SourceSurface> surf2 = ref->Snapshot();
+
+  RefPtr<DataSourceSurface> dataSurf1 = surf1->GetDataSurface();
+  RefPtr<DataSourceSurface> dataSurf2 = surf2->GetDataSurface();
+
+  for (int y = 0; y < dt->GetSize().height; y++) {
+    VERIFY(memcmp(dataSurf1->GetData() + y * dataSurf1->Stride(),
+                  dataSurf2->GetData() + y * dataSurf2->Stride(),
+                  dataSurf1->GetSize().width * 4) == 0);
+  }
+
+}
+
new file mode 100644
--- /dev/null
+++ b/gfx/2d/unittest/TestBugs.h
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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/. */
+
+#pragma once
+
+#include "TestBase.h"
+
+class TestBugs : public TestBase
+{
+public:
+  TestBugs();
+
+  void CairoClip918671();
+};
+
--- a/gfx/cairo/README
+++ b/gfx/cairo/README
@@ -203,16 +203,18 @@ win32-gdi-font-cache.patch: Bug 717178, 
 win32-gdi-font-cache-no-HFONT.patch: Bug 717178, don't cache GDI font faces when an HFONT belonging to the caller is passed in
 
 fix-win32-font-assertion.patch: Bug 838617, fix assertion from bug 717178 that was in the wrong place
 
 xlib-flush-glyphs.patch: bug 839745, flush glyphs when necessary
 
 dasharray-zero-gap.patch: bug 885585, ensure strokes get painted when the gaps in a dash array are all zero length
 
+cairo-mask-extends-bug.patch: bug 918671, sometimes when building a mask we wouldn't clear it properly. This is fixed in cairo 1.12
+
 ==== pixman patches ====
 
 pixman-android-cpu-detect.patch: Add CPU detection support for Android, where we can't reliably access /proc/self/auxv.
 
 pixman-rename-and-endian.patch: include cairo-platform.h for renaming of external symbols and endian macros
 
 NOTE: we previously supported ARM assembler on MSVC, this has been removed because of the maintenance burden
 
new file mode 100644
--- /dev/null
+++ b/gfx/cairo/cairo-mask-extends-bug.patch
@@ -0,0 +1,41 @@
+diff --git a/gfx/cairo/cairo/src/cairo-image-surface.c b/gfx/cairo/cairo/src/cairo-image-surface.c
+--- a/gfx/cairo/cairo/src/cairo-image-surface.c
++++ b/gfx/cairo/cairo/src/cairo-image-surface.c
+@@ -1788,18 +1788,35 @@ static cairo_status_t
+ 					    cairo_boxes_t *boxes)
+ {
+     cairo_boxes_t clear;
+     cairo_box_t box;
+     cairo_status_t status;
+     struct _cairo_boxes_chunk *chunk;
+     int i;
+ 
+-    if (boxes->num_boxes < 1 && clip_region == NULL)
+-	return _cairo_image_surface_fixup_unbounded (dst, extents, NULL);
++    // If we have no boxes then we need to clear the entire extents
++    // because we have nothing to draw.
++    if (boxes->num_boxes < 1 && clip_region == NULL) {
++        int x = extents->unbounded.x;
++        int y = extents->unbounded.y;
++        int width = extents->unbounded.width;
++        int height = extents->unbounded.height;
++
++        pixman_color_t color = { 0 };
++        pixman_box32_t box = { x, y, x + width, y + height };
++
++        if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
++                                       dst->pixman_image,
++                                       &color,
++                                       1, &box)) {
++            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
++        }
++        return CAIRO_STATUS_SUCCESS;
++    }
+ 
+     _cairo_boxes_init (&clear);
+ 
+     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
+     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
+     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
+     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
+ 
--- a/gfx/cairo/cairo/src/cairo-image-surface.c
+++ b/gfx/cairo/cairo/src/cairo-image-surface.c
@@ -1788,18 +1788,35 @@ static cairo_status_t
 					    cairo_boxes_t *boxes)
 {
     cairo_boxes_t clear;
     cairo_box_t box;
     cairo_status_t status;
     struct _cairo_boxes_chunk *chunk;
     int i;
 
-    if (boxes->num_boxes < 1 && clip_region == NULL)
-	return _cairo_image_surface_fixup_unbounded (dst, extents, NULL);
+    // If we have no boxes then we need to clear the entire extents
+    // because we have nothing to draw.
+    if (boxes->num_boxes < 1 && clip_region == NULL) {
+        int x = extents->unbounded.x;
+        int y = extents->unbounded.y;
+        int width = extents->unbounded.width;
+        int height = extents->unbounded.height;
+
+        pixman_color_t color = { 0 };
+        pixman_box32_t box = { x, y, x + width, y + height };
+
+        if (! pixman_image_fill_boxes (PIXMAN_OP_CLEAR,
+                                       dst->pixman_image,
+                                       &color,
+                                       1, &box)) {
+            return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+        }
+        return CAIRO_STATUS_SUCCESS;
+    }
 
     _cairo_boxes_init (&clear);
 
     box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
     box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
     box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
     box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
 
--- a/gfx/ipc/GfxMessageUtils.h
+++ b/gfx/ipc/GfxMessageUtils.h
@@ -655,11 +655,31 @@ struct ParamTraits<mozilla::layers::Comp
 
 template <>
 struct ParamTraits<mozilla::gfx::SurfaceFormat>
   : public EnumSerializer<mozilla::gfx::SurfaceFormat,
                           mozilla::gfx::FORMAT_B8G8R8A8,
                           mozilla::gfx::FORMAT_UNKNOWN>
 {};
 
+template <>
+struct ParamTraits<mozilla::layers::ScrollableLayerGuid>
+{
+  typedef mozilla::layers::ScrollableLayerGuid paramType;
+
+  static void Write(Message* aMsg, const paramType& aParam)
+  {
+    WriteParam(aMsg, aParam.mLayersId);
+    WriteParam(aMsg, aParam.mPresShellId);
+    WriteParam(aMsg, aParam.mScrollId);
+  }
+
+  static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
+  {
+    return (ReadParam(aMsg, aIter, &aResult->mLayersId) &&
+            ReadParam(aMsg, aIter, &aResult->mPresShellId) &&
+            ReadParam(aMsg, aIter, &aResult->mScrollId));
+  }
+};
+
 } /* namespace IPC */
 
 #endif /* __GFXMESSAGEUTILS_H__ */
--- a/gfx/layers/FrameMetrics.h
+++ b/gfx/layers/FrameMetrics.h
@@ -250,12 +250,78 @@ public:
   CSSToLayoutDeviceScale mDevPixelsPerCSSPixel;
 
   // Whether or not this frame may have touch listeners.
   bool mMayHaveTouchListeners;
 
   uint32_t mPresShellId;
 };
 
+/**
+ * This class allows us to uniquely identify a scrollable layer. The
+ * mLayersId identifies the layer tree (corresponding to a child process
+ * and/or tab) that the scrollable layer belongs to. The mPresShellId
+ * is a temporal identifier (corresponding to the document loaded that
+ * contains the scrollable layer, which may change over time). The
+ * mScrollId corresponds to the actual frame that is scrollable.
+ */
+struct ScrollableLayerGuid {
+  uint64_t mLayersId;
+  uint32_t mPresShellId;
+  FrameMetrics::ViewID mScrollId;
+
+  ScrollableLayerGuid()
+    : mLayersId(0)
+    , mPresShellId(0)
+    , mScrollId(0)
+  {
+    MOZ_COUNT_CTOR(ScrollableLayerGuid);
+  }
+
+  ScrollableLayerGuid(uint64_t aLayersId, uint32_t aPresShellId,
+                      FrameMetrics::ViewID aScrollId)
+    : mLayersId(aLayersId)
+    , mPresShellId(aPresShellId)
+    , mScrollId(aScrollId)
+  {
+    MOZ_COUNT_CTOR(ScrollableLayerGuid);
+  }
+
+  ScrollableLayerGuid(uint64_t aLayersId, const FrameMetrics& aMetrics)
+    : mLayersId(aLayersId)
+    , mPresShellId(aMetrics.mPresShellId)
+    , mScrollId(aMetrics.mScrollId)
+  {
+    MOZ_COUNT_CTOR(ScrollableLayerGuid);
+  }
+
+  ScrollableLayerGuid(uint64_t aLayersId)
+    : mLayersId(aLayersId)
+    , mPresShellId(0)
+    , mScrollId(FrameMetrics::ROOT_SCROLL_ID)
+  {
+    MOZ_COUNT_CTOR(ScrollableLayerGuid);
+    // TODO: get rid of this constructor once all callers know their
+    // presShellId and scrollId
+  }
+
+  ~ScrollableLayerGuid()
+  {
+    MOZ_COUNT_DTOR(ScrollableLayerGuid);
+  }
+
+  bool operator==(const ScrollableLayerGuid& other) const
+  {
+    return mLayersId == other.mLayersId
+        && mPresShellId == other.mPresShellId
+        && mScrollId == other.mScrollId;
+  }
+
+  bool operator!=(const ScrollableLayerGuid& other) const
+  {
+    return !(*this == other);
+  }
+};
+
 }
 }
 
 #endif /* GFX_FRAMEMETRICS_H */
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/composite/APZCTreeManager.cpp
@@ -116,16 +116,32 @@ APZCTreeManager::UpdatePanZoomController
       const CompositorParent::LayerTreeState* state = CompositorParent::GetIndirectShadowTree(aLayersId);
       if (state && state->mController.get()) {
         // If we get here, aLayer is a scrollable container layer and somebody
         // has registered a GeckoContentController for it, so we need to ensure
         // it has an APZC instance to manage its scrolling.
 
         apzc = container->GetAsyncPanZoomController();
 
+        // If the container doesn't have an APZC already, try to find one of our
+        // pre-existing ones that matches. In particular, if we find an APZC whose
+        // ScrollableLayerGuid is the same, then we know what happened is that the
+        // layout of the page changed causing the layer tree to be rebuilt, but the
+        // underlying content for which the APZC was originally created is still
+        // there. So it makes sense to pick up that APZC instance again and use it here.
+        if (apzc == nullptr) {
+          ScrollableLayerGuid target(aLayersId, container->GetFrameMetrics());
+          for (size_t i = 0; i < aApzcsToDestroy->Length(); i++) {
+            if (aApzcsToDestroy->ElementAt(i)->Matches(target)) {
+              apzc = aApzcsToDestroy->ElementAt(i);
+              break;
+            }
+          }
+        }
+
         // The APZC we get off the layer may have been destroyed previously if the layer was inactive
         // or omitted from the layer tree for whatever reason from a layers update. If it later comes
         // back it will have a reference to a destroyed APZC and so we need to throw that out and make
         // a new one.
         bool newApzc = (apzc == nullptr || apzc->IsDestroyed());
         if (newApzc) {
           apzc = new AsyncPanZoomController(aLayersId, this, state->mController,
                                             AsyncPanZoomController::USE_GESTURE_DETECTOR);
@@ -164,17 +180,17 @@ APZCTreeManager::UpdatePanZoomController
         aParent = apzc;
 
         if (newApzc && apzc->IsRootForLayersId()) {
           // If we just created a new apzc that is the root for its layers ID, then
           // we need to update its zoom constraints which might have arrived before this
           // was created
           bool allowZoom;
           CSSToScreenScale minZoom, maxZoom;
-          if (state->mController->GetZoomConstraints(&allowZoom, &minZoom, &maxZoom)) {
+          if (state->mController->GetRootZoomConstraints(&allowZoom, &minZoom, &maxZoom)) {
             apzc->UpdateZoomConstraints(allowZoom, minZoom, maxZoom);
           }
         }
       }
     }
 
     container->SetAsyncPanZoomController(apzc);
   }
@@ -500,22 +516,26 @@ APZCTreeManager::ReceiveInputEvent(Widge
     }
     default: {
       return ProcessEvent(aEvent, aOutTargetGuid, &aEvent);
     }
   }
 }
 
 void
-APZCTreeManager::UpdateCompositionBounds(const ScrollableLayerGuid& aGuid,
-                                         const ScreenIntRect& aCompositionBounds)
+APZCTreeManager::UpdateRootCompositionBounds(const uint64_t& aLayersId,
+                                             const ScreenIntRect& aCompositionBounds)
 {
-  nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
-  if (apzc) {
-    apzc->UpdateCompositionBounds(aCompositionBounds);
+  // There can be multiple root APZCs for a given layers id (e.g. tabs in
+  // a single-process setup) and in such a case we probably want to notify
+  // all of them.
+  nsTArray< nsRefPtr<AsyncPanZoomController> > rootApzcs;
+  GetRootAPZCsFor(aLayersId, &rootApzcs);
+  for (size_t i = 0; i < rootApzcs.Length(); i++) {
+    rootApzcs[i]->UpdateCompositionBounds(aCompositionBounds);
   }
 }
 
 void
 APZCTreeManager::ZoomToRect(const ScrollableLayerGuid& aGuid,
                             const CSSRect& aRect)
 {
   nsRefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aGuid);
@@ -646,18 +666,30 @@ APZCTreeManager::GetTargetAPZC(const Scr
     target = GetAPZCAtPoint(apzc, point);
     if (target) {
       break;
     }
   }
   return target.forget();
 }
 
+void
+APZCTreeManager::GetRootAPZCsFor(const uint64_t& aLayersId,
+                                 nsTArray< nsRefPtr<AsyncPanZoomController> >* aOutRootApzcs)
+{
+  MonitorAutoLock lock(mTreeLock);
+  // The root may have siblings, check those too
+  for (AsyncPanZoomController* apzc = mRootApzc; apzc; apzc = apzc->GetPrevSibling()) {
+    FindRootAPZCs(apzc, aLayersId, aOutRootApzcs);
+  }
+}
+
 AsyncPanZoomController*
-APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid) {
+APZCTreeManager::FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid)
+{
   mTreeLock.AssertCurrentThreadOwns();
 
   // This walks the tree in depth-first, reverse order, so that it encounters
   // APZCs front-to-back on the screen.
   for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
     AsyncPanZoomController* match = FindTargetAPZC(child, aGuid);
     if (match) {
       return match;
@@ -721,16 +753,35 @@ APZCTreeManager::GetAPZCAtPoint(AsyncPan
   if (aApzc->VisibleRegionContains(ScreenPoint(hitTestPointForThisLayer.x, hitTestPointForThisLayer.y))) {
     APZC_LOG("Successfully matched untransformed point %f %f to visible region for APZC %p\n",
              hitTestPointForThisLayer.x, hitTestPointForThisLayer.y, aApzc);
     return aApzc;
   }
   return nullptr;
 }
 
+void
+APZCTreeManager::FindRootAPZCs(AsyncPanZoomController* aApzc,
+                               const uint64_t& aLayersId,
+                               nsTArray< nsRefPtr<AsyncPanZoomController> >* aOutRootApzcs)
+{
+  mTreeLock.AssertCurrentThreadOwns();
+
+  if (aApzc->IsRootForLayersId(aLayersId)) {
+    aOutRootApzcs->AppendElement(aApzc);
+    // If this APZC is a root for this layers id then we know nothing else
+    // in the subtree rooted here will match so we can early-exit
+    return;
+  }
+
+  for (AsyncPanZoomController* child = aApzc->GetLastChild(); child; child = child->GetPrevSibling()) {
+    FindRootAPZCs(child, aLayersId, aOutRootApzcs);
+  }
+}
+
 /* This function sets the aTransformToApzcOut and aTransformToGeckoOut out-parameters
    to some useful transformations that input events may need applied. This is best
    illustrated with an example. Consider a chain of layers, L, M, N, O, P, Q, R. Layer L
    is the layer that corresponds to the returned APZC instance, and layer R is the root
    of the layer tree. Layer M is the parent of L, N is the parent of M, and so on.
    When layer L is displayed to the screen by the compositor, the set of transforms that
    are applied to L are (in order from top to bottom):
 
--- a/gfx/layers/composite/APZCTreeManager.h
+++ b/gfx/layers/composite/APZCTreeManager.h
@@ -27,82 +27,16 @@ class InputData;
 
 namespace layers {
 
 class Layer;
 class AsyncPanZoomController;
 class CompositorParent;
 
 /**
- * This class allows us to uniquely identify a scrollable layer. The
- * mLayersId identifies the layer tree (corresponding to a child process
- * and/or tab) that the scrollable layer belongs to. The mPresShellId
- * is a temporal identifier (corresponding to the document loaded that
- * contains the scrollable layer, which may change over time). The
- * mScrollId corresponds to the actual frame that is scrollable.
- */
-struct ScrollableLayerGuid {
-  uint64_t mLayersId;
-  uint32_t mPresShellId;
-  FrameMetrics::ViewID mScrollId;
-
-  ScrollableLayerGuid()
-    : mLayersId(0)
-    , mPresShellId(0)
-    , mScrollId(0)
-  {
-    MOZ_COUNT_CTOR(ScrollableLayerGuid);
-  }
-
-  ScrollableLayerGuid(uint64_t aLayersId, uint32_t aPresShellId,
-                      FrameMetrics::ViewID aScrollId)
-    : mLayersId(aLayersId)
-    , mPresShellId(aPresShellId)
-    , mScrollId(aScrollId)
-  {
-    MOZ_COUNT_CTOR(ScrollableLayerGuid);
-  }
-
-  ScrollableLayerGuid(uint64_t aLayersId, const FrameMetrics& aMetrics)
-    : mLayersId(aLayersId)
-    , mPresShellId(aMetrics.mPresShellId)
-    , mScrollId(aMetrics.mScrollId)
-  {
-    MOZ_COUNT_CTOR(ScrollableLayerGuid);
-  }
-
-  ScrollableLayerGuid(uint64_t aLayersId)
-    : mLayersId(aLayersId)
-    , mPresShellId(0)
-    , mScrollId(FrameMetrics::ROOT_SCROLL_ID)
-  {
-    MOZ_COUNT_CTOR(ScrollableLayerGuid);
-    // TODO: get rid of this constructor once all callers know their
-    // presShellId and scrollId
-  }
-
-  ~ScrollableLayerGuid()
-  {
-    MOZ_COUNT_DTOR(ScrollableLayerGuid);
-  }
-
-  bool operator==(const ScrollableLayerGuid& other) const
-  {
-    return mLayersId == other.mLayersId
-        && mPresShellId == other.mPresShellId
-        && mScrollId == other.mScrollId;
-  }
-
-  bool operator!=(const ScrollableLayerGuid& other) const
-  {
-    return !(*this == other);
-  }
-};
-
-/**
  * This class manages the tree of AsyncPanZoomController instances. There is one
  * instance of this class owned by each CompositorParent, and it contains as
  * many AsyncPanZoomController instances as there are scrollable container layers.
  * This class generally lives on the compositor thread, although some functions
  * may be called from other threads as noted; thread safety is ensured internally.
  *
  * The bulk of the work of this class happens as part of the UpdatePanZoomControllerTree
  * function, which is when a layer tree update is received by the compositor.
@@ -195,24 +129,25 @@ public:
    *
    * @param aPoint point to transform
    * @param aOutTransformedPoint resulting transformed point
    */
   void TransformCoordinateToGecko(const ScreenIntPoint& aPoint,
                                   LayoutDeviceIntPoint* aOutTransformedPoint);
 
   /**
-   * Updates the composition bounds, i.e. the dimensions of the final size of
-   * the frame this is tied to during composition onto, in device pixels. In
-   * general, this will just be:
-   * { x = 0, y = 0, width = surface.width, height = surface.height }, however
-   * there is no hard requirement for this.
+   * Updates the composition bounds on the root APZC for the given layers id.
+   * See FrameMetrics::mCompositionBounds for the definition of what the
+   * composition bounds are. This function is only meant for updating the
+   * composition bounds on the root APZC because that is the one that is
+   * zoomable, and the zoom may need to be adjusted immediately upon a change
+   * in the composition bounds.
    */
-  void UpdateCompositionBounds(const ScrollableLayerGuid& aGuid,
-                               const ScreenIntRect& aCompositionBounds);
+  void UpdateRootCompositionBounds(const uint64_t& aLayersId,
+                                   const ScreenIntRect& aCompositionBounds);
 
   /**
    * Kicks an animation to zoom to a rect. This may be either a zoom out or zoom
    * in. The actual animation is done on the compositor thread after being set
    * up. |aRect| must be given in CSS pixels, relative to the document.
    */
   void ZoomToRect(const ScrollableLayerGuid& aGuid,
                   const CSSRect& aRect);
@@ -299,22 +234,27 @@ public:
   /* Some helper functions to find an APZC given some identifying input. These functions
      lock the tree of APZCs while they find the right one, and then return an addref'd
      pointer to it. This allows caller code to just use the target APZC without worrying
      about it going away. These are public for testing code and generally should not be
      used by other production code.
   */
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScrollableLayerGuid& aGuid);
   already_AddRefed<AsyncPanZoomController> GetTargetAPZC(const ScreenPoint& aPoint);
+  void GetRootAPZCsFor(const uint64_t& aLayersId,
+                       nsTArray< nsRefPtr<AsyncPanZoomController> >* aOutRootApzcs);
   void GetInputTransforms(AsyncPanZoomController *aApzc, gfx3DMatrix& aTransformToApzcOut,
                           gfx3DMatrix& aTransformToGeckoOut);
 private:
   /* Helpers */
   AsyncPanZoomController* FindTargetAPZC(AsyncPanZoomController* aApzc, const ScrollableLayerGuid& aGuid);
   AsyncPanZoomController* GetAPZCAtPoint(AsyncPanZoomController* aApzc, const gfxPoint& aHitTestPoint);
+  void FindRootAPZCs(AsyncPanZoomController* aApzc,
+                     const uint64_t& aLayersId,
+                     nsTArray< nsRefPtr<AsyncPanZoomController> >* aOutRootApzcs);
   already_AddRefed<AsyncPanZoomController> CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2);
   already_AddRefed<AsyncPanZoomController> RootAPZCForLayersId(AsyncPanZoomController* aApzc);
   already_AddRefed<AsyncPanZoomController> GetTouchInputBlockAPZC(const WidgetTouchEvent& aEvent, ScreenPoint aPoint);
   nsEventStatus ProcessTouchEvent(const WidgetTouchEvent& touchEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetTouchEvent* aOutEvent);
   nsEventStatus ProcessMouseEvent(const WidgetMouseEvent& mouseEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetMouseEvent* aOutEvent);
   nsEventStatus ProcessEvent(const WidgetInputEvent& inputEvent, ScrollableLayerGuid* aOutTargetGuid, WidgetInputEvent* aOutEvent);
 
   /**
--- a/gfx/layers/ipc/AsyncPanZoomController.cpp
+++ b/gfx/layers/ipc/AsyncPanZoomController.cpp
@@ -1285,23 +1285,19 @@ void AsyncPanZoomController::NotifyLayer
   APZC_LOG_FM(aLayerMetrics, "%p got a NotifyLayersUpdated with aIsFirstPaint=%d", this, aIsFirstPaint);
 
   mPaintThrottler.TaskComplete(GetFrameTime());
   bool needContentRepaint = false;
   if (aLayerMetrics.mCompositionBounds.width == mFrameMetrics.mCompositionBounds.width &&
       aLayerMetrics.mCompositionBounds.height == mFrameMetrics.mCompositionBounds.height) {
     // Remote content has sync'd up to the composition geometry
     // change, so we can accept the viewport it's calculated.
-    CSSToScreenScale previousResolution = mFrameMetrics.CalculateIntrinsicScale();
+    if (mFrameMetrics.mViewport.width != aLayerMetrics.mViewport.width)
+      needContentRepaint = true;
     mFrameMetrics.mViewport = aLayerMetrics.mViewport;
-    CSSToScreenScale newResolution = mFrameMetrics.CalculateIntrinsicScale();
-    if (previousResolution != newResolution) {
-      needContentRepaint = true;
-      mFrameMetrics.mZoom.scale *= newResolution.scale / previousResolution.scale;
-    }
   }
 
   if (aIsFirstPaint || isDefault) {
     mPaintThrottler.ClearHistory();
     mPaintThrottler.SetMaxDurations(gNumPaintDurationSamples);
 
     mX.CancelTouch();
     mY.CancelTouch();
@@ -1540,19 +1536,17 @@ void AsyncPanZoomController::UpdateScrol
     aScrollOffset.x, aScrollOffset.y);
 
   ReentrantMonitorAutoEnter lock(mMonitor);
   mFrameMetrics.mScrollOffset = aScrollOffset;
 }
 
 bool AsyncPanZoomController::Matches(const ScrollableLayerGuid& aGuid)
 {
-  // TODO: also check the presShellId, once that is fully propagated
-  // everywhere in RenderFrameParent and AndroidJNI.
-  return aGuid.mLayersId == mLayersId && aGuid.mScrollId == mFrameMetrics.mScrollId;
+  return aGuid == ScrollableLayerGuid(mLayersId, mFrameMetrics);
 }
 
 void AsyncPanZoomController::GetGuid(ScrollableLayerGuid* aGuidOut)
 {
   if (!aGuidOut) {
     return;
   }
   aGuidOut->mLayersId = mLayersId;
--- a/gfx/layers/ipc/AsyncPanZoomController.h
+++ b/gfx/layers/ipc/AsyncPanZoomController.h
@@ -637,16 +637,20 @@ public:
 
   /* Returns true if there is no APZC higher in the tree with the same
    * layers id.
    */
   bool IsRootForLayersId() const {
     return !mParent || (mParent->mLayersId != mLayersId);
   }
 
+  bool IsRootForLayersId(const uint64_t& aLayersId) const {
+    return (mLayersId == aLayersId) && IsRootForLayersId();
+  }
+
 private:
   // This is a raw pointer to avoid introducing a reference cycle between
   // AsyncPanZoomController and APZCTreeManager. Since these objects don't
   // live on the main thread, we can't use the cycle collector with them.
   // The APZCTreeManager owns the lifetime of the APZCs, so nulling this
   // pointer out in Destroy() will prevent accessing deleted memory.
   APZCTreeManager* mTreeManager;
 
--- a/gfx/layers/ipc/GeckoContentController.h
+++ b/gfx/layers/ipc/GeckoContentController.h
@@ -60,22 +60,23 @@ public:
 
   /**
    * Schedules a runnable to run on the controller/UI thread at some time
    * in the future.
    */
   virtual void PostDelayedTask(Task* aTask, int aDelayMs) = 0;
 
   /**
-   * Retrieves the last known zoom constraints. This function should return
-   * false if there are no last known zoom constraints.
+   * Retrieves the last known zoom constraints for the root scrollable layer
+   * for this layers tree. This function should return false if there are no
+   * last known zoom constraints.
    */
-  virtual bool GetZoomConstraints(bool* aOutAllowZoom,
-                                  CSSToScreenScale* aOutMinZoom,
-                                  CSSToScreenScale* aOutMaxZoom)
+  virtual bool GetRootZoomConstraints(bool* aOutAllowZoom,
+                                      CSSToScreenScale* aOutMinZoom,
+                                      CSSToScreenScale* aOutMaxZoom)
   {
     return false;
   }
 
   /**
    * Request any special actions be performed when panning starts
    */
   virtual void HandlePanBegin() {}
--- a/gfx/tests/gtest/TestMoz2D.cpp
+++ b/gfx/tests/gtest/TestMoz2D.cpp
@@ -2,16 +2,26 @@
  * 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/. */
 
 #include "gtest/gtest.h"
 #include "TestBase.h"
 #include "TestPoint.h"
 #include "TestScaling.h"
+#include "TestBugs.h"
+
+TEST(Moz2D, Bugs) {
+  TestBugs* test = new TestBugs();
+  int failures = 0;
+  test->RunTests(&failures);
+  delete test;
+
+  ASSERT_EQ(failures, 0);
+}
 
 TEST(Moz2D, Point) {
   TestBase* test = new TestPoint();
   int failures = 0;
   test->RunTests(&failures);
   delete test;
 
   ASSERT_EQ(failures, 0);
--- a/gfx/tests/gtest/moz.build
+++ b/gfx/tests/gtest/moz.build
@@ -24,16 +24,17 @@ GTEST_SOURCES += [
     'TestTiledLayerBuffer.cpp',
 ]
 
 # Because of gkmedia on windows we wont find these
 # symbols in xul.dll.
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows':
     GTEST_SOURCES += [ '%s/gfx/2d/unittest/%s' % (TOPSRCDIR, p) for p in [
         'TestBase.cpp',
+        'TestBugs.cpp',
         'TestPoint.cpp',
         'TestScaling.cpp',
     ]]
     GTEST_SOURCES += [
         'TestMoz2D.cpp',
         'TestRect.cpp',
     ]
 
--- a/hal/gonk/GonkFMRadio.cpp
+++ b/hal/gonk/GonkFMRadio.cpp
@@ -32,16 +32,17 @@ namespace hal_impl {
 
 uint32_t GetFMRadioFrequency();
 
 static int sRadioFD;
 static bool sRadioEnabled;
 static pthread_t sRadioThread;
 static hal::FMRadioSettings sRadioSettings;
 static int sTavaruaVersion;
+static bool sTavaruaMode;
 
 static int
 setControl(uint32_t id, int32_t value)
 {
   struct v4l2_control control;
   control.id = id;
   control.value = value;
   return ioctl(sRadioFD, VIDIOC_S_CTRL, &control);
@@ -143,16 +144,17 @@ initTavaruaRadio(hal::FMRadioSettings &a
    * HAL uses units of 1k for frequencies
    * V4L2 uses units of 62.5kHz
    * Multiplying by (10000 / 625) converts from HAL units to V4L2.
    */
 
   struct v4l2_tuner tuner = {0};
   tuner.rangelow = (aInfo.lowerLimit() * 10000) / 625;
   tuner.rangehigh = (aInfo.upperLimit() * 10000) / 625;
+  tuner.audmode = V4L2_TUNER_MODE_STEREO;
   rc = ioctl(fd, VIDIOC_S_TUNER, &tuner);
   if (rc < 0) {
     HAL_LOG(("Unable to adjust band limits"));
     return;
   }
 
   rc = setControl(V4L2_CID_PRIVATE_TAVARUA_REGION, TAVARUA_REGION_OTHER);
   if (rc < 0) {
@@ -215,26 +217,29 @@ runTavaruaRadio(void *)
 
   while (sRadioEnabled) {
     if (ioctl(sRadioFD, VIDIOC_DQBUF, &buffer) < 0) {
       if (errno == EINTR)
         continue;
       break;
     }
 
+    /* The tavarua driver reports a number of things asynchronously.
+     * In those cases, the status update comes from this thread. */
     for (unsigned int i = 0; i < buffer.bytesused; i++) {
       switch (buf[i]) {
       case TAVARUA_EVT_RADIO_READY:
         // The driver sends RADIO_READY both when we turn the radio on and when we turn 
         // the radio off.
         if (sRadioEnabled) {
           NS_DispatchToMainThread(new RadioUpdate(hal::FM_RADIO_OPERATION_ENABLE,
                                                   hal::FM_RADIO_OPERATION_STATUS_SUCCESS));
         }
         break;
+
       case TAVARUA_EVT_SEEK_COMPLETE:
         NS_DispatchToMainThread(new RadioUpdate(hal::FM_RADIO_OPERATION_SEEK,
                                                 hal::FM_RADIO_OPERATION_STATUS_SUCCESS));
         break;
       case TAVARUA_EVT_TUNE_SUCC:
         NS_DispatchToMainThread(new RadioUpdate(hal::FM_RADIO_OPERATION_TUNE,
                                                 hal::FM_RADIO_OPERATION_STATUS_SUCCESS));
         break;
@@ -265,72 +270,113 @@ EnableFMRadio(const hal::FMRadioSettings
 
   struct v4l2_capability cap;
   int rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
   if (rc < 0) {
     HAL_LOG(("Unable to query radio device"));
     return;
   }
 
+  sTavaruaMode = !strcmp((char *)cap.driver, "radio-tavarua");
   HAL_LOG(("Radio: %s (%s)\n", cap.driver, cap.card));
 
   if (!(cap.capabilities & V4L2_CAP_RADIO)) {
     HAL_LOG(("/dev/radio0 isn't a radio"));
     return;
   }
 
   if (!(cap.capabilities & V4L2_CAP_TUNER)) {
     HAL_LOG(("/dev/radio0 doesn't support the tuner interface"));
     return;
   }
-  sRadioFD = fd.forget();
   sRadioSettings = aInfo;
 
-  // Tavarua specific start
-  sTavaruaVersion = cap.version;
-  pthread_create(&sRadioThread, nullptr, runTavaruaRadio, nullptr);
-  // Tavarua specific end
+  if (sTavaruaMode) {
+    sRadioFD = fd.forget();
+    sTavaruaVersion = cap.version;
+    pthread_create(&sRadioThread, nullptr, runTavaruaRadio, nullptr);
+    return;
+  }
+
+  struct v4l2_tuner tuner = {0};
+  tuner.type = V4L2_TUNER_RADIO;
+  tuner.rangelow = (aInfo.lowerLimit() * 10000) / 625;
+  tuner.rangehigh = (aInfo.upperLimit() * 10000) / 625;
+  tuner.audmode = V4L2_TUNER_MODE_STEREO;
+  rc = ioctl(fd, VIDIOC_S_TUNER, &tuner);
+  if (rc < 0) {
+    HAL_LOG(("Unable to adjust band limits"));
+  }
+
+  sRadioFD = fd.forget();
+  sRadioEnabled = true;
+
+  hal::FMRadioOperationInformation info;
+  info.operation() = hal::FM_RADIO_OPERATION_ENABLE;
+  info.status() = hal::FM_RADIO_OPERATION_STATUS_SUCCESS;
+  hal::NotifyFMRadioStatus(info);
 }
 
 void
 DisableFMRadio()
 {
   if (!sRadioEnabled)
     return;
 
   sRadioEnabled = false;
 
-  // Tavarua specific start
-  int rc = setControl(V4L2_CID_PRIVATE_TAVARUA_STATE, FM_OFF);
-  if (rc < 0) {
-    HAL_LOG(("Unable to turn off radio"));
+  if (sTavaruaMode) {
+    int rc = setControl(V4L2_CID_PRIVATE_TAVARUA_STATE, FM_OFF);
+    if (rc < 0) {
+      HAL_LOG(("Unable to turn off radio"));
+    }
+
+    pthread_join(sRadioThread, nullptr);
   }
-  // Tavarua specific end
-
-  pthread_join(sRadioThread, nullptr);
 
   close(sRadioFD);
 
   hal::FMRadioOperationInformation info;
   info.operation() = hal::FM_RADIO_OPERATION_DISABLE;
   info.status() = hal::FM_RADIO_OPERATION_STATUS_SUCCESS;
   hal::NotifyFMRadioStatus(info);
 }
 
 void
 FMRadioSeek(const hal::FMRadioSeekDirection& aDirection)
 {
   struct v4l2_hw_freq_seek seek = {0};
   seek.type = V4L2_TUNER_RADIO;
   seek.seek_upward = aDirection == hal::FMRadioSeekDirection::FM_RADIO_SEEK_DIRECTION_UP;
+
+  /* ICS and older don't have the spacing field */
+#if ANDROID_VERSION == 15
+  seek.reserved[0] = sRadioSettings.spaceType() * 1000;
+#else
+  seek.spacing = sRadioSettings.spaceType() * 1000;
+#endif
+
   int rc = ioctl(sRadioFD, VIDIOC_S_HW_FREQ_SEEK, &seek);
+  if (sTavaruaMode && rc >= 0)
+    return;
+
+  hal::FMRadioOperationInformation info;
+  info.operation() = hal::FM_RADIO_OPERATION_SEEK;
+  info.status() = rc < 0 ? hal::FM_RADIO_OPERATION_STATUS_FAIL :
+                           hal::FM_RADIO_OPERATION_STATUS_SUCCESS;
+  hal::NotifyFMRadioStatus(info);
+
   if (rc < 0) {
     HAL_LOG(("Could not initiate hardware seek"));
     return;
   }
+
+  info.operation() = hal::FM_RADIO_OPERATION_TUNE;
+  info.status() = hal::FM_RADIO_OPERATION_STATUS_SUCCESS;
+  hal::NotifyFMRadioStatus(info);
 }
 
 void
 GetFMRadioSettings(hal::FMRadioSettings* aInfo)
 {
   if (!sRadioEnabled) {
     return;
   }
@@ -351,16 +397,25 @@ SetFMRadioFrequency(const uint32_t frequ
 {
   struct v4l2_frequency freq = {0};
   freq.type = V4L2_TUNER_RADIO;
   freq.frequency = (frequency * 10000) / 625;
 
   int rc = ioctl(sRadioFD, VIDIOC_S_FREQUENCY, &freq);
   if (rc < 0)
     HAL_LOG(("Could not set radio frequency"));
+
+  if (sTavaruaMode && rc >= 0)
+    return;
+
+  hal::FMRadioOperationInformation info;
+  info.operation() = hal::FM_RADIO_OPERATION_TUNE;
+  info.status() = rc < 0 ? hal::FM_RADIO_OPERATION_STATUS_FAIL :
+                           hal::FM_RADIO_OPERATION_STATUS_SUCCESS;
+  hal::NotifyFMRadioStatus(info);
 }
 
 uint32_t
 GetFMRadioFrequency()
 {
   if (!sRadioEnabled)
     return 0;
 
--- a/ipc/glue/MessageChannel.cpp
+++ b/ipc/glue/MessageChannel.cpp
@@ -79,16 +79,25 @@ MessageChannel::~MessageChannel()
     IPC_ASSERT(mCxxStackFrames.empty(), "mismatched CxxStackFrame ctor/dtors");
 #ifdef OS_WIN
     DebugOnly<BOOL> ok = CloseHandle(mEvent);
     MOZ_ASSERT(ok);
 #endif
     Clear();
 }
 
+static void
+PrintErrorMessage(Side side, const char* channelName, const char* msg)
+{
+    const char *from = (side == ChildSide)
+                       ? "Child"
+                       : ((side == ParentSide) ? "Parent" : "Unknown");
+    printf_stderr("\n###!!! [%s][%s] Error: %s\n\n", from, channelName, msg);
+}
+
 bool
 MessageChannel::Connected() const
 {
     mMonitor->AssertCurrentThreadOwns();
 
     // The transport layer allows us to send messages before
     // receiving the "connected" ack from the remote side.
     return (ChannelOpening == mChannelState || ChannelConnected == mChannelState);
@@ -208,17 +217,20 @@ MessageChannel::CommonThreadOpenInit(Mes
 }
 
 bool
 MessageChannel::Echo(Message* aMsg)
 {
     nsAutoPtr<Message> msg(aMsg);
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
-    IPC_ASSERT(MSG_ROUTING_NONE != msg->routing_id(), "need a route");
+    if (MSG_ROUTING_NONE == msg->routing_id()) {
+        ReportMessageRouteError("MessageChannel::Echo");
+        return false;
+    }
 
     MonitorAutoLock lock(*mMonitor);
 
     if (!Connected()) {
         ReportConnectionError("MessageChannel");
         return false;
     }
 
@@ -230,17 +242,20 @@ bool
 MessageChannel::Send(Message* aMsg)
 {
     Message copy = *aMsg;
     CxxStackFrame frame(*this, OUT_MESSAGE, &copy);
 
     nsAutoPtr<Message> msg(aMsg);
     AssertWorkerThread();
     mMonitor->AssertNotCurrentThreadOwns();
-    IPC_ASSERT(MSG_ROUTING_NONE != msg->routing_id(), "need a route");
+    if (MSG_ROUTING_NONE == msg->routing_id()) {
+        ReportMessageRouteError("MessageChannel::Send");
+        return false;
+    }
 
     MonitorAutoLock lock(*mMonitor);
     if (!Connected()) {
         ReportConnectionError("MessageChannel");
         return false;
     }
     mLink->SendMessage(msg.forget());
     return true;
@@ -1249,24 +1264,21 @@ MessageChannel::OnChannelConnected(int32
 void
 MessageChannel::DispatchOnChannelConnected(int32_t peer_pid)
 {
     AssertWorkerThread();
     if (mListener)
         mListener->OnChannelConnected(peer_pid);
 }
 
-
-static void
-PrintErrorMessage(Side side, const char* channelName, const char* msg)
+void
+MessageChannel::ReportMessageRouteError(const char* channelName) const
 {
-    const char *from = (side == ChildSide)
-                       ? "Child"
-                       : ((side == ParentSide) ? "Parent" : "Unknown");
-    printf_stderr("\n###!!! [%s][%s] Error: %s\n\n", from, channelName, msg);
+    PrintErrorMessage(mSide, channelName, "Need a route");
+    mListener->OnProcessingError(MsgRouteError);
 }
 
 void
 MessageChannel::ReportConnectionError(const char* aChannelName) const
 {
     const char* errorMsg = nullptr;
     switch (mChannelState) {
       case ChannelClosed:
--- a/ipc/glue/MessageChannel.h
+++ b/ipc/glue/MessageChannel.h
@@ -164,16 +164,17 @@ class MessageChannel : HasResultCodes
 
   private:
     void CommonThreadOpenInit(MessageChannel *aTargetChan, Side aSide);
     void OnOpenAsSlave(MessageChannel *aTargetChan, Side aSide);
 
     void PostErrorNotifyTask();
     void OnNotifyMaybeChannelError();
     void ReportConnectionError(const char* aChannelName) const;
+    void ReportMessageRouteError(const char* channelName) const;
     bool MaybeHandleError(Result code, const char* channelName);
 
     void Clear();
 
     // Send OnChannelConnected notification to listeners.
     void DispatchOnChannelConnected(int32_t peer_pid);
 
     // Any protocol that requires blocking until a reply arrives, will send its
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -511,17 +511,17 @@ static void DestroyViewID(void* aObject,
   delete id;
 }
 
 /**
  * A namespace class for static layout utilities.
  */
 
 bool
-nsLayoutUtils::FindIDFor(nsIContent* aContent, ViewID* aOutViewId)
+nsLayoutUtils::FindIDFor(const nsIContent* aContent, ViewID* aOutViewId)
 {
   void* scrollIdProperty = aContent->GetProperty(nsGkAtoms::RemoteId);
   if (scrollIdProperty) {
     *aOutViewId = *static_cast<ViewID*>(scrollIdProperty);
     return true;
   }
   return false;
 }
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -80,17 +80,17 @@ class nsLayoutUtils
 public:
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef FrameMetrics::ViewID ViewID;
 
   /**
    * Finds previously assigned ViewID for the given content element, if any.
    * Returns whether a ViewID was previously assigned.
    */
-  static bool FindIDFor(nsIContent* aContent, ViewID* aOutViewId);
+  static bool FindIDFor(const nsIContent* aContent, ViewID* aOutViewId);
 
   /**
    * Finds previously assigned or generates a unique ViewID for the given
    * content element. If aRoot is true, the special ID
    * FrameMetrics::ROOT_SCROLL_ID is used.
    */
   static ViewID FindOrCreateIDFor(nsIContent* aContent, bool aRoot = false);
 
--- a/layout/build/moz.build
+++ b/layout/build/moz.build
@@ -13,16 +13,26 @@ EXPORTS += [
 ]
 
 SOURCES += [
     'nsContentDLF.cpp',
     'nsLayoutModule.cpp',
     'nsLayoutStatics.cpp',
 ]
 
+if CONFIG['MOZ_NFC']:
+    SHARED_LIBRARY_LIBS += [
+        '%s/dom/nfc/%sdom_nfc_s.%s' % (TOPOBJDIR, CONFIG['LIB_PREFIX'], CONFIG['LIB_SUFFIX'])
+    ]
+
+if CONFIG['MOZ_NFC']:
+    LOCAL_INCLUDES += [
+        '/dom/nfc'
+    ]
+
 FAIL_ON_WARNINGS = True
 
 LIBXUL_LIBRARY = True
 
 MSVC_ENABLE_PGO = True
 
 LIBRARY_NAME = 'gklayout'
 
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -466,17 +466,17 @@ load 762902.html
 load 762764-1.html
 load 765409.html
 asserts(0-200) load 765621.html # bug 703550
 asserts(0-200) load 767765.html # bug 407550, bug 871758, and various nscoord_MAX related asserts
 load 769303-1.html
 load 769303-2.html
 load 769120.html
 load 777838.html
-load 784600.html
+skip-if(Android) load 784600.html
 load 786740-1.html
 asserts(0-4) test-pref(font.size.inflation.emPerLine,15) load 791601.xhtml # 3 counts of bug 871327, 1 bug 367185
 test-pref(font.size.inflation.minTwips,120) load 794693.html
 asserts(8) load 798020-1.html
 load 798235-1.html
 load 799207-1.html
 asserts(12) load 799207-2.html
 load 801268-1.html
--- a/layout/ipc/RenderFrameParent.cpp
+++ b/layout/ipc/RenderFrameParent.cpp
@@ -583,19 +583,19 @@ public:
                            const CSSToScreenScale& aMaxZoom)
   {
     mHaveZoomConstraints = true;
     mAllowZoom = aAllowZoom;
     mMinZoom = aMinZoom;
     mMaxZoom = aMaxZoom;
   }
 
-  virtual bool GetZoomConstraints(bool* aOutAllowZoom,
-                                  CSSToScreenScale* aOutMinZoom,
-                                  CSSToScreenScale* aOutMaxZoom)
+  virtual bool GetRootZoomConstraints(bool* aOutAllowZoom,
+                                      CSSToScreenScale* aOutMinZoom,
+                                      CSSToScreenScale* aOutMaxZoom)
   {
     if (mHaveZoomConstraints) {
       *aOutAllowZoom = mAllowZoom;
       *aOutMinZoom = mMinZoom;
       *aOutMaxZoom = mMaxZoom;
     }
     return mHaveZoomConstraints;
   }
@@ -822,29 +822,30 @@ RenderFrameParent::OwnerContentChanged(n
 {
   NS_ABORT_IF_FALSE(mFrameLoader->GetOwnerContent() == aContent,
                     "Don't build new map if owner is same!");
   BuildViewMap();
 }
 
 void
 RenderFrameParent::NotifyInputEvent(const WidgetInputEvent& aEvent,
+                                    ScrollableLayerGuid* aOutTargetGuid,
                                     WidgetInputEvent* aOutEvent)
 {
   if (GetApzcTreeManager()) {
-    GetApzcTreeManager()->ReceiveInputEvent(aEvent, nullptr, aOutEvent);
+    GetApzcTreeManager()->ReceiveInputEvent(aEvent, aOutTargetGuid, aOutEvent);
   }
 }
 
 void
 RenderFrameParent::NotifyDimensionsChanged(ScreenIntSize size)
 {
   if (GetApzcTreeManager()) {
-    GetApzcTreeManager()->UpdateCompositionBounds(ScrollableLayerGuid(mLayersId),
-                                                  ScreenIntRect(ScreenIntPoint(), size));
+    GetApzcTreeManager()->UpdateRootCompositionBounds(
+      mLayersId, ScreenIntRect(ScreenIntPoint(), size));
   }
 }
 
 void
 RenderFrameParent::ActorDestroy(ActorDestroyReason why)
 {
   if (mLayersId != 0) {
     CompositorParent::DeallocateLayerTreeId(mLayersId);
@@ -996,43 +997,46 @@ RenderFrameParent::BuildDisplayList(nsDi
                       aBuilder, *aLists.Content(), aFrame);
   } else {
     aLists.Content()->AppendToTop(
       new (aBuilder) nsDisplayRemote(aBuilder, aFrame, this));
   }
 }
 
 void
-RenderFrameParent::ZoomToRect(const CSSRect& aRect)
+RenderFrameParent::ZoomToRect(uint32_t aPresShellId, ViewID aViewId,
+                              const CSSRect& aRect)
 {
   if (GetApzcTreeManager()) {
-    GetApzcTreeManager()->ZoomToRect(ScrollableLayerGuid(mLayersId),
+    GetApzcTreeManager()->ZoomToRect(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId),
                                      aRect);
   }
 }
 
 void
-RenderFrameParent::ContentReceivedTouch(bool aPreventDefault)
+RenderFrameParent::ContentReceivedTouch(const ScrollableLayerGuid& aGuid,
+                                        bool aPreventDefault)
 {
   if (GetApzcTreeManager()) {
-    GetApzcTreeManager()->ContentReceivedTouch(ScrollableLayerGuid(mLayersId),
-                                               aPreventDefault);
+    GetApzcTreeManager()->ContentReceivedTouch(aGuid, aPreventDefault);
   }
 }
 
 void
-RenderFrameParent::UpdateZoomConstraints(bool aAllowZoom,
+RenderFrameParent::UpdateZoomConstraints(uint32_t aPresShellId,
+                                         ViewID aViewId,
+                                         bool aAllowZoom,
                                          const CSSToScreenScale& aMinZoom,
                                          const CSSToScreenScale& aMaxZoom)
 {
-  if (mContentController) {
+  if (mContentController && aViewId == FrameMetrics::ROOT_SCROLL_ID) {
     mContentController->SaveZoomConstraints(aAllowZoom, aMinZoom, aMaxZoom);
   }
   if (GetApzcTreeManager()) {
-    GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId),
+    GetApzcTreeManager()->UpdateZoomConstraints(ScrollableLayerGuid(mLayersId, aPresShellId, aViewId),
                                                 aAllowZoom, aMinZoom, aMaxZoom);
   }
 }
 
 void
 RenderFrameParent::UpdateScrollOffset(uint32_t aPresShellId, ViewID aViewId, const CSSIntPoint& aScrollOffset)
 {
   if (GetApzcTreeManager()) {
--- a/layout/ipc/RenderFrameParent.h
+++ b/layout/ipc/RenderFrameParent.h
@@ -25,16 +25,17 @@ namespace mozilla {
 class InputEvent;
 
 namespace layers {
 class APZCTreeManager;
 class GestureEventListener;
 class TargetConfig;
 class LayerTransactionParent;
 struct TextureFactoryIdentifier;
+struct ScrollableLayerGuid;
 }
 
 namespace layout {
 
 class RemoteContentController;
 
 class RenderFrameParent : public PRenderFrameParent,
                           public mozilla::layers::ShadowLayersManager
@@ -42,16 +43,17 @@ class RenderFrameParent : public PRender
   typedef mozilla::layers::FrameMetrics FrameMetrics;
   typedef mozilla::layers::ContainerLayer ContainerLayer;
   typedef mozilla::layers::Layer Layer;
   typedef mozilla::layers::LayerManager LayerManager;
   typedef mozilla::layers::TargetConfig TargetConfig;
   typedef mozilla::layers::LayerTransactionParent LayerTransactionParent;
   typedef mozilla::FrameLayerBuilder::ContainerParameters ContainerParameters;
   typedef mozilla::layers::TextureFactoryIdentifier TextureFactoryIdentifier;
+  typedef mozilla::layers::ScrollableLayerGuid ScrollableLayerGuid;
   typedef FrameMetrics::ViewID ViewID;
 
 public:
   typedef std::map<ViewID, nsRefPtr<nsContentView> > ViewMap;
 
   /**
    * Select the desired scrolling behavior.  If ASYNC_PAN_ZOOM is
    * chosen, then RenderFrameParent will watch input events and use
@@ -88,26 +90,39 @@ public:
                                      const nsIntRect& aVisibleRect,
                                      nsDisplayItem* aItem,
                                      const ContainerParameters& aContainerParameters);
 
   void OwnerContentChanged(nsIContent* aContent);
 
   void SetBackgroundColor(nscolor aColor) { mBackgroundColor = gfxRGBA(aColor); };
 
+  /**
+   * Notify the APZ code of an input event, and get back the untransformed event.
+   * @param aOutTargetGuid An out-parameter that will contain the identifier
+   *        of the APZC instance that handled the event, if one was found. This
+   *        argument may be null.
+   * @param aOutEvent An out-parameter that contains aEvent with the async transforms
+   *        unapplied. This can be passed to Gecko for hit testing and normal event
+   *        dispatch. This argument may not be null.
+   */
   void NotifyInputEvent(const WidgetInputEvent& aEvent,
+                        ScrollableLayerGuid* aOutTargetGuid,
                         WidgetInputEvent* aOutEvent);
 
   void NotifyDimensionsChanged(ScreenIntSize size);
 
-  void ZoomToRect(const CSSRect& aRect);
+  void ZoomToRect(uint32_t aPresShellId, ViewID aViewId, const CSSRect& aRect);
 
-  void ContentReceivedTouch(bool aPreventDefault);
+  void ContentReceivedTouch(const ScrollableLayerGuid& aGuid,
+                            bool aPreventDefault);
 
-  void UpdateZoomConstraints(bool aAllowZoom,
+  void UpdateZoomConstraints(uint32_t aPresShellId,
+                             ViewID aViewId,
+                             bool aAllowZoom,
                              const CSSToScreenScale& aMinZoom,
                              const CSSToScreenScale& aMaxZoom);
 
   void UpdateScrollOffset(uint32_t aPresShellId,
                           ViewID aViewId,
                           const CSSIntPoint& aScrollOffset);
 
   bool HitTest(const nsRect& aRect);
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -175,17 +175,17 @@ ElementTransitions::CanPerformOnComposit
       continue;
     }
     
     existsProperty = true;
 
     if (!css::CommonElementAnimationData::CanAnimatePropertyOnCompositor(mElement,
                                                                          pt.mProperty,
                                                                          aFlags) ||
-        !css::CommonElementAnimationData::IsCompositorAnimationDisabledForFrame(frame)) {
+        css::CommonElementAnimationData::IsCompositorAnimationDisabledForFrame(frame)) {
       return false;
     }
     if (pt.mProperty == eCSSProperty_opacity) {
       hasOpacity = true;
     } else if (pt.mProperty == eCSSProperty_transform) {
       hasTransform = true;
     }
   }
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -1,13 +1,13 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
-DIST_FILES = package-name.txt
+DIST_FILES := package-name.txt.in
 
 ifdef MOZ_ANDROID_ANR_REPORTER
 DEFINES += -DMOZ_ANDROID_ANR_REPORTER=1
 endif
 
 ifneq (,$(findstring -march=armv7,$(OS_CFLAGS)))
 MIN_CPU_VERSION=7
 else
@@ -71,35 +71,30 @@ DEFINES += \
 ifdef MOZ_PKG_SPECIAL
 DEFINES += -DMOZ_PKG_SPECIAL=$(MOZ_PKG_SPECIAL)
 endif
 
 ifdef MOZ_LINKER_EXTRACT
 DEFINES += -DMOZ_LINKER_EXTRACT=1
 endif
 
-PP_JAVAFILES = $(filter-out R.java,$(gecko-mozglue_PP_JAVAFILES) $(gecko-browser_PP_JAVAFILES))
-
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
-  $(PP_JAVAFILES) \
   gecko.ap_  \
   res/values/strings.xml \
-  R.java \
-  package-name.txt \
+  .aapt.deps \
   fennec_ids.txt \
-  Manifest.java \
   javah.out \
   jni-stubs.inc \
   GeneratedJNIWrappers.cpp \
   GeneratedJNIWrappers.h \
   $(NULL)
 
-GARBAGE_DIRS += classes db jars res sync services
+GARBAGE_DIRS += classes db jars res sync services generated
 
 # Bug 567884 - Need a way to find appropriate icons during packaging
 ifeq ($(MOZ_APP_NAME),fennec)
 ICON_PATH = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_48x48.png
 ICON_PATH_HDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_72x72.png
 ICON_PATH_XHDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_96x96.png
 ICON_PATH_XXHDPI = $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/content/fennec_144x144.png
 else
@@ -116,24 +111,17 @@ ALL_JARS = \
   sync-thirdparty.jar \
   websockets.jar \
   $(NULL)
 
 ifdef MOZ_WEBRTC
 ALL_JARS += webrtc.jar
 endif
 
-# We process ANDROID_RESFILES specially for now; the following flag
-# disables the default processing.
-IGNORE_ANDROID_RESFILES=1
-
-include $(topsrcdir)/config/rules.mk
-
-# Override the Java settings with some specific android settings
-include $(topsrcdir)/config/android-common.mk
+include $(topsrcdir)/config/config.mk
 
 # Note that we're going to set up a dependency directly between embed_android.dex and the java files
 # Instead of on the .class files, since more than one .class file might be produced per .java file
 # Sync dependencies are provided in a single jar. Sync classes themselves are delivered as source,
 # because Android resource classes must be compiled together in order to avoid overlapping resource
 # indices.
 classes.dex: $(ALL_JARS)
 	@echo "DX classes.dex"
@@ -160,34 +148,54 @@ jni-stubs.inc: gecko-browser.jar gecko-m
 	$(PYTHON) $(topsrcdir)/mobile/android/base/jni-generator.py javah.out $@
 
 ANNOTATION_PROCESSOR_JAR_FILES := $(DEPTH)/build/annotationProcessors/annotationProcessors.jar
 
 GeneratedJNIWrappers.cpp: $(ANNOTATION_PROCESSOR_JAR_FILES)
 GeneratedJNIWrappers.cpp: $(ALL_JARS)
 	$(JAVA) -classpath $(JAVA_BOOTCLASSPATH):$(ANNOTATION_PROCESSOR_JAR_FILES) org.mozilla.gecko.annotationProcessors.AnnotationProcessor $(ALL_JARS)
 
-# AndroidManifest.xml includes these files, so they need to be marked as dependencies.
-SERVICES_MANIFEST_FRAGMENTS = $(wildcard $(topsrcdir)/mobile/android/services/manifests/*.in)
+gecko_package_dir = generated/org/mozilla/gecko
+# Like generated/org/mozilla/fennec_$USERID.
+android_package_dir = $(addprefix generated/,$(subst .,/,$(ANDROID_PACKAGE_NAME)))
 
-android-tgts = \
-  AndroidManifest.xml \
-  package-name.txt \
-  $(PP_JAVAFILES) \
+# These _PP_JAVAFILES are specified in moz.build and defined in
+# backend.mk, which is included by config.mk.  Therefore this needs to
+# be defined after config.mk is included.
+PP_JAVAFILES := $(filter-out $(gecko_package_dir)/R.java,$(gecko-mozglue_PP_JAVAFILES) $(gecko-browser_PP_JAVAFILES))
+
+manifest := \
+  AndroidManifest.xml.in \
   $(NULL)
 
-android-preqs = \
-  Makefile.in \
-  widget/GeckoView.java.frag \
-  $(SERVICES_MANIFEST_FRAGMENTS) \
-  $(NULL)
+PP_TARGETS += manifest
+
+# Certain source files need to be preprocessed.  This special rule
+# generates these files into generated/org/mozilla/gecko for
+# consumption by the build system and IDEs.
+
+preprocessed := $(addsuffix .in,$(subst $(gecko_package_dir)/,,$(filter $(gecko_package_dir)/%,$(PP_JAVAFILES))))
+
+preprocessed_PATH := $(gecko_package_dir)
+preprocessed_KEEP_PATH := 1
+
+PP_TARGETS += preprocessed
 
-$(android-tgts): % : %.in $(android-preqs)
-	$(call py_action,preprocessor, \
-             $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $< -o $@)
+# Certain source files have Java package name @ANDROID_PACKAGE_NAME@.
+# We hate these files but they are necessary for backwards
+# compatibility.  These special rules generate these files into
+# generated/org/mozilla/{firefox,firefox_beta,fennec,fennec_$USER} for
+# consumption by the build system and IDEs.
+
+preprocessed_package := $(addsuffix .in,$(subst $(android_package_dir)/,,$(filter $(android_package_dir)/%,$(PP_JAVAFILES))))
+
+preprocessed_package_PATH := $(android_package_dir)
+preprocessed_package_KEEP_PATH := 1
+
+PP_TARGETS += preprocessed_package
 
 res/drawable-mdpi/icon.png: $(ICON_PATH)
 	$(NSINSTALL) -D res/drawable-mdpi
 	cp $(ICON_PATH) $@
 
 res/drawable-hdpi/icon.png: $(ICON_PATH_HDPI)
 	$(NSINSTALL) -D res/drawable-hdpi
 	cp $(ICON_PATH_HDPI) $@
@@ -219,22 +227,36 @@ res/values/strings.xml: $(call mkdir_dep
 MULTILOCALE_STRINGS_XML_FILES := $(wildcard res/values-*/strings.xml)
 all_resources = \
   $(MULTILOCALE_STRINGS_XML_FILES) \
   AndroidManifest.xml \
   $(subst resources/,res/,$(ANDROID_RESFILES)) \
   $(ANDROID_GENERATED_RESFILES) \
   $(NULL)
 
-R.java: $(all_resources)
-	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -J . --custom-package org.mozilla.gecko --non-constant-id
+# generated/org/mozilla/gecko/R.java and gecko.ap_ are both produced
+# by aapt; this saves an aapt invocation.
+
+$(gecko_package_dir)/R.java: .aapt.deps
+gecko.ap_: .aapt.deps
 
-gecko.ap_: $(all_resources)
-	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar  -S res -F $@
+.aapt.deps: $(all_resources)
+	$(AAPT) package -f -M AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res --custom-package org.mozilla.gecko --non-constant-id \
+		-J $(gecko_package_dir)/ \
+		-F gecko.ap_
+	@$(TOUCH) $@
 
-fennec_ids.txt: fennec-ids-generator.py R.java
-	$(PYTHON) $(topsrcdir)/mobile/android/base/fennec-ids-generator.py -i R.java -o $@
+fennec_ids.txt: $(gecko_package_dir)/R.java fennec-ids-generator.py
+	$(PYTHON) $(topsrcdir)/mobile/android/base/fennec-ids-generator.py -i $< -o $@
+
+# We process ANDROID_RESFILES specially for now; the following flag
+# disables the default processing.
+IGNORE_ANDROID_RESFILES=1
 
-libs:: classes.dex package-name.txt jni-stubs.inc GeneratedJNIWrappers.cpp fennec_ids.txt
+include $(topsrcdir)/config/rules.mk
+
+# Override the Java settings with some specific android settings
+include $(topsrcdir)/config/android-common.mk
+
+libs:: classes.dex jni-stubs.inc GeneratedJNIWrappers.cpp fennec_ids.txt
 	$(INSTALL) classes.dex $(FINAL_TARGET)
-	$(INSTALL) package-name.txt $(FINAL_TARGET)
 	@(diff jni-stubs.inc $(topsrcdir)/mozglue/android/jni-stubs.inc >/dev/null && diff GeneratedJNIWrappers.cpp $(topsrcdir)/widget/android/GeneratedJNIWrappers.cpp >/dev/null) || \
 	 (echo "*** Error: The generated JNI code has changed. Please run cp $(CURDIR)/jni-stubs.inc $(topsrcdir)/mozglue/android && cp $(CURDIR)/GeneratedJNIWrappers.* $(topsrcdir)/widget/android and repeat the build." && exit 1)
--- a/mobile/android/base/android-services.mozbuild
+++ b/mobile/android/base/android-services.mozbuild
@@ -547,17 +547,16 @@ sync_java_files = [
     'sync/CollectionKeys.java',
     'sync/CommandProcessor.java',
     'sync/CommandRunner.java',
     'sync/config/AccountPickler.java',
     'sync/config/activities/SelectEnginesActivity.java',
     'sync/config/ClientRecordTerminator.java',
     'sync/config/ConfigurationMigrator.java',
     'sync/CredentialException.java',
-    'sync/CredentialsSource.java',
     'sync/crypto/CryptoException.java',
     'sync/crypto/CryptoInfo.java',
     'sync/crypto/HKDF.java',
     'sync/crypto/HMACVerificationException.java',
     'sync/crypto/KeyBundle.java',
     'sync/crypto/MissingCryptoInputException.java',
     'sync/crypto/NoKeyBundleException.java',
     'sync/crypto/PersistedCrypto5Keys.java',
@@ -782,13 +781,13 @@ sync_java_files = [
     'sync/SynchronizerConfiguration.java',
     'sync/ThreadPool.java',
     'sync/UnexpectedJSONException.java',
     'sync/UnknownSynchronizerConfigurationVersionException.java',
     'sync/Utils.java',
 ]
 
 sync_generated_java_files = [
-    'background/common/GlobalConstants.java',
-    'sync/SyncConstants.java',
-    'background/announcements/AnnouncementsConstants.java',
-    'background/healthreport/HealthReportConstants.java',
+    'org/mozilla/gecko/background/announcements/AnnouncementsConstants.java',
+    'org/mozilla/gecko/background/common/GlobalConstants.java',
+    'org/mozilla/gecko/background/healthreport/HealthReportConstants.java',
+    'org/mozilla/gecko/sync/SyncConstants.java',
 ]
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -15,26 +15,26 @@ mgjar.sources += [
     'mozglue/ByteBufferInputStream.java',
     'mozglue/DirectBufferAllocator.java',
     'mozglue/GeneratableAndroidBridgeTarget.java',
     'mozglue/NativeReference.java',
     'mozglue/NativeZip.java',
     'mozglue/OptionalGeneratedParameter.java',
 ]
 mgjar.generated_sources += [
-    'mozglue/GeckoLoader.java',
+    'org/mozilla/gecko/mozglue/GeckoLoader.java',
 ]
-mgjar.javac_flags = '-Xlint:all'
+mgjar.javac_flags += ['-Xlint:all']
 
 wsjar = add_java_jar('websockets')
 wsjar.sources += [ thirdparty_source_dir + f for f in [
     'com/codebutler/android_websockets/HybiParser.java',
     'com/codebutler/android_websockets/WebSocketClient.java',
 ] ]
-wsjar.javac_flags = '-Xlint:all,-serial'
+wsjar.javac_flags += ['-Xlint:all,-serial']
 
 gujar = add_java_jar('gecko-util')
 gujar.sources += [
     'util/ActivityResultHandler.java',
     'util/ActivityResultHandlerMap.java',
     'util/Clipboard.java',
     'util/EventDispatcher.java',
     'util/FloatUtils.java',
@@ -46,164 +46,116 @@ gujar.sources += [
     'util/HardwareUtils.java',
     'util/INIParser.java',
     'util/INISection.java',
     'util/JSONUtils.java',
     'util/StringUtils.java',
     'util/ThreadUtils.java',
     'util/UiAsyncTask.java',
 ]
-gujar.extra_jars=[
+gujar.extra_jars = [
     'gecko-mozglue.jar'
 ]
-gujar.javac_flags = '-Xlint:all,-deprecation'
+gujar.javac_flags += ['-Xlint:all,-deprecation']
 
 stjar = add_java_jar('sync-thirdparty')
 stjar.sources += [ thirdparty_source_dir + f for f in sync_thirdparty_java_files ]
-stjar.javac_flags = '-Xlint:none'
+stjar.javac_flags = ['-Xlint:none']
 
 if CONFIG['MOZ_WEBRTC']:
     video_root = TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src/org/webrtc/videoengine/'
     audio_root = TOPSRCDIR + '/media/webrtc/trunk/webrtc/modules/audio_device/android/java/src/org/webrtc/voiceengine/'
     wrjar = add_java_jar('webrtc')
     wrjar.sources += [
         video_root + 'CaptureCapabilityAndroid.java',
         video_root + 'VideoCaptureAndroid.java',
         video_root + 'VideoCaptureDeviceInfoAndroid.java',
+    ]
+    wrjar.sources += [
+        audio_root + 'AudioManagerAndroid.java',
         audio_root + 'WebRTCAudioDevice.java',
-        audio_root + 'AudioManagerAndroid.java',
     ]
     wrjar.extra_jars = [
         'gecko-browser.jar',
         'gecko-util.jar',
         'gecko-mozglue.jar',
     ]
-    wrjar.javac_flags = '-Xlint:all,-deprecation,-cast'
+    wrjar.javac_flags += ['-Xlint:all,-deprecation,-cast']
 
 gbjar = add_java_jar('gecko-browser')
 gbjar.sources += [
-    'ANRReporter.java',
     'ActivityHandlerHelper.java',
     'AlertNotification.java',
-    'AppNotificationClient.java',
-    'AutocompleteHandler.java',
     'animation/AnimatorProxy.java',
     'animation/HeightChangeAnimation.java',
     'animation/PropertyAnimator.java',
     'animation/Rotate3DAnimation.java',
     'animation/ViewHelper.java',
+    'ANRReporter.java',
+    'AppNotificationClient.java',
+    'AutocompleteHandler.java',
     'BackButton.java',
     'BaseGeckoInterface.java',
     'BrowserApp.java',
     'BrowserToolbar.java',
     'BrowserToolbarBackground.java',
     'CameraImageResultHandler.java',
     'CameraVideoResultHandler.java',
     'CanvasDelegate.java',
     'ContactService.java',
     'ContextGetter.java',
     'CustomEditText.java',
+    'DataReportingNotification.java',
+    'db/BrowserContract.java',
     'db/BrowserDB.java',
+    'db/BrowserProvider.java',
+    'db/DBUtils.java',
+    'db/FormHistoryProvider.java',
     'db/LocalBrowserDB.java',
-    'db/DBUtils.java',
-    'DataReportingNotification.java',
+    'db/PasswordsProvider.java',
+    'db/PerProfileContentProvider.java',
+    'db/TabsProvider.java',
     'Distribution.java',
     'DoorHanger.java',
     'DoorHangerPopup.java',
     'EditBookmarkDialog.java',
     'favicons/cache/FaviconCache.java',
     'favicons/cache/FaviconCacheElement.java',
     'favicons/cache/FaviconsForURL.java',
     'favicons/Favicons.java',
     'favicons/LoadFaviconTask.java',
     'favicons/OnFaviconLoadedListener.java',
     'FilePickerResultHandler.java',
     'FilePickerResultHandlerSync.java',
     'FindInPageBar.java',
     'FormAssistPopup.java',
     'ForwardButton.java',
     'GeckoAccessibility.java',
-    'GeckoApplication.java',
-    'GeckoApp.java',
-    'GeckoAppShell.java',
     'GeckoActivity.java',
     'GeckoActivityStatus.java',
+    'GeckoApp.java',
+    'GeckoApplication.java',
+    'GeckoAppShell.java',
     'GeckoBatteryManager.java',
     'GeckoConnectivityReceiver.java',
     'GeckoEditable.java',
     'GeckoEvent.java',
     'GeckoHalDefines.java',
     'GeckoInputConnection.java',
+    'GeckoJavaSampler.java',
     'GeckoMessageReceiver.java',
+    'GeckoNetworkManager.java',
     'GeckoProfile.java',
+    'GeckoScreenOrientationListener.java',
     'GeckoSmsManager.java',
     'GeckoThread.java',
-    'GeckoJavaSampler.java',
-    'GlobalHistory.java',
+    'GeckoUpdateReceiver.java',
     'GeckoView.java',
     'GeckoViewChrome.java',
     'GeckoViewContent.java',
-    'health/BrowserHealthRecorder.java',
-    'health/BrowserHealthReporter.java',
-    'InputMethods.java',
-    'JavaAddonManager.java',
-    'LightweightTheme.java',
-    'LightweightThemeDrawable.java',
-    'MemoryMonitor.java',
-    'MotionEventInterceptor.java',
-    'NotificationClient.java',
-    'NotificationHandler.java',
-    'NotificationHelper.java',
-    'NotificationService.java',
-    'NSSBridge.java',
-    'OrderedBroadcastHelper.java',
-    'PageActionLayout.java',
-    'PrefsHelper.java',
-    'PrivateTab.java',
-    'prompts/Prompt.java',
-    'prompts/PromptInput.java',
-    'prompts/PromptService.java',
-    'prompts/IconGridInput.java',
-    'Restarter.java',
-    'sqlite/ByteBufferInputStream.java',
-    'sqlite/MatrixBlobCursor.java',
-    'sqlite/SQLiteBridge.java',
-    'sqlite/SQLiteBridgeException.java',
-    'ReaderModeUtils.java',
-    'RemoteTabs.java',
-    'RobocopAPI.java',
-    'ServiceNotificationClient.java',
-    'ScrollAnimator.java',
-    'SessionParser.java',
-    'ShapedButton.java',
-    'SharedPreferencesHelper.java',
-    'SiteIdentityPopup.java',
-    'SmsManager.java',
-    'SurfaceBits.java',
-    'Tab.java',
-    'TabCounter.java',
-    'Tabs.java',
-    'TabsPanel.java',
-    'TabsTray.java',
-    'TabsAccessor.java',
-    'Telemetry.java',
-    'TextSelection.java',
-    'TextSelectionHandle.java',
-    'ThumbnailHelper.java',
-    'TouchEventInterceptor.java',
-    'VideoPlayer.java',
-    'WebAppAllocator.java',
-    'WebAppImpl.java',
-    'ZoomConstraints.java',
-    'db/BrowserContract.java',
-    'db/BrowserProvider.java',
-    'db/FormHistoryProvider.java',
-    'db/PerProfileContentProvider.java',
-    'db/PasswordsProvider.java',
-    'db/TabsProvider.java',
     'gfx/Axis.java',
     'gfx/BitmapUtils.java',
     'gfx/BufferedCairoImage.java',
     'gfx/CairoGLInfo.java',
     'gfx/CairoImage.java',
     'gfx/CairoUtils.java',
     'gfx/DisplayPortCalculator.java',
     'gfx/DisplayPortMetrics.java',
@@ -237,120 +189,175 @@ gbjar.sources += [
     'gfx/SubdocumentScrollHelper.java',
     'gfx/TextLayer.java',
     'gfx/TextureGenerator.java',
     'gfx/TextureReaper.java',
     'gfx/TileLayer.java',
     'gfx/TouchEventHandler.java',
     'gfx/ViewTransform.java',
     'gfx/VirtualLayer.java',
+    'GlobalHistory.java',
+    'health/BrowserHealthRecorder.java',
+    'health/BrowserHealthReporter.java',
+    'home/BookmarkFolderView.java',
     'home/BookmarksListAdapter.java',
     'home/BookmarksListView.java',
     'home/BookmarksPage.java',
-    'home/BookmarkFolderView.java',
     'home/BrowserSearch.java',
+    'home/FadedTextView.java',
     'home/HistoryPage.java',
+    'home/HomeBanner.java',
     'home/HomeFragment.java',
     'home/HomeListView.java',
     'home/HomePager.java',
     'home/HomePagerTabStrip.java',
-    'home/HomeBanner.java',
-    'home/FadedTextView.java',
     'home/LastTabsPage.java',
     'home/MostRecentPage.java',
     'home/MultiTypeCursorAdapter.java',
     'home/PinSiteDialog.java',
     'home/ReadingListPage.java',
     'home/SearchEngine.java',
     'home/SearchEngineRow.java',
     'home/SearchLoader.java',
     'home/SimpleCursorLoader.java',
     'home/SuggestClient.java',
     'home/TabMenuStrip.java',
     'home/TopSitesGridItemView.java',
     'home/TopSitesGridView.java',
     'home/TopSitesPage.java',
     'home/TopSitesThumbnailView.java',
     'home/TwoLinePageRow.java',
+    'InputMethods.java',
+    'JavaAddonManager.java',
+    'LightweightTheme.java',
+    'LightweightThemeDrawable.java',
+    'MemoryMonitor.java',
     'menu/GeckoMenu.java',
     'menu/GeckoMenuInflater.java',
     'menu/GeckoMenuItem.java',
     'menu/GeckoSubMenu.java',
     'menu/MenuItemActionBar.java',
     'menu/MenuItemActionView.java',
     'menu/MenuItemDefault.java',
     'menu/MenuPanel.java',
     'menu/MenuPopup.java',
+    'MotionEventInterceptor.java',
+    'NotificationClient.java',
+    'NotificationHandler.java',
+    'NotificationHelper.java',
+    'NotificationService.java',
+    'NSSBridge.java',
+    'OrderedBroadcastHelper.java',
+    'PageActionLayout.java',
     'preferences/AlignRightLinkPreference.java',
     'preferences/AndroidImport.java',
     'preferences/AndroidImportPreference.java',
     'preferences/FontSizePreference.java',
+    'preferences/GeckoPreferenceFragment.java',
     'preferences/GeckoPreferences.java',
-    'preferences/GeckoPreferenceFragment.java',
     'preferences/LinkPreference.java',
     'preferences/MultiChoicePreference.java',
     'preferences/PrivateDataPreference.java',
+    'preferences/SearchEnginePreference.java',
     'preferences/SearchPreferenceCategory.java',
-    'preferences/SearchEnginePreference.java',
     'preferences/SyncPreference.java',
+    'PrefsHelper.java',
+    'PrivateTab.java',
+    'prompts/IconGridInput.java',
+    'prompts/Prompt.java',
+    'prompts/PromptInput.java',
+    'prompts/PromptService.java',
+    'ReaderModeUtils.java',
+    'ReferrerReceiver.java',
+    'RemoteTabs.java',
+    'Restarter.java',
+    'RobocopAPI.java',
+    'ScrollAnimator.java',
+    'ServiceNotificationClient.java',
+    'SessionParser.java',
+    'ShapedButton.java',
+    'SharedPreferencesHelper.java',
+    'SiteIdentityPopup.java',
+    'SmsManager.java',
+    'sqlite/ByteBufferInputStream.java',
+    'sqlite/MatrixBlobCursor.java',
+    'sqlite/SQLiteBridge.java',
+    'sqlite/SQLiteBridgeException.java',
+    'SurfaceBits.java',
+    'Tab.java',
+    'TabCounter.java',
+    'Tabs.java',
+    'TabsAccessor.java',
+    'TabsPanel.java',
+    'TabsTray.java',
+    'Telemetry.java',
+    'TextSelection.java',
+    'TextSelectionHandle.java',
+    'ThumbnailHelper.java',
+    'TouchEventInterceptor.java',
+    'updater/UpdateService.java',
     'updater/UpdateServiceHelper.java',
-    'updater/UpdateService.java',
+    'VideoPlayer.java',
+    'WebAppAllocator.java',
+    'WebAppImpl.java',
     'widget/ActivityChooserModel.java',
     'widget/AllCapsTextView.java',
     'widget/AnimatedHeightLayout.java',
+    'widget/ArrowPopup.java',
     'widget/ButtonToast.java',
     'widget/CheckableLinearLayout.java',
     'widget/ClickableWhenDisabledEditText.java',
-    'widget/ArrowPopup.java',
     'widget/DateTimePicker.java',
     'widget/Divider.java',
     'widget/FaviconView.java',
     'widget/FlowLayout.java',
+    'widget/GeckoActionProvider.java',
     'widget/GeckoPopupMenu.java',
-    'widget/GeckoActionProvider.java',
     'widget/IconTabWidget.java',
     'widget/TabRow.java',
     'widget/ThumbnailView.java',
     'widget/TwoWayView.java',
-    'GeckoNetworkManager.java',
-    'GeckoScreenOrientationListener.java',
-    'GeckoUpdateReceiver.java',
-    'ReferrerReceiver.java',
+    'ZoomConstraints.java',
 ]
 gbjar.sources += [ thirdparty_source_dir + f for f in [
     'com/googlecode/eyesfree/braille/selfbraille/ISelfBrailleService.java',
     'com/googlecode/eyesfree/braille/selfbraille/SelfBrailleClient.java',
     'com/googlecode/eyesfree/braille/selfbraille/WriteData.java',
 ] ]
+android_package_dir = CONFIG['ANDROID_PACKAGE_NAME'].replace('.', '/')
+# All generated sources are handled specially in Makefile.in.  And
+# R.java is handled even more specially than the others!
+gbjar.generated_sources += [ android_package_dir + f for f in [
+    '/App.java',
+    '/WebApp.java',
+    '/WebApps.java',
+] ]
 gbjar.generated_sources += [
-    'App.java',
-    'AppConstants.java',
-    'R.java',
-    'SysInfo.java',
-    'WebApp.java',
-    'WebApps.java',
-    'widget/GeckoEditText.java',
-    'widget/GeckoImageButton.java',
-    'widget/GeckoImageView.java',
-    'widget/GeckoLinearLayout.java',
-    'widget/GeckoRelativeLayout.java',
-    'widget/GeckoTextSwitcher.java',
-    'widget/GeckoTextView.java',
+    'org/mozilla/gecko/AppConstants.java',
+    'org/mozilla/gecko/R.java',
+    'org/mozilla/gecko/SysInfo.java',
+    'org/mozilla/gecko/widget/GeckoEditText.java',
+    'org/mozilla/gecko/widget/GeckoImageButton.java',
+    'org/mozilla/gecko/widget/GeckoImageView.java',
+    'org/mozilla/gecko/widget/GeckoLinearLayout.java',
+    'org/mozilla/gecko/widget/GeckoRelativeLayout.java',
+    'org/mozilla/gecko/widget/GeckoTextSwitcher.java',
+    'org/mozilla/gecko/widget/GeckoTextView.java',
 ]
 if CONFIG['MOZ_CRASHREPORTER']:
     gbjar.sources += [ 'CrashReporter.java ']
 gbjar.sources += sync_java_files
 gbjar.generated_sources += sync_generated_java_files
-gbjar.extra_jars=[
+gbjar.extra_jars = [
     'gecko-mozglue.jar',
     'gecko-util.jar',
     'sync-thirdparty.jar',
     'websockets.jar',
 ]
-gbjar.javac_flags = '-Xlint:all,-deprecation,-fallthrough'
+gbjar.javac_flags += ['-Xlint:all,-deprecation,-fallthrough']
 
 ANDROID_GENERATED_RESFILES += [
     'res/drawable-hdpi/icon.png',
     'res/drawable-mdpi/icon.png',
     'res/drawable-xhdpi/icon.png',
     'res/drawable-xxhdpi/icon.png',
     'res/values/strings.xml',
 ]
deleted file mode 100644
--- a/mobile/android/base/sync/CredentialsSource.java
+++ /dev/null
@@ -1,9 +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/. */
-
-package org.mozilla.gecko.sync;
-
-public interface CredentialsSource {
-  public abstract String credentials();
-}
--- a/mobile/android/base/sync/GlobalSession.java
+++ b/mobile/android/base/sync/GlobalSession.java
@@ -24,16 +24,17 @@ import org.mozilla.gecko.sync.crypto.Cry
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.delegates.FreshStartDelegate;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
 import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
 import org.mozilla.gecko.sync.delegates.KeyUploadDelegate;
 import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
 import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.HttpResponseObserver;
 import org.mozilla.gecko.sync.net.SyncResponse;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 import org.mozilla.gecko.sync.stage.AndroidBrowserBookmarksServerSyncStage;
@@ -53,17 +54,17 @@ import org.mozilla.gecko.sync.stage.Pass
 import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
 import org.mozilla.gecko.sync.stage.UploadMetaGlobalStage;
 
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Bundle;
 import ch.boye.httpclientandroidlib.HttpResponse;
 
-public class GlobalSession implements CredentialsSource, PrefsSource, HttpResponseObserver {
+public class GlobalSession implements PrefsSource, HttpResponseObserver {
   private static final String LOG_TAG = "GlobalSession";
 
   public static final String API_VERSION   = "1.1";
   public static final long STORAGE_VERSION = 5;
 
   public SyncConfiguration config = null;
 
   protected Map<Stage, GlobalSyncStage> stages;
@@ -84,64 +85,41 @@ public class GlobalSession implements Cr
    */
   public KeyBundle keyBundleForCollection(String collection) throws NoCollectionKeysSetException {
     return config.getCollectionKeys().keyBundleForCollection(collection);
   }
 
   /*
    * Config passthrough for convenience.
    */
-  @Override
-  public String credentials() {
-    return config.credentials();
+  public AuthHeaderProvider getAuthHeaderProvider() {
+    return config.getAuthHeaderProvider();
   }
 
   public URI wboURI(String collection, String id) throws URISyntaxException {
     return config.wboURI(collection, id);
   }
 
-  /*
-   * Validators.
-   */
-  private static boolean isInvalidString(String s) {
-    return s == null ||
-           s.trim().length() == 0;
-  }
-
-  private static boolean anyInvalidStrings(String s, String...strings) {
-    if (isInvalidString(s)) {
-      return true;
-    }
-    for (String str : strings) {
-      if (isInvalidString(str)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  public GlobalSession(String userAPI,
-                       String serverURL,
+  public GlobalSession(String serverURL,
                        String username,
-                       String password,
+                       AuthHeaderProvider authHeaderProvider,
                        String prefsPath,
                        KeyBundle syncKeyBundle,
                        GlobalSessionCallback callback,
                        Context context,
                        Bundle extras,
                        ClientsDataDelegate clientsDelegate)
                            throws SyncConfigurationException, IllegalArgumentException, IOException, ParseException, NonObjectJSONException {
+    if (username == null) {
+      throw new IllegalArgumentException("username must not be null.");
+    }
     if (callback == null) {
       throw new IllegalArgumentException("Must provide a callback to GlobalSession constructor.");
     }
 
-    if (anyInvalidStrings(username, password)) {
-      throw new SyncConfigurationException();
-    }
-
     Logger.debug(LOG_TAG, "GlobalSession initialized with bundle " + extras);
     URI serverURI;
     try {
       serverURI = (serverURL == null) ? null : new URI(serverURL);
     } catch (URISyntaxException e) {
       throw new SyncConfigurationException();
     }
 
@@ -150,21 +128,19 @@ public class GlobalSession implements Cr
         syncKeyBundle.getHMACKey() == null) {
       throw new SyncConfigurationException();
     }
 
     this.callback        = callback;
     this.context         = context;
     this.clientsDelegate = clientsDelegate;
 
-    config = new SyncConfiguration(prefsPath, this);
-    config.userAPI       = userAPI;
+    config = new SyncConfiguration(username, authHeaderProvider, prefsPath, this);
+
     config.serverURL     = serverURI;
-    config.username      = username;
-    config.password      = password;
     config.syncKeyBundle = syncKeyBundle;
 
     registerCommands();
     prepareStages();
 
     Collection<String> knownStageNames = SyncConfiguration.validEngineNames();
     config.stagesToSync = Utils.getStagesToSyncFromBundle(knownStageNames, extras);
 
@@ -564,32 +540,31 @@ public class GlobalSession implements Cr
         return;
       }
     } catch (Exception e) {
       Logger.warn(LOG_TAG, "Exception parsing HTTP 400 body.", e);
     }
   }
 
   public void fetchInfoCollections(JSONRecordFetchDelegate callback) throws URISyntaxException {
-    final JSONRecordFetcher fetcher = new JSONRecordFetcher(config.infoCollectionsURL(), credentials());
+    final JSONRecordFetcher fetcher = new JSONRecordFetcher(config.infoCollectionsURL(), getAuthHeaderProvider());
     fetcher.fetch(callback);
   }
 
   /**
    * Upload new crypto/keys.
    *
    * @param keys
    *          new keys.
    * @param keyUploadDelegate
    *          a delegate.
    */
   public void uploadKeys(final CollectionKeys keys,
                          final KeyUploadDelegate keyUploadDelegate) {
     SyncStorageRecordRequest request;
-    final GlobalSession self = this;
     try {
       request = new SyncStorageRecordRequest(this.config.keysURI());
     } catch (URISyntaxException e) {
       keyUploadDelegate.onKeyUploadFailed(e);
       return;
     }
 
     request.delegate = new SyncStorageRequestDelegate() {
@@ -604,30 +579,30 @@ public class GlobalSession implements Cr
         Logger.debug(LOG_TAG, "Keys uploaded.");
         BaseResource.consumeEntity(response); // We don't need the response at all.
         keyUploadDelegate.onKeysUploaded();
       }
 
       @Override
       public void handleRequestFailure(SyncStorageResponse response) {
         Logger.debug(LOG_TAG, "Failed to upload keys.");
-        self.interpretHTTPFailure(response.httpResponse());
+        GlobalSession.this.interpretHTTPFailure(response.httpResponse());
         BaseResource.consumeEntity(response); // The exception thrown should not need the body of the response.
         keyUploadDelegate.onKeyUploadFailed(new HTTPFailureException(response));
       }
 
       @Override
       public void handleRequestError(Exception ex) {
         Logger.warn(LOG_TAG, "Got exception trying to upload keys", ex);
         keyUploadDelegate.onKeyUploadFailed(ex);
       }
 
       @Override
-      public String credentials() {
-        return self.credentials();
+      public AuthHeaderProvider getAuthHeaderProvider() {
+        return GlobalSession.this.getAuthHeaderProvider();
       }
     };
 
     // Convert keys to an encrypted crypto record.
     CryptoRecord keysRecord;
     try {
       keysRecord = keys.asCryptoRecord();
       keysRecord.setKeyBundle(config.syncKeyBundle);
@@ -743,17 +718,17 @@ public class GlobalSession implements Cr
    * @param session the current session.
    * @param freshStartDelegate delegate to notify on fresh start or failure.
    */
   protected static void freshStart(final GlobalSession session, final FreshStartDelegate freshStartDelegate) {
     Logger.debug(LOG_TAG, "Fresh starting.");
 
     final MetaGlobal mg = session.generateNewMetaGlobal();
 
-    session.wipeServer(session, new WipeServerDelegate() {
+    session.wipeServer(session.getAuthHeaderProvider(), new WipeServerDelegate() {
 
       @Override
       public void onWiped(long timestamp) {
         Logger.debug(LOG_TAG, "Successfully wiped server.  Resetting all stages and purging cached meta/global and crypto/keys records.");
 
         session.resetAllStages();
         session.config.purgeMetaGlobal();
         session.config.purgeCryptoKeys();
@@ -843,22 +818,22 @@ public class GlobalSession implements Cr
   //
   // When an engine is disabled: wipe its collections on the server, reupload
   // meta/global.
   //
   // On syncing each stage: if server has engine version 0 or old, wipe server,
   // reset client to prompt reupload.
   // If sync ID mismatch: take that syncID and reset client.
 
-  protected void wipeServer(final CredentialsSource credentials, final WipeServerDelegate wipeDelegate) {
+  protected void wipeServer(final AuthHeaderProvider authHeaderProvider, final WipeServerDelegate wipeDelegate) {
     SyncStorageRequest request;
     final GlobalSession self = this;
 
     try {
-      request = new SyncStorageRequest(config.storageURL(false));
+      request = new SyncStorageRequest(config.storageURL());
     } catch (URISyntaxException ex) {
       Logger.warn(LOG_TAG, "Invalid URI in wipeServer.");
       wipeDelegate.onWipeFailed(ex);
       return;
     }
 
     request.delegate = new SyncStorageRequestDelegate() {
 
@@ -884,18 +859,18 @@ public class GlobalSession implements Cr
 
       @Override
       public void handleRequestError(Exception ex) {
         Logger.warn(LOG_TAG, "Got exception in wipeServer.", ex);
         wipeDelegate.onWipeFailed(ex);
       }
 
       @Override
-      public String credentials() {
-        return credentials.credentials();
+      public AuthHeaderProvider getAuthHeaderProvider() {
+        return GlobalSession.this.getAuthHeaderProvider();
       }
     };
     request.delete();
   }
 
   public void wipeAllStages() {
     Logger.info(LOG_TAG, "Wiping all stages.");
     // Includes "clients".
@@ -977,17 +952,16 @@ public class GlobalSession implements Cr
 
   /**
    * Generate a fresh meta/global record.
    * @return meta/global record.
    */
   public MetaGlobal generateNewMetaGlobal() {
     final String newSyncID   = Utils.generateGuid();
     final String metaURL     = this.config.metaURL();
-    final String credentials = this.credentials();
 
     ExtendedJSONObject engines = new ExtendedJSONObject();
     for (String engineName : enabledEngineNames()) {
       EngineSettings engineSettings = null;
       try {
         GlobalSyncStage globalStage = this.getSyncStageByName(engineName);
         Integer version = globalStage.getStorageVersion();
         if (version == null) {
@@ -997,17 +971,17 @@ public class GlobalSession implements Cr
       } catch (NoSuchStageException e) {
         // No trouble; Android Sync might not recognize this engine yet.
         // By default, version 0.  Other clients will see the 0 version and reset/wipe accordingly.
         engineSettings = new EngineSettings(Utils.generateGuid(), 0);
       }
       engines.put(engineName, engineSettings.toJSONObject());
     }
 
-    MetaGlobal metaGlobal = new MetaGlobal(metaURL, credentials);
+    MetaGlobal metaGlobal = new MetaGlobal(metaURL, this.getAuthHeaderProvider());
     metaGlobal.setSyncID(newSyncID);
     metaGlobal.setStorageVersion(STORAGE_VERSION);
     metaGlobal.setEngines(engines);
 
     return metaGlobal;
   }
 
   /**
--- a/mobile/android/base/sync/JSONRecordFetcher.java
+++ b/mobile/android/base/sync/JSONRecordFetcher.java
@@ -4,46 +4,48 @@
 
 package org.mozilla.gecko.sync;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.delegates.JSONRecordFetchDelegate;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 
 /**
  * An object which fetches a chunk of JSON from a URI, using certain credentials,
  * and informs its delegate of the result.
  */
 public class JSONRecordFetcher {
   private static final long DEFAULT_AWAIT_TIMEOUT_MSEC = 2 * 60 * 1000;   // Two minutes.
   private static final String LOG_TAG = "JSONRecordFetcher";
 
-  protected final String credentials;
+  protected final AuthHeaderProvider authHeaderProvider;
   protected final String uri;
   protected JSONRecordFetchDelegate delegate;
 
-  public JSONRecordFetcher(final String uri, final String credentials) {
+  public JSONRecordFetcher(final String uri, final AuthHeaderProvider authHeaderProvider) {
     this.uri = uri;
-    this.credentials = credentials;
+    this.authHeaderProvider = authHeaderProvider;
   }
 
   protected String getURI() {
     return this.uri;
   }
 
   private class JSONFetchHandler implements SyncStorageRequestDelegate {
 
     // SyncStorageRequestDelegate methods for fetching.
-    public String credentials() {
-      return credentials;
+    @Override
+    public AuthHeaderProvider getAuthHeaderProvider() {
+      return authHeaderProvider;
     }
 
     public String ifUnmodifiedSince() {
       return null;
     }
 
     public void handleRequestSuccess(SyncStorageResponse response) {
       if (response.wasSuccessful()) {
--- a/mobile/android/base/sync/MetaGlobal.java
+++ b/mobile/android/base/sync/MetaGlobal.java
@@ -11,44 +11,45 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
 import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalMalformedSyncIDException;
 import org.mozilla.gecko.sync.MetaGlobalException.MetaGlobalMalformedVersionException;
 import org.mozilla.gecko.sync.delegates.MetaGlobalDelegate;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 
 public class MetaGlobal implements SyncStorageRequestDelegate {
   private static final String LOG_TAG = "MetaGlobal";
   protected String metaURL;
-  protected String credentials;
 
   // Fields.
   protected ExtendedJSONObject  engines;
   protected Long                storageVersion;
   protected String              syncID;
 
   // Lookup tables.
   protected Map<String, String> syncIDs;
   protected Map<String, Integer> versions;
   protected Map<String, MetaGlobalException> exceptions;
 
   // Temporary location to store our callback.
   private MetaGlobalDelegate callback;
 
   // A little hack so we can use the same delegate implementation for upload and download.
   private boolean isUploading;
+  protected final AuthHeaderProvider authHeaderProvider;
 
-  public MetaGlobal(String metaURL, String credentials) {
-    this.metaURL     = metaURL;
-    this.credentials = credentials;
+  public MetaGlobal(String metaURL, AuthHeaderProvider authHeaderProvider) {
+    this.metaURL = metaURL;
+    this.authHeaderProvider = authHeaderProvider;
   }
 
   public void fetch(MetaGlobalDelegate delegate) {
     this.callback = delegate;
     try {
       this.isUploading = false;
       SyncStorageRecordRequest r = new SyncStorageRecordRequest(this.metaURL);
       r.delegate = this;
@@ -242,17 +243,22 @@ public class MetaGlobal implements SyncS
   }
 
   public void setSyncID(String syncID) {
     this.syncID = syncID;
   }
 
   // SyncStorageRequestDelegate methods for fetching.
   public String credentials() {
-    return this.credentials;
+    return null;
+  }
+
+  @Override
+  public AuthHeaderProvider getAuthHeaderProvider() {
+    return authHeaderProvider;
   }
 
   public String ifUnmodifiedSince() {
     return null;
   }
 
   public void handleRequestSuccess(SyncStorageResponse response) {
     if (this.isUploading) {
--- a/mobile/android/base/sync/PersistedMetaGlobal.java
+++ b/mobile/android/base/sync/PersistedMetaGlobal.java
@@ -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/. */
 
 package org.mozilla.gecko.sync;
 
 import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.CryptoRecord;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 
 import android.content.SharedPreferences;
 
 public class PersistedMetaGlobal {
   public static final String LOG_TAG = "PersistedMetaGlobal";
 
   public static final String META_GLOBAL_SERVER_RESPONSE_BODY = "metaGlobalServerResponseBody";
   public static final String META_GLOBAL_LAST_MODIFIED        = "metaGlobalLastModified";
@@ -27,25 +27,25 @@ public class PersistedMetaGlobal {
    * @param metaUrl
    *          meta/global server URL
    * @param credentials
    *          Sync credentials
    *
    * @return <MetaGlobal> set from previously fetched meta/global record from
    *         server
    */
-  public MetaGlobal metaGlobal(String metaUrl, String credentials) {
+  public MetaGlobal metaGlobal(String metaUrl, AuthHeaderProvider authHeaderProvider) {
     String json = prefs.getString(META_GLOBAL_SERVER_RESPONSE_BODY, null);
     if (json == null) {
       return null;
     }
     MetaGlobal metaGlobal = null;
     try {
       CryptoRecord cryptoRecord = CryptoRecord.fromJSONRecord(json);
-      MetaGlobal mg = new MetaGlobal(metaUrl, credentials);
+      MetaGlobal mg = new MetaGlobal(metaUrl, authHeaderProvider);
       mg.setFromRecord(cryptoRecord);
       metaGlobal = mg;
     } catch (Exception e) {
       Logger.warn(LOG_TAG, "Got exception decrypting persisted meta/global.", e);
     }
     return metaGlobal;
   }
 
--- a/mobile/android/base/sync/SyncConfiguration.java
+++ b/mobile/android/base/sync/SyncConfiguration.java
@@ -11,22 +11,23 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.crypto.PersistedCrypto5Keys;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
 
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 
-public class SyncConfiguration implements CredentialsSource {
+public class SyncConfiguration {
 
   public class EditorBranch implements Editor {
 
     private String prefix;
     private Editor editor;
 
     public EditorBranch(SyncConfiguration config, String prefix) {
       if (!prefix.endsWith(".")) {
@@ -174,28 +175,27 @@ public class SyncConfiguration implement
     }
   }
 
   public static final String DEFAULT_USER_API = "https://auth.services.mozilla.com/user/1.0/";
 
   private static final String LOG_TAG = "SyncConfiguration";
 
   // These must be set in GlobalSession's constructor.
-  public String          userAPI;
   public URI             serverURL;
   public URI             clusterURL;
-  public String          username;
   public KeyBundle       syncKeyBundle;
 
   public CollectionKeys  collectionKeys;
   public InfoCollections infoCollections;
   public MetaGlobal      metaGlobal;
-  public String          password;
   public String          syncID;
 
+  protected final String username;
+
   /**
    * Persisted collection of enabledEngineNames.
    * <p>
    * Can contain engines Android Sync is not currently aware of, such as "prefs"
    * or "addons".
    * <p>
    * Copied from latest downloaded meta/global record and used to generate a
    * fresh meta/global record for upload.
@@ -238,16 +238,18 @@ public class SyncConfiguration implement
   public long userSelectedEnginesTimestamp;
 
   // Fields that maintain a reference to a SharedPreferences instance, used for
   // persistence.
   // Behavior is undefined if the PrefsSource is switched out in flight.
   public String          prefsPath;
   public PrefsSource     prefsSource;
 
+  protected final AuthHeaderProvider authHeaderProvider;
+
   public static final String PREF_PREFS_VERSION = "prefs.version";
   public static final long CURRENT_PREFS_VERSION = 1;
 
   public static final String CLIENTS_COLLECTION_TIMESTAMP = "serverClientsTimestamp";  // When the collection was touched.
   public static final String CLIENT_RECORD_TIMESTAMP = "serverClientRecordTimestamp";  // When our record was touched.
 
   public static final String PREF_CLUSTER_URL = "clusterURL";
   public static final String PREF_SYNC_ID = "syncID";
@@ -262,17 +264,19 @@ public class SyncConfiguration implement
   public static final String PREF_ACCOUNT_GUID = "account.guid";
   public static final String PREF_CLIENT_NAME = "account.clientName";
   public static final String PREF_NUM_CLIENTS = "account.numClients";
 
   /**
    * Create a new SyncConfiguration instance. Pass in a PrefsSource to
    * provide access to preferences.
    */
-  public SyncConfiguration(String prefsPath, PrefsSource prefsSource) {
+  public SyncConfiguration(String username, AuthHeaderProvider authHeaderProvider, String prefsPath, PrefsSource prefsSource) {
+    this.username = username;
+    this.authHeaderProvider = authHeaderProvider;
     this.prefsPath   = prefsPath;
     this.prefsSource = prefsSource;
     this.loadFromPrefs(getPrefs());
   }
 
   public SharedPreferences getPrefs() {
     Logger.trace(LOG_TAG, "Returning prefs for " + prefsPath);
     return prefsSource.getPrefs(prefsPath, Utils.SHARED_PREFERENCES_MODE);
@@ -432,19 +436,18 @@ public class SyncConfiguration implement
       edit.remove(PREF_USER_SELECTED_ENGINES_TO_SYNC_TIMESTAMP);
     }
     // Don't bother saving userSelectedEngines - these should only be changed by
     // SelectEnginesActivity.
     edit.commit();
     // TODO: keys.
   }
 
-  @Override
-  public String credentials() {
-    return username + ":" + password;
+  public AuthHeaderProvider getAuthHeaderProvider() {
+    return authHeaderProvider;
   }
 
   public CollectionKeys getCollectionKeys() {
     return collectionKeys;
   }
 
   public void setCollectionKeys(CollectionKeys k) {
     collectionKeys = k;
@@ -473,46 +476,50 @@ public class SyncConfiguration implement
     return infoBaseURL() + "collections";
   }
 
   public String infoCollectionCountsURL() {
     return infoBaseURL() + "collection_counts";
   }
 
   public String metaURL() {
-    return clusterURL + GlobalSession.API_VERSION + "/" + username + "/storage/meta/global";
+    return storageURL() + "/meta/global";
   }
 
-  public String storageURL(boolean trailingSlash) {
-    return clusterURL + GlobalSession.API_VERSION + "/" + username +
-           (trailingSlash ? "/storage/" : "/storage");
+  /**
+   * Return path to storage endpoint without trailing slash.
+   *
+   * @return storage endpoint without trailing slash.
+   */
+  public String storageURL() {
+    return clusterURL + GlobalSession.API_VERSION + "/" + username + "/storage";
   }
 
   public URI collectionURI(String collection) throws URISyntaxException {
-    return new URI(storageURL(true) + collection);
+    return new URI(storageURL() + "/" + collection);
   }
 
   public URI collectionURI(String collection, boolean full) throws URISyntaxException {
     // Do it this way to make it easier to add more params later.
     // It's pretty ugly, I'll grant.
     boolean anyParams = full;
     String  uriParams = "";
     if (anyParams) {
       StringBuilder params = new StringBuilder("?");
       if (full) {
         params.append("full=1");
       }
       uriParams = params.toString();
     }
-    String uri = storageURL(true) + collection + uriParams;
+    String uri = storageURL() + "/" + collection + uriParams;
     return new URI(uri);
   }
 
   public URI wboURI(String collection, String id) throws URISyntaxException {
-    return new URI(storageURL(true) + collection + "/" + id);
+    return new URI(storageURL() + "/" + collection + "/" + id);
   }
 
   public URI keysURI() throws URISyntaxException {
     return wboURI("crypto", "keys");
   }
 
   public URI getClusterURL() {
     return clusterURL;
--- a/mobile/android/base/sync/config/ClientRecordTerminator.java
+++ b/mobile/android/base/sync/config/ClientRecordTerminator.java
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.config;
 
 import java.net.URI;
 
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.GlobalSession;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 
 /**
  * Bug 770785: when an Android Account is deleted, we need to (try to) delete
  * the associated client GUID from the server's clients table.
@@ -22,31 +23,31 @@ import org.mozilla.gecko.sync.net.SyncSt
 public class ClientRecordTerminator {
   public static final String LOG_TAG = "ClientRecTerminator";
 
   protected ClientRecordTerminator() {
     super(); // Stop this class from being instantiated.
   }
 
   public static void deleteClientRecord(final String username,
-      final String password,
       final String clusterURL,
-      final String clientGuid)
+      final String clientGuid,
+      final AuthHeaderProvider authHeaderProvider)
     throws Exception {
 
     // Would prefer to delegate to SyncConfiguration, but that would proliferate static methods.
     final String collection = "clients";
     final URI wboURI = new URI(clusterURL + GlobalSession.API_VERSION + "/" + username + "/storage/" + collection + "/" + clientGuid);
 
     // Would prefer to break this out into a self-contained client library.
     final SyncStorageRecordRequest r = new SyncStorageRecordRequest(wboURI);
     r.delegate = new SyncStorageRequestDelegate() {
       @Override
-      public String credentials() {
-        return username + ":" + password;
+      public AuthHeaderProvider getAuthHeaderProvider() {
+        return authHeaderProvider;
       }
 
       @Override
       public String ifUnmodifiedSince() {
         return null;
       }
 
       @Override
--- a/mobile/android/base/sync/net/SyncStorageRequest.java
+++ b/mobile/android/base/sync/net/SyncStorageRequest.java
@@ -87,22 +87,17 @@ public class SyncStorageRequest implemen
 
     SyncStorageResourceDelegate(SyncStorageRequest request) {
       super(request);
       this.request = request;
     }
 
     @Override
     public AuthHeaderProvider getAuthHeaderProvider() {
-      String credentials = request.delegate.credentials();
-      if (credentials == null) {
-        return null;
-      }
-
-      return new BasicAuthHeaderProvider(credentials);
+      return request.delegate.getAuthHeaderProvider();
     }
 
     @Override
     public void handleHttpResponse(HttpResponse response) {
       Logger.debug(LOG_TAG, "SyncStorageResourceDelegate handling response: " + response.getStatusLine() + ".");
       SyncStorageRequestDelegate d = this.request.delegate;
       SyncStorageResponse res = new SyncStorageResponse(response);
       // It is the responsibility of the delegate handlers to completely consume the response.
--- a/mobile/android/base/sync/net/SyncStorageRequestDelegate.java
+++ b/mobile/android/base/sync/net/SyncStorageRequestDelegate.java
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.net;
 
 public interface SyncStorageRequestDelegate {
-  String credentials();
+  public AuthHeaderProvider getAuthHeaderProvider();
+
   String ifUnmodifiedSince();
 
   // TODO: at this point we can access X-Weave-Timestamp, compare
   // that to our local timestamp, and compute an estimate of clock
   // skew. Bug 721887.
 
   /**
    * Override this to handle a successful SyncStorageRequest.
--- a/mobile/android/base/sync/receivers/SyncAccountDeletedService.java
+++ b/mobile/android/base/sync/receivers/SyncAccountDeletedService.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko.sync.receivers
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.background.common.GlobalConstants;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.config.AccountPickler;
 import org.mozilla.gecko.sync.config.ClientRecordTerminator;
+import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
 
 import android.accounts.AccountManager;
 import android.app.IntentService;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -124,15 +125,15 @@ public class SyncAccountDeletedService e
     }
 
     if (clusterURL == null) {
       Logger.warn(LOG_TAG, "Cluster URL was null; not deleting client record from server.");
       return;
     }
 
     try {
-      ClientRecordTerminator.deleteClientRecord(encodedUsername, password, clusterURL, clientGuid);
+      ClientRecordTerminator.deleteClientRecord(encodedUsername, clusterURL, clientGuid, new BasicAuthHeaderProvider(encodedUsername, password));
     } catch (Exception e) {
       // This should never happen, but we really don't want to die in a background thread.
       Logger.warn(LOG_TAG, "Got exception deleting client record from server; ignoring.", e);
     }
   }
 }
--- a/mobile/android/base/sync/repositories/ConstrainedServer11Repository.java
+++ b/mobile/android/base/sync/repositories/ConstrainedServer11Repository.java
@@ -1,32 +1,31 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories;
 
 import java.net.URISyntaxException;
 
-import org.mozilla.gecko.sync.CredentialsSource;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 
 /**
  * A kind of Server11Repository that supports explicit setting of limit and sort on operations.
  *
  * @author rnewman
  *
  */
 public class ConstrainedServer11Repository extends Server11Repository {
 
   private String sort = null;
   private long limit  = -1;
 
-  public ConstrainedServer11Repository(String serverURI, String username, String collection, CredentialsSource credentialsSource, long limit, String sort) throws URISyntaxException {
-    super(serverURI, username, collection, credentialsSource);
-
+  public ConstrainedServer11Repository(String collection, String storageURL, AuthHeaderProvider authHeaderProvider, long limit, String sort) throws URISyntaxException {
+    super(collection, storageURL, authHeaderProvider);
     this.limit = limit;
     this.sort  = sort;
   }
 
   @Override
   protected String getDefaultSort() {
     return sort;
   }
--- a/mobile/android/base/sync/repositories/Server11Repository.java
+++ b/mobile/android/base/sync/repositories/Server11Repository.java
@@ -3,66 +3,56 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.repositories;
 
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 
-import org.mozilla.gecko.sync.CredentialsSource;
 import org.mozilla.gecko.sync.Utils;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 
 import android.content.Context;
 
 /**
  * A Server11Repository implements fetching and storing against the Sync 1.1 API.
  * It doesn't do crypto: that's the job of the middleware.
  *
  * @author rnewman
  */
 public class Server11Repository extends Repository {
-
-  private String serverURI;
-  private String username;
   protected String collection;
-  private String collectionPath;
-  private URI collectionPathURI;
-  public CredentialsSource credentialsSource;
+  protected URI collectionURI;
+  protected final AuthHeaderProvider authHeaderProvider;
   public static final String VERSION_PATH_FRAGMENT = "1.1/";
 
   /**
+   * Construct a new repository that fetches and stores against the Sync 1.1. API.
    *
-   * @param serverURI
-   *        URI of the Sync 1.1 server (string)
-   * @param username
-   *        Username on the server (string)
-   * @param collection
-   *        Name of the collection (string)
+   * @param collection name.
+   * @param storageURL full URL to storage endpoint.
+   * @param authHeaderProvider to use in requests.
    * @throws URISyntaxException
    */
-  public Server11Repository(String serverURI, String username, String collection, CredentialsSource credentialsSource) throws URISyntaxException {
-    this.serverURI  = serverURI;
-    this.username   = username;
+  public Server11Repository(String collection, String storageURL, AuthHeaderProvider authHeaderProvider) throws URISyntaxException {
     this.collection = collection;
-
-    this.collectionPath = this.serverURI + VERSION_PATH_FRAGMENT + this.username + "/storage/" + this.collection;
-    this.collectionPathURI = new URI(this.collectionPath);
-    this.credentialsSource = credentialsSource;
+    this.collectionURI = new URI(storageURL + (storageURL.endsWith("/") ? collection : "/" + collection));
+    this.authHeaderProvider = authHeaderProvider;
   }
 
   @Override
   public void createSession(RepositorySessionCreationDelegate delegate,
                             Context context) {
     delegate.onSessionCreated(new Server11RepositorySession(this));
   }
 
   public URI collectionURI() {
-    return this.collectionPathURI;
+    return this.collectionURI;
   }
 
   public URI collectionURI(boolean full, long newer, long limit, String sort, String ids) throws URISyntaxException {
     ArrayList<String> params = new ArrayList<String>();
     if (full) {
       params.add("full=1");
     }
     if (newer >= 0) {
@@ -76,37 +66,41 @@ public class Server11Repository extends 
     if (sort != null) {
       params.add("sort=" + sort);       // We trust these values.
     }
     if (ids != null) {
       params.add("ids=" + ids);         // We trust these values.
     }
 
     if (params.size() == 0) {
-      return this.collectionPathURI;
+      return this.collectionURI;
     }
 
     StringBuilder out = new StringBuilder();
     char indicator = '?';
     for (String param : params) {
       out.append(indicator);
       indicator = '&';
       out.append(param);
     }
-    String uri = this.collectionPath + out.toString();
+    String uri = this.collectionURI + out.toString();
     return new URI(uri);
   }
 
   public URI wboURI(String id) throws URISyntaxException {
-    return new URI(this.collectionPath + "/" + id);
+    return new URI(this.collectionURI + "/" + id);
   }
 
   // Override these.
   @SuppressWarnings("static-method")
   protected long getDefaultFetchLimit() {
     return -1;
   }
 
   @SuppressWarnings("static-method")
   protected String getDefaultSort() {
     return null;
   }
+
+  public AuthHeaderProvider getAuthHeaderProvider() {
+    return authHeaderProvider;
+  }
 }
--- a/mobile/android/base/sync/repositories/Server11RepositorySession.java
+++ b/mobile/android/base/sync/repositories/Server11RepositorySession.java
@@ -20,16 +20,17 @@ import org.mozilla.gecko.background.comm
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.DelayedWorkTracker;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.HTTPFailureException;
 import org.mozilla.gecko.sync.Server11PreviousPostFailedException;
 import org.mozilla.gecko.sync.Server11RecordPostFailedException;
 import org.mozilla.gecko.sync.UnexpectedJSONException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.SyncStorageCollectionRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 import org.mozilla.gecko.sync.net.WBOCollectionRequestDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionBeginDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionFetchRecordsDelegate;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionGuidsSinceDelegate;
@@ -130,18 +131,18 @@ public class Server11RepositorySession e
       this.request = null;
     }
 
     public RequestFetchDelegateAdapter(RepositorySessionFetchRecordsDelegate delegate) {
       this.delegate = delegate;
     }
 
     @Override
-    public String credentials() {
-      return serverRepository.credentialsSource.credentials();
+    public AuthHeaderProvider getAuthHeaderProvider() {
+      return serverRepository.getAuthHeaderProvider();
     }
 
     @Override
     public String ifUnmodifiedSince() {
       return null;
     }
 
     @Override
@@ -437,18 +438,18 @@ public class Server11RepositorySession e
                   outgoing.size() + " records (" +
                   byteCount + " bytes).");
       this.outgoing = outgoing;
       this.outgoingGuids = outgoingGuids;
       this.byteCount = byteCount;
     }
 
     @Override
-    public String credentials() {
-      return serverRepository.credentialsSource.credentials();
+    public AuthHeaderProvider getAuthHeaderProvider() {
+      return serverRepository.getAuthHeaderProvider();
     }
 
     @Override
     public String ifUnmodifiedSince() {
       return null;
     }
 
     @Override
--- a/mobile/android/base/sync/stage/AndroidBrowserBookmarksServerSyncStage.java
+++ b/mobile/android/base/sync/stage/AndroidBrowserBookmarksServerSyncStage.java
@@ -3,16 +3,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.stage;
 
 import java.net.URISyntaxException;
 
 import org.mozilla.gecko.sync.JSONRecordFetcher;
 import org.mozilla.gecko.sync.MetaGlobalException;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.repositories.RecordFactory;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.android.AndroidBrowserBookmarksRepository;
 import org.mozilla.gecko.sync.repositories.domain.BookmarkRecordFactory;
 import org.mozilla.gecko.sync.repositories.domain.VersionConstants;
 
 public class AndroidBrowserBookmarksServerSyncStage extends ServerSyncStage {
   protected static final String LOG_TAG = "BookmarksStage";
@@ -36,21 +37,23 @@ public class AndroidBrowserBookmarksServ
   public Integer getStorageVersion() {
     return VersionConstants.BOOKMARKS_ENGINE_VERSION;
   }
 
   @Override
   protected Repository getRemoteRepository() throws URISyntaxException {
     // If this is a first sync, we need to check server counts to make sure that we aren't
     // going to screw up. SafeConstrainedServer11Repository does this. See Bug 814331.
-    final JSONRecordFetcher countsFetcher = new JSONRecordFetcher(session.config.infoCollectionCountsURL(), session.credentials());
-    return new SafeConstrainedServer11Repository(session.config.getClusterURLString(),
-                                                 session.config.username,
-                                                 getCollection(),
-                                                 session,
+    AuthHeaderProvider authHeaderProvider = session.getAuthHeaderProvider();
+    final JSONRecordFetcher countsFetcher = new JSONRecordFetcher(session.config.infoCollectionCountsURL(), authHeaderProvider);
+    String collection = getCollection();
+    return new SafeConstrainedServer11Repository(
+                                                 collection,
+                                                 session.config.storageURL(),
+                                                 session.getAuthHeaderProvider(),
                                                  BOOKMARKS_REQUEST_LIMIT,
                                                  BOOKMARKS_SORT,
                                                  countsFetcher);
   }
 
   @Override
   protected Repository getLocalRepository() {
     return new AndroidBrowserBookmarksRepository();
--- a/mobile/android/base/sync/stage/AndroidBrowserHistoryServerSyncStage.java
+++ b/mobile/android/base/sync/stage/AndroidBrowserHistoryServerSyncStage.java
@@ -39,20 +39,21 @@ public class AndroidBrowserHistoryServer
 
   @Override
   protected Repository getLocalRepository() {
     return new AndroidBrowserHistoryRepository();
   }
 
   @Override
   protected Repository getRemoteRepository() throws URISyntaxException {
-    return new ConstrainedServer11Repository(session.config.getClusterURLString(),
-                                             session.config.username,
-                                             getCollection(),
-                                             session,
+    String collection = getCollection();
+    return new ConstrainedServer11Repository(
+                                             collection,
+                                             session.config.storageURL(),
+                                             session.getAuthHeaderProvider(),
                                              HISTORY_REQUEST_LIMIT,
                                              HISTORY_SORT);
   }
 
   @Override
   protected RecordFactory getRecordFactory() {
     return new HistoryRecordFactory();
   }
--- a/mobile/android/base/sync/stage/EnsureCrypto5KeysStage.java
+++ b/mobile/android/base/sync/stage/EnsureCrypto5KeysStage.java
@@ -11,16 +11,17 @@ import java.util.Set;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.sync.CollectionKeys;
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.InfoCollections;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.crypto.PersistedCrypto5Keys;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 
 public class EnsureCrypto5KeysStage
 extends AbstractNonRepositorySyncStage
 implements SyncStorageRequestDelegate {
 
@@ -58,18 +59,18 @@ implements SyncStorageRequestDelegate {
       request.delegate = this;
       request.get();
     } catch (URISyntaxException e) {
       session.abort(e, "Invalid URI.");
     }
   }
 
   @Override
-  public String credentials() {
-    return session.credentials();
+  public AuthHeaderProvider getAuthHeaderProvider() {
+    return session.getAuthHeaderProvider();
   }
 
   @Override
   public String ifUnmodifiedSince() {
     // TODO: last key time!
     return null;
   }
 
--- a/mobile/android/base/sync/stage/FetchMetaGlobalStage.java
+++ b/mobile/android/base/sync/stage/FetchMetaGlobalStage.java
@@ -57,23 +57,23 @@ public class FetchMetaGlobalStage extend
       session.abort(null, "No info/collections set in FetchMetaGlobalStage.");
       return;
     }
 
     long lastModified = session.config.persistedMetaGlobal().lastModified();
     if (!infoCollections.updateNeeded(META_COLLECTION, lastModified)) {
       // Try to use our local collection keys for this session.
       Logger.info(LOG_TAG, "Trying to use persisted meta/global for this session.");
-      MetaGlobal global = session.config.persistedMetaGlobal().metaGlobal(session.config.metaURL(), session.credentials());
+      MetaGlobal global = session.config.persistedMetaGlobal().metaGlobal(session.config.metaURL(), session.getAuthHeaderProvider());
       if (global != null) {
         Logger.info(LOG_TAG, "Using persisted meta/global for this session.");
         session.processMetaGlobal(global); // Calls session.advance().
         return;
       }
       Logger.info(LOG_TAG, "Failed to use persisted meta/global for this session.");
     }
 
     // We need an update: fetch or upload meta/global as necessary.
     Logger.info(LOG_TAG, "Fetching fresh meta/global for this session.");
-    MetaGlobal global = new MetaGlobal(session.config.metaURL(), session.credentials());
+    MetaGlobal global = new MetaGlobal(session.config.metaURL(), session.getAuthHeaderProvider());
     global.fetch(new StageMetaGlobalDelegate(session));
   }
 }
--- a/mobile/android/base/sync/stage/FormHistoryServerSyncStage.java
+++ b/mobile/android/base/sync/stage/FormHistoryServerSyncStage.java
@@ -34,20 +34,21 @@ public class FormHistoryServerSyncStage 
 
   @Override
   public Integer getStorageVersion() {
     return VersionConstants.FORMS_ENGINE_VERSION;
   }
 
   @Override
   protected Repository getRemoteRepository() throws URISyntaxException {
-    return new ConstrainedServer11Repository(session.config.getClusterURLString(),
-                                             session.config.username,
-                                             getCollection(),
-                                             session,
+    String collection = getCollection();
+    return new ConstrainedServer11Repository(
+                                             collection,
+                                             session.config.storageURL(),
+                                             session.getAuthHeaderProvider(),
                                              FORM_HISTORY_REQUEST_LIMIT,
                                              FORM_HISTORY_SORT);
   }
 
   @Override
   protected Repository getLocalRepository() {
     return new FormHistoryRepositorySession.FormHistoryRepository();
   }
--- a/mobile/android/base/sync/stage/SafeConstrainedServer11Repository.java
+++ b/mobile/android/base/sync/stage/SafeConstrainedServer11Repository.java
@@ -2,19 +2,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.sync.stage;
 
 import java.net.URISyntaxException;
 
 import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.CredentialsSource;
 import org.mozilla.gecko.sync.InfoCounts;
 import org.mozilla.gecko.sync.JSONRecordFetcher;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.repositories.ConstrainedServer11Repository;
 import org.mozilla.gecko.sync.repositories.Repository;
 import org.mozilla.gecko.sync.repositories.Server11RepositorySession;
 import org.mozilla.gecko.sync.repositories.delegates.RepositorySessionCreationDelegate;
 
 import android.content.Context;
 
 /**
@@ -27,25 +27,24 @@ import android.content.Context;
  *
  * "First sync" means that our sync timestamp is not greater than zero.
  */
 public class SafeConstrainedServer11Repository extends ConstrainedServer11Repository {
 
   // This can be lazily evaluated if we need it.
   private JSONRecordFetcher countFetcher;
 
-  public SafeConstrainedServer11Repository(String serverURI,
-                                           String username,
-                                           String collection,
-                                           CredentialsSource credentialsSource,
+  public SafeConstrainedServer11Repository(String collection,
+                                           String storageURL,
+                                           AuthHeaderProvider authHeaderProvider,
                                            long limit,
                                            String sort,
                                            JSONRecordFetcher countFetcher)
     throws URISyntaxException {
-    super(serverURI, username, collection, credentialsSource, limit, sort);
+    super(collection, storageURL, authHeaderProvider, limit, sort);
     this.countFetcher = countFetcher;
   }
 
   @Override
   public void createSession(RepositorySessionCreationDelegate delegate,
                             Context context) {
     delegate.onSessionCreated(new CountCheckingServer11RepositorySession(this, this.getDefaultFetchLimit()));
   }
--- a/mobile/android/base/sync/stage/ServerSyncStage.java
+++ b/mobile/android/base/sync/stage/ServerSyncStage.java
@@ -6,28 +6,28 @@ package org.mozilla.gecko.sync.stage;
 
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
 
 import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.CredentialsSource;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.HTTPFailureException;
 import org.mozilla.gecko.sync.MetaGlobalException;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.WipeServerDelegate;
 import org.mozilla.gecko.sync.middleware.Crypto5MiddlewareRepository;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.SyncStorageRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRequestDelegate;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 import org.mozilla.gecko.sync.repositories.InactiveSessionException;
 import org.mozilla.gecko.sync.repositories.InvalidSessionTransitionException;
 import org.mozilla.gecko.sync.repositories.RecordFactory;
 import org.mozilla.gecko.sync.repositories.Repository;
@@ -140,20 +140,20 @@ public abstract class ServerSyncStage ex
 
   protected abstract String getCollection();
   protected abstract String getEngineName();
   protected abstract Repository getLocalRepository();
   protected abstract RecordFactory getRecordFactory();
 
   // Override this in subclasses.
   protected Repository getRemoteRepository() throws URISyntaxException {
-    return new Server11Repository(session.config.getClusterURLString(),
-                                  session.config.username,
-                                  getCollection(),
-                                  session);
+    String collection = getCollection();
+    return new Server11Repository(collection,
+                                  session.config.storageURL(),
+                                  session.getAuthHeaderProvider());
   }
 
   /**
    * Return a Crypto5Middleware-wrapped Server11Repository.
    *
    * @throws NoCollectionKeysSetException
    * @throws URISyntaxException
    */
@@ -369,17 +369,17 @@ public abstract class ServerSyncStage ex
     }
 
     Logger.info(LOG_TAG, "Wiping stage complete.");
   }
 
   /**
    * Asynchronously wipe collection on server.
    */
-  protected void wipeServer(final CredentialsSource credentials, final WipeServerDelegate wipeDelegate) {
+  protected void wipeServer(final AuthHeaderProvider authHeaderProvider, final WipeServerDelegate wipeDelegate) {
     SyncStorageRequest request;
 
     try {
       request = new SyncStorageRequest(session.config.collectionURI(getCollection()));
     } catch (URISyntaxException ex) {
       Logger.warn(LOG_TAG, "Invalid URI in wipeServer.");
       wipeDelegate.onWipeFailed(ex);
       return;
@@ -410,18 +410,18 @@ public abstract class ServerSyncStage ex
 
       @Override
       public void handleRequestError(Exception ex) {
         Logger.warn(LOG_TAG, "Got exception in wipeServer.", ex);
         wipeDelegate.onWipeFailed(ex);
       }
 
       @Override
-      public String credentials() {
-        return credentials.credentials();
+      public AuthHeaderProvider getAuthHeaderProvider() {
+        return authHeaderProvider;
       }
     };
 
     request.delete();
   }
 
   /**
    * Synchronously wipe the server.
@@ -431,17 +431,17 @@ public abstract class ServerSyncStage ex
   public void wipeServer(final GlobalSession session) throws Exception {
     this.session = session;
 
     final WipeWaiter monitor = new WipeWaiter();
 
     final Runnable doWipe = new Runnable() {
       @Override
       public void run() {
-        wipeServer(session, new WipeServerDelegate() {
+        wipeServer(session.getAuthHeaderProvider(), new WipeServerDelegate() {
           @Override
           public void onWiped(long timestamp) {
             synchronized (monitor) {
               monitor.notify();
             }
           }
 
           @Override
--- a/mobile/android/base/sync/stage/SyncClientsEngineStage.java
+++ b/mobile/android/base/sync/stage/SyncClientsEngineStage.java
@@ -19,16 +19,17 @@ import org.mozilla.gecko.sync.CommandPro
 import org.mozilla.gecko.sync.CryptoRecord;
 import org.mozilla.gecko.sync.ExtendedJSONObject;
 import org.mozilla.gecko.sync.HTTPFailureException;
 import org.mozilla.gecko.sync.NoCollectionKeysSetException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BaseResource;
 import org.mozilla.gecko.sync.net.SyncStorageCollectionRequest;
 import org.mozilla.gecko.sync.net.SyncStorageRecordRequest;
 import org.mozilla.gecko.sync.net.SyncStorageResponse;
 import org.mozilla.gecko.sync.net.WBOCollectionRequestDelegate;
 import org.mozilla.gecko.sync.net.WBORequestDelegate;
 import org.mozilla.gecko.sync.repositories.NullCursorException;
 import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
@@ -91,18 +92,18 @@ public class SyncClientsEngineStage exte
    */
   public class ClientDownloadDelegate extends WBOCollectionRequestDelegate {
 
     // We use this on each WBO, so lift it out.
     final ClientsDataDelegate clientsDelegate = session.getClientsDelegate();
     boolean localAccountGUIDDownloaded = false;
 
     @Override
-    public String credentials() {
-      return session.credentials();
+    public AuthHeaderProvider getAuthHeaderProvider() {
+      return session.getAuthHeaderProvider();
     }
 
     @Override
     public String ifUnmodifiedSince() {
       // TODO last client download time?
       return null;
     }
 
@@ -210,18 +211,18 @@ public class SyncClientsEngineStage exte
   }
 
   public class ClientUploadDelegate extends WBORequestDelegate {
     protected static final String LOG_TAG = "ClientUploadDelegate";
     public Long currentlyUploadingRecordTimestamp;
     public boolean currentlyUploadingLocalRecord;
 
     @Override
-    public String credentials() {
-      return session.credentials();
+    public AuthHeaderProvider getAuthHeaderProvider() {
+      return session.getAuthHeaderProvider();
     }
 
     private void setUploadDetails(boolean isLocalRecord) {
       // Use the timestamp for the whole collection per Sync storage 1.1 spec.
       currentlyUploadingRecordTimestamp = session.config.getPersistedServerClientsTimestamp();
       currentlyUploadingLocalRecord = isLocalRecord;
     }
 
--- a/mobile/android/base/sync/syncadapter/SyncAdapter.java
+++ b/mobile/android/base/sync/syncadapter/SyncAdapter.java
@@ -5,34 +5,36 @@
 package org.mozilla.gecko.sync.syncadapter;
 
 import java.io.IOException;
 import java.net.URI;
 import java.security.NoSuchAlgorithmException;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.json.simple.parser.ParseException;
+import org.mozilla.gecko.background.common.GlobalConstants;
+import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.sync.AlreadySyncingException;
 import org.mozilla.gecko.sync.CredentialException;
-import org.mozilla.gecko.background.common.GlobalConstants;
-import org.mozilla.gecko.background.common.log.Logger;
-import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.NonObjectJSONException;
 import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
+import org.mozilla.gecko.sync.SyncConstants;
 import org.mozilla.gecko.sync.SyncException;
 import org.mozilla.gecko.sync.ThreadPool;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.sync.config.AccountPickler;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
+import org.mozilla.gecko.sync.net.AuthHeaderProvider;
+import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 import org.mozilla.gecko.sync.net.ConnectionMonitorThread;
 import org.mozilla.gecko.sync.setup.Constants;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
 import org.mozilla.gecko.sync.stage.GlobalSyncStage.Stage;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
@@ -497,18 +499,18 @@ public class SyncAdapter extends Abstrac
         }
       });
     } catch (IllegalArgumentException e) {
       // Do nothing.
     }
 
     // TODO: default serverURL.
     final KeyBundle keyBundle = new KeyBundle(username, syncKey);
-    GlobalSession globalSession = new GlobalSession(SyncConfiguration.DEFAULT_USER_API,
-                                                    serverURL, username, password, prefsPath,
+    final AuthHeaderProvider authHeaderProvider = new BasicAuthHeaderProvider(username, password);
+    GlobalSession globalSession = new GlobalSession(serverURL, username, authHeaderProvider, prefsPath,
                                                     keyBundle, this, this.mContext, extras, this);
 
     globalSession.start();
   }
 
   private void notifyMonitor() {
     synchronized (syncMonitor) {
       Logger.trace(LOG_TAG, "Notifying sync monitor.");
--- a/mobile/android/tests/background/junit3/src/sync/TestClientsStage.java
+++ b/mobile/android/tests/background/junit3/src/sync/TestClientsStage.java
@@ -3,20 +3,20 @@
 
 package org.mozilla.gecko.background.sync;
 
 import org.json.simple.JSONArray;
 import org.mozilla.gecko.background.helpers.AndroidSyncTestCase;
 import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback;
 import org.mozilla.gecko.background.testhelpers.MockClientsDataDelegate;
 import org.mozilla.gecko.sync.GlobalSession;
-import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.ClientsDataDelegate;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
+import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 import org.mozilla.gecko.sync.repositories.android.ClientsDatabaseAccessor;
 import org.mozilla.gecko.sync.repositories.domain.ClientRecord;
 import org.mozilla.gecko.sync.stage.SyncClientsEngineStage;
 
 import android.content.Context;
 
 public class TestClientsStage extends AndroidSyncTestCase {
   private static final String TEST_USERNAME    = "johndoe";
@@ -36,19 +36,18 @@ public class TestClientsStage extends An
     // and remote timestamps, tracked failed records, and tracked records to fetch.
 
     final Context context = getApplicationContext();
     final ClientsDatabaseAccessor dataAccessor = new ClientsDatabaseAccessor(context);
     final GlobalSessionCallback callback = new DefaultGlobalSessionCallback();
     final ClientsDataDelegate delegate = new MockClientsDataDelegate();
 
     final GlobalSession session = new GlobalSession(
-        SyncConfiguration.DEFAULT_USER_API,
         null,
-        TEST_USERNAME, TEST_PASSWORD, null,
+        TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), null,
         new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY),
         callback, context, null, delegate);
 
     SyncClientsEngineStage stage = new SyncClientsEngineStage() {
 
       @Override
       public synchronized ClientsDatabaseAccessor getClientsDatabaseAccessor() {
         if (db == null) {
--- a/mobile/android/tests/background/junit3/src/sync/TestResetting.java
+++ b/mobile/android/tests/background/junit3/src/sync/TestResetting.java
@@ -11,22 +11,22 @@ import org.mozilla.gecko.background.test
 import org.mozilla.gecko.background.testhelpers.DefaultGlobalSessionCallback;
 import org.mozilla.gecko.background.testhelpers.MockRecord;
 import org.mozilla.gecko.background.testhelpers.WBORepository;
 import org.mozilla.gecko.background.testhelpers.WaitHelper;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.GlobalSession;
 import org.mozilla.gecko.sync.MetaGlobalException;
 import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.SynchronizerConfiguration;
 import org.mozilla.gecko.sync.crypto.CryptoException;
 import org.mozilla.gecko.sync.crypto.KeyBundle;
 import org.mozilla.gecko.sync.delegates.GlobalSessionCallback;
+import org.mozilla.gecko.sync.net.BasicAuthHeaderProvider;
 import org.mozilla.gecko.sync.repositories.domain.Record;
 import org.mozilla.gecko.sync.stage.NoSuchStageException;
 import org.mozilla.gecko.sync.synchronizer.Synchronizer;
 
 /**
  * Test the on-device side effects of reset operations on a stage.
  *
  * See also "TestResetCommands" in the unit test suite.
@@ -148,19 +148,18 @@ public class TestResetting extends Andro
           }
         }
       });
     }
   }
 
   private GlobalSession createDefaultGlobalSession(final GlobalSessionCallback callback) throws SyncConfigurationException, IllegalArgumentException, NonObjectJSONException, IOException, ParseException, CryptoException {
     return new GlobalSession(
-        SyncConfiguration.DEFAULT_USER_API,
         null,
-        TEST_USERNAME, TEST_PASSWORD, null,
+        TEST_USERNAME, new BasicAuthHeaderProvider(TEST_USERNAME, TEST_PASSWORD), null,
         new KeyBundle(TEST_USERNAME, TEST_SYNC_KEY),
         callback, getApplicationContext(), null, null) {
 
       @Override
       public boolean engineIsEnabled(String engineName,
                                      EngineSettings engineSettings)
         throws MetaGlobalException {
         return true;
--- a/mobile/android/tests/background/junit3/src/sync/TestSyncConfiguration.java
+++ b/mobile/android/tests/background/junit3/src/sync/TestSyncConfiguration.java
@@ -24,62 +24,62 @@ public class TestSyncConfiguration exten
   public SharedPreferences getPrefs(String name, int mode) {
     return this.getApplicationContext().getSharedPreferences(name, mode);
   }
 
   public void testEnabledEngineNames() {
     SyncConfiguration config = null;
     SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
 
-    config = new SyncConfiguration(TEST_PREFS_NAME, this);
+    config = newSyncConfiguration();
     config.enabledEngineNames = new HashSet<String>();
     config.enabledEngineNames.add("test1");
     config.enabledEngineNames.add("test2");
     config.persistToPrefs();
     assertTrue(prefs.contains(SyncConfiguration.PREF_ENABLED_ENGINE_NAMES));
-    config = new SyncConfiguration(TEST_PREFS_NAME, this);
+    config = newSyncConfiguration();
     Set<String> expected = new HashSet<String>();
     for (String name : new String[] { "test1", "test2" }) {
       expected.add(name);
     }
     assertEquals(expected, config.enabledEngineNames);
 
     config.enabledEngineNames = null;
     config.persistToPrefs();
     assertFalse(prefs.contains(SyncConfiguration.PREF_ENABLED_ENGINE_NAMES));
-    config = new SyncConfiguration(TEST_PREFS_NAME, this);
+    config = newSyncConfiguration();
     assertNull(config.enabledEngineNames);
   }
 
   public void testSyncID() {
     SyncConfiguration config = null;
     SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
 
-    config = new SyncConfiguration(TEST_PREFS_NAME, this);
+    config = newSyncConfiguration();
     config.syncID = "test1";
     config.persistToPrefs();
     assertTrue(prefs.contains(SyncConfiguration.PREF_SYNC_ID));
-    config = new SyncConfiguration(TEST_PREFS_NAME, this);
+    config = newSyncConfiguration();
     assertEquals("test1", config.syncID);
   }
 
   public void testStoreSelectedEnginesToPrefs() {
     SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
     // Store engines, excluding history/forms special case.
     Map<String, Boolean> expectedEngines = new HashMap<String, Boolean>();
     expectedEngines.put("test1", true);
     expectedEngines.put("test2", false);
     expectedEngines.put("test3", true);
 
     SyncConfiguration.storeSelectedEnginesToPrefs(prefs, expectedEngines);
 
     // Read values from selectedEngines.
     assertTrue(prefs.contains(SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC));
     SyncConfiguration config = null;
-    config = new SyncConfiguration(TEST_PREFS_NAME, this);
+    config = newSyncConfiguration();
     config.loadFromPrefs(prefs);
     assertEquals(expectedEngines, config.userSelectedEngines);
   }
 
   /**
    * Tests dependency of forms engine on history engine.
    */
   public void testSelectedEnginesHistoryAndForms() {
@@ -90,30 +90,34 @@ public class TestSyncConfiguration exten
 
     SyncConfiguration.storeSelectedEnginesToPrefs(prefs, storedEngines);
 
     // Expected engines.
     storedEngines.put("forms", true);
     // Read values from selectedEngines.
     assertTrue(prefs.contains(SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC));
     SyncConfiguration config = null;
-    config = new SyncConfiguration(TEST_PREFS_NAME, this);
+    config = newSyncConfiguration();
     config.loadFromPrefs(prefs);
     assertEquals(storedEngines, config.userSelectedEngines);
   }
 
   public void testsSelectedEnginesNoHistoryNorForms() {
     SharedPreferences prefs = getPrefs(TEST_PREFS_NAME, 0);
     // Store engines, excluding history/forms special case.
     Map<String, Boolean> storedEngines = new HashMap<String, Boolean>();
     storedEngines.put("forms", true);
 
     SyncConfiguration.storeSelectedEnginesToPrefs(prefs, storedEngines);
 
     // Read values from selectedEngines.
     assertTrue(prefs.contains(SyncConfiguration.PREF_USER_SELECTED_ENGINES_TO_SYNC));
     SyncConfiguration config = null;
-    config = new SyncConfiguration(TEST_PREFS_NAME, this);
+    config = newSyncConfiguration();
     config.loadFromPrefs(prefs);
     // Forms should not be selected if history is not present.
     assertTrue(config.userSelectedEngines.isEmpty());
   }
+
+  protected SyncConfiguration newSyncConfiguration() {
+    return new SyncConfiguration(null, null, TEST_PREFS_NAME, this);
+  }
 }
--- a/mobile/android/tests/background/junit3/src/testhelpers/MockGlobalSession.java
+++ b/mobile/android/tests/background/junit3/src/testhelpers/MockGlobalSession.java
@@ -4,31 +4,30 @@
 package org.mozilla.gecko.background.testhelpers;
 
 import java.io.IOException;
 import java.util.HashMap;
 
 import org.json.simple.parser.ParseException;
 import org.mozilla.gecko.sync.EngineSettings;
 import org.mozilla.gecko.sync.NonObjectJSONException;
-import org.mozilla.gecko.sync.SyncConfiguration;
 import org.mozilla.gecko.sync.SyncConfigurationException;
 import org.mozilla.gecko.sync.c