Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 26 Feb 2014 16:42:16 -0500
changeset 170800 6b08917b4d2fef32a7de9b4110ed348375cc0a82
parent 170716 8bc0fba339392c010b4c2ae2bf5f9f370ad39cd3 (current diff)
parent 170799 bb9edb4d5144d414e355b8d09a74c94ba57096bf (diff)
child 170801 0a61ab3b106c04d0e2062cf852f76deb05ff139f
push id40306
push userryanvm@gmail.com
push dateWed, 26 Feb 2014 21:42:00 +0000
treeherdermozilla-inbound@6b08917b4d2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone30.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 m-c to inbound.
browser/devtools/shared/event-emitter.js
browser/devtools/shared/test/browser_eventemitter_basic.js
configure.in
services/common/hawk.js
services/common/tests/unit/test_hawk.js
widget/gonk/nativewindow/GonkBufferQueue.cpp
widget/gonk/nativewindow/GonkConsumerBase.cpp
widget/gonk/nativewindow/GonkConsumerBase.h
--- a/b2g/config/emulator-ics/config.json
+++ b/b2g/config/emulator-ics/config.json
@@ -1,13 +1,13 @@
 {
     "config_version": 2,
     "tooltool_manifest": "releng-emulator-ics.tt",
     "mock_target": "mozilla-centos6-x86_64",
-    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git"],
+    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git", "libxml2"],
     "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
     "build_targets": ["droid", "package-emulator", "package-tests"],
     "upload_files": [
         "{workdir}/out/target/product/generic/*.tar.bz2",
         "{workdir}/out/target/product/generic/tests/*.zip",
         "{workdir}/out/emulator.tar.gz",
         "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
         "{workdir}/sources.xml"
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -1,29 +1,36 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/b2g-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2gmozilla"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -1,25 +1,31 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator/config.json
+++ b/b2g/config/emulator/config.json
@@ -1,13 +1,13 @@
 {
     "config_version": 2,
     "tooltool_manifest": "releng-emulator.tt",
     "mock_target": "mozilla-centos6-x86_64",
-    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git"],
+    "mock_packages": ["ccache", "make", "bison", "flex", "gcc", "g++", "mpfr", "zlib-devel", "ncurses-devel", "zip", "autoconf213", "glibc-static", "perl-Digest-SHA", "wget", "alsa-lib", "atk", "cairo", "dbus-glib", "fontconfig", "freetype", "glib2", "gtk2", "libXRender", "libXt", "pango", "mozilla-python27-mercurial", "openssh-clients", "nss-devel", "glibc-devel.i686", "libstdc++.i686", "zlib-devel.i686", "ncurses-devel.i686", "libX11-devel.i686", "mesa-libGL-devel.i686", "mesa-libGL-devel", "libX11-devel", "git", "libxml2"],
     "mock_files": [["/home/cltbld/.ssh", "/home/mock_mozilla/.ssh"]],
     "build_targets": ["droid", "package-emulator", "package-tests"],
     "upload_files": [
         "{workdir}/out/target/product/generic/*.tar.bz2",
         "{workdir}/out/target/product/generic/tests/*.zip",
         "{workdir}/out/emulator.tar.gz",
         "{objdir}/dist/b2g-*.crashreporter-symbols.zip",
         "{workdir}/sources.xml"
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -1,29 +1,36 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/b2g-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2gmozilla"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="022eadd5917615ff00c47eaaafa792b45e9c8a28"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,9 @@
 {
-    "revision": "d1729e9d8fcc010e42ef73befa93d3c07a4304c6", 
+    "git": {
+        "remote": "", 
+        "branch": "", 
+        "revision": ""
+    }, 
+    "revision": "8bb0cf53956e54999a5f876434207216d9d8982a", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -1,27 +1,33 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -1,21 +1,26 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -1,28 +1,35 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was https://git.mozilla.org/b2g-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2gmozilla"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -1,27 +1,33 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="575fdbf046e966a5915b1f1e800e5d6ad0ea14c0"/>
   <project name="platform/development" path="development" revision="b1025ec93beeb480caaf3049d171283c3846461d"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -1,25 +1,31 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="97a5b461686757dbb8ecab2aac5903e41d2e1afe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="905bfa3548eb75cf1792d0d8412b92113bbd4318"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="c3d7efc45414f1b44cd9c479bb2758c91c4707c0"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -1,27 +1,33 @@
 <?xml version="1.0" ?><manifest>
+  <!--original fetch url was https://android.googlesource.com/-->
   <remote fetch="https://git.mozilla.org/external/aosp" name="aosp"/>
+  <!--original fetch url was git://github.com/mozilla-b2g/-->
   <remote fetch="https://git.mozilla.org/b2g" name="b2g"/>
+  <!--original fetch url was git://github.com/mozilla/-->
   <remote fetch="https://git.mozilla.org/b2g" name="mozilla"/>
+  <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
+  <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
+  <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="ec159aac19ff25912f1d68ffb44b29f797583ef5"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="c8d34e6e98d4b99921fda59ddd89f2dcdce201fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="8c449b53328059e9b55bb34baec9b27a15055a7e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="52ca41d9fa6ef88e65d9da52e375716c68d48646"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -384,17 +384,32 @@ panel[noactions] > richlistbox > richlis
   visibility: collapse;
 }
 
 #urlbar[pageproxystate="invalid"] > #identity-box {
   pointer-events: none;
 }
 
 #identity-icon-labels {
-  max-width: 12vw;
+  max-width: 18em;
+}
+@media (max-width: 700px) {
+  #identity-icon-labels {
+    max-width: 70px;
+  }
+}
+@media (max-width: 600px) {
+  #identity-icon-labels {
+    max-width: 60px;
+  }
+}
+@media (max-width: 500px) {
+  #identity-icon-labels {
+    max-width: 50px;
+  }
 }
 
 #identity-icon-country-label {
   direction: ltr;
 }
 
 #identity-box.verifiedIdentity > #identity-icon-labels > #identity-icon-label {
   -moz-margin-end: 0.25em !important;
--- a/browser/base/content/test/general/browser_windowopen_reflows.js
+++ b/browser/base/content/test/general/browser_windowopen_reflows.js
@@ -20,25 +20,27 @@ const EXPECTED_REFLOWS = [
   // Focusing the content area causes a reflow.
   "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|",
 
   // Sometimes sessionstore collects data during this test, which causes a sync reflow
   // (https://bugzilla.mozilla.org/show_bug.cgi?id=892154 will fix this)
   "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm",
 ];
 
-if (Services.appinfo.OS == "Darwin") {
-  // TabsInTitlebar._update causes a reflow on OS X trying to do calculations
+if (Services.appinfo.OS == "WINNT" || Services.appinfo.OS == "Darwin") {
+  // TabsInTitlebar._update causes a reflow on OS X and Windows trying to do calculations
   // since layout info is already dirty. This doesn't seem to happen before
-  // MozAfterPaint on other platforms.
+  // MozAfterPaint on Linux.
   EXPECTED_REFLOWS.push("rect@chrome://browser/content/browser.js|" +
                           "TabsInTitlebar._update@chrome://browser/content/browser.js|" +
                           "updateAppearance@chrome://browser/content/browser.js|" +
                           "handleEvent@chrome://browser/content/tabbrowser.xml|");
+}
 
+if (Services.appinfo.OS == "Darwin") {
   // _onOverflow causes a reflow getting widths.
   EXPECTED_REFLOWS.push("OverflowableToolbar.prototype._onOverflow@resource:///modules/CustomizableUI.jsm|" +
                         "OverflowableToolbar.prototype.init@resource:///modules/CustomizableUI.jsm|" +
                         "OverflowableToolbar.prototype.observe@resource:///modules/CustomizableUI.jsm|" +
                         "gBrowserInit._delayedStartup@chrome://browser/content/browser.js|");
   // Same as above since in packaged builds there are no function names and the resource URI includes "app"
   EXPECTED_REFLOWS.push("@resource://app/modules/CustomizableUI.jsm|" +
                           "@resource://app/modules/CustomizableUI.jsm|" +
--- a/browser/components/customizableui/content/panelUI.xml
+++ b/browser/components/customizableui/content/panelUI.xml
@@ -212,17 +212,17 @@
           this._mainViewHeight = this._viewStack.clientHeight;
 
           this._transitioning = true;
           this._viewContainer.addEventListener("transitionend", function trans() {
             this._viewContainer.removeEventListener("transitionend", trans);
             this._transitioning = false;
           }.bind(this));
 
-          let newHeight = this._heightOfSubview(viewNode);
+          let newHeight = this._heightOfSubview(viewNode, this._subViews);
           this._viewContainer.style.height = newHeight + "px";
 
           this._subViewObserver.observe(viewNode, {
             attributes: true,
             characterData: true,
             childList: true,
             subtree: true
           });
@@ -319,17 +319,17 @@
           this._mainView.style.height =
             this.getBoundingClientRect().height + "px";
           this.ignoreMutations = false;
         ]]></body>
       </method>
       <method name="_syncContainerWithSubView">
         <body><![CDATA[
           if (!this.ignoreMutations && this.showingSubView) {
-            let newHeight = this._heightOfSubview(this._currentSubView);
+            let newHeight = this._heightOfSubview(this._currentSubView, this._subViews);
             this._viewContainer.style.height = newHeight + "px";
           }
         ]]></body>
       </method>
       <method name="_syncContainerWithMainView">
         <body><![CDATA[
           if (!this.ignoreMutations && !this.showingSubView && !this._transitioning) {
             let height;
@@ -340,26 +340,60 @@
             }
             this._viewContainer.style.height = height + "px";
           }
         ]]></body>
       </method>
 
       <method name="_heightOfSubview">
         <parameter name="aSubview"/>
+        <parameter name="aContainerToCheck"/>
         <body><![CDATA[
+          function getFullHeight(element) {
+            //XXXgijs: unfortunately, scrollHeight rounds values, and there's no alternative
+            // that works with overflow: auto elements. Fortunately for us,
+            // we have exactly 1 (potentially) scrolling element in here (the subview body),
+            // and rounding 1 value is OK - rounding more than 1 and adding them means we get
+            // off-by-1 errors. Now we might be off by a subpixel, but we care less about that.
+            // So, use scrollHeight *only* if the element is vertically scrollable.
+            let height;
+            let elementCS;
+            if (element.scrollTopMax) {
+              height = element.scrollHeight;
+              // Bounding client rects include borders, scrollHeight doesn't:
+              elementCS = win.getComputedStyle(element);
+              height += parseFloat(elementCS.borderTopWidth) +
+                        parseFloat(elementCS.borderBottomWidth);
+            } else {
+              height = element.getBoundingClientRect().height;
+              if (height > 0) {
+                elementCS = win.getComputedStyle(element);
+              }
+            }
+            if (elementCS) {
+              // Include margins - but not borders or paddings because they
+              // were dealt with above.
+              height += parseFloat(elementCS.marginTop) + parseFloat(elementCS.marginBottom);
+            }
+            return height;
+          }
+          let win = aSubview.ownerDocument.defaultView;
           let body = aSubview.querySelector(".panel-subview-body");
-          let height = body ? body.scrollHeight : aSubview.scrollHeight;
+          let height = getFullHeight(body || aSubview);
           if (body) {
             let header = aSubview.querySelector(".panel-subview-header");
             let footer = aSubview.querySelector(".panel-subview-footer");
-            height += (header ? header.scrollHeight : 0) +
-                      (footer ? footer.scrollHeight : 0);
+            height += (header ? getFullHeight(header) : 0) +
+                      (footer ? getFullHeight(footer) : 0);
           }
-          return height;
+          if (aContainerToCheck) {
+            let containerCS = win.getComputedStyle(aContainerToCheck);
+            height += parseFloat(containerCS.paddingTop) + parseFloat(containerCS.paddingBottom);
+          }
+          return Math.round(height);
         ]]></body>
       </method>
 
     </implementation>
   </binding>
 
   <binding id="panelview">
     <implementation>
--- a/browser/components/customizableui/src/CustomizeMode.jsm
+++ b/browser/components/customizableui/src/CustomizeMode.jsm
@@ -287,16 +287,22 @@ CustomizeMode.prototype = {
 
     // Entering; want to exit once we've done that.
     if (this._handler.isEnteringCustomizeMode) {
       LOG("Attempted to exit while we're in the middle of entering. " +
           "We'll exit after we've entered");
       return;
     }
 
+    if (this.resetting) {
+      LOG("Attempted to exit while we're resetting. " +
+          "We'll exit after resetting has finished.");
+      return;
+    }
+
     this._handler.isExitingCustomizeMode = true;
 
     CustomizableUI.removeListener(this);
 
     this.document.removeEventListener("keypress", this);
     this.window.PanelUI.menuButton.removeEventListener("mousedown", this);
     this.window.PanelUI.menuButton.open = false;
 
@@ -880,16 +886,19 @@ CustomizeMode.prototype = {
 
       this.persistCurrentSets(true);
 
       this._updateResetButton();
       this._updateUndoResetButton();
       this._updateEmptyPaletteNotice();
       this._showPanelCustomizationPlaceholders();
       this.resetting = false;
+      if (!this._wantToBeInCustomizeMode) {
+        this.exit();
+      }
     }.bind(this)).then(null, ERROR);
   },
 
   undoReset: function() {
     this.resetting = true;
 
     return Task.spawn(function() {
       this._removePanelCustomizationPlaceholders();
--- a/browser/devtools/app-manager/app-projects.js
+++ b/browser/devtools/app-manager/app-projects.js
@@ -1,13 +1,13 @@
 const {Cc,Ci,Cu} = require("chrome");
 const ObservableObject = require("devtools/shared/observable-object");
 const promise = require("sdk/core/promise");
 
-const {EventEmitter} = Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
 const {generateUUID} = Cc['@mozilla.org/uuid-generator;1'].getService(Ci.nsIUUIDGenerator);
 
 /**
  * IndexedDB wrapper that just save project objects
  *
  * The only constraint is that project objects have to have
  * a unique `location` object.
  */
--- a/browser/devtools/app-manager/content/projects.js
+++ b/browser/devtools/app-manager/content/projects.js
@@ -11,17 +11,17 @@ const {devtools} = Cu.import("resource:/
 const {require} = devtools;
 const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
 const {AppProjects} = require("devtools/app-manager/app-projects");
 const {AppValidator} = require("devtools/app-manager/app-validator");
 const {Services} = Cu.import("resource://gre/modules/Services.jsm");
 const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
 const {installHosted, installPackaged, getTargetForApp,
        reloadApp, launchApp, closeApp} = require("devtools/app-actor-front");
-const {EventEmitter} = Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 const promise = require("sdk/core/promise");
 
 const MANIFEST_EDITOR_ENABLED = "devtools.appmanager.manifestEditor.enabled";
 
 window.addEventListener("message", function(event) {
   try {
     let json = JSON.parse(event.data);
--- a/browser/devtools/app-manager/content/utils.js
+++ b/browser/devtools/app-manager/content/utils.js
@@ -11,17 +11,17 @@
  *
  */
 
 let Utils = (function() {
   const Cu = Components.utils;
   const {Services} = Cu.import("resource://gre/modules/Services.jsm", {});
   const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
   const {require} = devtools;
-  const EventEmitter = require("devtools/shared/event-emitter");
+  const EventEmitter = require("devtools/toolkit/event-emitter");
 
 
   function _createSetEventForwarder(key, finalStore) {
     return function(event, path, value) {
       finalStore.emit("set", [key].concat(path), value);
     };
   }
 
--- a/browser/devtools/commandline/BuiltinCommands.jsm
+++ b/browser/devtools/commandline/BuiltinCommands.jsm
@@ -12,17 +12,17 @@ const BRAND_SHORT_NAME = Cc["@mozilla.or
 this.EXPORTED_SYMBOLS = [ "CmdAddonFlags", "CmdCommands", "DEFAULT_DEBUG_PORT", "connect" ];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource://gre/modules/osfile.jsm");
 
 Cu.import("resource://gre/modules/devtools/gcli.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
 let Telemetry = devtools.require("devtools/shared/telemetry");
 let telemetry = new Telemetry();
 
 XPCOMUtils.defineLazyModuleGetter(this, "gDevTools",
                                   "resource:///modules/devtools/gDevTools.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AppCacheUtils",
--- a/browser/devtools/debugger/debugger-controller.js
+++ b/browser/devtools/debugger/debugger-controller.js
@@ -85,17 +85,17 @@ const FRAME_TYPE = {
   CONDITIONAL_BREAKPOINT_EVAL: 1,
   WATCH_EXPRESSIONS_EVAL: 2,
   PUBLIC_CLIENT_EVAL: 3
 };
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource:///modules/devtools/SimpleListWidget.jsm");
 Cu.import("resource:///modules/devtools/BreadcrumbsWidget.jsm");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
--- a/browser/devtools/debugger/panel.js
+++ b/browser/devtools/debugger/panel.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const promise = require("sdk/core/promise");
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 const { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {});
 
 function DebuggerPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
   this._destroyer = null;
 
--- a/browser/devtools/framework/gDevTools.jsm
+++ b/browser/devtools/framework/gDevTools.jsm
@@ -5,17 +5,17 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = [ "gDevTools", "DevTools", "gDevToolsBrowser" ];
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 Cu.import("resource://gre/modules/devtools/Loader.jsm");
 
 var ProfilerController = devtools.require("devtools/profiler/controller");
 
 const FORBIDDEN_IDS = new Set(["toolbox", ""]);
 const MAX_ORDINAL = 99;
 
--- a/browser/devtools/framework/selection.js
+++ b/browser/devtools/framework/selection.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cu, Ci} = require("chrome");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 /**
  * API
  *
  *   new Selection(walker=null, node=null, track={attributes,detached});
  *   destroy()
  *   node (readonly)
  *   setNode(node, origin="unknown")
--- a/browser/devtools/framework/sidebar.js
+++ b/browser/devtools/framework/sidebar.js
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cu} = require("chrome");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 var promise = require("sdk/core/promise");
-var EventEmitter = require("devtools/shared/event-emitter");
+var EventEmitter = require("devtools/toolkit/event-emitter");
 var Telemetry = require("devtools/shared/telemetry");
 
 const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 /**
  * ToolSidebar provides methods to register tabs in the sidebar.
  * It's assumed that the sidebar contains a xul:tabbox.
  *
--- a/browser/devtools/framework/target.js
+++ b/browser/devtools/framework/target.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
 var promise = require("sdk/core/promise");
-var EventEmitter = require("devtools/shared/event-emitter");
+var EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerServer",
   "resource://gre/modules/devtools/dbg-server.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "DebuggerClient",
   "resource://gre/modules/devtools/dbg-client.jsm");
 
 const targets = new WeakMap();
@@ -347,16 +347,18 @@ TabTarget.prototype = {
     this._tab.removeEventListener("TabClose", this);
     this._tab.parentNode.removeEventListener("TabSelect", this);
   },
 
   /**
    * Setup listeners for remote debugging, updating existing ones as necessary.
    */
   _setupRemoteListeners: function TabTarget__setupRemoteListeners() {
+    this.client.addListener("closed", this.destroy);
+
     this._onTabDetached = (aType, aPacket) => {
       // We have to filter message to ensure that this detach is for this tab
       if (aPacket.from == this._form.actor) {
         this.destroy();
       }
     };
     this.client.addListener("tabDetached", this._onTabDetached);
 
@@ -379,16 +381,17 @@ TabTarget.prototype = {
     }.bind(this);
     this.client.addListener("tabNavigated", this._onTabNavigated);
   },
 
   /**
    * Teardown listeners for remote debugging.
    */
   _teardownRemoteListeners: function TabTarget__teardownRemoteListeners() {
+    this.client.removeListener("closed", this.destroy);
     this.client.removeListener("tabNavigated", this._onTabNavigated);
     this.client.removeListener("tabDetached", this._onTabDetached);
   },
 
   /**
    * Handle tabs events.
    */
   handleEvent: function (event) {
--- a/browser/devtools/framework/test/browser.ini
+++ b/browser/devtools/framework/test/browser.ini
@@ -5,16 +5,17 @@ support-files =
   browser_toolbox_options_disable_cache.sjs
   head.js
 
 [browser_devtools_api.js]
 [browser_dynamic_tool_enabling.js]
 [browser_keybindings.js]
 [browser_new_activation_workflow.js]
 [browser_target_events.js]
+[browser_target_remote.js]
 [browser_toolbox_dynamic_registration.js]
 [browser_toolbox_highlight.js]
 [browser_toolbox_hosts.js]
 [browser_toolbox_options.js]
 [browser_toolbox_options_disable_cache.js]
 [browser_toolbox_options_disable_js.js]
 # [browser_toolbox_raise.js] # Bug 962258
 # skip-if = os == "win"
--- a/browser/devtools/framework/test/browser_devtools_api.js
+++ b/browser/devtools/framework/test/browser_devtools_api.js
@@ -2,17 +2,17 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 // Tests devtools API
 
 const Cu = Components.utils;
 const toolId = "test-tool";
 
 let tempScope = {};
-Cu.import("resource:///modules/devtools/shared/event-emitter.js", tempScope);
+Cu.import("resource://gre/modules/devtools/event-emitter.js", tempScope);
 let EventEmitter = tempScope.EventEmitter;
 
 function test() {
   addTab("about:blank", function(aBrowser, aTab) {
     runTests(aTab);
   });
 }
 
new file mode 100644
--- /dev/null
+++ b/browser/devtools/framework/test/browser_target_remote.js
@@ -0,0 +1,39 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+let { DebuggerServer } =
+  Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
+let { DebuggerClient } =
+  Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {});
+let { devtools } =
+  Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
+
+// Ensure target is closed if client is closed directly
+function test() {
+  waitForExplicitFinish();
+
+  if (!DebuggerServer.initialized) {
+    DebuggerServer.init(function () { return true; });
+    DebuggerServer.addBrowserActors();
+  }
+
+  var client = new DebuggerClient(DebuggerServer.connectPipe());
+  client.connect(() => {
+    client.listTabs(response => {
+      let options = {
+        form: response,
+        client: client,
+        chrome: true
+      };
+
+      devtools.TargetFactory.forRemoteTab(options).then(target => {
+        target.on("close", () => {
+          ok(true, "Target was closed");
+          DebuggerServer.destroy();
+          finish();
+        });
+        client.close();
+      });
+    });
+  });
+}
--- a/browser/devtools/framework/toolbox-hosts.js
+++ b/browser/devtools/framework/toolbox-hosts.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cu} = require("chrome");
 
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
 
 /**
  * A toolbox host represents an object that contains a toolbox (e.g. the
  * sidebar or a separate window). Any host object should implement the
  * following functions:
--- a/browser/devtools/framework/toolbox-options.js
+++ b/browser/devtools/framework/toolbox-options.js
@@ -2,17 +2,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const {Cu, Cc, Ci} = require("chrome");
 
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 
 exports.OptionsPanel = OptionsPanel;
 
 XPCOMUtils.defineLazyGetter(this, "l10n", function() {
--- a/browser/devtools/framework/toolbox.js
+++ b/browser/devtools/framework/toolbox.js
@@ -6,17 +6,17 @@
 
 const MAX_ORDINAL = 99;
 const ZOOM_PREF = "devtools.toolbox.zoomValue";
 const MIN_ZOOM = 0.5;
 const MAX_ZOOM = 2;
 
 let {Cc, Ci, Cu} = require("chrome");
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 let Telemetry = require("devtools/shared/telemetry");
 let HUDService = require("devtools/webconsole/hudservice");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/scratchpad-manager.jsm");
 Cu.import("resource:///modules/devtools/DOMHelpers.jsm");
--- a/browser/devtools/inspector/inspector-panel.js
+++ b/browser/devtools/inspector/inspector-panel.js
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 let {CssLogic} = require("devtools/styleinspector/css-logic");
 
 loader.lazyGetter(this, "MarkupView", () => require("devtools/markupview/markup-view").MarkupView);
 loader.lazyGetter(this, "HTMLBreadcrumbs", () => require("devtools/inspector/breadcrumbs").HTMLBreadcrumbs);
 loader.lazyGetter(this, "ToolSidebar", () => require("devtools/framework/sidebar").ToolSidebar);
 loader.lazyGetter(this, "SelectorSearch", () => require("devtools/inspector/selector-search").SelectorSearch);
 
 const LAYOUT_CHANGE_TIMER = 250;
--- a/browser/devtools/markupview/html-editor.js
+++ b/browser/devtools/markupview/html-editor.js
@@ -2,17 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  "use strict";
 
 const {Cu} = require("chrome");
 const Editor = require("devtools/sourceeditor/editor");
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 exports.HTMLEditor = HTMLEditor;
 
 function ctrl(k) {
   return (Services.appinfo.OS == "Darwin" ? "Cmd-" : "Ctrl-") + k;
 }
 function stopPropagation(e) {
   e.stopPropagation();
@@ -178,9 +178,9 @@ HTMLEditor.prototype = {
     this.doc.defaultView.removeEventListener("resize",
       this.refresh, true);
     this.container.removeEventListener("click", this.hide, false);
     this.editorInner.removeEventListener("click", stopPropagation, false);
 
     this.hide(false);
     this.container.parentNode.removeChild(this.container);
   }
-};
\ No newline at end of file
+};
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -17,17 +17,17 @@ const CONTAINER_FLASHING_DURATION = 500;
 const NEW_SELECTION_HIGHLIGHTER_TIMER = 1000;
 
 const {UndoStack} = require("devtools/shared/undo");
 const {editableField, InplaceEditor} = require("devtools/shared/inplace-editor");
 const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 const {HTMLEditor} = require("devtools/markupview/html-editor");
 const promise = require("sdk/core/promise");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm");
 Cu.import("resource://gre/modules/devtools/Templater.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 loader.lazyGetter(this, "DOMParser", function() {
  return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser);
--- a/browser/devtools/netmonitor/netmonitor-controller.js
+++ b/browser/devtools/netmonitor/netmonitor-controller.js
@@ -101,17 +101,17 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/VariablesView.jsm");
 Cu.import("resource:///modules/devtools/VariablesViewController.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const Editor = require("devtools/sourceeditor/editor");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Chart",
   "resource:///modules/devtools/Chart.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
   "resource://gre/modules/Task.jsm");
--- a/browser/devtools/netmonitor/panel.js
+++ b/browser/devtools/netmonitor/panel.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 function NetMonitorPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
   this._destroyer = null;
 
   this._view = this.panelWin.NetMonitorView;
   this._controller = this.panelWin.NetMonitorController;
--- a/browser/devtools/profiler/cleopatra.js
+++ b/browser/devtools/profiler/cleopatra.js
@@ -1,17 +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/. */
 
 "use strict";
 
 let { Cu }       = require("chrome");
 let { defer }    = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 const { PROFILE_IDLE, PROFILE_COMPLETED, PROFILE_RUNNING } = require("devtools/profiler/consts");
 
 /**
  * An implementation of a profile visualization that uses Cleopatra.
  * It consists of an iframe with Cleopatra loaded in it and some
  * surrounding meta-data (such as UIDs).
  *
--- a/browser/devtools/profiler/controller.js
+++ b/browser/devtools/profiler/controller.js
@@ -15,17 +15,17 @@ if (isJSM) {
   this["loader"] = { lazyGetter: XPCOMUtils.defineLazyGetter.bind(XPCOMUtils) };
   this["require"] = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 } else {
   var { Cu } = require("chrome");
 }
 
 const { L10N_BUNDLE } = require("devtools/profiler/consts");
 
-var EventEmitter = require("devtools/shared/event-emitter");
+var EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 Cu.import("resource://gre/modules/devtools/Console.jsm");
 Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 loader.lazyGetter(this, "L10N", () => new ViewHelpers.L10N(L10N_BUNDLE));
 
--- a/browser/devtools/profiler/panel.js
+++ b/browser/devtools/profiler/panel.js
@@ -11,17 +11,17 @@ const {
   PROFILE_RUNNING,
   PROFILE_COMPLETED,
   SHOW_PLATFORM_DATA,
   L10N_BUNDLE
 } = require("devtools/profiler/consts");
 
 const { TextEncoder } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
 
-var EventEmitter = require("devtools/shared/event-emitter");
+var EventEmitter = require("devtools/toolkit/event-emitter");
 var Cleopatra    = require("devtools/profiler/cleopatra");
 var Sidebar      = require("devtools/profiler/sidebar");
 var ProfilerController = require("devtools/profiler/controller");
 var { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource://gre/modules/devtools/Console.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
--- a/browser/devtools/profiler/sidebar.js
+++ b/browser/devtools/profiler/sidebar.js
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 let { Cu } = require("chrome");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const {
   PROFILE_IDLE,
   PROFILE_COMPLETED,
   PROFILE_RUNNING,
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -6,17 +6,17 @@
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/FloatingScrollbars.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 var require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 let Telemetry = require("devtools/shared/telemetry");
 let {TouchEventHandler} = require("devtools/touch-events");
 
 this.EXPORTED_SYMBOLS = ["ResponsiveUIManager"];
 
 const MIN_WIDTH = 50;
--- a/browser/devtools/scratchpad/scratchpad-panel.js
+++ b/browser/devtools/scratchpad/scratchpad-panel.js
@@ -1,17 +1,17 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const {Cu} = require("chrome");
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
 
 
 function ScratchpadPanel(iframeWindow, toolbox) {
   let { Scratchpad } = iframeWindow;
   this._toolbox = toolbox;
   this.panelWin = iframeWindow;
   this.scratchpad = Scratchpad;
--- a/browser/devtools/shadereditor/panel.js
+++ b/browser/devtools/shadereditor/panel.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const { Cc, Ci, Cu, Cr } = require("chrome");
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const { WebGLFront } = require("devtools/server/actors/webgl");
 
 function ShaderEditorPanel(iframeWindow, toolbox) {
   this.panelWin = iframeWindow;
   this._toolbox = toolbox;
   this._destroyer = null;
 
   EventEmitter.decorate(this);
--- a/browser/devtools/shadereditor/shadereditor.js
+++ b/browser/devtools/shadereditor/shadereditor.js
@@ -9,17 +9,17 @@ Cu.import("resource://gre/modules/Servic
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 Cu.import("resource://gre/modules/devtools/Loader.jsm");
 Cu.import("resource:///modules/devtools/SideMenuWidget.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 const Editor = require("devtools/sourceeditor/editor");
 
 // The panel's window global is an EventEmitter firing the following events:
 const EVENTS = {
   // When new programs are received from the server.
   NEW_PROGRAM: "ShaderEditor:NewProgram",
   PROGRAMS_ADDED: "ShaderEditor:ProgramsAdded",
--- a/browser/devtools/shared/DeveloperToolbar.jsm
+++ b/browser/devtools/shared/DeveloperToolbar.jsm
@@ -30,17 +30,17 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
                                   "resource://gre/modules/devtools/Loader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "require",
                                   "resource://gre/modules/devtools/Require.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
-                                  "resource:///modules/devtools/shared/event-emitter.js");
+                                  "resource://gre/modules/devtools/event-emitter.js");
 
 XPCOMUtils.defineLazyGetter(this, "prefBranch", function() {
   let prefService = Cc["@mozilla.org/preferences-service;1"]
                     .getService(Ci.nsIPrefService);
   return prefService.getBranch(null)
                     .QueryInterface(Ci.nsIPrefBranch2);
 });
 
--- a/browser/devtools/shared/inplace-editor.js
+++ b/browser/devtools/shared/inplace-editor.js
@@ -35,17 +35,17 @@ const CONTENT_TYPES = {
 };
 const MAX_POPUP_ENTRIES = 10;
 
 const FOCUS_FORWARD = Ci.nsIFocusManager.MOVEFOCUS_FORWARD;
 const FOCUS_BACKWARD = Ci.nsIFocusManager.MOVEFOCUS_BACKWARD;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 /**
  * Mark a span editable.  |editableField| will listen for the span to
  * be focused and create an InlineEditor to handle text input.
  * Changes will be committed when the InlineEditor's input is blurred
  * or dropped when the user presses escape.
  *
  * @param {object} aOptions
--- a/browser/devtools/shared/observable-object.js
+++ b/browser/devtools/shared/observable-object.js
@@ -25,17 +25,17 @@
  *   emitter.on("get", console.log);
  *   let obj = emitter.object;
  *   obj.x.y[0] = 50;
  *
  */
 
 "use strict";
 
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 function ObservableObject(object = {}) {
   EventEmitter.decorate(this);
   let handler = new Handler(this);
   this.object = new Proxy(object, handler);
   handler._wrappers.set(this.object, object);
   handler._paths.set(object, []);
 }
--- a/browser/devtools/shared/test/browser.ini
+++ b/browser/devtools/shared/test/browser.ini
@@ -4,17 +4,16 @@ support-files =
   browser_layoutHelpers_iframe.html
   browser_templater_basic.html
   browser_toolbar_basic.html
   browser_toolbar_webconsole_errors_count.html
   head.js
   leakhunt.js
 
 [browser_css_color.js]
-[browser_eventemitter_basic.js]
 [browser_layoutHelpers.js]
 [browser_observableobject.js]
 [browser_outputparser.js]
 [browser_require_basic.js]
 [browser_telemetry_button_paintflashing.js]
 [browser_telemetry_button_responsive.js]
 [browser_telemetry_button_scratchpad.js]
 [browser_telemetry_button_tilt.js]
--- a/browser/devtools/shared/widgets/BreadcrumbsWidget.jsm
+++ b/browser/devtools/shared/widgets/BreadcrumbsWidget.jsm
@@ -6,17 +6,17 @@
 "use strict";
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 const ENSURE_SELECTION_VISIBLE_DELAY = 50; // ms
 
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 this.EXPORTED_SYMBOLS = ["BreadcrumbsWidget"];
 
 /**
  * A breadcrumb-like list of items.
  *
  * Note: this widget should be used in tandem with the WidgetMethods in
  * ViewHelpers.jsm.
--- a/browser/devtools/shared/widgets/Chart.jsm
+++ b/browser/devtools/shared/widgets/Chart.jsm
@@ -15,17 +15,17 @@ const TAU = PI * 2;
 const EPSILON = 0.0000001;
 const NAMED_SLICE_MIN_ANGLE = TAU / 8;
 const NAMED_SLICE_TEXT_DISTANCE_RATIO = 1.9;
 const HOVERED_SLICE_TRANSLATE_DISTANCE_RATIO = 20;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 this.EXPORTED_SYMBOLS = ["Chart"];
 
 /**
  * Localization convenience methods.
  */
 let L10N = new ViewHelpers.L10N(NET_STRINGS_URI);
 
--- a/browser/devtools/shared/widgets/FastListWidget.js
+++ b/browser/devtools/shared/widgets/FastListWidget.js
@@ -1,16 +1,16 @@
 /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const { Cu, Ci } = require("chrome");
 const { ViewHelpers } = Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {});
 
 /**
  * A list menu widget that attempts to be very fast.
  *
  * Note: this widget should be used in tandem with the WidgetMethods in
  * ViewHelpers.jsm.
--- a/browser/devtools/shared/widgets/SideMenuWidget.jsm
+++ b/browser/devtools/shared/widgets/SideMenuWidget.jsm
@@ -4,17 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 this.EXPORTED_SYMBOLS = ["SideMenuWidget"];
 
 /**
  * A simple side menu, with the ability of grouping menu items.
  *
  * Note: this widget should be used in tandem with the WidgetMethods in
  * ViewHelpers.jsm.
--- a/browser/devtools/shared/widgets/Spectrum.js
+++ b/browser/devtools/shared/widgets/Spectrum.js
@@ -1,15 +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/. */
 
 "use strict";
 
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 /**
  * Spectrum creates a color picker widget in any container you give it.
  *
  * Simple usage example:
  *
  * const {Spectrum} = require("devtools/shared/widgets/Spectrum");
  * let s = new Spectrum(containerElement, [255, 126, 255, 1]);
--- a/browser/devtools/shared/widgets/Tooltip.js
+++ b/browser/devtools/shared/widgets/Tooltip.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const {Cc, Cu, Ci} = require("chrome");
 const promise = require("sdk/core/promise");
 const IOService = Cc["@mozilla.org/network/io-service;1"]
   .getService(Ci.nsIIOService);
 const {Spectrum} = require("devtools/shared/widgets/Spectrum");
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 const {colorUtils} = require("devtools/css-color");
 const Heritage = require("sdk/core/heritage");
 const {CSSTransformPreviewer} = require("devtools/shared/widgets/CSSTransformPreviewer");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "setNamedTimeout",
--- a/browser/devtools/shared/widgets/VariablesView.jsm
+++ b/browser/devtools/shared/widgets/VariablesView.jsm
@@ -16,17 +16,17 @@ const APPEND_PAGE_SIZE_DEFAULT = 500;
 const PAGE_SIZE_SCROLL_HEIGHT_RATIO = 100;
 const PAGE_SIZE_MAX_JUMPS = 30;
 const SEARCH_ACTION_MAX_DELAY = 300; // ms
 const ITEM_FLASH_DURATION = 300 // ms
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
 
 XPCOMUtils.defineLazyModuleGetter(this, "devtools",
   "resource://gre/modules/devtools/Loader.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
--- a/browser/devtools/sourceeditor/editor.js
+++ b/browser/devtools/sourceeditor/editor.js
@@ -14,17 +14,17 @@ const AUTO_CLOSE  = "devtools.editor.aut
 const L10N_BUNDLE = "chrome://browser/locale/devtools/sourceeditor.properties";
 const XUL_NS      = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
 
 // Maximum allowed margin (in number of lines) from top or bottom of the editor
 // while shifting to a line which was initially out of view.
 const MAX_VERTICAL_OFFSET = 3;
 
 const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
-const events  = require("devtools/shared/event-emitter");
+const events  = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/Services.jsm");
 const L10N = Services.strings.createBundle(L10N_BUNDLE);
 
 // CM_STYLES, CM_SCRIPTS and CM_IFRAME represent the HTML,
 // JavaScript and CSS that is injected into an iframe in
 // order to initialize a CodeMirror instance.
 
--- a/browser/devtools/styleeditor/StyleEditorUI.jsm
+++ b/browser/devtools/styleeditor/StyleEditorUI.jsm
@@ -11,17 +11,17 @@ const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
 let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource:///modules/devtools/gDevTools.jsm");
 Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
 Cu.import("resource:///modules/devtools/SplitView.jsm");
 Cu.import("resource:///modules/devtools/StyleSheetEditor.jsm");
 
 const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
 const { PrefObserver, PREF_ORIG_SOURCES } = require("devtools/styleeditor/utils");
 
--- a/browser/devtools/styleeditor/StyleSheetEditor.jsm
+++ b/browser/devtools/styleeditor/StyleSheetEditor.jsm
@@ -16,17 +16,17 @@ const Editor  = require("devtools/source
 const promise = require("sdk/core/promise");
 const {CssLogic} = require("devtools/styleinspector/css-logic");
 const AutoCompleter = require("devtools/sourceeditor/autocomplete");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/FileUtils.jsm");
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/osfile.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
 
 const LOAD_ERROR = "error-load";
 const SAVE_ERROR = "error-save";
 
 // max update frequency in ms (avoid potential typing lag and/or flicker)
 // @see StyleEditor.updateStylesheet
 const UPDATE_STYLESHEET_THROTTLE_DELAY = 500;
--- a/browser/devtools/styleeditor/styleeditor-panel.js
+++ b/browser/devtools/styleeditor/styleeditor-panel.js
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 let promise = require("sdk/core/promise");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource:///modules/devtools/StyleEditorUI.jsm");
 Cu.import("resource:///modules/devtools/StyleEditorUtil.jsm");
 
 loader.lazyGetter(this, "StyleSheetsFront",
   () => require("devtools/server/actors/stylesheets").StyleSheetsFront);
 
 loader.lazyGetter(this, "StyleEditorFront",
--- a/browser/devtools/styleeditor/utils.js
+++ b/browser/devtools/styleeditor/utils.js
@@ -2,17 +2,17 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cc, Ci, Cu, Cr} = require("chrome");
 
 Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource:///modules/devtools/shared/event-emitter.js");
+Cu.import("resource://gre/modules/devtools/event-emitter.js");
 
 exports.PREF_ORIG_SOURCES = "devtools.styleeditor.source-maps-enabled";
 
 /**
  * A PreferenceObserver observes a pref branch for pref changes.
  * It emits an event for each preference change.
  */
 function PrefObserver(branchName) {
--- a/browser/devtools/styleinspector/computed-view.js
+++ b/browser/devtools/styleinspector/computed-view.js
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const {Cc, Ci, Cu} = require("chrome");
 
 const ToolDefinitions = require("main").Tools;
 const {CssLogic} = require("devtools/styleinspector/css-logic");
 const {ELEMENT_STYLE} = require("devtools/server/actors/styles");
 const promise = require("sdk/core/promise");
-const {EventEmitter} = require("devtools/shared/event-emitter");
+const {EventEmitter} = require("devtools/toolkit/event-emitter");
 const {OutputParser} = require("devtools/output-parser");
 const {Tooltip} = require("devtools/shared/widgets/Tooltip");
 const {PrefObserver, PREF_ORIG_SOURCES} = require("devtools/styleeditor/utils");
 const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
--- a/browser/devtools/tilt/tilt.js
+++ b/browser/devtools/tilt/tilt.js
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 const {Cu} = require("chrome");
 
 let {TiltVisualizer} = require("devtools/tilt/tilt-visualizer");
 let TiltGL = require("devtools/tilt/tilt-gl");
 let TiltUtils = require("devtools/tilt/tilt-utils");
-let EventEmitter = require("devtools/shared/event-emitter");
+let EventEmitter = require("devtools/toolkit/event-emitter");
 let Telemetry = require("devtools/shared/telemetry");
 
 Cu.import("resource://gre/modules/Services.jsm");
 
 // Tilt notifications dispatched through the nsIObserverService.
 const TILT_NOTIFICATIONS = {
   // Called early in the startup of a new tilt instance
   STARTUP: "tilt-startup",
--- a/browser/devtools/webconsole/panel.js
+++ b/browser/devtools/webconsole/panel.js
@@ -4,17 +4,17 @@
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 
 loader.lazyImporter(this, "devtools", "resource://gre/modules/devtools/Loader.jsm");
 loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
 loader.lazyGetter(this, "HUDService", () => require("devtools/webconsole/hudservice"));
-loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
+loader.lazyGetter(this, "EventEmitter", () => require("devtools/toolkit/event-emitter"));
 loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
 
 /**
  * A DevToolPanel that controls the Web Console.
  */
 function WebConsolePanel(iframeWindow, toolbox)
 {
   this._frameWindow = iframeWindow;
--- a/browser/devtools/webconsole/test/browser.ini
+++ b/browser/devtools/webconsole/test/browser.ini
@@ -263,10 +263,11 @@ run-if = os == "mac"
 [browser_webconsole_autocomplete_popup_close_on_tab_switch.js]
 [browser_console_hide_jsterm_when_devtools_chrome_enabled_false.js]
 [browser_webconsole_output_01.js]
 [browser_webconsole_output_02.js]
 [browser_webconsole_output_03.js]
 [browser_webconsole_output_04.js]
 [browser_webconsole_output_events.js]
 [browser_console_variables_view_highlighter.js]
+[browser_webconsole_start_netmon_first.js]
 [browser_webconsole_console_trace_duplicates.js]
 [browser_webconsole_cd_iframe.js]
new file mode 100644
--- /dev/null
+++ b/browser/devtools/webconsole/test/browser_webconsole_start_netmon_first.js
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Check that the webconsole works if the network monitor is first opened, then
+// the user switches to the webconsole. See bug 970914.
+
+function test() {
+  Task.spawn(runner).then(finishTest);
+
+  function* runner() {
+    const {tab} = yield loadTab("data:text/html;charset=utf8,<p>hello");
+
+    const target = TargetFactory.forTab(tab);
+    const toolbox = yield gDevTools.showToolbox(target, "netmonitor");
+
+    const hud = yield openConsole(tab);
+
+    hud.jsterm.execute("console.log('foobar bug970914')");
+
+    yield waitForMessages({
+      webconsole: hud,
+      messages: [{
+        name: "console.log",
+        text: "foobar bug970914",
+        category: CATEGORY_WEBDEV,
+        severity: SEVERITY_LOG,
+      }],
+    });
+
+    let text = hud.outputNode.textContent;
+    isnot(text.indexOf("foobar bug970914"), -1, "console.log message confirmed");
+    ok(!/logging API|disabled by a script/i.test(text),
+       "no warning about disabled console API");
+  }
+}
+
--- a/browser/devtools/webconsole/webconsole.js
+++ b/browser/devtools/webconsole/webconsole.js
@@ -10,17 +10,17 @@ const {Cc, Ci, Cu} = require("chrome");
 
 let WebConsoleUtils = require("devtools/toolkit/webconsole/utils").Utils;
 
 loader.lazyServiceGetter(this, "clipboardHelper",
                          "@mozilla.org/widget/clipboardhelper;1",
                          "nsIClipboardHelper");
 loader.lazyImporter(this, "Services", "resource://gre/modules/Services.jsm");
 loader.lazyImporter(this, "promise", "resource://gre/modules/Promise.jsm", "Promise");
-loader.lazyGetter(this, "EventEmitter", () => require("devtools/shared/event-emitter"));
+loader.lazyGetter(this, "EventEmitter", () => require("devtools/toolkit/event-emitter"));
 loader.lazyGetter(this, "AutocompletePopup",
                   () => require("devtools/shared/autocomplete-popup").AutocompletePopup);
 loader.lazyGetter(this, "ToolSidebar",
                   () => require("devtools/framework/sidebar").ToolSidebar);
 loader.lazyGetter(this, "NetworkPanel",
                   () => require("devtools/webconsole/network-panel").NetworkPanel);
 loader.lazyGetter(this, "ConsoleOutput",
                   () => require("devtools/webconsole/console-output").ConsoleOutput);
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,4 +1,4 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 0.8.990
+Current extension version is: 0.8.1041
 
--- a/browser/extensions/pdfjs/components/PdfStreamConverter.js
+++ b/browser/extensions/pdfjs/components/PdfStreamConverter.js
@@ -536,28 +536,40 @@ var RangedChromeActions = (function Rang
           // manually to fetch the PDF in chunks.
           return;
         }
         this.headers[aHeader] = aValue;
       }
     };
     originalRequest.visitRequestHeaders(httpHeaderVisitor);
 
+    var self = this;
+    var xhr_onreadystatechange = function xhr_onreadystatechange() {
+      if (this.readyState === 1) { // LOADING
+        var netChannel = this.channel;
+        if ('nsIPrivateBrowsingChannel' in Ci &&
+            netChannel instanceof Ci.nsIPrivateBrowsingChannel) {
+          var docIsPrivate = self.isInPrivateBrowsing();
+          netChannel.setPrivate(docIsPrivate);
+        }
+      }
+    };
     var getXhr = function getXhr() {
       const XMLHttpRequest = Components.Constructor(
           '@mozilla.org/xmlextras/xmlhttprequest;1');
-      return new XMLHttpRequest();
+      var xhr = new XMLHttpRequest();
+      xhr.addEventListener('readystatechange', xhr_onreadystatechange);
+      return xhr;
     };
 
     this.networkManager = new NetworkManager(this.pdfUrl, {
       httpHeaders: httpHeaderVisitor.headers,
       getXhr: getXhr
     });
 
-    var self = this;
     // If we are in range request mode, this means we manually issued xhr
     // requests, which we need to abort when we leave the page
     domWindow.addEventListener('unload', function unload(e) {
       self.networkManager.abortAllRequests();
       domWindow.removeEventListener(e.type, unload);
     });
   }
 
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -15,18 +15,18 @@
  * limitations under the License.
  */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
   (typeof window !== 'undefined' ? window : this).PDFJS = {};
 }
 
-PDFJS.version = '0.8.990';
-PDFJS.build = '54f6291';
+PDFJS.version = '0.8.1041';
+PDFJS.build = '2188bcb';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* Copyright 2012 Mozilla Foundation
@@ -3304,17 +3304,17 @@ var LinkAnnotation = (function LinkAnnot
     var action = dict.get('A');
     if (action) {
       var linkType = action.get('S').name;
       if (linkType === 'URI') {
         var url = action.get('URI');
         if (isName(url)) {
           // Some bad PDFs do not put parentheses around relative URLs.
           url = '/' + url.name;
-        } else {
+        } else if (url) {
           url = addDefaultProtocolToUrl(url);
         }
         // TODO: pdf spec mentions urls can be relative to a Base
         // entry in the dictionary.
         if (!isValidUrl(url, false)) {
           url = '';
         }
         data.url = url;
@@ -3344,17 +3344,17 @@ var LinkAnnotation = (function LinkAnnot
       // simple destination link
       var dest = dict.get('Dest');
       data.dest = isName(dest) ? dest.name : dest;
     }
   }
 
   // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
   function addDefaultProtocolToUrl(url) {
-    if (url.indexOf('www.') === 0) {
+    if (url && url.indexOf('www.') === 0) {
       return ('http://' + url);
     }
     return url;
   }
 
   Util.inherit(LinkAnnotation, Annotation, {
     hasOperatorList: function LinkAnnotation_hasOperatorList() {
       return false;
@@ -4081,16 +4081,17 @@ var WorkerTransport = (function WorkerTr
         messageHandler.on('RequestDataRange',
           function transportDataRange(data) {
             pdfDataRangeTransport.requestDataRange(data.begin, data.end);
           }, this);
       }
 
       messageHandler.on('GetDoc', function transportDoc(data) {
         var pdfInfo = data.pdfInfo;
+        this.numPages = data.pdfInfo.numPages;
         var pdfDocument = new PDFDocumentProxy(pdfInfo, this);
         this.pdfDocument = pdfDocument;
         this.workerReadyPromise.resolve(pdfDocument);
       }, this);
 
       messageHandler.on('NeedPassword', function transportPassword(data) {
         if (this.passwordCallback) {
           return this.passwordCallback(updatePassword,
@@ -4285,16 +4286,23 @@ var WorkerTransport = (function WorkerTr
 
     getData: function WorkerTransport_getData(promise) {
       this.messageHandler.send('GetData', null, function(data) {
         promise.resolve(data);
       });
     },
 
     getPage: function WorkerTransport_getPage(pageNumber, promise) {
+      if (pageNumber <= 0 || pageNumber > this.numPages ||
+          (pageNumber|0) !== pageNumber) {
+        var pagePromise = new PDFJS.LegacyPromise();
+        pagePromise.reject(new Error('Invalid page request'));
+        return pagePromise;
+      }
+
       var pageIndex = pageNumber - 1;
       if (pageIndex in this.pagePromises)
         return this.pagePromises[pageIndex];
       var promise = new PDFJS.LegacyPromise();
       this.pagePromises[pageIndex] = promise;
       this.messageHandler.send('GetPageRequest', { pageIndex: pageIndex });
       return promise;
     },
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -15,18 +15,18 @@
  * limitations under the License.
  */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
   (typeof window !== 'undefined' ? window : this).PDFJS = {};
 }
 
-PDFJS.version = '0.8.990';
-PDFJS.build = '54f6291';
+PDFJS.version = '0.8.1041';
+PDFJS.build = '2188bcb';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 /* Copyright 2012 Mozilla Foundation
@@ -3304,17 +3304,17 @@ var LinkAnnotation = (function LinkAnnot
     var action = dict.get('A');
     if (action) {
       var linkType = action.get('S').name;
       if (linkType === 'URI') {
         var url = action.get('URI');
         if (isName(url)) {
           // Some bad PDFs do not put parentheses around relative URLs.
           url = '/' + url.name;
-        } else {
+        } else if (url) {
           url = addDefaultProtocolToUrl(url);
         }
         // TODO: pdf spec mentions urls can be relative to a Base
         // entry in the dictionary.
         if (!isValidUrl(url, false)) {
           url = '';
         }
         data.url = url;
@@ -3344,17 +3344,17 @@ var LinkAnnotation = (function LinkAnnot
       // simple destination link
       var dest = dict.get('Dest');
       data.dest = isName(dest) ? dest.name : dest;
     }
   }
 
   // Lets URLs beginning with 'www.' default to using the 'http://' protocol.
   function addDefaultProtocolToUrl(url) {
-    if (url.indexOf('www.') === 0) {
+    if (url && url.indexOf('www.') === 0) {
       return ('http://' + url);
     }
     return url;
   }
 
   Util.inherit(LinkAnnotation, Annotation, {
     hasOperatorList: function LinkAnnotation_hasOperatorList() {
       return false;
@@ -3872,16 +3872,19 @@ var ChunkedStreamManager = (function Chu
     }
   };
 
   return ChunkedStreamManager;
 })();
 
 
 
+// The maximum number of bytes fetched per range request
+var RANGE_CHUNK_SIZE = 65536;
+
 // TODO(mack): Make use of PDFJS.Util.inherit() when it becomes available
 var BasePdfManager = (function BasePdfManagerClosure() {
   function BasePdfManager() {
     throw new Error('Cannot initialize BaseManagerManager');
   }
 
   BasePdfManager.prototype = {
     onLoadedStream: function BasePdfManager_onLoadedStream() {
@@ -3985,32 +3988,29 @@ var LocalPdfManager = (function LocalPdf
       function LocalPdfManager_terminate() {
     return;
   };
 
   return LocalPdfManager;
 })();
 
 var NetworkPdfManager = (function NetworkPdfManagerClosure() {
-
-  var CHUNK_SIZE = 65536;
-
   function NetworkPdfManager(args, msgHandler) {
 
     this.msgHandler = msgHandler;
 
     var params = {
       msgHandler: msgHandler,
       httpHeaders: args.httpHeaders,
       withCredentials: args.withCredentials,
       chunkedViewerLoading: args.chunkedViewerLoading,
       disableAutoFetch: args.disableAutoFetch,
       initialData: args.initialData
     };
-    this.streamManager = new ChunkedStreamManager(args.length, CHUNK_SIZE,
+    this.streamManager = new ChunkedStreamManager(args.length, RANGE_CHUNK_SIZE,
                                                   args.url, params);
 
     this.pdfModel = new PDFDocument(this, this.streamManager.getStream(),
                                     args.password);
   }
 
   NetworkPdfManager.prototype = Object.create(BasePdfManager.prototype);
   NetworkPdfManager.prototype.constructor = NetworkPdfManager;
@@ -31948,57 +31948,95 @@ var Lexer = (function LexerClosure() {
     }
     return -1;
   }
 
   Lexer.prototype = {
     nextChar: function Lexer_nextChar() {
       return (this.currentChar = this.stream.getByte());
     },
+    peekChar: function Lexer_peekChar() {
+      return this.stream.peekBytes(1)[0];
+    },
     getNumber: function Lexer_getNumber() {
-      var floating = false;
       var ch = this.currentChar;
-      var allDigits = ch >= 0x30 && ch <= 0x39;
-      var strBuf = this.strBuf;
-      strBuf.length = 0;
-      strBuf.push(String.fromCharCode(ch));
+      var eNotation = false;
+      var divideBy = 0; // different from 0 if it's a floating point value
+
+      var sign = 1;
+
+
+      if (ch === 0x2D) { // '-'
+        sign = -1;
+        ch = this.nextChar();
+      } else if (ch === 0x2B) { // '+'
+        ch = this.nextChar();
+      }
+      if (ch === 0x2E) { // '.'
+        divideBy = 10;
+        ch = this.nextChar();
+      }
+
+      if (ch < 0x30 || ch > 0x39) { // '0' - '9'
+        error('Invalid number: ' + String.fromCharCode(ch));
+        return 0;
+      }
+
+      var baseValue = ch - 0x30; // '0'
+      var powerValue = 0;
+      var powerValueSign = 1;
+
       while ((ch = this.nextChar()) >= 0) {
-        if (ch >= 0x30 && ch <= 0x39) { // '0'-'9'
-          strBuf.push(String.fromCharCode(ch));
-        } else if (ch === 0x2E && !floating) { // '.'
-          strBuf.push('.');
-          floating = true;
-          allDigits = false;
+        if (0x30 <= ch && ch <= 0x39) { // '0' - '9'
+          var currentDigit = ch - 0x30; // '0'
+          if (eNotation) { // We are after an 'e' or 'E'
+            powerValue = powerValue * 10 + currentDigit;
+          } else {
+            if (divideBy !== 0) { // We are after a point
+              divideBy *= 10;
+            }
+            baseValue = baseValue * 10 + currentDigit;
+          }
+        } else if (ch === 0x2E) { // '.'
+          if (divideBy === 0) {
+            divideBy = 1;
+          } else {
+            // A number can have only one '.'
+            break;
+          }
         } else if (ch === 0x2D) { // '-'
           // ignore minus signs in the middle of numbers to match
           // Adobe's behavior
           warn('Badly formated number');
-          allDigits = false;
         } else if (ch === 0x45 || ch === 0x65) { // 'E', 'e'
-          floating = true;
-          allDigits = false;
+          // 'E' can be either a scientific notation or the beginning of a new
+          // operator
+          var hasE = true;
+          ch = this.peekChar();
+          if (ch === 0x2B || ch === 0x2D) { // '+', '-'
+            powerValueSign = (ch === 0x2D) ? -1 : 1;
+            this.nextChar(); // Consume the sign character
+          } else if (ch < 0x30 || ch > 0x39) { // '0' - '9'
+            // The 'E' must be the beginning of a new operator
+            break;
+          }
+          eNotation = true;
         } else {
           // the last character doesn't belong to us
           break;
         }
       }
-      var value;
-      if (allDigits) {
-        value = 0;
-        var charCodeOfZero = 48;    // '0'
-        for (var i = 0, ii = strBuf.length; i < ii; i++) {
-          value = value * 10 + (strBuf[i].charCodeAt(0) - charCodeOfZero);
-        }
-      } else {
-        value = parseFloat(strBuf.join(''));
-        if (isNaN(value)) {
-          error('Invalid floating point number: ' + value);
-        }
-      }
-      return value;
+
+      if (divideBy !== 0) {
+        baseValue /= divideBy;
+      }
+      if (eNotation) {
+        baseValue *= Math.pow(10, powerValueSign * powerValue);
+      }
+      return sign * baseValue;
     },
     getString: function Lexer_getString() {
       var numParen = 1;
       var done = false;
       var strBuf = this.strBuf;
       strBuf.length = 0;
 
       var ch = this.nextChar();
@@ -34943,24 +34981,30 @@ var WorkerMessageHandler = PDFJS.WorkerM
             return;
           }
 
           var length = fullRequestXhr.getResponseHeader('Content-Length');
           length = parseInt(length, 10);
           if (!isInt(length)) {
             return;
           }
+          source.length = length;
+          if (length <= 2 * RANGE_CHUNK_SIZE) {
+            // The file size is smaller than the size of two chunks, so it does
+            // not make any sense to abort the request and retry with a range
+            // request.
+            return;
+          }
 
           // NOTE: by cancelling the full request, and then issuing range
           // requests, there will be an issue for sites where you can only
           // request the pdf once. However, if this is the case, then the
           // server should not be returning that it can support range requests.
           networkManager.abortRequest(fullRequestXhrId);
 
-          source.length = length;
           try {
             pdfManager = new NetworkPdfManager(source, handler);
             pdfManagerPromise.resolve(pdfManager);
           } catch (ex) {
             pdfManagerPromise.reject(ex);
           }
         },
 
@@ -35154,18 +35198,18 @@ var WorkerMessageHandler = PDFJS.WorkerM
     handler.on('RenderPageRequest', function wphSetupRenderPage(data) {
       pdfManager.getPage(data.pageIndex).then(function(page) {
 
         var pageNum = data.pageIndex + 1;
         var start = Date.now();
         // Pre compile the pdf page and fetch the fonts/images.
         page.getOperatorList(handler).then(function(operatorList) {
 
-          info('page=%d - getOperatorList: time=%dms, len=%d', pageNum,
-              Date.now() - start, operatorList.fnArray.length);
+          info('page=' + pageNum + ' - getOperatorList: time=' +
+               (Date.now() - start) + 'ms, len=' + operatorList.fnArray.length);
 
         }, function(e) {
 
           var minimumStackMessage =
               'worker.js: while trying to getPage() and getOperatorList()';
 
           var wrappedException;
 
@@ -35196,18 +35240,18 @@ var WorkerMessageHandler = PDFJS.WorkerM
     }, this);
 
     handler.on('GetTextContent', function wphExtractText(data, deferred) {
       pdfManager.getPage(data.pageIndex).then(function(page) {
         var pageNum = data.pageIndex + 1;
         var start = Date.now();
         page.extractTextContent().then(function(textContent) {
           deferred.resolve(textContent);
-          info('text indexing: page=%d - time=%dms', pageNum,
-              Date.now() - start);
+          info('text indexing: page=' + pageNum + ' - time=' +
+               (Date.now() - start) + 'ms');
         }, function (e) {
           // Skip errored pages
           deferred.reject(e);
         });
       });
     });
 
     handler.on('Cleanup', function wphCleanup(data, deferred) {
@@ -35219,18 +35263,53 @@ var WorkerMessageHandler = PDFJS.WorkerM
       pdfManager.terminate();
       deferred.resolve();
     });
   }
 };
 
 var consoleTimer = {};
 
+var workerConsole = {
+  log: function log() {
+    var args = Array.prototype.slice.call(arguments);
+    globalScope.postMessage({
+      action: 'console_log',
+      data: args
+    });
+  },
+
+  error: function error() {
+    var args = Array.prototype.slice.call(arguments);
+    globalScope.postMessage({
+      action: 'console_error',
+      data: args
+    });
+    throw 'pdf.js execution error';
+  },
+
+  time: function time(name) {
+    consoleTimer[name] = Date.now();
+  },
+
+  timeEnd: function timeEnd(name) {
+    var time = consoleTimer[name];
+    if (!time) {
+      error('Unknown timer name ' + name);
+    }
+    this.log('Timer:', name, Date.now() - time);
+  }
+};
+
+
 // Worker thread?
 if (typeof window === 'undefined') {
+  if (!('console' in globalScope)) {
+    globalScope.console = workerConsole;
+  }
 
   // Listen for unsupported features so we can pass them on to the main thread.
   PDFJS.UnsupportedManager.listen(function (msg) {
     globalScope.postMessage({
       action: '_unsupported_feature',
       data: msg
     });
   });
@@ -36909,114 +36988,138 @@ var JpxImage = (function JpxImageClosure
       function transformCalculate(subbands, u0, v0) {
       var ll = subbands[0];
       for (var i = 1, ii = subbands.length, j = 1; i < ii; i += 3, j++) {
         ll = this.iterate(ll, subbands[i], subbands[i + 1],
                           subbands[i + 2], u0, v0);
       }
       return ll;
     };
-    Transform.prototype.expand = function expand(buffer, bufferPadding, step) {
+    Transform.prototype.extend = function extend(buffer, offset, size) {
         // Section F.3.7 extending... using max extension of 4
-        var i1 = bufferPadding - 1, j1 = bufferPadding + 1;
-        var i2 = bufferPadding + step - 2, j2 = bufferPadding + step;
+        var i1 = offset - 1, j1 = offset + 1;
+        var i2 = offset + size - 2, j2 = offset + size;
         buffer[i1--] = buffer[j1++];
         buffer[j2++] = buffer[i2--];
         buffer[i1--] = buffer[j1++];
         buffer[j2++] = buffer[i2--];
         buffer[i1--] = buffer[j1++];
         buffer[j2++] = buffer[i2--];
-        buffer[i1--] = buffer[j1++];
-        buffer[j2++] = buffer[i2--];
+        buffer[i1] = buffer[j1];
+        buffer[j2] = buffer[i2];
     };
     Transform.prototype.iterate = function Transform_iterate(ll, hl, lh, hh,
                                                             u0, v0) {
       var llWidth = ll.width, llHeight = ll.height, llItems = ll.items;
       var hlWidth = hl.width, hlHeight = hl.height, hlItems = hl.items;
       var lhWidth = lh.width, lhHeight = lh.height, lhItems = lh.items;
       var hhWidth = hh.width, hhHeight = hh.height, hhItems = hh.items;
 
       // Section F.3.3 interleave
       var width = llWidth + hlWidth;
       var height = llHeight + lhHeight;
       var items = new Float32Array(width * height);
-      for (var i = 0, ii = llHeight; i < ii; i++) {
+      var i, j, k, l;
+
+      for (i = 0; i < llHeight; i++) {
         var k = i * llWidth, l = i * 2 * width;
-        for (var j = 0, jj = llWidth; j < jj; j++, k++, l += 2)
+        for (var j = 0; j < llWidth; j++, k++, l += 2) {
           items[l] = llItems[k];
-      }
-      for (var i = 0, ii = hlHeight; i < ii; i++) {
-        var k = i * hlWidth, l = i * 2 * width + 1;
-        for (var j = 0, jj = hlWidth; j < jj; j++, k++, l += 2)
+        }
+      }
+      for (i = 0; i < hlHeight; i++) {
+        k = i * hlWidth, l = i * 2 * width + 1;
+        for (j = 0; j < hlWidth; j++, k++, l += 2) {
           items[l] = hlItems[k];
-      }
-      for (var i = 0, ii = lhHeight; i < ii; i++) {
-        var k = i * lhWidth, l = (i * 2 + 1) * width;
-        for (var j = 0, jj = lhWidth; j < jj; j++, k++, l += 2)
+        }
+      }
+      for (i = 0; i < lhHeight; i++) {
+        k = i * lhWidth, l = (i * 2 + 1) * width;
+        for (j = 0; j < lhWidth; j++, k++, l += 2) {
           items[l] = lhItems[k];
-      }
-      for (var i = 0, ii = hhHeight; i < ii; i++) {
-        var k = i * hhWidth, l = (i * 2 + 1) * width + 1;
-        for (var j = 0, jj = hhWidth; j < jj; j++, k++, l += 2)
+        }
+      }
+      for (i = 0; i < hhHeight; i++) {
+        k = i * hhWidth, l = (i * 2 + 1) * width + 1;
+        for (j = 0; j < hhWidth; j++, k++, l += 2) {
           items[l] = hhItems[k];
+        }
       }
 
       var bufferPadding = 4;
-      var bufferLength = new Float32Array(Math.max(width, height) +
-        2 * bufferPadding);
-      var buffer = new Float32Array(bufferLength);
-      var bufferOut = new Float32Array(bufferLength);
+      var rowBuffer = new Float32Array(width + 2 * bufferPadding);
 
       // Section F.3.4 HOR_SR
       for (var v = 0; v < height; v++) {
         if (width == 1) {
           // if width = 1, when u0 even keep items as is, when odd divide by 2
           if ((u0 % 1) !== 0) {
             items[v * width] /= 2;
           }
           continue;
         }
-
-        var k = v * width;
-        var l = bufferPadding;
-        for (var u = 0; u < width; u++, k++, l++)
-          buffer[l] = items[k];
-
-        this.expand(buffer, bufferPadding, width);
-        this.filter(buffer, bufferPadding, width, u0, bufferOut);
-
         k = v * width;
-        l = bufferPadding;
-        for (var u = 0; u < width; u++, k++, l++)
-          items[k] = bufferOut[l];
-      }
+        rowBuffer.set(items.subarray(k, k + width), bufferPadding);
+
+        this.extend(rowBuffer, bufferPadding, width);
+        this.filter(rowBuffer, bufferPadding, width, u0, rowBuffer);
+
+        items.set(rowBuffer.subarray(bufferPadding, bufferPadding + width), k);
+      }
+
+      // Accesses to the items array can take long, because it may not fit into
+      // CPU cache and has to be fetched from main memory. Since subsequent
+      // accesses to the items array are not local when reading columns, we
+      // have a cache miss every time. To reduce cache misses, get up to
+      // 'numBuffers' items at a time and store them into the individual
+      // buffers. The colBuffers should be small enough to fit into CPU cache.
+      var numBuffers = 16;
+      var colBuffers = [];
+      for (i = 0; i < numBuffers; i++) {
+        colBuffers.push(new Float32Array(height + 2 * bufferPadding));
+      }
+      var b, currentBuffer = 0, ll = bufferPadding + height;
 
       // Section F.3.5 VER_SR
       for (var u = 0; u < width; u++) {
         if (height == 1) {
           // if height = 1, when v0 even keep items as is, when odd divide by 2
           if ((v0 % 1) !== 0) {
             items[u] /= 2;
           }
           continue;
         }
 
-        var k = u;
-        var l = bufferPadding;
-        for (var v = 0; v < height; v++, k += width, l++)
-          buffer[l] = items[k];
-
-        this.expand(buffer, bufferPadding, height);
-        this.filter(buffer, bufferPadding, height, v0, bufferOut);
-
-        k = u;
-        l = bufferPadding;
-        for (var v = 0; v < height; v++, k += width, l++)
-          items[k] = bufferOut[l];
-      }
+        // if we ran out of buffers, copy several image columns at once
+        if (currentBuffer === 0) {
+          numBuffers = Math.min(width - u, numBuffers);
+          for (k = u, l = bufferPadding; l < ll; k += width, l++) {
+            for (b = 0; b < numBuffers; b++) {
+              colBuffers[b][l] = items[k + b];
+            }
+          }
+          currentBuffer = numBuffers;
+        }
+
+        currentBuffer--;
+        var buffer = colBuffers[currentBuffer];
+        this.extend(buffer, bufferPadding, height);
+        this.filter(buffer, bufferPadding, height, v0, buffer);
+
+        // If this is last buffer in this group of buffers, flush all buffers.
+        if (currentBuffer === 0) {
+          k = u - numBuffers + 1;
+          for (l = bufferPadding; l < ll; k += width, l++) {
+            for (b = 0; b < numBuffers; b++) {
+              items[k + b] = colBuffers[b][l];
+            }
+          }
+        }
+      }
+
       return {
         width: width,
         height: height,
         items: items
       };
     };
     return Transform;
   })();
@@ -39408,27 +39511,26 @@ var JpegImage = (function jpegImage() {
     return offset - startOffset;
   }
 
   function buildComponentData(frame, component) {
     var lines = [];
     var blocksPerLine = component.blocksPerLine;
     var blocksPerColumn = component.blocksPerColumn;
     var samplesPerLine = blocksPerLine << 3;
-    var R = new Int32Array(64), r = new Uint8Array(64);
+    var R = new Int32Array(64);
 
     // A port of poppler's IDCT method which in turn is taken from:
     //   Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
     //   "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
     //   IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
     //   988-991.
-    function quantizeAndInverse(zz, dataOut, dataIn) {
+    function quantizeAndInverse(zz, p) {
       var qt = component.quantizationTable;
       var v0, v1, v2, v3, v4, v5, v6, v7, t;
-      var p = dataIn;
       var i;
 
       // dequant
       for (i = 0; i < 64; i++)
         p[i] = zz[i] * qt[i];
 
       // inverse DCT on rows
       for (i = 0; i < 8; ++i) {
@@ -39502,17 +39604,17 @@ var JpegImage = (function jpegImage() {
       // inverse DCT on columns
       for (i = 0; i < 8; ++i) {
         var col = i;
 
         // check for all-zero AC coefficients
         if (p[1*8 + col] == 0 && p[2*8 + col] == 0 && p[3*8 + col] == 0 &&
             p[4*8 + col] == 0 && p[5*8 + col] == 0 && p[6*8 + col] == 0 &&
             p[7*8 + col] == 0) {
-          t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14;
+          t = (dctSqrt2 * p[i+0] + 8192) >> 14;
           p[0*8 + col] = t;
           p[1*8 + col] = t;
           p[2*8 + col] = t;
           p[3*8 + col] = t;
           p[4*8 + col] = t;
           p[5*8 + col] = t;
           p[6*8 + col] = t;
           p[7*8 + col] = t;
@@ -39565,34 +39667,33 @@ var JpegImage = (function jpegImage() {
         p[2*8 + col] = v2 + v5;
         p[5*8 + col] = v2 - v5;
         p[3*8 + col] = v3 + v4;
         p[4*8 + col] = v3 - v4;
       }
 
       // convert to 8-bit integers
       for (i = 0; i < 64; ++i) {
-        var sample = 128 + ((p[i] + 8) >> 4);
-        dataOut[i] = sample < 0 ? 0 : sample > 0xFF ? 0xFF : sample;
+        p[i] = clampTo8bit((p[i] + 2056) >> 4);
       }
     }
 
     var i, j;
     for (var blockRow = 0; blockRow < blocksPerColumn; blockRow++) {
       var scanLine = blockRow << 3;
       for (i = 0; i < 8; i++)
         lines.push(new Uint8Array(samplesPerLine));
       for (var blockCol = 0; blockCol < blocksPerLine; blockCol++) {
-        quantizeAndInverse(component.blocks[blockRow][blockCol], r, R);
+        quantizeAndInverse(component.blocks[blockRow][blockCol], R);
 
         var offset = 0, sample = blockCol << 3;
         for (j = 0; j < 8; j++) {
           var line = lines[scanLine + j];
           for (i = 0; i < 8; i++)
-            line[sample + i] = r[offset++];
+            line[sample + i] = R[offset++];
         }
       }
     }
     return lines;
   }
 
   function clampTo8bit(a) {
     return a < 0 ? 0 : a > 255 ? 255 : a;
@@ -39643,17 +39744,17 @@ var JpegImage = (function jpegImage() {
             var blocksPerLine = Math.ceil(Math.ceil(frame.samplesPerLine / 8) * component.h / maxH);
             var blocksPerColumn = Math.ceil(Math.ceil(frame.scanLines  / 8) * component.v / maxV);
             var blocksPerLineForMcu = mcusPerLine * component.h;
             var blocksPerColumnForMcu = mcusPerColumn * component.v;
             var blocks = [];
             for (var i = 0; i < blocksPerColumnForMcu; i++) {
               var row = [];
               for (var j = 0; j < blocksPerLineForMcu; j++)
-                row.push(new Int32Array(64));
+                row.push(new Int16Array(64));
               blocks.push(row);
             }
             component.blocksPerLine = blocksPerLine;
             component.blocksPerColumn = blocksPerColumn;
             component.blocks = blocks;
           }
         }
         frame.maxH = maxH;
@@ -39847,184 +39948,146 @@ var JpegImage = (function jpegImage() {
           scaleX: component.h / frame.maxH,
           scaleY: component.v / frame.maxV
         });
       }
     },
     getData: function getData(width, height) {
       var scaleX = this.width / width, scaleY = this.height / height;
 
-      var component1, component2, component3, component4;
-      var component1Line, component2Line, component3Line, component4Line;
-      var x, y;
+      var component, componentLine, componentScaleX, componentScaleY;
+      var x, y, i;
       var offset = 0;
       var Y, Cb, Cr, K, C, M, Ye, R, G, B;
       var colorTransform;
-      var dataLength = width * height * this.components.length;
+      var numComponents = this.components.length;
+      var dataLength = width * height * numComponents;
       var data = new Uint8Array(dataLength);
-      switch (this.components.length) {
-        case 1:
-          component1 = this.components[0];
-          for (y = 0; y < height; y++) {
-            component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
-            for (x = 0; x < width; x++) {
-              Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-
-              data[offset++] = Y;
-            }
-          }
-          break;
-        case 2:
-          // PDF might compress two component data in custom colorspace
-          component1 = this.components[0];
-          component2 = this.components[1];
-          for (y = 0; y < height; y++) {
-            component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
-            component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
-            for (x = 0; x < width; x++) {
-              Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-              data[offset++] = Y;
-              Y = component2Line[0 | (x * component2.scaleX * scaleX)];
-              data[offset++] = Y;
-            }
-          }
-          break;
+
+      // First construct image data ...
+      for (i = 0; i < numComponents; i++) {
+        component = this.components[i];
+        componentScaleX = component.scaleX * scaleX;
+        componentScaleY = component.scaleY * scaleY;
+        offset = i;
+        for (y = 0; y < height; y++) {
+          componentLine = component.lines[0 | (y * componentScaleY)];
+          for (x = 0; x < width; x++) {
+            data[offset] = componentLine[0 | (x * componentScaleX)];
+            offset += numComponents;
+          }
+        }
+      }
+
+      // ... then transform colors, if necessary
+      switch (numComponents) {
+        case 1: case 2: break;
+        // no color conversion for one or two compoenents
+
         case 3:
           // The default transform for three components is true
           colorTransform = true;
           // The adobe transform marker overrides any previous setting
           if (this.adobe && this.adobe.transformCode)
             colorTransform = true;
           else if (typeof this.colorTransform !== 'undefined')
             colorTransform = !!this.colorTransform;
 
-          component1 = this.components[0];
-          component2 = this.components[1];
-          component3 = this.components[2];
-          for (y = 0; y < height; y++) {
-            component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
-            component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
-            component3Line = component3.lines[0 | (y * component3.scaleY * scaleY)];
-            for (x = 0; x < width; x++) {
-              if (!colorTransform) {
-                R = component1Line[0 | (x * component1.scaleX * scaleX)];
-                G = component2Line[0 | (x * component2.scaleX * scaleX)];
-                B = component3Line[0 | (x * component3.scaleX * scaleX)];
-              } else {
-                Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-                Cb = component2Line[0 | (x * component2.scaleX * scaleX)];
-                Cr = component3Line[0 | (x * component3.scaleX * scaleX)];
-
-                R = clampTo8bit(Y + 1.402 * (Cr - 128));
-                G = clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
-                B = clampTo8bit(Y + 1.772 * (Cb - 128));
-              }
-
-              data[offset++] = R;
-              data[offset++] = G;
-              data[offset++] = B;
+          if (colorTransform) {
+            for (i = 0; i < dataLength; i += numComponents) {
+              Y  = data[i    ];
+              Cb = data[i + 1];
+              Cr = data[i + 2];
+
+              R = clampTo8bit(Y + 1.402 * (Cr - 128));
+              G = clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
+              B = clampTo8bit(Y + 1.772 * (Cb - 128));
+
+              data[i    ] = R;
+              data[i + 1] = G;
+              data[i + 2] = B;
             }
           }
           break;
         case 4:
           // The default transform for four components is false
           colorTransform = false;
           // The adobe transform marker overrides any previous setting
           if (this.adobe && this.adobe.transformCode)
             colorTransform = true;
           else if (typeof this.colorTransform !== 'undefined')
             colorTransform = !!this.colorTransform;
 
-          component1 = this.components[0];
-          component2 = this.components[1];
-          component3 = this.components[2];
-          component4 = this.components[3];
-          for (y = 0; y < height; y++) {
-            component1Line = component1.lines[0 | (y * component1.scaleY * scaleY)];
-            component2Line = component2.lines[0 | (y * component2.scaleY * scaleY)];
-            component3Line = component3.lines[0 | (y * component3.scaleY * scaleY)];
-            component4Line = component4.lines[0 | (y * component4.scaleY * scaleY)];
-            for (x = 0; x < width; x++) {
-              if (!colorTransform) {
-                C = component1Line[0 | (x * component1.scaleX * scaleX)];
-                M = component2Line[0 | (x * component2.scaleX * scaleX)];
-                Ye = component3Line[0 | (x * component3.scaleX * scaleX)];
-                K = component4Line[0 | (x * component4.scaleX * scaleX)];
-              } else {
-                Y = component1Line[0 | (x * component1.scaleX * scaleX)];
-                Cb = component2Line[0 | (x * component2.scaleX * scaleX)];
-                Cr = component3Line[0 | (x * component3.scaleX * scaleX)];
-                K = component4Line[0 | (x * component4.scaleX * scaleX)];
-
-                C = 255 - clampTo8bit(Y + 1.402 * (Cr - 128));
-                M = 255 - clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
-                Ye = 255 - clampTo8bit(Y + 1.772 * (Cb - 128));
-              }
-              data[offset++] = C;
-              data[offset++] = M;
-              data[offset++] = Ye;
-              data[offset++] = K;
+          if (colorTransform) {
+            for (i = 0; i < dataLength; i += numComponents) {
+              Y  = data[i];
+              Cb = data[i + 1];
+              Cr = data[i + 2];
+
+              C = 255 - clampTo8bit(Y + 1.402 * (Cr - 128));
+              M = 255 - clampTo8bit(Y - 0.3441363 * (Cb - 128) - 0.71413636 * (Cr - 128));
+              Ye = 255 - clampTo8bit(Y + 1.772 * (Cb - 128));
+
+              data[i    ] = C;
+              data[i + 1] = M;
+              data[i + 2] = Ye;
+              // K is unchanged
             }
           }
           break;
         default:
           throw 'Unsupported color mode';
       }
       return data;
     },
     copyToImageData: function copyToImageData(imageData) {
       var width = imageData.width, height = imageData.height;
+      var imageDataBytes = width * height * 4;
       var imageDataArray = imageData.data;
       var data = this.getData(width, height);
-      var i = 0, j = 0, x, y;
+      var i = 0, j = 0;
       var Y, K, C, M, R, G, B;
       switch (this.components.length) {
         case 1:
-          for (y = 0; y < height; y++) {
-            for (x = 0; x < width; x++) {
-              Y = data[i++];
-
-              imageDataArray[j++] = Y;
-              imageDataArray[j++] = Y;
-              imageDataArray[j++] = Y;
-              imageDataArray[j++] = 255;
-            }
+          while (j < imageDataBytes) {
+            Y = data[i++];
+
+            imageDataArray[j++] = Y;
+            imageDataArray[j++] = Y;
+            imageDataArray[j++] = Y;
+            imageDataArray[j++] = 255;
           }
           break;
         case 3:
-          for (y = 0; y < height; y++) {
-            for (x = 0; x < width; x++) {
-              R = data[i++];
-              G = data[i++];
-              B = data[i++];
-
-              imageDataArray[j++] = R;
-              imageDataArray[j++] = G;
-              imageDataArray[j++] = B;
-              imageDataArray[j++] = 255;
-            }
+          while (j < imageDataBytes) {
+            R = data[i++];
+            G = data[i++];
+            B = data[i++];
+
+            imageDataArray[j++] = R;
+            imageDataArray[j++] = G;
+            imageDataArray[j++] = B;
+            imageDataArray[j++] = 255;
           }
           break;
         case 4:
-          for (y = 0; y < height; y++) {
-            for (x = 0; x < width; x++) {
-              C = data[i++];
-              M = data[i++];
-              Y = data[i++];
-              K = data[i++];
-
-              R = 255 - clampTo8bit(C * (1 - K / 255) + K);
-              G = 255 - clampTo8bit(M * (1 - K / 255) + K);
-              B = 255 - clampTo8bit(Y * (1 - K / 255) + K);
-
-              imageDataArray[j++] = R;
-              imageDataArray[j++] = G;
-              imageDataArray[j++] = B;
-              imageDataArray[j++] = 255;
-            }
+          while (j < imageDataBytes) {
+            C = data[i++];
+            M = data[i++];
+            Y = data[i++];
+            K = data[i++];
+
+            R = 255 - clampTo8bit(C * (1 - K / 255) + K);
+            G = 255 - clampTo8bit(M * (1 - K / 255) + K);
+            B = 255 - clampTo8bit(Y * (1 - K / 255) + K);
+
+            imageDataArray[j++] = R;
+            imageDataArray[j++] = G;
+            imageDataArray[j++] = B;
+            imageDataArray[j++] = 255;
           }
           break;
         default:
           throw 'Unsupported color mode';
       }
     }
   };
 
index 4b5551e23600acf956df706d73cab427db50b90c..bef02743fc108697e14e0e5daab8181f7ef91dd8
GIT binary patch
literal 199
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6`aE46Ln;`jUU1|(WFXM`uzZ<i
z<8)EMt{|mXaV+9Z51a(Fx;mVKK5(4(?3xhb{-Jg@&)@K)^B+&rnEJfwd;GyU=5cQm
zmdWd%;*dFSquSq7&2B0!w?AW7!m9JlifsPJ_iD0D2q;cxm@%pB&|CHR$^+^G@rA;P
x69iKx8$64;Ssyf6Fud%7>fwf<{~}+$G0pUl&6i=kdI{(<22WQ%mvv4FO#q)8O6mXr
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1da6dc949cd6451c2d8ea39e1618d0323d2e1ec1
GIT binary patch
literal 304
zc$@(+0nh%4P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002@Nkl<Zcmd7S
zZ7u^*6o>J%mRW)o*bZ%{dl2K@N_?~eFJnrG5D`)>eWA=I9=*xr<Q5%0Cz1F+A8+pO
z<B|V9+DLsuU2Q&`fPNqQfs}Vf)0{xcgki`Bq`WbxasVw}dC|;3ixK@OBhX|>Z>GuI
z4!;9U26Pv$_Z4XH%%iCpph2GpV-c{*6Zhs6SfR_EJq5;V+<H<#lJk9T>?sh4&K}p+
z6sU+@u52lw#15CH6i}kr=3>#xgHlS7GA<BXbmC-rZcFmx0#QWS?|~#|o8+1eP-27A
zDkGpok#Q2T14`r>$J0E366+j!0VQ&&@3-ef{(7H#?13Ev59AjB0000<MNUMnLSTa3
C-hk%-
index f681e4ee44e4dd520759b974a7a1f6f868f30894..de1d0fc901c2d2369660026bd466d4c3f0a62eba
GIT binary patch
literal 193
zc$@*j06zbTP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0001pNkl<Zcmb8l
z(F(y(0LJm}m3RU#E2%{@;a)2jO1V(0iI%7xbspi*CY{r<o$~!IzrX$-8{`wAJL`B*
zabpz=u5T4fKUnbaoLd(%7nBqoO44s|>QONN1jjx$vyv5uZYI@G&FX~xujj12+YK~w
v*fr|J-NDGo&9wKH*qTY?mdrSMOX2+jbf@g_m202_00000NkvXXu0mjfGEh>(
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0250307c0d10b0c0a38a8381361ec265ef3080c8
GIT binary patch
literal 296
zc$@(!0oVSCP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002*Nkl<Zcmd7K
zYc2y}7{&3k7CW#5+i@Fv5ckVUeCrOB=?o!4L`b!?9jdE1)U-}3$~@<j=a;<ir}M}E
zKduqK0sk^k!V45ic!A!BHzt0d`>D^w4Rl6cnRtQcFE3nm0&QVWiRnO%{h3-*x?K4w
z&|<T)juHwyggkNid*D8(twj0Vg*|d<GH`2Xa#4XBN3mX@0EQ2*<IWB-hw<?$DnEec
z054<mea*|jMMS=*`RE2mJg+L-)m%4^g;|(S%62rbc+A9@15C#n+r}K=X{oVg%>kYa
uWt-+4V4d~Up94HjH;lQ?oa>Bv?A`$+U7<=?MIved0000<MNUMnLSTYHgMp0z
index f681e4ee44e4dd520759b974a7a1f6f868f30894..de1d0fc901c2d2369660026bd466d4c3f0a62eba
GIT binary patch
literal 193
zc$@*j06zbTP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0001pNkl<Zcmb8l
z(F(y(0LJm}m3RU#E2%{@;a)2jO1V(0iI%7xbspi*CY{r<o$~!IzrX$-8{`wAJL`B*
zabpz=u5T4fKUnbaoLd(%7nBqoO44s|>QONN1jjx$vyv5uZYI@G&FX~xujj12+YK~w
v*fr|J-NDGo&9wKH*qTY?mdrSMOX2+jbf@g_m202_00000NkvXXu0mjfGEh>(
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0250307c0d10b0c0a38a8381361ec265ef3080c8
GIT binary patch
literal 296
zc$@(!0oVSCP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002*Nkl<Zcmd7K
zYc2y}7{&3k7CW#5+i@Fv5ckVUeCrOB=?o!4L`b!?9jdE1)U-}3$~@<j=a;<ir}M}E
zKduqK0sk^k!V45ic!A!BHzt0d`>D^w4Rl6cnRtQcFE3nm0&QVWiRnO%{h3-*x?K4w
z&|<T)juHwyggkNid*D8(twj0Vg*|d<GH`2Xa#4XBN3mX@0EQ2*<IWB-hw<?$DnEec
z054<mea*|jMMS=*`RE2mJg+L-)m%4^g;|(S%62rbc+A9@15C#n+r}K=X{oVg%>kYa
uWt-+4V4d~Up94HjH;lQ?oa>Bv?A`$+U7<=?MIved0000<MNUMnLSTYHgMp0z
index 4b5551e23600acf956df706d73cab427db50b90c..bef02743fc108697e14e0e5daab8181f7ef91dd8
GIT binary patch
literal 199
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6`aE46Ln;`jUU1|(WFXM`uzZ<i
z<8)EMt{|mXaV+9Z51a(Fx;mVKK5(4(?3xhb{-Jg@&)@K)^B+&rnEJfwd;GyU=5cQm
zmdWd%;*dFSquSq7&2B0!w?AW7!m9JlifsPJ_iD0D2q;cxm@%pB&|CHR$^+^G@rA;P
x69iKx8$64;Ssyf6Fud%7>fwf<{~}+$G0pUl&6i=kdI{(<22WQ%mvv4FO#q)8O6mXr
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..1da6dc949cd6451c2d8ea39e1618d0323d2e1ec1
GIT binary patch
literal 304
zc$@(+0nh%4P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002@Nkl<Zcmd7S
zZ7u^*6o>J%mRW)o*bZ%{dl2K@N_?~eFJnrG5D`)>eWA=I9=*xr<Q5%0Cz1F+A8+pO
z<B|V9+DLsuU2Q&`fPNqQfs}Vf)0{xcgki`Bq`WbxasVw}dC|;3ixK@OBhX|>Z>GuI
z4!;9U26Pv$_Z4XH%%iCpph2GpV-c{*6Zhs6SfR_EJq5;V+<H<#lJk9T>?sh4&K}p+
z6sU+@u52lw#15CH6i}kr=3>#xgHlS7GA<BXbmC-rZcFmx0#QWS?|~#|o8+1eP-27A
zDkGpok#Q2T14`r>$J0E366+j!0VQ&&@3-ef{(7H#?13Ev59AjB0000<MNUMnLSTa3
C-hk%-
index a9e82db331e9dfc6e3a0d660423bbca5f31d3dcd..40925e25ace9954a0e3092c1cd19a02eca82fd07
GIT binary patch
literal 403
zc$@)~0c`$>P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e00046Nkl<Z7#U5$
z!Aima00!WH40Z|h(5;J?N_G%(p1Sr79=dkuK`L<Ii0bZT1wxtyMI;e|fiRdlp|B1?
zL1J!ou!0=c_NO*S-v<O3r$&Q4_GnOJ9RE?G>f7wOH{J8@xqHK&Z&Rg&Ka^Nx_w{OH
z9m_}{f#t3B*DH2;L<wVFhR=6;G=&JJqS4fy&Sx(JfN?%K<yjd5MtI6Ij0v-{Q|2QV
z;b!@;w+aCh{fqtu{s?=kd~mZERKE;FFqMRYsmQ<>RN>ve93sSHo*-nGyj%E|okxgm
zwh?+OeAn@Q=~fY<MGGPK`n`<yE}K*kV4ZaYsIYmz19inWhIxvZa0*Tl6BLJe-%wY8
zndUZ4Zc)To5(-8ra+79r8#4f6a!04h11=%JB=>1{^q7nZVNPje{Tf@WFvlD#Z27f@
xHm5*9K*0Q3+R{Et{`F7g<H*w1(pZ3ikza!z$HP=Cb}Ik?002ovPDHLkV1gF|uTTI0
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..adb240eaad3c4cd7329cccd7af188e6472302a00
GIT binary patch
literal 933
zc$@*H16urvP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg000AQNkl<Zcmb7^
zUuaWj7{(tnFA^{XcefjD=!K+>+qx@PFC2mwUI+_V#0!U0aTB~4lirBT6~rN1X&QR5
ziS$l!Yw6r@1zSsJY|}JHn=~zE#x^mTTW2Vij5U8sa-O{(2WEP{rm**SIDC2jyypZ$
zu-UMQe)e*dDJ}~sIR)q!6*{`)VITiso_|U8Pg*R?r@W{^akpIH<d-Te(an*il5jR!
z&}=@Gzzd7D_~PwQ&)x33-Jzbv+iP*rES4qJyxD>_^Ea`77qaQWFHU10yx4`egk5sl
z*L^xY$SjrrLXvIv1<huXIYnXW;z_ik3APcX_2S9Gl$DZnbNvFR`G8qPcBo}P+-NlJ
zmi^fwD=7`<e+z1tManSqd}!xhIIz_?cJ6&Xq_WJ`F4s_lT=bY3rkO5;THCR$KFx!i
z6Aluu!M4`+LP+JM<sm?<_i>3!=HiuO_NUk4Dp-rxP!Akej+u+9vmRIn=r&V)#%D{n
z^zUANtej%Bh>gI#bW1tXbffYiQ;O^U>#+0frzN8px$(&j*!fOcii#hF0H5;dS{O~x
z=S_6reYxw?v=&yqLID5#!X%TKfeij91FHA;2r34j@JZrQ0y-RKPWX|~NnBFBbpz%c
z7q~EgZXP;JDo^gvnLnpIa}H*V2_{l!Q_vB|0y?R)$}wZ8OsOAB?m`Ya;#fc@cR@Lo
zFkanZjIove73hd#0iBh8<-Ga{=^$r0Tb?LGM;r_2lqZyv4r2UcJ`!g6t{xKI0vhi~
zL!7ZwIN_;I)1Xld7GXzp3)m?Jm0q1b;Q_WM`xzBx>C=Ky3r+X&vC@<M*bboUKsC$=
zBh{bj+!)M%uk`#6dDKIvBvn4#b)XB7%QbV2(?YZs<Qv3m(2fs;_fR*I=wnpnXRg5o
zYkc0-VTJ{Rfemk=<CKJ<va7>BuMa*c3vhgNxHQU1A<8>!BO1^qZdBz;qo)pU{QGfz
zcC>Vl4}~z}{DyDa%c6YEn7EQD-TS-~F4$(r@gu8)3{f$|Igarwo?)kOMowd*%vkQ~
z;PE5a0e#@w-4VHJPVfO0lZ?>dBf*f<q@|h@k*m8q;6j6OprzBl&|AIFUv;YY7kWGW
zXpz*G<H8>Ap@H*>o|iYvBj&g{ULJXQGto0}-g^jp^k@GIS5r3yiD|~C00000NkvXX
Hu0mjfs1U=|
index 2c1076d467cf676d338f8437a2dd062f27108106..e68846aa5f609f48e89b25692abdd85c2de7ecb9
GIT binary patch
literal 179
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6sytmBLn;{eUNGc3<RH-cuzYC+
z6Th^R0!ve`nWhd;&O`^Dpor+#_a2mUwI<%&Ds<ocX?*WLqdprhKaUrdMd!Pdr@Ya6
z%U$Mm{NM@Udk4<)EM1WPILqu;%!Q4c_N*<*ykI0eXXZ6_-bQbw3pGu%I*X6F^d8x6
dAM)#99H-!Av0COEwLn)ec)I$ztaD0e0su3%MKS;Y
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3ad8af5173850f4b645f9c94f4efe3379564b128
GIT binary patch
literal 266
zc$@(W0rmcgP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002dNkl<ZcmeIq
zQA)!w9DwovNp=T!g59OrvMt_EUlc_|Tv;h)#WBVZQT7tN!e^j}W3*`!M11J?d;etU
zzr+=v39b=Da5(aj;P^9mPxL*oH@wBOw^po(b>u=O3C8jVap{PU;A41oOzOaJ;Key$
zQU*)*)D8A5V+RX%R3~;UVg_@zlxMcgLkF6gqD74k8E7`-9X9B`!HkM$kBXUZFs0<F
zN6EBnpeT3@P@vidiZu^`)~NGAM$UbNoa}UvvEnY$s#!FbkxUYd<aZkS0@>+2AR>HC
Q6951J07*qoM6N<$f&iRyUH||9
index 10845c695d7b832450d530702ffab9f674427618..cb85a841b18be0235fc6c6714223609e1097d1f4
GIT binary patch
literal 301
zc$@((0n+}7P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002=Nkl<ZcmZw7
zze)o^6ov64B3Rl4Qj3*fVJAL-jkPefVCQRyZ;+7MN+IQ_C}I#%TqAK~h<_HuAXwN0
z7B|8s+~Z}UFzaN0%Ll_fD1JQRG2sJ?J`}jBf`R3s_FX}G?1ck&;`lUi@T!Vk<dQ!~
zRH1SsF9OIfJ}bY|e3U1D&{bZ)%IxON9N-pfTp`$2HP<(4M|HOINC(*gJ95u?wp7P;
z?18O8V*pf*-12T@*$ic;8GyN~T}JwhLa9xG6s3jFeO^z}ulE7{r#9DyXS@u>J24O|
z%<gUT;=gZemJMK>QaP!}IU9e5CrM>v9W%fW1qojxzD%=Q00000NkvXXu0mjf%W{5L
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..5c13f77ff003460753a39d9e406c0020231cabda
GIT binary patch
literal 583
zc$@)80=WH&P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0006GNkl<Zcmb8t
zKWGzS7{~FS6k7xZ2dh~m3f8%Tvr7u%;Gj^@-MWg1Ac#<OF{2<>sDncb1tl(lO0{5H
zQE6&xnvkURPmGNv7*b6L!Th=V`QF__%SrC--TQe6-{l_O7Xsbk5HrdU;SJO<GTh{*
zkul&6h6aC%;5QIO0cDWW%HZw`B1|h0yElYtbJ4nsxoE;ojhm6OJ~2}E6MhJLnOz&Z
z-=H8gtzVEAn$|D)CN!;I@KxygFduP@;qD7Q3r)8kTaW3?bkKnsH?9lNvm0}Eed&IK
zHKFNt(kdg}^{>pV0KIxYb5^yMTWCRz8#4m*=<-RYnu#WwP~*n506n@GajHIFM;%}f
zFY^Y^aW7$86$8At-QN{yj&9v@sxj9<1L$1g8gpFdYaS((q*!NG$}P*BQ`PAzs=(Gm
zuGm&PFW5_{a(v>7UM*fj4M<$)vPc?t4M_V?iB(Vmj)#B6xFk|MFXcmJ%3gpyBWK$S
zOgPLXDIdy{Wt3sfzR7D`46gK~gc4x?9LbFFLr|r0SztMRsut(_U<wZkC_s$`J-3I=
z1-=U+AI&2V<OL4Q+~M0G;+NuxLyf?}aPcV@{Q46M^@k9GnjII<{C&xJe<nsIU{SLJ
zz2jFo=SSi``qA|q`WWRKJ#%(;wC_Y89BTeE@cd?Fs{N|lr|p^F&l1t$3pj@D^AD`K
Vd>iii;Sc}-002ovPDHLkV1iPk2)h6P
index 55a9efe42f1318ada3290f56edc9214eab3d7fdd..be763e0c4a02cab5d7842c8999faade8c47059bf
GIT binary patch
literal 175
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6$~;{hLn;{eb{X<9DT=r}_bOuI
z*S;pAB4U5DMLQrPIWf`wN4P|1^q&c>d5`zJymvU>ZK0k3(_cShdv}w=iShns``k;6
z|9a2*kZNL>>-ng7x$0%-AZ2dv-evusD-M1!nVC^#Cw7NZpelLZ;<(0t-0Qey{BDRJ
YJiB<=q@5ck0$sr1>FVdQ&MBb@0Mz?GUH||9
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..8570984f2d9952ebb8543a6c8bbca2408be3fe90
GIT binary patch
literal 276
zc$@(g0qg#WP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002nNkl<ZcmeH{
zOG?Ht6h`k_x&vK-E9(N<(w06K;A0(%gSJTsBB&rDA_{fl7CxmHt=d--L>&Czfjc{g
zj6%Epm%+!Y13m~u!|`;DXFGIF9(|doYCM^ve(0R2@MwmrSf3_JJZz&%)@Kv4!2LS1
zV0}4}<8B$5v%a3la66C8Hg!&j6gN{uYNm4{!PR#}Vyttbi*Y&9#dbQsBEkhDB5R!!
zZ3qqBhHg41f;Mp0Iq}XP49B>3;N<f^K!bA!nlW(Z$VcGi5U2L^M?LjK!`Y()2li>V
a-`N}fhF>K<1*gRT0000<MNUMnLSTX{Jai8L
index d23d84a5435ebff9e4ae226659c25feba770dd1b..675d6da2c09cebd7e2375d94cbc43de49a28a6e8
GIT binary patch
literal 360
zc$@)f0hj)XP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0003mNkl<Z7#V%R
zF-rmg0EXcY#6@U`6rv^CT7n9}p&~b1>IXDM<M{&wN4ExD9SVY`8iJylj6$)9qQgiy
zFhu1%9HQD1I=VMBEeY&-BoQN~|Ioyd2$CdEixzp31oaCWn=P+KizYTUO<G=!HT6-a
zPLqanlrg4b)3J=<9MQmGRo|#mrFxatj7H^?PotW-N>lYJjH!bP6)MzmI9A`JeaMrW
zP{;Eb78VxP+o^u+tz)%w>Y7tjQAHKiynbv>Q2u<>aK#ZG+*=LzzJU35q7H&2Nb8UG
z4tHis9hc+YH714zU~vDD-<VaGf7hUhNtOr!0z}ASQrtD<S5Ig=?w)f)i85tM+_>l4
zafLJ>w7618y&iZMZti8jkXl?(NPqY>rLdN@q_C#sSI-x0yte^Yo}f<v0000<MNUMn
GLSTa5F_{_w
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b9e74312270af04fa2b9b033675d8674faab64e6
GIT binary patch
literal 731
zc$@*-0wn#3P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0007_Nkl<ZcmcJ~
zUr2Lx90u^mmDq%63`rAqV>h8e7=r0Vcp)Y9Pr|5OlrS&sF1(Z=>P7`I$&2V#B8FQ@
z#xx11n2B@MtaN4N=HFayP|U&0*qP^fzdz3rbvx5{@V?*A7yO;ybIvoweHnhs|HM2|
zKI2b<|A+)(s$d&G<Se(D5ZesM({plLvf#)BVWXR2CiyRqrPOdNPf59TOKMqgXnI<H
z=R2OrCx^x4_C(SKtAYd5i8wOO)+CLyqqtzdkRFTsrv~5XsqK8~#lE+u2IGD`W@ZQa
zAv+2S_O9Fe>YW}mq85+9hKEosr^Z)ai~BEfeTNO#3*wjb*wP4^U`OFpp(!|`#~2s8
z`FYx|7Q`+s4a0>};|dO&@9px<s|9~wvCm`EH$)-0_I$>Bxm8wN7W`#thbT7CssC=I
zTAKz9&;++jKrz^NzcAADM`@&iv`7W`N3qmw3RZ&e8hPgH3^G7Qpcx$&o`vOn_6(y+
zZas$_WXt7wl$(nFs}3E|%QjcV-;}eBGn_%TTz6djMaiyYk%erz{(qejCHZ9%NywHf
z{V9J|qQg-{A#0$GFYt5L61R9<|A{{;zE^$lK~~|*404N++(Ztym|$2*&p8|pI3TP1
z`L<k!M1&sV1|E4Mq|CfG14UM;c_QiOnxfxS;gNJrN&0K*YoN#)`n$A6uAbZACv+A6
z@BCPjRYhCu@9Kv^)&TpsC%?=e&V?D_7++#N9~Sj;8k3L1Mw(w9_rMN|agO$B3tTa+
zOUWj;#HO6qFYdL4(LOj)Vw~>ol$YO^mh!s0;lvGNuWs=UoKADO*y*%)pt=Qi+&XoY
ztsnG;h7yz6Kt7lcW&?@I(9rw6m9415J&yxVq8aUYUbLfGo*u)4nY;A)5mO4m-#Y*R
N002ovPDHLkV1o45W##|?
index f36bba81e041f42e3e73ecac0413da2b7c6cc90b..e1c7598886bd49e194764015577b766aadd82288
GIT binary patch
literal 359
zc$@)e0hs=YP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0003lNkl<Z7#VfJ
zF-rmg0EXcY!bNBh?jTyC%_XP^T#Vdo@eedb<MjgyN1GaSZ72wuY6uLZMJW`EAUceM
z14A_K4k4&UA?e<@vXa2(k;WoTT7NLeQl&?aDp?E(4_`mX1RZ*KxVU)qf)2a5xcWv0
zpC`Xqu;S@>x?uT5p77|>RR|+!(Z0%SPBBerLNU!<<!RHVt<YebNB2}S8sZF}E-hNL
z6zZ38j@I<+t%QSvgY$f@(8mMKjcNT^P)aGKl+vO?A2#>(Nsaeb!tN(Ep1s3u|3Lqc
zXA482_4)TIcUT&Mg&ka9PU%bJ(4vmb9tomENw9}a{m@cGL+1YGpu!Cenlx!}GpOuu
z%G3xmxmwG;o&*<z^2>28mt2*pe<GUIl2){=CCw_Lp-;j?w+ux$rQ`qr002ovPDHLk
FV1jvRo<jft
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cb257b41c537552a19f711ced5ec19cad5fc1c9f
GIT binary patch
literal 714
zc$@*s0yX`KP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0007!Nkl<Zcmc)J
zK}geK7zXgymDHq2MA8H=)*&<qL(n{g2SK4EA)|Itm<KxrJ4z6qR1lLqgjb;$HnM_Q
z5>7D_=c-w$rRM%>rppb3*+sVXe|le>e}?;(Er{M9e0<;c?0eV_qyI8^j_+&`1R|)U
z;XGO}fI0Zt9GrYA<6DaHV~zRM1twVFK>**dj<uL|J_Y#J!YQ$@F^Yl$yub!OSyfoW
z2B&2>W85SZR6yh2FUfJb!D6Sq1r_=#U#<w<r#bqXuh!*Mo~~-V-q)--bRSj{#227I
zU&Qi`<wx~(R7g2=m`rqlGI&>5b6Imp7B9ZQ6dlA8G-$eSq@9Y$Onc`L6}j4VAGA1e
z1=skwPmHutJ|&xcR~vkBjDocAI6jNzhpOjziuITk{*=Ke2$x|I3s}%U+A3|7NKzG}
zAk>06vGjn<q!`YWjDjDJ@kzLDxJV`F<TOEWAV@(XS;CW;6+LHrNQH{2Lg5_kj{Y9g
z!g|z7sUlf^PT_-?Ju*wFB3ZV_@J@tIg(y`dOTYoI*u1hysUlfs+VEC{?)~LA=&QkN
zp}#>6XdlOMA5}2zo(U{7GxQ7|5$+DtKDyz>3|zQm6o@A`;T9ZPLCJCIg`0Wi>*q<x
z!m>{U9GDRL?<%aEPKbabJ1?6A$s(GnBf}UMn8ID;D}MVOPR2!KxT(5{c95|#cUhyO
zcqQP07oE6>JRD?syzAu0o}Dy0+GSP$>9RT+BSRRAndFjb%&=+RP43=DhB_K4i;_&1
zr8a2C%jAM~ORYRlKIV)PyKSo<qlvcq?Y4{(GSj}3n_ham!QJZb-F8M@QP;N9-|KF@
w)sS9Fx%9`ANhhh8%IN|tr(!-Gqkl8M0N&iw@8RFz)Bpeg07*qoM6N<$f{`^)u>b%7
index b27050e2116e305c929ab43c02e3a0c05a00df90..a187be6c9ba78003d9d2013e4cdc1c7f73bb8949
GIT binary patch
literal 174
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6N<Cd1Ln;`PlN1;paQ)lw+{`0z
zf+g9Y#<^8O&ESu7Yl_B?ZZ1R7KaQ;>28}V=>tyzpi1dq!_s#Y(o?Z6PqD=UotbK;z
z+=pt1eY;;C=TG8Xk<7mK*`GaMCo^*7N1nAT`yj#0VsudA+GmM(2Yq*^+n%4r$i(=*
XtGDvpiMgkM4q)(f^>bP0l+XkKeAzzU
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4efbaa6758dce6ea82f9e03e81c0196cd806b266
GIT binary patch
literal 260
zc$@(Q0sH=mP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0002XNkl<ZcmeH{
z&B}s66owD8@qR=YYP?CMM1;JUgaO?&vuMB(L<C#562eUrfyC!fj6Xqq;CVLk;(0i)
z3lS`w?+et`01QET05=213d+DL7$LYD`27WIh5z^s)(W+#&kHJ4V&iSSO3bWKFxS7Z
zhP!@onsGtS>|Mj3PYt*CIh*)L;+Ye)qJLer!U=dbLBLZSzSesM4tY9KKocB+w3G#Z
zP#|$ck0S&$A%{+O@CHd@not;m^nk=r!lx-oOkfDo1ASdr=)nV-#q?0Gf`(oI0000<
KMNUMnLSTYMTxkmc
index 7755eee779e5ad801d274ba8184673bcba08779c..eaab35f09e12fed1a285ca765b38846f84ebbb91
GIT binary patch
literal 259
zc$@(P0sQ`nP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002WNkl<Zcma)$
zJ<7sB5QeAv@D%B^vrw?#!d|q`6|@k%klw*Y{3RqsK(P=k1Q9iC;|V@?oXNNhSuC6f
zl6l{K5*B_Moa3tk;0QsG*Awp*04*yj+yb~MaHzsHpaX`8^bVJR2NsO};Vg7}{AGXO
zvkE5x{(z_EvkFIn_b^Mb7kCe|6glSO7!3F^lbAadGR*$h7||v~ZpEDn36Z+xM`_S;
z%AE?klEf{rj!oRqku+YgQz{9n4s^AxBs;TU0m?@U%oo}~^9E?zG!7ESS7rbJ002ov
JPDHLkV1f;GXr2H7
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..896face455a605a86196bce9ad3b7d640468dd17
GIT binary patch
literal 425
zc$@*L0apHrP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0004SNkl<Zcmd7L
zyGkoj7{&2#2zDvNMnqA346TOXTWFCdh+-`&f(V{29L_6PiWjWCCm9n%f&@jBsJR>)
zyTrz@9NlC#^DUV~uyB6O#`Wc|{GJapsNf}n_~s#6@aR;~Ks|!^o;hKkb<`q>uf_@c
ze2Ny_{735Rz+(^grfCv7@DMF@(?E&?)gFc+;s(Y=f4GnKw)K%<_IcMs6%8~k4%~hd
z1#ZH&m*NR=jd<c<P467I4jUU4N4lRgIiYtBRKm>9Z9?xHxKc#XI|a&$D7>pcNfCv2
z6(}mA@U8*{MHJpuAa5+piu*}@=C6x$-8&9=MtcJe#2}8pdIkrw28vjvgyHy0F}R~Z
zCUA)rP9TO&f3a5-II~coM6B}%`OpmoPD3uR3@7y8J#|5W6U7S>1Ne&^?G!jBIjmz4
zBlw35uM~LQ#}Ub*j1tayY3;VeknSU$Z13T)Kdqf~GA)J#k0F^Bw@*|4^-q28r{Use
T)~jCX00000NkvXXu0mjf;mWr^
index 63a7c320e9a981f83c3416f754e4db1a6ab504d4..306eb43b86861ffd83ab17541d64a4e8d240c86a
GIT binary patch
literal 108
zc%17D@N?(olHy`uVBq!ia0vp^>_9BQ!3HF6HKu+5QpTPxjv*44lM^HyKK%b*U#Aeq
zu;`*{L_>wHfPM2NofDJ17YG^bX|d`%n5z@V{_rc;Tt)`NYtfrMyS6_7YG?3t^>bP0
Hl+XkKJQO0C
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f7570bc0d30db3dafe54aa7c1fe92367690f5046
GIT binary patch
literal 152
zc%17D@N?(olHy`uVBq!ia0vp^d_b(g!2%>Zo;S(>sd!Hp$B+ufWQooP^)>=V3JT0Z
z$G`noR@ib>ZRMZ;zy7B?RLGuin*8K{y@Up1n}eABCY96wr#d)VuzZRTnDjQlktL_y
z<57djB$XEmhvE+MurwWXw|F2ZV0`Mr1B0n74EE`D>#U8d6@XSTc)I$ztaD0e0s!v6
BGz<U$
index e139f3017d6379d324fcdab5e850fc9bd80928ff..b5cf1bd06139d17c90cb6ab492221803f5047543
GIT binary patch
literal 295
zc$@(z0oeYDP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002)Nkl<ZcmZP|
z0{q|c{~Z)={m=QI0TqIXXaAo-Adoc$n}SD3@ag~8Nbm+&K}R|+*q7V~RB#?>G;VmC
z;q~VKH(~JG$%=&H*l#BhBA@m%+@JRU8U%hjmgvvG%fOT9|Lqt|?CCOwE9L($f#A18
zKxs~}zd3<Q4naikbTgca`F|b+Ya<}i5G8ey5Ycma3<ur*p8-Ljmu|!S4rJYch#n1Q
z*l+Ux1PsCyAVdz@G3-$Je-s8`3J@Zjv>BF({67qbqF`wWgvfL;hE+U&_WnNzfk1a(
t2EvOl{_oukEDQ`x40a3-IG`;90|2DgL5N;Bd29dx002ovPDHLkV1nayd!_&Y
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..91ab76593eadd6280b2a554d8d3eb1430d7ef6ba
GIT binary patch
literal 550
zc$@(y0@?kEP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0005)Nkl<Zcmd7M
zKWGzS7=ZETVn}ciS_N09V5|rZh2kIv|4^4MRUF&|?d0I#5cd*62s+dv{-YfNl^{jj
zB&60xtBLfIQ*&|}jcJm>V8EdrV)CkilFRiwZGwaE58mndUOxVhkz-=YH-{A&5&o{d
zns22dWrs@ZlkDB%fnWKmLb;Wa?OQuga#3zxZ}MmDC0|@s<g2T>&JT+HXqXKe@Ow>O
zxH{3h$him+5RYuj9yN~lP7jG!JjhF_%4%QAQk5*<6Jqsm?Kz+C$$K}&xzJc>>|@Nm
zsKzm_h^c1H4jjOTZ(zSQ>)J$FIwS8?teL?fGyt^0A!|lm<t`CFC~r3VaDU_Z#tHMT
zs!N^X<c_8;xo+m2uIB)nFKFD9oYSLW(AJWYwKJxCK{T9$KVVErwp(~7VQO(%=`g1K
z0Y5GR#<aa%U&I3xZ^`S9=x7voH%9Gk?O_dSSd)^mF~w@b!D=(@ZRvIiN|=}Bl>!cm
zrf{tQ1#;(QSpf${lMm-1Pv*3|P{2Xa=o32VET52+0uG8MJ)VX%$q`vnz(LU@4ksYN
zlb}3P@CY_uRWrYD9_C5zkwt}Z+X>H)v#KVxI|eagyX2`tMhu(u=AyNL7l4cY^~bW%
oyZVDVb*O{JA&&H6n13-p0bKq8;5tc*kN^Mx07*qoM6N<$g1cw`kpKVy
index 9ba3667e94986235e8a27dff14d6a70f26e49193..1957f79ab95a970cc93eaeadec532661c5a1ae55
GIT binary patch
literal 242
zc$@+901f|%P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002FNkl<Zcmb8o
zK?;IU5C-6Zpc53d>kgj4Lv#w4(S5>&h#<m)I)MZ&f}llE5ky&tPujPrzj~ug_S!Tb
zyaE4ThW;A3m>|Q|$T30}L=f&H#|39(FQ@U4`qXaxf1Bc1+XmFJ4%~M*)ck=@jF*AE
z@OmCGUIsRTT4WE_AE@?zRCReJsxQhE$k7T*n^xpdHBOme(Nrc9n@SO5E{eDjb45p(
sF&)`4S3;ynbtti233MRw&&qfF1f{Oim%bd<nE(I)07*qoM6N<$f<Ve*x&QzG
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..16ebcb8ef1e923710574bb914e19526f2545abdb
GIT binary patch
literal 398
zc$@)_0df9`P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg00041Nkl<Zcmd7N
zJ4ypl7{&1;s3@c{OGq0V8yDaXVy9wf73@>k=KUzNjE&+Z(ng)kL^NUuQIUigABdoZ
zjSq~+fdO@9zMHugg5R&b=MNYE`8du+Zn4FCK6*TGn{x~k1gJ8@hCRLGEpOaj+8e8g
zB8)MpkFy_r`|-8kb8}@LQy6}n7&Pq1SAK);+5#pKbni>{<G#dNM+m|9w8Klu+i7e%
z1~<e6uMPGj?M;kA=h$IaQdzFR3l#x7vU0QxFO&tmki|oBcp)y}xeO!FJDw@P50tcJ
z`hk{A9Z0a}(v*2#CB6cP)Jr`1oq7oo{J4l!<gq@h=*-=T0*~}q1!wM0<arp($~$v0
zVdi)+oS9S4okW(Fnwb^mLc){@b2(AV(D18e<hh(kbKk9&R?p>+q`3FZOa;uPgpuN|
s!;t41i6pD68cF@RkkFqi61Km+Pl0_ej2E!U-~a#s07*qoM6N<$f+7928vp<R
index 272a3ca8351f251e8e9c6179b5d0fc5496f3a5c7..8219ecf83c6bcf74acc8d0cf5935347a7937edb5
GIT binary patch
literal 238
zc$@+501^L*P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002BNkl<Zcma*d
zK?;IE6vpufK_{q1tM1?lIz$JFI#9F_5kwfM6G+e^2wDV1fs}<f(%yxA#nkhS*`oO^
z=E3);KOVZ6AjRECFvkES2t;k_Psg|*dAZ{DNbQ8b&cVf*6^nvcb<Bo{S$QmpRmZ4@
zlZBWZE$oFIh@Geh3bC=Z#D+2fIa*=Uq!l^zc}^Z;U6+S4n<NXc5?R2rm1rN!H|^WA
oop^{4X;0>6;%ZmspUL<91jYXM#X%ehtN;K207*qoM6N<$g5$DeH~;_u
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..758c01d8364c5597d7e9ead825cf4e7754c8d929
GIT binary patch
literal 396
zc$@)@0dxL|P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003~Nkl<Zcmd7K
zyGjE=6vpu*s3@c{kB~MtHa>uFpq+}Hm0+F1Hup;*cG@Vugl*K#ZX`wwAsWOGa}fz>
zkwzm~KZOBxbLOmLAviyn;=uQ(|M3vS0uJzqrx86=v5yr@f+Xsjpdf{JHeYJ!j=0AI
zdMIPgH=xkW`qFa+9gXf=3-i7Kg{HTb-3Hnk9k+}r-+)2^XB#c8_HcDb96Kz|zFy%@
zr+?TdjvvNrduZwmN(16Fr=vAAblkd2oaVF}#;t%j0<#gojle8GW2g(H0CO!c4%7t3
zfvP|ZM9}o82$~*|&j5vrIb8luF-IZ#_Cih;7v`L-ntKx&oSShnYR(gBlz!%<)m)pf
zQ#kWyr_@|dB;m;HB%5m!ww^R+i9!MvS4hZno`~brs}PswLc)&W<cl4X=VHQ&;aIWQ
q+%yqI9(gM&%*_(!b0P8JZ{IsjqP}qdC0j-S0000<MNUMnLSTZQ0jpd9
index da02bc69f7aab143771a3d6373b1c547605d0798..98e7ce481c163c0d4221be87d262096c631f800e
GIT binary patch
literal 245
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6_ISEDhEy<4J-?BwDL{nn!R9Sn
zezMp$J0}Z%5nJo{{*m$yvn_2Bw=O7&im*63D@e3?++e=)=tH^QooM&X3qQwRIQ(C~
z{hy4Eq$i8!k>1w*T#Q92I_?)jA__{b8r{ocmDkjB;))luQR&DQs#s?5{OcWsXDuPe
zmo+wBW`Ex!Y-z#88@{DbU>|qCUYXlY&65@XZDezLlfot}w3kTg-zv6Kc{)$s27`wd
tL8q?PzUn!-=+u@K&b74>{cp1VFo`V}NvvaB+5+?kgQu&X%Q~loCIFI;U?~6q
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a01b02380b90e5ab32727ac5460eca3108a8f1e5
GIT binary patch
literal 405
zc$@*10c!q<P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg00048Nkl<Zcmd7Q
z!7c+)6vpvGSeDpGkg%1A2WTyH;~jVd?aZ{X@Blo3wZsG1N;eiV!n8$1BSeI>rkxqu
zT8M?#!bm@}5SjL#xxE$==eN2ibN;KL|31hDNQNMj#dAQK=y(1Y5EDv)44Ux1HIb1A
zxbp_wkVaG@>bwr8M;#f}fPp8}M8Vcj2^jETNAO_u3+Qn1AmKun1#~zl_u)W~3TUX}
zUO^Qa7tmniPLU0*H;_gJx9U(qIvhx$jGJF7BlQ!YX-bCSn%DhRa1}MU;;H}2mpt`A
ziKiME#syC?(4NFOPciVagfos`@JYn1UN>;cY3;X2BrFj7v{2+Y+YX6@#fO0+3LJCQ
zBvH>3vz-&<Iqh6xCPAXE2c|j)usFWCxlDs3AH-oIk7Lo>-ueoS%1%d+z!pldaMb1S
zJy+Y=T^nDZ7)fV{#%PX`f<=ncJWbF5{oQ;4iDXE!#q;ab00000NkvXXu0mjfx2&{B
index a4d6c8ea7512a65aa46bc8dfa2eadf0d84911837..fb9daa337656a75091ea00d4c5600ba4f557d834
GIT binary patch
literal 246
zc$@+D015wzP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002JNkl<Zcmb8q
zG0MU~5XJFnEG%;Z&tPHchu|$NExd|&1X~MR36aFYMpRG`1PdV$`6L9<10+p~=Y#CB
zOI!={n`YQQgpnUVtVnDETZ9Ki-+~YsQpymzf+e5sO3JMk1o+3z;1<|{j|6c|0$&FU
zu2+YcFCv__^n`FRxD#LO4`;)D=E>4@1mz9~E$`$~;b_k}_F6G1q{7jr18lHWj_7~<
wLcH<tH7nQ5h{*_^2~@(vy6VI~X-Pxm4aA%w=kn*`ng9R*07*qoM6N<$f(Be=$^ZZW
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a5cfd755b0b400bc6b7790c0fd41e7aa70d8aa1c
GIT binary patch
literal 403
zc$@)~0c`$>P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg00046Nkl<Zcmd7Q
zy-Gr19LMorQKLmmP=l>ObOG9sOZQNBke(N5=mxxi_UHnda|*&J&5TH*h$u8)^QA!?
z;xt&CUk(xa@IS{#Xz2Hu|6d*s2mgJH_rVY7C(gG%-^8f%*FGts5wO{2{YRVjxB;6j
z)&{h^5?<#`RuxU!x&ey~Rs;=NIsuDymORvHjS85o@x@1treDBhm4y+iG`#`_%Y4>Q
zrXd9kmiVNpL_-b4SmY!16&V{0L|Nd&m<o*k1`tGK5btG(3<<((yp!qw%C|E8KwhRF
zxbZNp8@QG^iw;z91a6L3lFmj4Ds%+SF>{h`q6-zeg7QAIlCLxaTHheG%?nYsXZ0`)
zJwbTMNirjGFS)Go0!$`0KT}Lg+!F?+fC96-Tkl6a7i8QNLsCG2!2H_bPUYYu$y1&U
xNi)wqhB>1K6qvvQRuRHFB2cYh4paDxeFMq5jmkNGJDLCh002ovPDHLkV1nI`spbFx
index 2bd1c1dfe84330ee65430f38f73abee8eb2bb72a..3ac21244dff26830f46ec462f2dab36e1a18938c
GIT binary patch
literal 321
zc$@)20lxl;P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e00039Nkl<ZC{tr#
zAPoM$gTgwvNF7WJ!hHgQm*z4k!SyIzoDC6$D0l>d-;VqjhMU0mZ4X2g!hLXQ*2lyD
zAO1T4QSzVf-}e8HzMQ-~=l=t+g42^3RNS0C9Q=RpM>>fAJ?a1b&&NYN8B~EX5F3G*
z)y-)~6N3zxFSVx?D9sL)fdf{kGziForAY+;dH)B&*<t^MkfqW=(*M@{zxqECDt-0e
z7Lbzv=@11M|L6W&_5aMLtqpo0evZcb4gXL7+x)-a|3!#`qyNwSKly31zdO`vtoDxY
z*Zn^U6g>)2a2N#7G$Xm3^>hP76r$iD7@qu}40l!X|5FfA2;Tt;<=`gB!NnK=_L!_3
TdOB@M00000NkvXXu0mjfBu|wT
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..cada9e7918da28bdf84af38c354dbf1e1c6fe31a
GIT binary patch
literal 586
zc$@)B0=4~#P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0006JNkl<Zcmd^-
zJ!=$E6oyY10%{dlND(E4g^IO81kob?hE&SJrZZNXAQBZT%Y0x$tc>6nm<X%An$7NH
z?(8NRRxoa6H(3=s|AFWA&YkR>`NYOT@I1}o-1mKoVd&o&{7f+mN-&#|()Zx;dz{8H
zjZ$((8_UU@2);#emg03$I7{)Q2)+sjYw5ZuyjRhz2zmk^;u<K2OTRkNtOyQc^e~=T
zA44~u6v2T{Z=E~Ark}<$>iyU5k4mtKpo5NDq;oH3c;DYmG_Dw9@94#Qd!Np$MYD$j
zPc4{FS9m_nZFoN1#o4faN{c<ie&rqw`=3)SzzYRxKK$~9mu22V8|~KPq2ogoK!eRW
z|AsH`?wUFo#k?X#q%>jOD4v!1b8BVb^Z<qEggwW56{#Bq<xJuBb*YQu&JC&mX-?!{
z|ChlqC{6Y?D|ituCR5i5{)DS}f@u5#w&9?aP)z8H!){D5DFPRzew~|8ur)5ugwd1O
zF*locapmY%f-3?GyC|7@16#0s)@JA!^=EMP7T3*v3)@Cf(hW-lb<GYQumj8NwKvm=
zzpn6f3Y(}Kns}(wdK1B>!9gw9*2_{C#gi$nn)e!<ASZ&Vz}44@x+qp}@<uc(f(@aw
zlCF!Q{V19h!N&-76hS!@VMVhd_z*+oD2h<=qzK+8urm}z*vVWdpvx&nC^;h;slPG5
Y0k(Qrk4L1bp8x;=07*qoM6N<$g1hz(@c;k-
index ccc62089faef81a6390f53ccbc2ade2ca52a4b1b..51275e54bee695c76a455579262ad642efe7220c
GIT binary patch
literal 257
zc$@(N0sj7pP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002UNkl<Zcma*d
zJxawu90c$=f$u8Mj{|IHm*5dn=skjXf>f!}1hmw`k2Xb!g|HAo2t*7E*&>DgR^vZU
zVV4ks^D731!9T-ielNTbGw_$axq|YpFKNTWBMo*4b40@@e=r<~g@MK&J_SO41MfMq
z6K6!=^stS5fYisq7foRJTRX628(*Bq(yKr%dZE{WZ`;7vZJ2IZv$kcQLwS8}%Xy#f
zfMcjMVUtA}0uh@ufx-#qxPlcm-vgSJD;yl)1oluX_K^Glse?0qV_8Mk00000NkvXX
Hu0mjf@9=3h
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..53d18daf7825ae12d99406068073d16ab682737e
GIT binary patch
literal 464
zc$@*y0WbcEP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0004(Nkl<Zcmd7P
zKX21O7{~G7WOeSq&{xp~sUVPC6?LpSc6DDwM?}|76%5^~BK0i<7{P56L_>|6%E6&Q
z<c~eFMUf>gKhE5R6HaVnnStjcWqH1ObaL>24WBUJ_Y#4uV1O`0z?e~qSOfwF1Pr+z
z$Bpe>*voD2#tn`c<-UL;j`nO=$Qx_VPMhTiws^}Shp<pIR@%sNYvF+C$i+ZHiL@Dt
z&cZj~Hw`5+omqU<P$JWrMPEaSOlKBfG?d76;3lsbNuhR+D6sasi==CALbMt3v+?7+
z;KZ8Ts!j<-8|*UpLzw<eIR*?fbr-y?2fR_9?Zbxs)ZtAvps)CkefaqFh<-Jor}fyE
zdi1IRKh^`b>j6L11HP{ZY}JG58#d<-o%HwW2=;PUN2XFHukd_-`kI$Y@{*S`_h91y
zIW}gls+39Ng#)bOp}H?Gw|H@Pf)(V=%H0Vs*gACdn;u{lW|A|ybdPtAQD7%+lCuPJ
zNHpGOlkX&todVvkrYUPEpq8BS?cYmI7hZsM*cGhfU(HW?%hSMo{ZqpL0000<MNUMn
GLSTX%=h>YA
index e52370e68dcaa9fd75a8764505d617d1cc8b2689..f9b75579b1e058baada95941a4a7ff0c80edb5cb
GIT binary patch
literal 309
zc$@(>0m}Y~P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002|Nkl<Z7#W?x
zze)lD0LSs)5Hu>}CT$H)>Cl*KShVy4rnvP0Z8?}Z*4h&|1f^pNMc6--g9AMzMF;T^
zdxEU<?%SexQ4RI^NPk0u5(5U5+17U)F~(-d5SuZ_`id=Vw^zw;?CkDU@@@~Cg#0EY
z`qiAmTGFz@*E#x=viw|&PAa0ARD_Oe$<Hxqcfy*fuh4c(`MqA!e9LI&BTaLBCBMf*
zOs_?f00EL-3-cnQ1)|di1_l;gx>y+IsY03~>NTiO@2lBS(WyDLQStmhYno%7XP%~a
zg|t=`Q(SSy6w-os!-I2sl2TAVdpUcr6!sO=uOix1Q2+A@lD3RUk?l9y00000NkvXX
Hu0mjfGKYz;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..456b133248fd5310857db3e2b174730f6488371b
GIT binary patch
literal 653
zc$@)^0&@L{P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg00071Nkl<Zcmd_m
zPe{{$7zgmTrXlIVQ>{bbX%$pI4<4dGmxrK3y9C*x5W092iXDWyS$NGul86ip{iUm*
zph&8bY4&exY`K>GnEG>Dd62o*(mD5i_k8$VY~O9Br=aKc@csAZc|K$K(~H}AmbW;?
zMG@u@&$EhH4=lw&FBkZQF-Ap9o)(M%&-~tka$b|+DChG;`IX(=w(){a#`%8{F<#$j
z!3oAVrx=lttE;Wi(dg)E3%QJl{>ms%ms(Jfo#2eJ;_GOI4YjBgwXk)xuK0A4^|Gqy
zg0)keVT6&~w6g^ktS^hRB{!`y&ScJIkb$(>x10P=3G|{G`Bfe0)oE%dg%qUCmd7})
z3^)d0=5pwC)whaONSkH-{G>RoP849(sVpfg@*ia0@S_s8gi(M+r$*3#0co@3D5sRA
zh9wlxpwskt8fi$I&Gs><q^_n=K&MXQgK@+mZT9d21BwykJ|d6JkVNscd*FezS)Dcc
zn0{q#g0{Tz37!1#*z4@DL)vU{XYxLMRQ$#VUSU0Vh<aX@H@{BY?I=g#qJ?h0=R0a%
z1{vmO5tb*f{u;W0-Nna8=;PZ`LOnGHYM@E4M~g8cC%o2@557N=`!CX?gBP(MWkpUm
zhUJ7wEpe~8dDpSQOSApUqw0P6$(+mW+}l{<$LDU#885ZO-KOKHl#{GDh@-Gq*yVZ%
zdr)3{{9nG}xR$u1#<7{ob#sz0w1nGk-{d%uea0~@F|vhmV6KPHmBjFt#(|SZ=KGAN
nvHmTN12T3PP54Lde_Q<o?a=%7G*Dw<00000NkvXXu0mjfaivhY
index 145316b8345d08154a776009b3e0e548f8f72fca..8437095273c46e84b404dcdc1157240cfdd1b454
GIT binary patch
literal 246
zc$@+D015wzP)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002JNkl<ZcmcJ_
zF)KxJ7{~GNA9tV(HoM_=8I-|b@+!Ox@4=2mu}XKi14$`XNs*$iK?mJ#Ih~Zr8}Ox0
zPd&T*zRRbchyPy*SU6w<=(9<-ZId3`SdUNWX4B4&XTCcg4Oq&K^R(xVe0%M)m>uWY
z?@M2Nt`6yC6T6=Kx^U>Q*>AFmU}|CQ^VA2Q+|HIZgo*jpkAZhSx|3}@2xVraKJvzU
wce9NLp>&q3J+HiVD_f9=9_zn#f#kpM2NJQXccvwU^Z)<=07*qoM6N<$g7779MF0Q*
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..9d9bfa4f63d6a8ae5cbaafa2efadd2c16b48a3d8
GIT binary patch
literal 456
zc$@*q0XP1MP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0004xNkl<ZcmeIt
zO{h$97{~EvyiL<+O4RjImn<e_;g*tQ!AL2h6tYobV<WOt7V0j^%EE$`Y$Pi+MR8x4
zbMJNBK|^z!rZHwnNi-s({$HL>&Eo0wtSl_%_c@)#x6@Nc{?`phhD&@IIESE8yJl-K
zSNKF1)hUn5sOZvq+E~U7KGIR4efOfQ^}884Zquc$Li5&n8S%Rr1@7~nmioPL?ToDQ
zyBRA(nRhf*zjpbgtnj-TYr+Ig8tT{lh2v82yBQlog$4`i$IR)&lJ~nAn?g*Tx2iXJ
zWWVJ6ZpK)6$s20w>%%>JCF}K+&F|>X@+#3QM<bCW(z~Tk;q1|$Q&dr}!(&z>D!p6D
zD}Un9_eZ=yRl_vval1L7BzJJ%w+GCj;t)~vyE&jFTPl6N#|&!ruPuHz2b3(`y7R*w
zDyWF(Z1=l4pkzsLTk9rI70-y-?RRDWXwkZ{`gNuh)5IL`x)Kb@EZ<zc%7kK)m}B@I
yLqE+HE8{##Fvlsc3#nwI>>3!A!A$=*8}1L$Je~+C1~_8?0000<MNUMnLSTZZg51Oa
index 02ed6c62ad8a22fc28d1c689a75bdff3b57bcc31..1f90f83da745ff2470745ecf1c0c276b7179b088
GIT binary patch
literal 243
zc$@+A01W?$P)<h;3K|Lk000e1NJLTq000mG000mO1ONa4wfZ;e0002GNkl<ZcmZRe
z3-~|j|2rU@@t^TO3L64JNd3W@|4;ru`@i--Gcp^Z077WpS@HkD|HuC~{%1vILluB2
z&D)Fr-}!&<|JMJU$ZU`TxRRUm|6l)q>)($5yeRDdaQJ-M|4aWbecXOn@Guga;V=~b
z@A-fE|GC#2l&u(8kl8S=_WnQr|Ky7m5@rlc$ZVK&-~ZG9k3Lz%WyHXU%!Wxf{y*{m
t;LXXb20&>fHX<n1861F66NODh005WCw%{Z<zMTL7002ovPDHLkV1l<$b{qfz
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b066fe5cb0ef03ceee653393df468690f382abdf
GIT binary patch
literal 458
zc$@*s0X6=KP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0004zNkl<ZcmeIt
zPl$|h9LMqR_%}_fN$p|%sU?R=IoMKC9N6|CiKK9nxH!pP9i+Ifn}gye<sc{7BH0~0
zyR-A`3>ungn#PzRCDDkC`n~n-$qc_|=6h2P`+3##e4qF2k^f~&;~by5E|5SX@g5gF
zM(<yuNlWp8DV8(1dw##x-#+geG!^f;#wxq_^p271ldeWX(c&g4vv>V@4qrL*vqBy9
zmb;|w9+AI3)?7T<DN#ecanlUjUHN~Mo;?1eKowPUGpw_^5<D_=>hQODDyXUp*o57Q
zk<^j>?O9%<$}VJ!)rCGJIWh710VUKc_nfi8UFd6Wq&>}xNGDg=Rgg%$YmQ;9d&EnM
z>U;L=QAvw#VE4vGm!-&}`ugz1AsMo}H!?0DWI=tocW|Gi?Cy<iE=P`e_3_U5xFqfF
zjh!yf9D#awYx{0lX?Jhzbs^7qs_Hi~J7k5~{c*sBJRz&fS2v8wGPC>R7<p!yQN^j%
zTP0z3f1Gv;JdOmHlNm|aJ-$)d)3w>|OZx}=1^9!Vb3w=BGynhq07*qoM6N<$f>h_@
AZvX%Q
index c308668b12c8304b567247622443d9b789f9acc5..6f85ec061ea167b1718d2865cfc1e53370f11b7a
GIT binary patch
literal 225
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6R(QHNhEy=Fy|9t%kby|+!~K<=
z=lYs7_Vv%s4-^nwVp00$&6?)LeSG^I3$L4YTv-}i{FpUUBct%;PlbZ%#R_fqh7bDx
z-F*1OP);pG_E<uLROI?ak<6Z-RPM_QWEnIlbjv<>xTK`(Chn5R(EeH9pPAiYO~EVU
zg;AX0YiF?m$$s9yK0f=U*jm^Eqt`WV2>kpZ@LOBJCk~ccO~LBz65exMPv3u}^Njbh
X)s)<0)dyODZf5Xw^>bP0l+XkKTSZs>
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..291e006797fc7f0e84d297e952630c719fe6eeab
GIT binary patch
literal 344
zc$@)P0jK_nP)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003WNkl<ZcmeH{
zu}T9$6h%+QPKzXn-{D6n_z$9=;5K4oWg!}{GL40#v9Xa9DJ(1`SeV8}#NZ#8#zazV
zWYKx<_=*&d0f$&g?t$A}-sR2~>zGl0Qy}Zomti9P@(RHP^G#|@5~=y7$K!siiboRh
zuIeZWmVB=G=|>dh^>JgTvTX_3{+V)mF&H3<DcC)^xu$Cg+0m1-^>EjY7F_lyu+m(`
z^5@!%E%1sIf<-iET7g&00wOY5YylCO%que#{I4g>zrp+oX2Hs@7Sy8){GqKd3+i8+
z(La(~<(6kl$Y?0+E!3g~6pVPYgsgOBL}3a(#z;E(drpoEc78P(r=PdlEn2u>S!eOM
qa*)PSBkN>jxL^#qr<+KRA;34`pdw#DmQPIp0000<MNUMnLSTZHc$r)P
index be9eceba944be98da1cbd80b54fc015de46b6f86..025dc9040e5073bfd18da3464566163456f72534
GIT binary patch
literal 225
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6R(QHNhEy=Fy|9q$P=HAL$NcZA
z*K(Cs@TYt-3~OskjEXVmVw>%D&|RWz?R3S%8@5!h6F=s6G4bYqaW?MzjoCkpng6|s
zXV#N@oaktrz{i#`@v)}nB&N==y>HnTvNCfR?M_V%Q~Gzyo8O~>Q6}#e!-ESy&GlaR
zu`s+4fAKGyamxbf<p$3>PlhLUim60w=5E=2>$USub|+s^j;X5ze{YfSp5y*9zfkTo
Z<J9IUxd-1q<^;N#!PC{xWt~$(696JQR_6c!
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..7f834df94000475b8edda3b062279b17277db9d8
GIT binary patch
literal 331
zc$@)C0kr;!P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003JNkl<ZcmeIu
zJ<3x-7zN;GaxX!P;02qAxB&~7V57JJ+hCQ#DvgD;jSEO05Rrf&3YKCaX<UJzwjV;$
zC=n8WGh-tOWEk*9;RDIjpTl`yr!GLcZmh4JxsjLD331$Me9=x5$1W2#=zNg07hEJH
zIB}Ru)F1)##p4%?6>$GH;g-ye=E3m76~FBj%$^S3p8p9*q*pSbd*{>iVWHsKF0S;I
z^gX<uru~8l?Ba-&D#Uz2E-A|w$VFxGFAM&&6OKQ~PdJ`%&hify^ot8NgX+<?B9-Es
zdsQkFRE@hjfRA`17ps*YwnBoL!(63?ub<EKw6<PCy~gCp@aEZG+xX-e)Dw)JkKXHQ
d=bLx_g<m(2eGF<5p*;Wq002ovPDHLkV1irSl*Ir5
index 21ceb3b165cc73de106009f21c8233fda247735b..aaa9430211e168a593f7e3bb486b3cac2be6556b
GIT binary patch
literal 177
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6Dm+~rLn;{8UeM)Zaui^FxJzhG
z!|qKIVyq93J2V|v60i`ubLP&1jLj#z)YdH6_dNZQ&xuJ2GPazLv>Ue+?>6bs6%sUl
z=5wmNX+x=cM?cG@Z*M=Wx3_WU$gY-DxaT(E)^*=hf#2W0ec7YVF<0AhkJ^MyI<bwP
b9`ng3|Geny8qbgkbOVE@tDnm{r-UW|^{hk$
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..3410f70dfa653e77cd7e6b9e2c69cb2e2869c7ef
GIT binary patch
literal 394
zc$@)>0d@X~P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003|Nkl<ZcmeIy
z%}N4M7{>AE8oCqP6^J2Th#(YoIRh@jaAR$9RboY0TBz8UW*<_dt4i~Ob~DGonWs6N
zDHmgSc1896;1BQmyd3<D;Vxe_>=B*_8?FdJfKrFg8ajkxH`r#|ZrHE^89r%(@^&LP
zaU~!CnZY3+ryJx4P}Ww4*H%5boJ10kK>!OHX7MpIn8%#kUo_liM?;42gn8)-kME$x
z2MsMkajI;x=~Nv!fDG?7K@n$i6P3?9=x2F1U4N$!WpzoMSmnfG0tr9{|91dxvNb`P
z@Pt@#g$O@Ts`FxkI-!h8tg$vKjo=3vo__&~$jeRS1pFY=P4m>Rm+nD{$E*W$KOT$2
zPbKiz-rYZ3=dFef!V_e{6&&9|na3K+gyQ5_WYNiu|AQk<P=;B#nHdu%AoG%9VY+Ur
o3&n_98FR~s8ZZEvZ~YJ60rV~$E@j|y*#H0l07*qoM6N<$f=C;tDF6Tf
index 9b2e2f5be21be969516530f04a10a9c97659b527..976365a50612903b56e307401195ad1159e91b3f
GIT binary patch
literal 178
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6Dm`5sLn;{OUeH~~<S4@W@Ybbd
z);CiR8fb9XvkBRVH6EDwVAp%TuCU31<_kZ+x_#i}LS_GXOEozs>^Ne|QKRngBbo7l
z(Z#9O-!Ih&DHL`j3;gi;Q|>%Z+C4MQ_`#CC(&&{H^BL7&PFp7v<NevAVM?eZ7i)g!
ceft{5d!ZM5IVQfV1v-Mk)78&qol`;+0R4_a@&Et;
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..b6a197fdf33da57ada4fec17e042708b1586fb29
GIT binary patch
literal 331
zc$@)C0kr;!P)<h;3K|Lk000e1NJLTq001BW001Be1ONa4*>kdg0003JNkl<ZcmeIy
z&q@MO7>4op8oHYTF~kcIgrY7-m_-=gLr9yLNJGQQw7)|`w#sbRZsr&`=k35ZXB7v&
zrAY4&X89~W4uka=>r9+FQTkQ_0Xjv(1s6q9K=4z^2Y#M8=iEFR2+oy!;P`O)ls|M1
zIuQI&@&RmN2ixxJx2v>4V~zJtjVOI7`6Jp1XPnuIh2Wc#513n~OwGtZFjew_qkVIo
zU$ytz5PVhoe+S{Q%8^qgO78)3#J^TUPB~o-R}j1l2nEaq#~hp3KyVxo3PjEPJUfe;
z5d?1nLIL%=*r2h(o>L)8FG~K1Hs*i>8(RooD*3?jlzsNIZU(`=k`J^Rc{e+0HChnt
dDXqo-;1^oHB*H?C%i{n5002ovPDHLkV1gg@i>m+t
index d71dd27711f6e100a15309a5831e491bbace64d4..584ba55881f9a192ddea645d6d8525bab205e289
GIT binary patch
literal 185
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf68a!PbLn;`1FBoz$1@g2!+&O99
zf!$e4*(<gwHMMTodbFuS=SV~N4Aq>j56dDxhu@!aQ2zL__%gK{mTjH$a~4^&m3zt@
zUaiuXsMG0KBR${yp3FT-zMKuGw=rB<eO&qY8<!2mJk0Vp9SV8APqJu>1}fgF!j@Pa
jH|<TrhI1RH+Mijv)lz5Ad+#+sw=j6R`njxgN@xNAEOkl?
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fb7db9383669cf734685ca7422bbab1032f486fd
GIT binary patch
literal 220
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4Ui#=T&Ln;{WUfJl$U?_6@q5h<M
zZk9T0Sk@jrBpP!-HTHn4P9D?73r>FP1#Umq<NNTSROrO@e-He-RCZ}!n0L23&W2%9
zoK%gKi@Kh|d(k%?WkAxTb4kBR!3o*F{vYl$zkYplYC<jZgfE|ZKSwWL6mP8Xl3C-z
zygQv~{S8a5vzgbqTvvFnb;BiR!dE`?!iMKI9}ax7i{;v9#}IYtbkoY`^&i;#6M}Bo
T&uF~~bS{IZtDnm{r-UW|#Cu$)
index 670acd93f5324c0f32e37e13d43c31890bdd123a..513d081bc2d2f3eb64801a5e8cde86ef4455829c
GIT binary patch
literal 136
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6{5@S9Ln;`P7g+!J&&MG-LGg5b
zi0J(bTQ@BD_<zEh2EnYO$r}H;1wK36+;l>154)g5P7Bj9n-%)M8r~??+_T|q$+)-V
kia5^-HX{oL#i@)8E52we&r^_U0~*cX>FVdQ&MBb@0BWi($p8QV
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d5d49d5ff107f01daa307bd0f89f98efc31eeec7
GIT binary patch
literal 160
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4U>7Fi*Ar*|t5-bTK29GBH`OkMs
z;LzH(r}lQj`-ICFx#MpBpCa|4zl7P1x1vYwH*5P29X)2dhZ~*=Z`AwIt>?Q+{9j-O
zLo#EO)0^fl@rko%`Z-H3Q%PTTaY>Is!UArQV{B|y4S@^{cTUS(`F>5r0%#?Jr>mdK
II;Vst0FRG1RsaA1
index 7991ee7a50703401c00aee71297564cd4755c481..156c26b941c12a13130e7a7c181d13300a85de89
GIT binary patch
literal 88
zc%17D@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6<UL&+Ln;`PB?2G(x7L}!$kNEc
kqo3#`!pg%J@xXwIAzIG(VVQKJ3{WY9r>mdKI;Vst01!SC>;M1&
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..959e1919d5a7a83a9c319de4d65ddaf6dc6c2763
GIT binary patch
literal 109
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UCY~;iAr*|t5<LkbJxzfh{>x6B
zz{uFh!Ff-a?~&O9p+bS}jK@2hEqD_O6oi80fl3Ux7>c+~q<V+<rvUXcc)I$ztaD0e
F0sx?19k&1g
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -738,17 +738,16 @@ html[dir='rtl'] #findPrevious {
 }
 html[dir='rtl'] #findNext {
   margin-left: 3px;
 }
 
 .toolbarButton::before,
 .secondaryToolbarButton::before {
   /* All matching images have a size of 16x16
-   * (except for the print button: 18x16)
    * All relevant containers have a size of 32x25 */
   position: absolute;
   display: inline-block;
   top: 4px;
   left: 7px;
 }
 
 html[dir="ltr"] .secondaryToolbarButton::before {
@@ -811,24 +810,16 @@ html[dir='rtl'] .toolbarButton.pageDown:
 .toolbarButton.presentationMode::before,
 .secondaryToolbarButton.presentationMode::before {
   content: url(images/toolbarButton-presentationMode.png);
 }
 
 .toolbarButton.print::before,
 .secondaryToolbarButton.print::before {
   content: url(images/toolbarButton-print.png);
-  left: 6px;
-}
-
-html[dir="ltr"] .secondaryToolbarButton.print::before {
-  left: 3px;
-}
-html[dir="rtl"] .secondaryToolbarButton.print::before {
-  right: 3px;
 }
 
 .toolbarButton.openFile::before,
 .secondaryToolbarButton.openFile::before {
   content: url(images/toolbarButton-openFile.png);
 }
 
 .toolbarButton.download::before,
@@ -1484,26 +1475,24 @@ html[dir='rtl'] #documentPropertiesConta
 
 #viewer.textLayer-shadow .textLayer > div {
   background-color: rgba(255,255,255, .6);
   color: black;
 }
 
 .grab-to-pan-grab {
   cursor: url("images/grab.cur"), move !important;
-  cursor: -moz-grab !important;
   cursor: grab !important;
 }
 .grab-to-pan-grab *:not(input):not(textarea):not(button):not(select):not(:link) {
   cursor: inherit !important;
 }
 .grab-to-pan-grab:active,
 .grab-to-pan-grabbing {
   cursor: url("images/grabbing.cur"), move !important;
-  cursor: -moz-grabbing !important;
   cursor: grabbing !important;
 
   position: fixed;
   background: transparent;
   display: block;
   top: 0;
   left: 0;
   right: 0;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -4910,17 +4910,16 @@ var DocumentOutlineView = function docum
 };
 
 
 document.addEventListener('DOMContentLoaded', function webViewerLoad(evt) {
   PDFView.initialize();
 
   var file = window.location.href.split('#')[0];
 
-
   document.getElementById('openFile').setAttribute('hidden', 'true');
   document.getElementById('secondaryOpenFile').setAttribute('hidden', 'true');
 
   // Special debugging flags in the hash section of the URL.
   var hash = document.location.hash.substring(1);
   var hashParams = PDFView.parseQueryString(hash);
 
   if ('disableWorker' in hashParams) {
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -717,27 +717,33 @@ toolbarpaletteitem[place="palette"] > #s
 }
 
 #edit-controls@inAnyPanel@ > toolbarbutton,
 #zoom-controls@inAnyPanel@ > toolbarbutton {
   border: 0;
   padding: .5em;
   margin: 0;
   -moz-box-flex: 1;
-  /* reduce the width with 2px for each button to compensate for two separators
-     of 3px. */
-  min-width: calc(@menuPanelButtonWidth@ - 2px);
-  max-width: calc(@menuPanelButtonWidth@ - 2px);
+  min-width: calc(@menuPanelButtonWidth@);
+  max-width: calc(@menuPanelButtonWidth@);
   /* We'd prefer to use height: auto here but it leads to layout bugs in the panel. Cope:
      1.2em for line height + 2 * .5em padding + margin on the label (2 * 2px) */
   height: calc(2.2em + 4px);
   max-height: none;
   -moz-box-orient: horizontal;
 }
 
+#edit-controls@inAnyPanel@ > #copy-button,
+#zoom-controls@inAnyPanel@ > #zoom-reset-button {
+  /* reduce the width with 2px for this button to compensate for two separators
+     of 1px. */
+  min-width: calc(@menuPanelButtonWidth@ - 2px);
+  max-width: calc(@menuPanelButtonWidth@ - 2px);
+}
+
 #edit-controls@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon,
 #zoom-controls@inAnyPanel@ > toolbarbutton[disabled] > .toolbarbutton-icon {
   opacity: .25;
 }
 
 #zoom-controls[cui-areatype="toolbar"] > #zoom-reset-button > .toolbarbutton-text {
 %ifdef XP_MACOSX
   min-width: 6ch;
@@ -757,29 +763,41 @@ toolbarpaletteitem[place="palette"] > #s
 #edit-controls@inAnyPanel@ > #cut-button:-moz-locale-dir(rtl),
 #edit-controls@inAnyPanel@ > #paste-button:-moz-locale-dir(ltr),
 #zoom-controls@inAnyPanel@ > #zoom-out-button:-moz-locale-dir(rtl),
 #zoom-controls@inAnyPanel@ > #zoom-in-button:-moz-locale-dir(ltr) {
   border-top-left-radius: 0;
   border-bottom-left-radius: 0;
 }
 
-#edit-controls > separator,
-#zoom-controls > separator {
+.toolbaritem-combined-buttons > separator {
   -moz-appearance: none;
   width: 3px;
   -moz-box-align: stretch;
   background-image: linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 40%, hsla(0,0%,100%,.3) 60%, hsla(0,0%,100%,0)),
                     linear-gradient(to bottom, hsla(210,54%,20%,0), hsla(210,54%,20%,.15) 40%, hsla(210,54%,20%,.15) 60%, hsla(210,54%,20%,0)),
                     linear-gradient(to bottom, hsla(0,0%,100%,0), hsla(0,0%,100%,.3) 40%, hsla(0,0%,100%,.3) 60%, hsla(0,0%,100%,0));
   background-size: 1px, 1px, 1px;
   background-position: 0 0, 1px 0, 2px 0;
   background-repeat: no-repeat;
 }
 
+.toolbaritem-combined-buttons@inAnyPanel@ > separator {
+  margin: .5em 0;
+  width: 1px;
+  background: hsla(210,4%,10%,.15);
+  transition-property: margin;
+  transition-duration: 10ms;
+  transition-timing-function: ease;
+}
+
+.toolbaritem-combined-buttons@inAnyPanel@:hover > separator {
+  margin: 0;
+}
+
 #widget-overflow > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
 .cui-widget-panelview,
 #widget-overflow-scroller {
   overflow-y: auto;
   overflow-x: hidden;
--- a/browser/themes/shared/devtools/app-manager/manifest-editor.inc.css
+++ b/browser/themes/shared/devtools/app-manager/manifest-editor.inc.css
@@ -49,19 +49,21 @@
 
 .manifest-editor .variables-view-variable {
   border-bottom: none;
 }
 
 .manifest-editor .variables-view-delete,
 .manifest-editor .variables-view-delete:hover,
 .manifest-editor .variables-view-delete:active,
+.manifest-editor .variable-or-property:focus .variables-view-delete,
 .manifest-editor .variables-view-add-property,
 .manifest-editor .variables-view-add-property:hover,
-.manifest-editor .variables-view-add-property:active {
+.manifest-editor .variables-view-add-property:active,
+.manifest-editor .variable-or-property:focus .variables-view-add-property {
   list-style-image: none;
   -moz-image-region: initial;
 }
 
 .manifest-editor .variables-view-delete::before,
 .manifest-editor .variables-view-add-property::before {
   width: 11px;
   height: 11px;
--- a/browser/themes/shared/tab-selected.svg
+++ b/browser/themes/shared/tab-selected.svg
@@ -30,17 +30,18 @@
         background-color: @fgTabBackgroundColor@;
         background-image: @fgTabTexture@;
         background-repeat: no-repeat;
         height: 100%;
         width: 100%;
       }
 
 %ifdef WINDOWS_AERO
-      @media (-moz-windows-default-theme) {
+      @media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
+             (-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
         #tab-background-fill {
           background-color: @customToolbarColor@;
         }
       }
 %endif
     ]]></style>
 
 %include ../../base/content/tab-shape.inc.svg
copy from browser/themes/windows/Toolbar.png
copy to browser/themes/windows/Toolbar-XP.png
index dce0b0a7d994d7dd5114da346217794e7677f4fb..57f6f7c7f4995517548e6015887710922fb5dd1b
GIT binary patch
literal 9463
zc$_Vobx>6A`~E?ir4(FhDUt48x}>B91QpmtTDm(IL@DX+5Rh8wW?7}Xr9pD(Mwa^V
z{(OJuk7v%DdFITVd#>lY?$@0AtB#fmF(C~h1_lPPn(C`J7#L479`B#w<36r8&Vl9_
z7%w~2Udiiw&mUwFBmuiG8jtw<SexL#M@2qOrH$g;VLf>gN>k9(%R(b^LavXUOoy9B
zO_gGXq3bLrAFZnk!%a3I!y^2mMPaTJ{kRXK3!goTh)8ecjCMI=@)8wz6M)H*^WZ$9
zXt>g1V6s>FVfrpseEUb)_l!^ff3f;zj^?|q_N=yEnBKqNs1<Saw=mG!j%c9WARAF?
z&_1$W2st2Z#{-(+8N%-PnDF-T2FQ<h4!6!`vhk!azl9!fZs_5~J}ZMCupH7#*$>Ug
zD;0`8qsM+bY`XbxdD=lobL$pctD=r++Cg`iG%=rJKO)pixEwnMJyQAMp@+?S>Oio$
z;B79Yv19*=$;c9eBn*UXzB6^Mcg!-@t==QAy*iS%lZ9)bM4WBZ%uc|D{HK?M$aaJ$
z&cHiTG*S)Psw%ldBGTnaIpBd|^u@S|OH=yv8A!K#2|EQx1lp$KEw($!IcBKY<r!Y=
zML)L75CooZsSN%Oos*+?KvPDiWy^lFpNrG=0?T{T)=++tlpb^u>V*D2a8wnz4n`(e
zF0(4t;{szmS=JexyS)~-(UicTCn+2oKiO|@J75ufsxj7s2_HerHOTmN|3HHcQii?9
z*Dhw{3!nuw`e_AsAxYMB{xRh3z`4Ejkr)}+=K$4rGPF8IQV}-_Hkg+tib2MNkPsZE
zD)NhW#h$A_L_PaD!Yv{bW8ITkGcSu{ejqB!+QUyd_1?o7s7l6I6U)v%^~i}|pz-IH
zobipG0B$zFIY+~sB@G8C*s|N3^9EvxsNS@J{I+m`$>75hYa1aNc>?37?<HSKvY%b2
zN4u*f3I{4HB;sFpQP)i);dkR8)ym?AOk)B&OngI0*a|^(e|{jHJ{9*@XlF#c@yY51
zvPSyIhJN17aY=br_UAt0gH;pO(Z8VsNteR%i(Wy)^{;dzIg4wbq~30Q(w^VBq<cuW
zb6(K!l1pV<5igxxY=NqskI=q<qc6A|GxI|F(3E=9$#;`@7;_Mprixyxhf7#EvB;a}
zN+r}%O=$nO)hV=#T2zU|Y{o~&^WQ;mX#Ckb?}p;&-zoRk%vMZC_{{-$#C}C9t826f
z<T<sJeND7!XXsNvA0Hm~E3MAkwKL}*{4+|4T?veuCRL+E^fEmJIVaZrh??;G^y0uL
zJQRA5dJsDTLuV-Y>fIi47J8oM5T+1(lI<DtuHS=?lP`|xdcD;oiDB-iV538Yvg9{_
zq}MRTwyN-yEUD7r8u^_irJBmif!~1RKcUpmu5Z`Ok6fd-WrHn$<(U-@2AG<Cj!9oN
z(wDp#X6O(hH-8mqqOus+s23Ot?^#^R`<K#=_q=`dBGm=O5k>2<9ROar;;f9$1G*JA
z<Lm|>=<YaCX+G>(%!S}|@mA1?AJQimM%P?1YAV9X@Hn+3CJbo!wOcNe@5d4(7my7F
z<Lje;f1v4^rgDpTumH>@;V%5dekUG(Fvr_Bevig6pGfnWX4m^nHs#Cw$gEQEc&Bnp
z4Rs-62ceo8Vy2n2B%ss@@H{JNQ!S*Z(@Yzkz@=lQ^jZ7?Af*mB{@xfp{cRh>zcu6E
zkH3Ne#4#_87SBIPc>Y@Pp0*1a=cG9kHXOasiwNa6%zbgl1?gemSzoOcHk|HM+Nf+f
z$67FGxuQPzpWLb(l_+~RDD)h++-h_pA|~uAKMa`=Qrvar2kH{xf6Z#a=D5YUR&Fn*
z^;&VhYQ<HUwDlf^itx-`CmDup(QNX#5EH&OsbnhVEh(LvgTFC^**P52621RRL;7xu
zq{X93vT0Cg6jmHUAX$XH-mNxvm!X>6Q)s;$w}7a@Vk2i3@ZVqBaO)iGJyZ6iH%f8m
zD`M({DP8k|YSy$F2ZzCT!Av)6c^!E@AT8gx_4QwYCC4O!JfXCR(70Z?WRsGQQ%bRm
zAPaG*!dl0p64|vRVB+%fGsN5^(I3sVUYfEz9PGbw3OOXaQv42nR7s`wr0sXKI$4#R
zr=XE&n@ev<2~Vzj5m(UB!0V>!;75T%hcu1>#Ia*%8(yqal!VNgTkGTP0B!=}TLE(V
zTVP+9<&)9jF81v;n?6;$#A7?ShM9&vzAOY+QL7weo6LfbjvXGrh4cTumioB&3gY=u
z!+ukOg8Or(u&H_)K&HKi=aef?W_`yEXuWATa;GHVBh_nkGvq{giyIEtx_SF7i1$xU
zu#627_Y-|)9r1aW?3+wZKtaQ})bH;X*y?zn!P*zhG5?9p;6vGHXld0)iZhWHeEB#&
zNm-3xytl66e)l|mSC|g-rfg|t9q$M3y2ps_bG6F!MD3-oB4FWN9o*+5flss^Ex@Kt
z&~ek-u)z72N(-0GK61<MlcGSbfIcbF?l11rOsnC39x8Fi3w(5%h&i)=GNIFpDj6f9
z?x|)C&zy5=CX)$!y?H9yPHj`Olc1eyLZmgUcqdFF3eAZWK@{LG$bz2dYdSxr^~6gd
z-gr0E(^{eOfE?v(-)(`2+>SH#;)k>7Ww|3RaV6BW&C-LV)B3y@o^EQWeFvk0i%YQ-
z5gh=kpzJ^Hl?jt27e<*zmA&_Ja%TTC08V0~VCT+~4_Jj33JrgSMGec-6{(#vipqsw
zf7rC45Be4D+3T79bA4lcZz(>&)JyGw<nXFRGH}S(i^4Xx-9=dv&R%NsH48K7Z@w~0
zJP%H3<VjRE2u&-;dDUZ#8#m%j<U?YVGS%(fPB8>9KgT~^{9ShkxRCIpi49>bi$0T0
zcV~|CVjDdn8t`~;kz7p`T}S{7^Z&G3Ix>D%Z-W|ebdTMA(P#Y~Qb!SS*cMhpr-&wH
zAC!n5zCMOV0$%?2;S+jBcv{1>61yzaR!26^QbKZ+jP**1Q(`+~CE+AlgnX6R3p2@`
zH|4KqhGdqQGI2EXMU5yn#yNxjr4jZ-X7z<Y^M0Nivg45dUpSQ+3--9~hcc1_@kYJ<
z_}M%&`oLnY*tbSAU%y#InuoBDH|5|0@z%W}qJidY=FX+z;m00dktHHsJr(44ozJ<6
z0s@<~*7VG$b3xTgTVEteBvx%4FJlWqBo=rf-D70D(*)oi+Xyctz9Az6euE!H!wv-O
zYS}e1%6@2V{NpGbM|Yu5=ZDnLbndUnDXzum$I80~XbBruI`_h!koi|`#;4J8VwHvc
z3UH(K9zKeDY%sUE&>5~#+!UKI9^!;Q%;%2e?&sHIMIF-15P@Ch?x(zA>v;l;xQ`xZ
z8$X~qXEhGI3C01(-O4~U`o>!sxQWcWCBssJ6%CC*)bpn_k6pw~!2ULud8r7MF!ZdE
ztd;eh8^89aXs^#`S7aJx&E)cTuKk14<0KOqJQ`R4sr$@7<XVzuHP!|GgSsGc_PaW5
z19gp3-wmuM1#V9zTvwF!vldk_Se*iE4vGWt-CPJnXKF@w3&Pt&W<FD-5ZJ#lU-^jN
zonK3*;iLvvst(2itaakdw8ec}#b*F9*Mj@3lY<5^TsiMb%*{CWI82H$0c3|)?sm{5
z4V(4@{D^hhw&$MS(q?!@Ek)uQw&kGV#30E#)K+5$YCeX?OLk9p_qOu}SnVPbaVRz3
zX4jv=c|G2)ZZhbyd6-1+)IzQX0DkWcRtQMsSTE~-r))ragp)!HcBwZ4S@~_NN6{xg
zke?dEO+pC<o}AT)(Q6QT+`be~KuuiiK%8+#Q#!OV?|%n4z$u!+pv3wnw14wsq<n7s
zq*EeZCUHHPD-QA<N?N;OQ`i|&FSX_Zj@E;*8Q?~Bz40a$=L%*PbQBRIloK(fqdefb
zQL|{--}#(Zl58v13TB;d2_!8H$1PTzwobU@#f=Q!04Y2Mg=@)9Nn~ZZM++Ckv%4|Q
zeh#JrMj`O{pF857u{%je8Fr4se9l`q!+naFAFHK~M{XSTD(<&Zf@qTIi}Td1lVqq1
z|JMBaKT90ju>TYscG7sJPe&J{C*CDs?wsZoTU0%%X%W%&z7!9)<hY_*Ul!#m`-B@S
zQ2AN}*j`&!7l81L=LJiz><F_3{YhJ%+5-$w%m$hAV)+OQWAVJy;~(G)&H9%4=T#f#
z$^>a%gI@YVsHN(MiQma;4)@_(i7N=(@jQ^q&aUO}J&!G4I3rlfsf;*TmJKc+q2jqt
z?ajSIrq-LAka+0?HDh;To}aiHR)an@?)~$HZXqx$gk^Q?IWT;mN#ph0R(FP12ZTbo
z0bfIc!(@<R{vTa-Ro~~Qfsr044dAL_y|*3t*E<RNA;pYmyWd5um>qtc>}`)Pz?0w>
z8Kgh1KA{q<xc^+qku(^uOq4-X##p6AI_tGwR+^Y)u4NN!Zi{`mzcIJ?p$CD3$Mk|e
zEg6sAP4crKgirNX2o`8}$QZ*dgCFWRc-qpZao1IE6E^<|*~+#fbLgu@r;T)5T~}Tz
zTj}y2T}V|rIN+GihIH$yny4{z%T3S#_Y3i<F+5!}Wqz75zs)6{7fv2rs9{Xt_+L9z
zT<I$O!Sn`MvQ2W^*a}T@8*V*t7k+?4OU!*n%k38b&3b+gdKeh7oBZ&4Nt|WG<K?hz
z5e~rh!$asZ17mXI*vOUkaxyA^5#{Hu^kWcw;ODOpJQW+yr>Mw&JBsTa35^mp_Zp&b
zguL6%2yT>FK5Nk|-^&AMPmC_9h<zz}KO+)zW0@q&93tY81(n7Nu18~4kX%qnGZs9h
zQC0AzMHDc0(rk!Xvjc`z=UKn(mRlEd0gNL<=8*lHQO@)w;<-0^@AKgn5}Qen=88K6
z8^5Da8P2V+2y<5}l(`|(X!G>@rENHBe;~>yzT)t(U|Ds0FgW=lTT^|+t=y{4wdjtF
zD9KQh^#pjqvvvv1L8J+go|61m8k{JY9(lcbT#+6ym-Xw^S4jVB{-@(k<Sw{%rPkp+
z+_nsufCS^J4T+jGZp(^KSvHgBU@G<pA%xV>*8wM3k$OhwV;`DV@w?1FH}OukAV^?;
zUCfkQA+g=<cY$%pzAK!&boh)d;q5{GwQv~Dq3u9cm7{4@U?%~a8(kD^UyFqh&~q>G
zFC{RzZ*s!o#n~HanrCc^``h2P8u^_ANjOcTDAAe-sk$Tk6+;OgtDp1x+1^2a_p=$g
z)$mLnH2(siW_?$$>dTk$gOx%?IKsK3qkp;blU6HJa#o(E)`pmVfK$!qt@j4&z2_%A
z@m-Sq`g0orH~3NL6!cJ;%8ybtv_&N3JzRB(a-UR>h+mA;6qS#Gy(zizQS)wpA8KZ(
zI(hkfoUpOFAKnXglDKf*V%BhVJ)zi>)T|Vl%M*T`sZ&k919L#{QT}mvcqJ?E2{Mux
z`&I|oc%EcOWSjFmz7bsyF%CTcMbeb(yk6?vo^GBc4sVxVoo=)Y_WC`!w*BW*kE=4?
z^XSw>OSd;Gj*^G8uTydp#xG5+%*L)(*c-z|@6Ux}L#b5s&NN4LgCgRy{wb|qC<tO)
z+x&C0=lmR7<Yf2v-}2#|q<xCcpS|d0lG&#%hVz^%wd?hOh6k&$w^x}=BiTznC53Z8
z?8^N1`RpjpwZ4Of2Apqriw{4!S2M*-g!(uhq^@W_zf6=Q=f_1VtRgmLUzu(C+kWgV
z@YXsKeXK4sXZvp{VGM68Od|@aRvx0)2banrUq9SzZ6mx{ZzVd^-$iIW2j?-sx)UK-
ziWkvdzTrsUWF=!>BViord}H!#21buxbMrsKl>k~~7Vo_q3MT26Zd7ZTlV{`trjwS&
zQmK}rZwO72op@}uG04?>MC}P7Rq5mN$$ag?%x|@wHdSkZS{PWH9;IIF1V@0a{47&b
zNyci1F<ESGl6j^@nXlC&^@x7m7q`R!Q)*mg)Qj=IBMN`g6F*a4&s2n7J~B%|ntxI1
zBc060L*<<t1V@+;X(fP(n)h|_QhZOM@});UuYese0in97Cl?1BO%TP5syHlH(Oko<
zo)-t#EH%ndYG>>ygR%$ZNPmXjpY4(GfrKhY1J~F+L+Ei8hIvjqz8*r(#ZXR8R^ppQ
z!sOa<7K`K-WbO2p86nk@YJ4)G_^=J753v3s^dnpu@bC?h_k8`HT$ay8Uq;E3bwiHa
z{pLGpz6@$+v+_&-El)}qDNfWXa_TC`4k2Zq(Kfl~UAgAiR$tw^meNtBekHS_P*c@-
zF^e=1p;zM?`X$8rv9rzCQqN~Tlpvf1>#-S&m&Q&Z+4AQB?v%Z+s0Z4bQPx2Ercxk<
zlh3#b=iPqcpS#?rgoGQt&YFqh`LhmsjF1Y;<?q&5w$2SvqM^mGOHej??-`%oEbQ^1
zRIl$V{D~#FaEtf4FJv5ruu7eI4>S{V(+#1D7*Z_GD_H^#=y<X}qVL}}z2?n!m;GdM
zZyD~jKhb4uj}lv`NnSi+V6J6!9joK`xI})B*YSQEsd^X`#$m6mC~aYWi+k;2|HeTS
zCC0eI+R8$aqTw<TUp2w*kX-145~+6VtX%PIv)krvS033I**l*zh_$l(S5xlQgPJez
zbZfkr+v06U*AGK;KA=hHUv2GLXdXv@kp!|<s|awb`CLPe95JFo+lo@tA|w*6W3d6h
z3Z^iy^n7Su{{zC8!u{R6?{1PL22vHx=%l$wxCw|tqdR~r?6*(&xCu{fc-fXxndo-<
z<bu>PzC-1K-)yHqq7^wVEerQOe3Lbw-rGeSrjAhzDazp4)!-wE5mHpg@9H{PXO0kZ
zr*}`#4|qgvXVr-f12`JWbDg+=7wLbCU_ytgXQD>IYK<4exjpqvpU;emoaa4zyxFzI
zO*7(-LI@_jE^KS%ZIgi9_?yFE($3(B{3Eez24tKy9-L|<F4kS`jM#|m?@>3CKTN9e
zjp?+B1LyW%j=!$?G7hZ@2L(#7o2O8MEX`%RI|%J+7>cERW}6x^HlpTHp5V2YoZ7p>
z?-qJ|w5sH+;6gU`ZG<^}!`)utNY~^xEm6~aosEd|2v%(yzXaGa+mBIEId}lA6?Vx1
z?5&H*=QTn@{>HxYikx8QF`_^Re#pch@S-##yP&(1$d#ga(C63k&=>c)e;Rts`%NWh
zGJTK4snGYF%NZ))rtx1g!@+ROdT@WBmR9RSgC+@c!=-_id5W22;I|QN#K%4};)S$%
z{Z0T7o3`mu2$%px^hbN|bP}DK5aET#g3wK!u%oZd>+#l1p=x7}E_bU)(RhJ;pH$B!
z#!*=|DK`eAxV*xXBG)1uIx_-QF`J`sWcmiVeZ*2jW&X+1#Dh-4_4oUES$6YSpL85E
zsXn!tuht*NQ|q8EtF5o-|NIQ(*^tYtsc6}y4|UZ}iamBH6hQ>V76v-t)7iAnDLeuo
zrGIUCok8qYy<ta(E3`4j(VKL;#kgTIJ?r6Ci|wqE!)}o+Xp!1f%455JkEPgA-)kFp
zrEc8Bt9y?NAqCbEaVDhaRc+6i8PWbXyOhQIX~Iu9-gc)e3W1DE4Ww>DJdpi5Qawr8
zH2x>GVIkpeUE;C>{0RDSp8VDa`)p|Cy5&-PXEu7M@CpIK9bnzfqwB+lFNH|C{lOg4
z4|H7(Wt_ywENpnB^@|gS3d6&Dk!Ymp;huv_oVFc$({2T#Tlz3I7wqT;X9vbOPSJEM
zw`?dhwx1`cHgx!gC|Y9);{g=to6k3ulXH(p6|ZN*T%s#os~o!iYlwB{;{w@sFJqh{
z-17=uN~K0HqO6?BO~q`UD7`3rdfWYi1Stv4J4e^aj}8zPGaV@X44~KkxU!DHSG?>i
zQhFjKDlDpvLmvHWMNQ>SJEO6yK+a2cC&v)%Dvj>ghapxe12rZLA<huV?=fyrjGnT^
z+=P!`9%Ai-qUVH`gMIiTksX>pO&@mVh`SQxWEYj0-aR`(^>y+ZtNAp1atyyoNvvi@
zt}FP~8Bn9DV7_IZC`MSNOR)eu8|W?kOBE@1X=dD=x{E~dn-3hswxiflp^3{#eF&=d
zvx`(Y0ToDn(XCH}Pk7~?ZP991{ckw3RfN93R_M$Z&*runaSL>K`JcmfP3Wl04ygyw
zZ$h@)BmINmL`~7;1y@E4w=H=WWdJH0o@V-VNJP@rlL>c>n;dYIYsFvRmkzEBqkM_n
z9CUY7v!w49NRIE^S&gu_cWbeOp0$e|?=c#&>Xby!5X@{P52X*yOfSQ<ikI$ase1#+
z<=$o`#2gDg9*68ejND>5+WE<lZh5*FgXD)^he}5DW$U^f@;9&U3{tLkwhIw&Ks=95
zLk?1W)Tw4_`{fRzT-Nhyal<$l@cOy#riILO#Z>!w?VGFn4H1LWuI;3jud|Yd$K~IQ
z8`VwyK-~CR?}}@`KAm{72{6=>ufiO})neW?1K$@M`Q83i++<MB!D@(_`ly?65F{OY
zl0x}_eY)t5DxK8WEyAoxxltDI#X|%VjLzD1r{AmKwd}$i(-gtpoWgiZG*A~fygWeZ
zUj&1Jt9w{+q1SR8-ak`)bi5751&t0ElbfzO+VK`)9ps2=;A;jaXy@3jjiqA%aU5=w
zScx~&nYZb=UkUXYX1N!Y3q#GuP<=*oSyiUL%Vawh8hQRSQlAszdQi`r?^LhwpWNlv
zJ|pxK{@jr72lP#(s?JT=de5(8%C=s#=kqRK=B0xhoUvmx@#~S_DfJI@pZ5S0>2#0)
zs6@$dW&2w5Ma?*r0Hp3$^|8$cuQUDzOHOO}#r*s%YVk{hBgW{Cc4Z$~xpaD=WE>qJ
zf}isKZ&2{+f()rNobgBXfUjMyymZ$@mm95KPN^tiU&0sd2u1jq<R9I2EiIj?Kj*Z{
z#dze=JPxldwWTNYe4i#6iW?QB1AsUlve|-x#eoS``x!m#HBRoD;_1(KJO*uU5AMD9
ziEyj=y{3bb*}18)-9L^)y3;lnzLs~iLc;uI;TnkVv1_BIw#Jpo#Fr!OqEg2V46w+_
zZMF%PVH@}n;lMOL8c7G%rKKWOCzyRbo$5-wAm<G_4@N`H(gp#WfBp&VW_uyuT_vxk
zyVg8tEjL3s0$=-B*=gBo_(oXr#ZRBPU|SkaAbT_ekxU@^Tg`jb7AGB4Bl+|)4NRhc
z;~sAF?zW}M=WEB<;#5XyGnumMCiN^tHz32IQw5Dxw-B^*bn=Mp@jeFP8PdF_Q@(vH
zM=7%C1wyfN%3@yB%8row(qw0qGc%umW7`!@)O%QXJnVOvHx&#;TtNRm_Lc^2zcXV8
zl?G;{THXrxr|-K@<bCaPL(~)jRoa9srTk47wdHd%vqX<Hh)oBWuo}{CU|mmcsd|t)
zHhAJtd3~$-;@xZGi}yCByVtIA+p4U1N#z5gcs|5%cJ^-&Xec?CGCe8GvP!l&Qo&_M
z15dqokR@h2P+*;?G2lcgz9M^hBwvV*n-G1Y&pJcGngY!Dn?@Yo5yhGEAE<GE78;+U
zFlbB?s>95l(Y3v3DIlXWRo}7r6>$-1N6pQ)|A45s;OZ)1tX4ep53&gHgcV7XaQ6jo
zv^~4Y@y~$URO-><BNyULh;N?q7CIOTcyYBcD@rCm^&&F*0@=ZnKaNL2otqy{=+-`T
z<<%YnY=p8kU^q<ope8D<5Ue$}tbakjE(CYvf>MuprsuLmhyNzWp%ol>x$!;pe5O4m
zP^kEUL4~Q1?^HY10%N)k8@~^E9qZE3&{U>&{<woN(y)|r;&wMxI?ITh&(<Q8FDWPT
zW$*JJk6P&sYU4T?t-yA@1H7OHpPM7^c@if&!<R?9ka07TExYPo<SRCwhckmFL2je}
zhvLN3wxb0y-KIltm!==4G(C*Iw8^K~X_|u>&gXhnouYnDzpzPFAG5^}Loh)xBVFVM
z|5eDvswzJ+S`u)m&<BGdxMMURQlK^Ym;m}hBzEwNUy?JQ5pD#mJKkPBVU}22woFWW
z$-SvSJf<z$1$E<FEs?<qAsob>lkJHap#S=}2rEO87_Q>h6%yXuyd7*V7u(d6HyIE;
z^jBx0m_&CzQl<zi3U<vfyZoq9gU(5rc;CQUB0`m2_DV0|<alD)Ak>B*pV1oq;rY+j
zR+BQnQUlvf+pY6N_k#Y5SBKh4%QaKdJ~O?C`EGBU#<#h%iGX-?1%{oZC7$4A0Iy2m
zb0g8kMXu_OK<TRPB|gEvDvZH|z$AH}9a`Feg)5?(jP&o;r`i^5T;|N{@TY7pgw^?n
z7W`7Mpyn(?f4=2Kp(A-4OyFm!mY+s%1Bx_SeEM9w-fSEbkAu3^R9aqR0dWGh*%X~W
zcK5BD!2_RV*#wRgE(@tGKPop=H%4|&_z2V(uoj+NksFY*aEzQYxPpux?2P#^aFd|@
z!XW2qNoUOuEFeyblp($^6FBO5bdtx_?N2EPnLlV7M>V;x^{1ij3)qYz>F@R9+TMmL
z$(!EX-1j|!bixp!aJW^5%6xcs8}HxuRo5KW@i)rvD=bz+?|9kLo9-Wx29{ihnaSsn
zb}EbA@5bMkTVzrDrlwGzp}rMO%1tnkK&qEVeBD1*#klxP%X0aay7wcV5!s69^4f&Z
z^rhKtIY*DbJ}qj)z{3%c!sMVz{usK|HT!~VvzFX)H@{5khCj`pOCu>mig#jf-Lgjb
zI0j*hV%Px1MU(`ldV9-CQ8Om4_%XQ+Zp6ze52gz}+Q{pqO>JmA85^DRBNHkS_)z|Q
zdgb9osE(V0Adl|mkSI2gB@3jU>tM>Rm<8S0sM?XtYDO3HTuc6X&}y`T%X9wnv?I@W
zUZmSB7V5*^YutoQbO;NCG7&<bP#I%Rb_p`g^RiUa?y3(9%=^+g+=qJ|7ut_5%VlO#
zq!0|n;2CwE&rGMb68`rq0Zwrv#|J-p;sm35aLA7V>BGTkkoW^lh|-1a+dHlM%yzyw
zoO`}&`wCa#=AQ!D%N1vGy<U{Eb0^GKGd|A`bLp~gy!^IB8<h)jX5TJ0x*h(i<yv$*
zkabOzXlu3b?-kn%E`}*jmajzUNjg3Z9u7n26ijbi0+I=;36oq_2)WgHExUd&k`g1W
zo2!#8(Z)@QT8sH1t7_R*0bP0CzxXg*j>(VvIhb2?u9bE+$QtD&CUBw@CCv_MaLmle
zIKIKQrwe7C?=tXo5WOef6|*U6Bv9Y#9Q>1$0R?v7>T2%FcV8OvIzu!hfAQShY13Uf
zAr_7_q?Yfjef=5_HqTfVNN$3a^3lKWa~ca>1pr_Gq55|)s>q!uy=}(7v`xOcO|AqF
z^5TX8PK8Vy5AyQ1TcxPt66{<sApqj|Z2r6N!!2fVFo81)`ljEWcm?2vIZ_*eHoTs4
zhcWze>6^Lfd`=5)M?G$)t<?6<bftNCO2zJ2GjaJny9@iEGhI-v;Su|Q$oI#F^DV__
z1<Un&emDi2T;B<g@#bJI!DDoO;{P^3`|u@LrVk&*sR?gyy#T@E?o&@jX^NTeUcjZl
zb{y%wLq%zxdr87g!rSKedWr1oK7@3Sy_VSV#2Car<vnE!AcV09K?Q8Gy@P$kA)>_g
zVko2p^Y+p6v4B{uNEYTr4$YR2F<3`+FUj1k8aQ~;B49B*Q%Ax(_<VA_M)>_(3T$Ay
znGnk->x`a`WNh4o!%w$dl^aSj_RZQVPlH-?$!6v$#XUC$i$o2}yF$kd|L0~xB&~vn
zViuA)$;!6vh3`a4k7RF#B@!jMAJ&IFxjeZg?u4$?GKaw#l8cvHn~n}q!-vCLxy`BX
ztNsYo51;mvHbUMraFe&yqO>WS7zi4;+z-Y(F_RGC(AGW=9gKQU=5KoLu5zMByJ47E
zjZ|}V&ibEGXN+Q+{;}=}r)EztvuWqM!Z%P}ZY8VwX!75iix3iV9jq#a%fNwa{gpck
z?#NCGG4ag{0$I-^t=n|wHV|(Fs1(z%>t>Jv-Ran$9l>>90!1;7CUUIkB^}s7D8pIw
zKt?HbdAV;95kK4#WJVKU2Pd)<6S&(p;OJwZg=xn#Zjymp%?9#h;Y@_WZyt+&fT5t6
zpmwT`6Lm7-pYM8t8{ZU{(uB8NK3#}cu=oec$$Y7cy%j|d6U2@{`afirOheP<S}w=b
zeO&H%jGk=wuUbvaOvqme70*q^B7+1-*M{yQ_Nbw){r>Z#xe`Bu{{MhR?NF<#MZPS)
z6@uKauRke38ovjT4&~sD_*n+NsT${?IbhEeA|=6zTH{aqR@JkL4JSIz%(oYl=n_u=
zQ~vn6dh^q~BZwI-+`Mu{VGwHt{`e`gvoURU_fAbc<L(UNl#3p}ywbY28Jzh3a0@l7
zy<!`da(D-T+nY^H1&54LR%ASIl7yg~O`^{}kUIvakAZn}QzJ7$PbSwS`fvcc|9eKo
zjny_809Oq^@Dn_p<WJj6^G_zbPq_Yx;luog)HFe(nu}n?%dOt!wyKHd`?B#8$+W(n
zrid(iTj6zQ2h)GELJy|S=)JCQEpMIh%l{i43e@TAy?yXr+_gObw?$$+UTR8Ouc{QF
Gq5ltFE|6#d
--- a/browser/themes/windows/browser-aero.css
+++ b/browser/themes/windows/browser-aero.css
@@ -17,17 +17,18 @@
     margin-top: 1px;
   }
 
   .panel-promo-message {
     font-style: italic;
   }
 }
 
-@media (-moz-windows-default-theme) {
+@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
+       (-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
   #navigator-toolbox > toolbar:not(:-moz-lwtheme),
   #browser-bottombox:not(:-moz-lwtheme),
   .browserContainer > findbar {
     background-color: @customToolbarColor@;
   }
 
   .tab-background-middle[selected=true]:not(:-moz-lwtheme) {
     background-color: @customToolbarColor@;
@@ -164,18 +165,16 @@
     border-top: 1px solid @toolbarShadowColor@ !important;
     background-clip: padding-box;
   }
 
   /* This code is only needed for restored windows (i.e. sizemode=normal)
      because of the border radius on the toolbar below the tab bar. */
   #main-window[sizemode=normal] #nav-bar {
     border-top: 1px solid @toolbarShadowColor@;
-    border-top-left-radius: 2.5px;
-    border-top-right-radius: 2.5px;
     background-clip: padding-box;
   }
 
   /* Cover the top border of the adjacent toolbar */
   #TabsToolbar {
     margin-bottom: -1px;
   }
 
@@ -192,17 +191,28 @@
   }
 
   #appcontent:not(:-moz-lwtheme) {
     background-color: -moz-dialog;
   }
 
   #main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
     background-color: rgba(255,255,255,.5);
-    border-radius: 4px;
+  }
+
+  @media (-moz-os-version: windows-vista),
+         (-moz-os-version: windows-win7) {
+    #main-window[sizemode=normal] #nav-bar {
+      border-top-left-radius: 2.5px;
+      border-top-right-radius: 2.5px;
+    }
+
+    #main-menubar:not(:-moz-lwtheme):not(:-moz-window-inactive) {
+      border-radius: 4px;
+    }
   }
 
   #ctrlTab-panel {
     background: transparent;
     -moz-appearance: -moz-win-glass;
     border-radius: 0;
     border: none;
     font: normal 1.2em "Segoe UI";
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -780,16 +780,25 @@ toolbarbutton[sdk-button="true"][cui-are
 .unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr),
 .unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) {
   list-style-image: url("chrome://browser/skin/menu-forward.png") !important;
 }
 
 #home-button.bookmark-item {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
+
+%ifndef WINDOWS_AERO
+@media (-moz-windows-theme: luna-silver) {
+  #home-button.bookmark-item {
+    list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
+  }
+}
+%endif
+
 #home-button.bookmark-item:-moz-lwtheme-brighttext {
   list-style-image: url("chrome://browser/skin/Toolbar-inverted.png");
 }
 
 #sync-button[cui-areatype="toolbar"][status="active"] {
   /* !important because we need to override the glass selectors that trigger
    * use of the Toolbar-inverted image. Those use a list of all primary toolbar
    * buttons, so we can't easily fix those selectors. */
new file mode 100644
--- /dev/null
+++ b/browser/themes/windows/customizableui/panelUIOverlay-aero.css
@@ -0,0 +1,7 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+%define WINDOWS_AERO
+%include panelUIOverlay.css
+%undef WINDOWS_AERO
--- a/browser/themes/windows/customizableui/panelUIOverlay.css
+++ b/browser/themes/windows/customizableui/panelUIOverlay.css
@@ -29,8 +29,29 @@
   padding: 0 2px;
   -moz-padding-start: 0;
   height: 18px;
 }
 
 .widget-overflow-list .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
   padding: 0 6px;
 }
+
+%ifdef WINDOWS_AERO
+/* Win8 and beyond. */
+@media not all and (-moz-os-version: windows-vista) {
+  @media not all and (-moz-os-version: windows-win7) {
+    panelview .toolbarbutton-1,
+    .subviewbutton,
+    .widget-overflow-list .toolbarbutton-1,
+    .panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
+    #edit-controls@inAnyPanel@ > toolbarbutton,
+    #zoom-controls@inAnyPanel@ > toolbarbutton {
+      border-radius: 0;
+    }
+
+    #edit-controls@inAnyPanel@,
+    #zoom-controls@inAnyPanel@ {
+      border-radius: 0;
+    }
+  }
+}
+%endif
--- a/browser/themes/windows/jar.mn
+++ b/browser/themes/windows/jar.mn
@@ -67,17 +67,17 @@ browser.jar:
         skin/classic/browser/Privacy-48.png
         skin/classic/browser/privatebrowsing-indicator.png
         skin/classic/browser/reload-stop-go.png
         skin/classic/browser/searchbar.css
         skin/classic/browser/searchbar-dropdown-arrow.png
         skin/classic/browser/Secure24.png
         skin/classic/browser/setDesktopBackground.css
         skin/classic/browser/slowStartup-16.png
-        skin/classic/browser/Toolbar.png
+        skin/classic/browser/Toolbar.png                             (Toolbar-XP.png)
         skin/classic/browser/Toolbar-inverted.png
         skin/classic/browser/Toolbar-lunaSilver.png
         skin/classic/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/browser/toolbarbutton-dropdown-arrow-inverted.png
         skin/classic/browser/urlbar-arrow.png
         skin/classic/browser/urlbar-popup-blocked.png
         skin/classic/browser/urlbar-history-dropmarker.png
         skin/classic/browser/notification-pluginNormal.png           (../shared/plugins/notification-pluginNormal.png)
@@ -385,18 +385,19 @@ browser.jar:
         skin/classic/aero/browser/Privacy-48.png                     (Privacy-48-aero.png)
         skin/classic/aero/browser/privatebrowsing-indicator.png
         skin/classic/aero/browser/reload-stop-go.png
         skin/classic/aero/browser/searchbar.css
         skin/classic/aero/browser/searchbar-dropdown-arrow.png       (searchbar-dropdown-arrow-aero.png)
         skin/classic/aero/browser/Secure24.png                       (Secure24-aero.png)
         skin/classic/aero/browser/setDesktopBackground.css
         skin/classic/aero/browser/slowStartup-16.png
-        skin/classic/aero/browser/Toolbar.png                        (Toolbar-aero.png)
+        skin/classic/aero/browser/Toolbar.png
         skin/classic/aero/browser/Toolbar-inverted.png
+        skin/classic/aero/browser/Toolbar-aero.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow.png
         skin/classic/aero/browser/toolbarbutton-dropdown-arrow-inverted.png
         skin/classic/aero/browser/urlbar-arrow.png
         skin/classic/aero/browser/urlbar-popup-blocked.png
         skin/classic/aero/browser/urlbar-history-dropmarker.png
         skin/classic/aero/browser/notification-pluginNormal.png     (../shared/plugins/notification-pluginNormal.png)
         skin/classic/aero/browser/notification-pluginAlert.png      (../shared/plugins/notification-pluginAlert.png)
         skin/classic/aero/browser/notification-pluginBlocked.png    (../shared/plugins/notification-pluginBlocked.png)
@@ -405,17 +406,17 @@ browser.jar:
         skin/classic/aero/browser/webRTC-sharingDevice-16.png
         skin/classic/aero/browser/customizableui/background-noise-toolbar.png  (customizableui/background-noise-toolbar.png)
         skin/classic/aero/browser/customizableui/customize-titleBar-toggle.png  (customizableui/customize-titleBar-toggle.png)
         skin/classic/aero/browser/customizableui/customizeFavicon.ico  (../shared/customizableui/customizeFavicon.ico)
         skin/classic/aero/browser/customizableui/customizeMode-gridTexture.png  (customizableui/customizeMode-gridTexture.png)
         skin/classic/aero/browser/customizableui/customizeMode-separatorHorizontal.png  (customizableui/customizeMode-separatorHorizontal.png)
         skin/classic/aero/browser/customizableui/customizeMode-separatorVertical.png  (customizableui/customizeMode-separatorVertical.png)
         skin/classic/aero/browser/customizableui/menuPanel-customizeFinish.png  (../shared/customizableui/menuPanel-customizeFinish.png)
-*       skin/classic/aero/browser/customizableui/panelUIOverlay.css  (customizableui/panelUIOverlay.css)
+*       skin/classic/aero/browser/customizableui/panelUIOverlay.css  (customizableui/panelUIOverlay-aero.css)
         skin/classic/aero/browser/customizableui/subView-arrow-back-inverted.png  (../shared/customizableui/subView-arrow-back-inverted.png)
 *       skin/classic/aero/browser/downloads/allDownloadsViewOverlay.css (downloads/allDownloadsViewOverlay-aero.css)
         skin/classic/aero/browser/downloads/buttons.png              (downloads/buttons-aero.png)
         skin/classic/aero/browser/downloads/contentAreaDownloadsView.css (downloads/contentAreaDownloadsView.css)
         skin/classic/aero/browser/downloads/download-glow.png        (downloads/download-glow.png)
         skin/classic/aero/browser/downloads/download-glow-menuPanel.png   (downloads/download-glow-menuPanel.png)
         skin/classic/aero/browser/downloads/download-glow-menuPanel-XPVista7.png   (downloads/download-glow-menuPanel-XPVista7.png)
         skin/classic/aero/browser/downloads/download-notification-finish.png (downloads/download-notification-finish.png)
@@ -637,10 +638,13 @@ browser.jar:
         skin/classic/aero/browser/devtools/tooltip/arrow-horizontal-dark@2x.png   (../shared/devtools/tooltip/arrow-horizontal-dark@2x.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-vertical-dark.png   (../shared/devtools/tooltip/arrow-vertical-dark.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-vertical-dark@2x.png   (../shared/devtools/tooltip/arrow-vertical-dark@2x.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-horizontal-light.png   (../shared/devtools/tooltip/arrow-horizontal-light.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-horizontal-light@2x.png   (../shared/devtools/tooltip/arrow-horizontal-light@2x.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-vertical-light.png   (../shared/devtools/tooltip/arrow-vertical-light.png)
         skin/classic/aero/browser/devtools/tooltip/arrow-vertical-light@2x.png   (../shared/devtools/tooltip/arrow-vertical-light@2x.png)
 
+% override chrome://browser/skin/Toolbar.png               chrome://browser/skin/Toolbar-aero.png                  os=WINNT osversion=6
+% override chrome://browser/skin/Toolbar.png               chrome://browser/skin/Toolbar-aero.png                  os=WINNT osversion=6.1
+
 % override chrome://browser/skin/sync-horizontalbar.png          chrome://browser/skin/sync-horizontalbar-XPVista7.png          os=WINNT osversion<6.2
 % override chrome://browser/skin/syncProgress-horizontalbar.png  chrome://browser/skin/syncProgress-horizontalbar-XPVista7.png  os=WINNT osversion<6.2
--- a/browser/themes/windows/places/organizer-aero.css
+++ b/browser/themes/windows/places/organizer-aero.css
@@ -31,17 +31,18 @@
     border-top: none;
   }
 
   #placesToolbar {
     background-image: linear-gradient(@toolbarHighlight@, rgba(255,255,255,0));
   }
 }
 
-@media (-moz-windows-default-theme) {
+@media (-moz-windows-default-theme) and (-moz-os-version: windows-vista),
+       (-moz-windows-default-theme) and (-moz-os-version: windows-win7) {
   #placesView,
   #infoPane,
   #placesList,
   #placeContent {
     background-color: #EEF3FA;
   }
 
   #placesToolbar {
--- a/browser/themes/windows/places/organizer.css
+++ b/browser/themes/windows/places/organizer.css
@@ -12,16 +12,25 @@
   opacity: .4;
 }
 
 #back-button,
 #forward-button {
   list-style-image: url("chrome://browser/skin/Toolbar.png");
 }
 
+%ifndef WINDOWS_AERO
+@media (-moz-windows-theme: luna-silver) {
+  #back-button,
+  #forward-button {
+    list-style-image: url("chrome://browser/skin/Toolbar-lunaSilver.png");
+  }
+}
+%endif
+
 #back-button {
   -moz-image-region: rect(0, 54px, 18px, 36px);
 }
 
 #forward-button {
   -moz-image-region: rect(0, 72px, 18px, 54px);
 }
 
--- a/configure.in
+++ b/configure.in
@@ -244,17 +244,19 @@ if test -n "$gonkdir" ; then
         MOZ_B2G_CAMERA=1
         MOZ_OMX_DECODER=1
         AC_SUBST(MOZ_OMX_DECODER)
         MOZ_OMX_ENCODER=1
         AC_SUBST(MOZ_OMX_ENCODER)
         AC_DEFINE(MOZ_OMX_ENCODER)
         ;;
     19)
-        GONK_INCLUDES="-I$gonkdir/frameworks/native/include"
+        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"
+        MOZ_B2G_CAMERA=1
+        MOZ_OMX_DECODER=1
         MOZ_B2G_BT=1
         MOZ_B2G_BT_BLUEDROID=1
         MOZ_NFC=1
 
         ;;
     *)
         AC_MSG_ERROR([Unsupported platform version: $ANDROID_VERSION])
         ;;
--- a/dom/camera/GonkCameraHwMgr.cpp
+++ b/dom/camera/GonkCameraHwMgr.cpp
@@ -158,22 +158,29 @@ GonkCameraHardware::Init()
   DOM_CAMERA_LOGI("Sensor orientation: base=%d, offset=%d, final=%d\n", info.orientation, offset, mSensorOrientation);
 
   // Disable shutter sound in android CameraService because gaia camera app will play it
   mCamera->sendCommand(CAMERA_CMD_ENABLE_SHUTTER_SOUND, 0, 0);
 
   mNativeWindow = new GonkNativeWindow();
   mNativeWindow->setNewFrameCallback(this);
   mCamera->setListener(this);
-#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+
+#if defined(MOZ_WIDGET_GONK)
+
+#if ANDROID_VERSION >= 19
+  mCamera->setPreviewTarget(mNativeWindow->getBufferQueue());
+#elif (ANDROID_VERSION == 17) || (ANDROID_VERSION == 18)
   mCamera->setPreviewTexture(mNativeWindow->getBufferQueue());
 #else
   mCamera->setPreviewTexture(mNativeWindow);
 #endif
 
+#endif
+
   return NS_OK;
 }
 
 sp<GonkCameraHardware>
 GonkCameraHardware::Connect(mozilla::nsGonkCameraControl* aTarget, uint32_t aCameraId)
 {
 #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 18
   sp<Camera> camera = Camera::connect(aCameraId, /* clientPackageName */String16("gonk.camera"), Camera::USE_CALLING_UID);
--- a/dom/wifi/WifiWorker.js
+++ b/dom/wifi/WifiWorker.js
@@ -291,17 +291,19 @@ var WifiManager = (function() {
 
   function syncDebug() {
     if (debugEnabled !== DEBUG) {
       let wanted = DEBUG;
       wifiCommand.setLogLevel(wanted ? "DEBUG" : "INFO", function(ok) {
         if (ok)
           debugEnabled = wanted;
       });
-      p2pManager.setDebug(DEBUG);
+      if (p2pSupported && p2pManager) {
+        p2pManager.setDebug(DEBUG);
+      }
     }
   }
 
   function getDebugEnabled(callback) {
     wifiCommand.getLogLevel(function(level) {
       if (level === null) {
         debug("Unable to get wpa_supplicant's log level");
         callback(false);
@@ -2497,16 +2499,89 @@ WifiWorker.prototype = {
 
       // Otherwise, let the client know that it failed, it's responsible for
       // trying again in a few seconds.
       sent = true;
       this._sendMessage(message, false, "ScanFailed", msg);
     }).bind(this));
   },
 
+  getWifiScanResults: function(callback) {
+    var count = 0;
+    var timer = null;
+    var self = this;
+
+    self.waitForScan(waitForScanCallback);
+    doScan();
+    function doScan() {
+      WifiManager.scan(true, function (ok) {
+        if (!ok) {
+          if (!timer) {
+            count = 0;
+            timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+          }
+
+          if (count++ >= 3) {
+            timer = null;
+            this.wantScanResults.splice(this.wantScanResults.indexOf(waitForScanCallback), 1);
+            callback.onfailure();
+            return;
+          }
+
+          // Else it's still running, continue waiting.
+          timer.initWithCallback(doScan, 10000, Ci.nsITimer.TYPE_ONE_SHOT);
+          return;
+        }
+      });
+    }
+
+    function waitForScanCallback(networks) {
+      if (networks === null) {
+        callback.onfailure();
+        return;
+      }
+
+      var wifiScanResults = new Array();
+      var net;
+      for (let net in networks) {
+        let value = networks[net];
+        wifiScanResults.push(transformResult(value));
+      }
+      callback.onready(wifiScanResults.length, wifiScanResults);
+    }
+
+    function transformResult(element) {
+      var result = new WifiScanResult();
+      result.connected = false;
+      for (let id in element) {
+        if (id === "__exposedProps__") {
+          continue;
+        }
+        if (id === "security") {
+          result[id] = 0;
+          var security = element[id];
+          for (let j = 0; j < security.length; j++) {
+            if (security[j] === "WPA-PSK") {
+              result[id] |= Ci.nsIWifiScanResult.WPA_PSK;
+            } else if (security[j] === "WPA-EAP") {
+              result[id] |= Ci.nsIWifiScanResult.WPA_EAP;
+            } else if (security[j] === "WEP") {
+              result[id] |= Ci.nsIWifiScanResult.WEP;
+            } else {
+             result[id] = 0;
+            }
+          }
+        } else {
+          result[id] = element[id];
+        }
+      }
+      return result;
+    }
+  },
+
   getKnownNetworks: function(msg) {
     const message = "WifiManager:getKnownNetworks:Return";
     if (!WifiManager.enabled) {
       this._sendMessage(message, false, "Wifi is disabled", msg);
       return;
     }
 
     this._reloadConfiguredNetworks((function(ok) {
--- a/ipc/moz.build
+++ b/ipc/moz.build
@@ -16,14 +16,14 @@ if CONFIG['MOZ_B2G_RIL']:
 
 if CONFIG['MOZ_B2G_BT_BLUEZ']:
     DIRS += ['dbus']
 
 if CONFIG['MOZ_NFC']:
     DIRS += ['nfc']
 
 if CONFIG['MOZ_B2G_RIL'] or CONFIG['MOZ_B2G_BT'] or CONFIG['MOZ_NFC'] or CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    DIRS += ['unixsocket']
+    DIRS += ['unixfd', 'unixsocket']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    DIRS += ['netd', 'keystore']
+    DIRS += ['keystore', 'netd']
 
 TOOL_DIRS += ['app']
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixFdWatcher.cpp
@@ -0,0 +1,119 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "UnixFdWatcher.h"
+
+#ifdef CHROMIUM_LOG
+#undef CHROMIUM_LOG
+#endif
+
+#if defined(MOZ_WIDGET_GONK)
+#include <android/log.h>
+#define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "I/O", args);
+#else
+#include <stdio.h>
+#define IODEBUG true
+#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
+#endif
+
+namespace mozilla {
+namespace ipc {
+
+UnixFdWatcher::~UnixFdWatcher()
+{
+  NS_WARN_IF(IsOpen()); /* mFd should have been closed already */
+}
+
+void
+UnixFdWatcher::Close()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+
+  if (NS_WARN_IF(!IsOpen())) {
+    /* mFd should have been open */
+    return;
+  }
+  OnClose();
+  RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
+  mFd.dispose();
+}
+
+void
+UnixFdWatcher::AddWatchers(unsigned long aWatchers, bool aPersistent)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+  MOZ_ASSERT(IsOpen());
+
+  // Before we add a watcher, we need to remove it! Removing is always
+  // safe, but adding the same watcher twice can lead to endless loops
+  // inside libevent.
+  RemoveWatchers(aWatchers);
+
+  if (aWatchers & READ_WATCHER) {
+    MessageLoopForIO::current()->WatchFileDescriptor(
+      mFd,
+      aPersistent,
+      MessageLoopForIO::WATCH_READ,
+      &mReadWatcher,
+      this);
+  }
+  if (aWatchers & WRITE_WATCHER) {
+    MessageLoopForIO::current()->WatchFileDescriptor(
+      mFd,
+      aPersistent,
+      MessageLoopForIO::WATCH_WRITE,
+      &mWriteWatcher,
+      this);
+  }
+}
+
+void
+UnixFdWatcher::RemoveWatchers(unsigned long aWatchers)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+  MOZ_ASSERT(IsOpen());
+
+  if (aWatchers & READ_WATCHER) {
+    mReadWatcher.StopWatchingFileDescriptor();
+  }
+  if (aWatchers & WRITE_WATCHER) {
+    mWriteWatcher.StopWatchingFileDescriptor();
+  }
+}
+
+void
+UnixFdWatcher::OnError(const char* aFunction, int aErrno)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+
+  CHROMIUM_LOG("%s failed with error %d (%s)",
+               aFunction, aErrno, strerror(aErrno));
+}
+
+UnixFdWatcher::UnixFdWatcher(MessageLoop* aIOLoop)
+: mIOLoop(aIOLoop)
+{
+  MOZ_ASSERT(mIOLoop);
+}
+
+UnixFdWatcher::UnixFdWatcher(MessageLoop* aIOLoop, int aFd)
+: mIOLoop(aIOLoop)
+, mFd(aFd)
+{
+  MOZ_ASSERT(mIOLoop);
+}
+
+void
+UnixFdWatcher::SetFd(int aFd)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == mIOLoop);
+  MOZ_ASSERT(!IsOpen());
+
+  mFd = aFd;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixFdWatcher.h
@@ -0,0 +1,62 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "base/message_loop.h"
+#include "mozilla/FileUtils.h"
+
+namespace mozilla {
+namespace ipc {
+
+class UnixFdWatcher : public MessageLoopForIO::Watcher
+{
+public:
+  enum {
+    READ_WATCHER = 1<<0,
+    WRITE_WATCHER = 1<<1
+  };
+
+  virtual ~UnixFdWatcher();
+
+  MessageLoop* GetIOLoop() const
+  {
+    return mIOLoop;
+  }
+
+  int GetFd() const
+  {
+    return mFd;
+  }
+
+  bool IsOpen() const
+  {
+    return GetFd() >= 0;
+  }
+
+  virtual void Close();
+
+  void AddWatchers(unsigned long aWatchers, bool aPersistent);
+  void RemoveWatchers(unsigned long aWatchers);
+
+  // Callback method that's run before closing the file descriptor
+  virtual void OnClose() {};
+
+  // Callback method that's run on POSIX errors
+  virtual void OnError(const char* aFunction, int aErrno);
+
+protected:
+  UnixFdWatcher(MessageLoop* aIOLoop);
+  UnixFdWatcher(MessageLoop* aIOLoop, int aFd);
+  void SetFd(int aFd);
+
+private:
+  MessageLoop* mIOLoop;
+  ScopedClose mFd;
+  MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
+  MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixFileWatcher.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <fcntl.h>
+#include "UnixFileWatcher.h"
+
+namespace mozilla {
+namespace ipc {
+
+UnixFileWatcher::~UnixFileWatcher()
+{
+}
+
+nsresult
+UnixFileWatcher::Open(const char* aFilename, int aFlags, mode_t aMode)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  int fd = TEMP_FAILURE_RETRY(open(aFilename, aFlags, aMode));
+  if (fd < 0) {
+    OnError("open", errno);
+    return NS_ERROR_FAILURE;
+  }
+  SetFd(fd);
+  OnOpened();
+
+  return NS_OK;
+}
+
+UnixFileWatcher::UnixFileWatcher(MessageLoop* aIOLoop)
+: UnixFdWatcher(aIOLoop)
+{
+}
+
+UnixFileWatcher::UnixFileWatcher(MessageLoop* aIOLoop, int aFd)
+: UnixFdWatcher(aIOLoop, aFd)
+{
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixFileWatcher.h
@@ -0,0 +1,28 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "UnixFdWatcher.h"
+
+namespace mozilla {
+namespace ipc {
+
+class UnixFileWatcher : public UnixFdWatcher
+{
+public:
+  virtual ~UnixFileWatcher();
+
+  nsresult Open(const char* aFilename, int aFlags, mode_t aMode = 0);
+
+  // Callback method for successful open requests
+  virtual void OnOpened() {};
+
+protected:
+  UnixFileWatcher(MessageLoop* aIOLoop);
+  UnixFileWatcher(MessageLoop* aIOLoop, int aFd);
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixSocketWatcher.cpp
@@ -0,0 +1,155 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include <fcntl.h>
+#include "UnixSocketWatcher.h"
+
+namespace mozilla {
+namespace ipc {
+
+UnixSocketWatcher::~UnixSocketWatcher()
+{
+}
+
+void UnixSocketWatcher::Close()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  mConnectionStatus = SOCKET_IS_DISCONNECTED;
+  UnixFdWatcher::Close();
+}
+
+nsresult
+UnixSocketWatcher::Connect(const struct sockaddr* aAddr, socklen_t aAddrLen)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(IsOpen());
+  MOZ_ASSERT(aAddr || !aAddrLen);
+
+  // Select non-blocking IO.
+  if (TEMP_FAILURE_RETRY(fcntl(GetFd(), F_SETFL, O_NONBLOCK)) < 0) {
+    OnError("fcntl", errno);
+    return NS_ERROR_FAILURE;
+  }
+
+  if (connect(GetFd(), aAddr, aAddrLen) < 0) {
+    if (errno == EINPROGRESS) {
+      // Select blocking IO again, since we've now at least queue'd the connect
+      // as nonblock.
+      int flags = TEMP_FAILURE_RETRY(fcntl(GetFd(), F_GETFL, 0));
+      if (flags < 0) {
+        OnError("fcntl", errno);
+        return NS_ERROR_FAILURE;
+      }
+      if (TEMP_FAILURE_RETRY(fcntl(GetFd(), F_SETFL, flags&~O_NONBLOCK)) < 0) {
+        OnError("fcntl", errno);
+        return NS_ERROR_FAILURE;
+      }
+      mConnectionStatus = SOCKET_IS_CONNECTING;
+      // Set up a write watch to receive the connect signal
+      AddWatchers(WRITE_WATCHER, false);
+    } else {
+      OnError("connect", errno);
+    }
+    return NS_ERROR_FAILURE;
+  }
+
+  mConnectionStatus = SOCKET_IS_CONNECTED;
+  OnConnected();
+
+  return NS_OK;
+}
+
+nsresult
+UnixSocketWatcher::Listen(const struct sockaddr* aAddr, socklen_t aAddrLen)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(IsOpen());
+  MOZ_ASSERT(aAddr || !aAddrLen);
+
+  if (bind(GetFd(), aAddr, aAddrLen) < 0) {
+    OnError("bind", errno);
+    return NS_ERROR_FAILURE;
+  }
+  if (listen(GetFd(), 1) < 0) {
+    OnError("listen", errno);
+    return NS_ERROR_FAILURE;
+  }
+  mConnectionStatus = SOCKET_IS_LISTENING;
+  OnListening();
+
+  return NS_OK;
+}
+
+UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop)
+: UnixFdWatcher(aIOLoop)
+, mConnectionStatus(SOCKET_IS_DISCONNECTED)
+{
+}
+
+UnixSocketWatcher::UnixSocketWatcher(MessageLoop* aIOLoop, int aFd,
+                                     ConnectionStatus aConnectionStatus)
+: UnixFdWatcher(aIOLoop, aFd)
+, mConnectionStatus(aConnectionStatus)
+{
+}
+
+void
+UnixSocketWatcher::SetSocket(int aFd, ConnectionStatus aConnectionStatus)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  SetFd(aFd);
+  mConnectionStatus = aConnectionStatus;
+}
+
+void
+UnixSocketWatcher::OnFileCanReadWithoutBlocking(int aFd)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(aFd == GetFd());
+
+  if (mConnectionStatus == SOCKET_IS_CONNECTED) {
+    OnSocketCanReceiveWithoutBlocking();
+  } else if (mConnectionStatus == SOCKET_IS_LISTENING) {
+    int fd = TEMP_FAILURE_RETRY(accept(GetFd(), NULL, NULL));
+    if (fd < 0) {
+      OnError("accept", errno);
+    } else {
+      OnAccepted(fd);
+    }
+  } else {
+    NS_NOTREACHED("invalid connection state for reading");
+  }
+}
+
+void
+UnixSocketWatcher::OnFileCanWriteWithoutBlocking(int aFd)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(aFd == GetFd());
+
+  if (mConnectionStatus == SOCKET_IS_CONNECTED) {
+    OnSocketCanSendWithoutBlocking();
+  } else if (mConnectionStatus == SOCKET_IS_CONNECTING) {
+    RemoveWatchers(WRITE_WATCHER);
+    int error = 0;
+    socklen_t len = sizeof(error);
+    if (getsockopt(GetFd(), SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+      OnError("getsockopt", errno);
+    } else if (error) {
+      OnError("connect", error);
+    } else {
+      mConnectionStatus = SOCKET_IS_CONNECTED;
+      OnConnected();
+    }
+  } else {
+    NS_NOTREACHED("invalid connection state for writing");
+  }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/UnixSocketWatcher.h
@@ -0,0 +1,66 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "UnixFdWatcher.h"
+
+namespace mozilla {
+namespace ipc {
+
+class UnixSocketWatcher : public UnixFdWatcher
+{
+public:
+  enum ConnectionStatus {
+    SOCKET_IS_DISCONNECTED = 0,
+    SOCKET_IS_LISTENING,
+    SOCKET_IS_CONNECTING,
+    SOCKET_IS_CONNECTED
+  };
+
+  virtual ~UnixSocketWatcher();
+
+  virtual void Close() MOZ_OVERRIDE;
+
+  ConnectionStatus GetConnectionStatus() const
+  {
+    return mConnectionStatus;
+  }
+
+  // Connect to a peer
+  nsresult Connect(const struct sockaddr* aAddr, socklen_t aAddrLen);
+
+  // Listen on socket for incomming connection requests
+  nsresult Listen(const struct sockaddr* aAddr, socklen_t aAddrLen);
+
+  // Callback method for accepted connections
+  virtual void OnAccepted(int aFd) {};
+
+  // Callback method for successful connection requests
+  virtual void OnConnected() {};
+
+  // Callback method for successful listen requests
+  virtual void OnListening() {};
+
+  // Callback method for receiving from socket
+  virtual void OnSocketCanReceiveWithoutBlocking() {};
+
+  // Callback method for sending on socket
+  virtual void OnSocketCanSendWithoutBlocking() {};
+
+protected:
+  UnixSocketWatcher(MessageLoop* aIOLoop);
+  UnixSocketWatcher(MessageLoop* aIOLoop, int aFd,
+                    ConnectionStatus aConnectionStatus);
+  void SetSocket(int aFd, ConnectionStatus aConnectionStatus);
+
+private:
+  void OnFileCanReadWithoutBlocking(int aFd) MOZ_OVERRIDE;
+  void OnFileCanWriteWithoutBlocking(int aFd) MOZ_OVERRIDE;
+
+  ConnectionStatus mConnectionStatus;
+};
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/ipc/unixfd/moz.build
@@ -0,0 +1,23 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS.mozilla.ipc += [
+    'UnixFdWatcher.h',
+    'UnixFileWatcher.h',
+    'UnixSocketWatcher.h'
+]
+
+SOURCES += [
+    'UnixFdWatcher.cpp',
+    'UnixFileWatcher.cpp',
+    'UnixSocketWatcher.cpp'
+]
+
+FAIL_ON_WARNINGS = True
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
--- a/ipc/unixsocket/UnixSocket.cpp
+++ b/ipc/unixsocket/UnixSocket.cpp
@@ -11,69 +11,62 @@
 #include <stdlib.h>
 #include <errno.h>
 
 #include <sys/socket.h>
 
 #include "base/eintr_wrapper.h"
 #include "base/message_loop.h"
 
+#include "mozilla/ipc/UnixSocketWatcher.h"
 #include "mozilla/Monitor.h"
 #include "mozilla/FileUtils.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsXULAppAPI.h"
 
 static const size_t MAX_READ_SIZE = 1 << 16;
 
 #undef CHROMIUM_LOG
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
-#define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "GonkDBus", args);
+#define CHROMIUM_LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "I/O", args);
 #else
-#define BTDEBUG true
-#define CHROMIUM_LOG(args...) if (BTDEBUG) printf(args);
+#define IODEBUG true
+#define CHROMIUM_LOG(args...) if (IODEBUG) printf(args);
 #endif
 
-static const int SOCKET_RETRY_TIME_MS = 1000;
-
 namespace mozilla {
 namespace ipc {
 
-class UnixSocketImpl : public MessageLoopForIO::Watcher
+class UnixSocketImpl : public UnixSocketWatcher
 {
 public:
-  UnixSocketImpl(UnixSocketConsumer* aConsumer, UnixSocketConnector* aConnector,
-                 const nsACString& aAddress,
-                 SocketConnectionStatus aConnectionStatus)
-    : mConsumer(aConsumer)
-    , mIOLoop(nullptr)
+  UnixSocketImpl(MessageLoop* mIOLoop,
+                 UnixSocketConsumer* aConsumer, UnixSocketConnector* aConnector,
+                 const nsACString& aAddress)
+    : UnixSocketWatcher(mIOLoop)
+    , mConsumer(aConsumer)
     , mConnector(aConnector)
     , mShuttingDownOnIOThread(false)
     , mAddress(aAddress)
     , mDelayedConnectTask(nullptr)
-    , mConnectionStatus(aConnectionStatus)
   {
   }
 
   ~UnixSocketImpl()
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(IsShutdownOnMainThread());
   }
 
   void QueueWriteData(UnixSocketRawData* aData)
   {
     mOutgoingQ.AppendElement(aData);
-    OnFileCanWriteWithoutBlocking(mFd);
-  }
-
-  bool isFdValid()
-  {
-    return mFd > 0;
+    AddWatchers(WRITE_WATCHER, false);
   }
 
   bool IsShutdownOnMainThread()
   {
     MOZ_ASSERT(NS_IsMainThread());
     return mConsumer == nullptr;
   }
 
@@ -89,34 +82,21 @@ public:
     return mShuttingDownOnIOThread;
   }
 
   void ShutdownOnIOThread()
   {
     MOZ_ASSERT(!NS_IsMainThread());
     MOZ_ASSERT(!mShuttingDownOnIOThread);
 
-    mReadWatcher.StopWatchingFileDescriptor();
-    mWriteWatcher.StopWatchingFileDescriptor();
+    RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
 
     mShuttingDownOnIOThread = true;
   }
 
-  void SetUpIO()
-  {
-    MOZ_ASSERT(!mIOLoop);
-    MOZ_ASSERT(mFd >= 0);
-    mIOLoop = MessageLoopForIO::current();
-    mIOLoop->WatchFileDescriptor(mFd,
-                                 true,
-                                 MessageLoopForIO::WATCH_READ,
-                                 &mReadWatcher,
-                                 this);
-  }
-
   void SetDelayedConnectTask(CancelableTask* aTask)
   {
     MOZ_ASSERT(NS_IsMainThread());
     mDelayedConnectTask = aTask;
   }
 
   void ClearDelayedConnectTask()
   {
@@ -140,26 +120,21 @@ public:
   void Connect();
 
   /**
    * Run bind/listen to prepare for further runs of accept()
    */
   void Listen();
 
   /**
-   * Accept an incoming connection
-   */
-  void Accept();
-
-  /**
    * Set up flags on whatever our current file descriptor is.
    *
    * @return true if successful, false otherwise
    */
-  bool SetSocketFlags();
+  bool SetSocketFlags(int aFd);
 
   void GetSocketAddr(nsAString& aAddrStr)
   {
     if (!mConnector) {
       NS_WARNING("No connector to get socket address from!");
       aAddrStr.Truncate();
       return;
     }
@@ -168,64 +143,34 @@ public:
 
   /**
    * Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
    * directly from main thread. All non-main-thread accesses should happen with
    * mImpl as container.
    */
   RefPtr<UnixSocketConsumer> mConsumer;
 
+  void OnAccepted(int aFd) MOZ_OVERRIDE;
+  void OnConnected() MOZ_OVERRIDE;
+  void OnError(const char* aFunction, int aErrno) MOZ_OVERRIDE;
+  void OnListening() MOZ_OVERRIDE;
+  void OnSocketCanReceiveWithoutBlocking() MOZ_OVERRIDE;
+  void OnSocketCanSendWithoutBlocking() MOZ_OVERRIDE;
+
 private:
 
   void FireSocketError();
 
   /**
-   * libevent triggered functions that reads data from socket when available and
-   * guarenteed non-blocking. Only to be called on IO thread.
-   *
-   * @param aFd File descriptor to read from
-   */
-  virtual void OnFileCanReadWithoutBlocking(int aFd);
-
-  /**
-   * libevent or developer triggered functions that writes data to socket when
-   * available and guarenteed non-blocking. Only to be called on IO thread.
-   *
-   * @param aFd File descriptor to read from
-   */
-  virtual void OnFileCanWriteWithoutBlocking(int aFd);
-
-  /**
-   * IO Loop pointer. Must be initalized and called from IO thread only.
-   */
-  MessageLoopForIO* mIOLoop;
-
-  /**
    * Raw data queue. Must be pushed/popped from IO thread only.
    */
   typedef nsTArray<UnixSocketRawData* > UnixSocketRawDataQueue;
   UnixSocketRawDataQueue mOutgoingQ;
 
   /**
-   * Read watcher for libevent. Only to be accessed on IO Thread.
-   */
-  MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
-
-  /**
-   * Write watcher for libevent. Only to be accessed on IO Thread.
-   */
-  MessageLoopForIO::FileDescriptorWatcher mWriteWatcher;
-
-  /**
-   * File descriptor to read from/write to. Connection happens on user provided
-   * thread. Read/write/close happens on IO thread.
-   */
-  ScopedClose mFd;
-
-  /**
    * Connector object used to create the connection we are currently using.
    */
   nsAutoPtr<UnixSocketConnector> mConnector;
 
   /**
    * If true, do not requeue whatever task we're running
    */
   bool mShuttingDownOnIOThread;
@@ -244,22 +189,16 @@ private:
    * Address struct of the socket currently in use
    */
   sockaddr_any mAddr;
 
   /**
    * Task member for delayed connect task. Should only be access on main thread.
    */
   CancelableTask* mDelayedConnectTask;
-
-  /**
-   * Socket connection status. Duplicate from UnixSocketConsumer. Should only
-   * be accessed on I/O thread.
-   */
-  SocketConnectionStatus mConnectionStatus;
 };
 
 template<class T>
 class DeleteInstanceRunnable : public nsRunnable
 {
 public:
   DeleteInstanceRunnable(T* aInstance)
   : mInstance(aInstance)
@@ -398,36 +337,37 @@ public:
     // upper layer
     mImpl->mConsumer->CloseSocket();
     return NS_OK;
   }
 private:
   UnixSocketImpl* mImpl;
 };
 
-class SocketAcceptTask : public CancelableTask {
+class SocketListenTask : public CancelableTask
+{
   virtual void Run();
 
   UnixSocketImpl* mImpl;
 public:
-  SocketAcceptTask(UnixSocketImpl* aImpl) : mImpl(aImpl) { }
+  SocketListenTask(UnixSocketImpl* aImpl) : mImpl(aImpl) { }
 
   virtual void Cancel()
   {
     MOZ_ASSERT(!NS_IsMainThread());
     mImpl = nullptr;
   }
 };
 
-void SocketAcceptTask::Run()
+void SocketListenTask::Run()
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   if (mImpl) {
-    mImpl->Accept();
+    mImpl->Listen();
   }
 }
 
 class SocketConnectTask : public Task {
   virtual void Run();
 
   UnixSocketImpl* mImpl;
 public:
@@ -473,206 +413,294 @@ public:
   ShutdownSocketTask(UnixSocketImpl* aImpl) : mImpl(aImpl) { }
 };
 
 void ShutdownSocketTask::Run()
 {
   MOZ_ASSERT(!NS_IsMainThread());
 
   // At this point, there should be no new events on the IO thread after this
-  // one with the possible exception of a SocketAcceptTask that
+  // one with the possible exception of a SocketListenTask that
   // ShutdownOnIOThread will cancel for us. We are now fully shut down, so we
   // can send a message to the main thread that will delete mImpl safely knowing
   // that no more tasks reference it.
   mImpl->ShutdownOnIOThread();
 
   nsRefPtr<nsIRunnable> t(new DeleteInstanceRunnable<UnixSocketImpl>(mImpl));
   nsresult rv = NS_DispatchToMainThread(t);
   NS_ENSURE_SUCCESS_VOID(rv);
 }
 
 void
 UnixSocketImpl::FireSocketError()
 {
-  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
 
   // Clean up watchers, statuses, fds
-  mReadWatcher.StopWatchingFileDescriptor();
-  mWriteWatcher.StopWatchingFileDescriptor();
-  mConnectionStatus = SOCKET_DISCONNECTED;
-  mFd.reset(-1);
+  Close();
 
   // Tell the main thread we've errored
   nsRefPtr<OnSocketEventTask> t =
     new OnSocketEventTask(this, OnSocketEventTask::CONNECT_ERROR);
   NS_DispatchToMainThread(t);
 }
 
 void
-UnixSocketImpl::Accept()
+UnixSocketImpl::Listen()
 {
-  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
   MOZ_ASSERT(mConnector);
 
   // This will set things we don't particularly care about, but it will hand
   // back the correct structure size which is what we do care about.
   if (!mConnector->CreateAddr(true, mAddrSize, mAddr, nullptr)) {
     NS_WARNING("Cannot create socket address!");
     FireSocketError();
     return;
   }
 
-  if (mFd.get() < 0) {
-    mFd = mConnector->Create();
-    if (mFd.get() < 0) {
+  if (!IsOpen()) {
+    int fd = mConnector->Create();
+    if (fd < 0) {
       NS_WARNING("Cannot create socket fd!");
       FireSocketError();
       return;
     }
+    SetFd(fd);
 
-    if (!SetSocketFlags()) {
+    if (!SetSocketFlags(GetFd())) {
       NS_WARNING("Cannot set socket flags!");
       FireSocketError();
       return;
     }
 
-    if (bind(mFd.get(), (struct sockaddr*)&mAddr, mAddrSize)) {
-#ifdef DEBUG
-      CHROMIUM_LOG("...bind(%d) gave errno %d", mFd.get(), errno);
-#endif
-      FireSocketError();
-      return;
-    }
-
-    if (listen(mFd.get(), 1)) {
-#ifdef DEBUG
-      CHROMIUM_LOG("...listen(%d) gave errno %d", mFd.get(), errno);
-#endif
-      FireSocketError();
-      return;
-    }
-
-    if (!mConnector->SetUpListenSocket(mFd)) {
-      NS_WARNING("Could not set up listen socket!");
-      FireSocketError();
-      return;
-    }
-
+    // calls OnListening on success, or OnError otherwise
+    nsresult rv = UnixSocketWatcher::Listen(
+      reinterpret_cast<struct sockaddr*>(&mAddr), mAddrSize);
+    NS_WARN_IF(NS_FAILED(rv));
   }
-
-  SetUpIO();
 }
 
 void
 UnixSocketImpl::Connect()
 {
-  MOZ_ASSERT(!NS_IsMainThread());
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
   MOZ_ASSERT(mConnector);
 
-  if (mFd.get() < 0) {
-    mFd = mConnector->Create();
-    if (mFd.get() < 0) {
+  if (!IsOpen()) {
+    int fd = mConnector->Create();
+    if (fd < 0) {
       NS_WARNING("Cannot create socket fd!");
       FireSocketError();
       return;
     }
+    SetFd(fd);
   }
 
-  int ret;
-
   if (!mConnector->CreateAddr(false, mAddrSize, mAddr, mAddress.get())) {
     NS_WARNING("Cannot create socket address!");
     FireSocketError();
     return;
   }
 
-  // Select non-blocking IO.
-  if (-1 == fcntl(mFd.get(), F_SETFL, O_NONBLOCK)) {
-    NS_WARNING("Cannot set nonblock!");
-    FireSocketError();
+  // calls OnConnected() on success, or OnError() otherwise
+  nsresult rv = UnixSocketWatcher::Connect(
+    reinterpret_cast<struct sockaddr*>(&mAddr), mAddrSize);
+  NS_WARN_IF(NS_FAILED(rv));
+}
+
+bool
+UnixSocketImpl::SetSocketFlags(int aFd)
+{
+  // Set socket addr to be reused even if kernel is still waiting to close
+  int n = 1;
+  setsockopt(aFd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+  // Set close-on-exec bit.
+  int flags = fcntl(aFd, F_GETFD);
+  if (-1 == flags) {
+    return false;
+  }
+
+  flags |= FD_CLOEXEC;
+  if (-1 == fcntl(aFd, F_SETFD, flags)) {
+    return false;
+  }
+
+  return true;
+}
+
+void
+UnixSocketImpl::OnAccepted(int aFd)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING);
+
+  if (!mConnector->SetUp(aFd)) {
+    NS_WARNING("Could not set up socket!");
     return;
   }
 
-  ret = connect(mFd.get(), (struct sockaddr*)&mAddr, mAddrSize);
-
-  if (ret) {
-    if (errno == EINPROGRESS) {
-      // Select blocking IO again, since we've now at least queue'd the connect
-      // as nonblock.
-      int current_opts = fcntl(mFd.get(), F_GETFL, 0);
-      if (-1 == current_opts) {
-        NS_WARNING("Cannot get socket opts!");
-        FireSocketError();
-        return;
-      }
-      if (-1 == fcntl(mFd.get(), F_SETFL, current_opts & ~O_NONBLOCK)) {
-        NS_WARNING("Cannot set socket opts to blocking!");
-        FireSocketError();
-        return;
-      }
-
-      // Set up a write watch to make sure we receive the connect signal
-      MessageLoopForIO::current()->WatchFileDescriptor(
-        mFd.get(),
-        false,
-        MessageLoopForIO::WATCH_WRITE,
-        &mWriteWatcher,
-        this);
-
-#ifdef DEBUG
-      CHROMIUM_LOG("UnixSocket Connection delayed!");
-#endif
-      return;
-    }
-#if DEBUG
-    CHROMIUM_LOG("Socket connect errno=%d\n", errno);
-#endif
-    FireSocketError();
+  RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
+  Close();
+  SetSocket(aFd, SOCKET_IS_CONNECTED);
+  if (!SetSocketFlags(GetFd())) {
     return;
   }
 
-  if (!SetSocketFlags()) {
+  nsRefPtr<OnSocketEventTask> t =
+    new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
+  NS_DispatchToMainThread(t);
+
+  AddWatchers(READ_WATCHER, true);
+  if (!mOutgoingQ.IsEmpty()) {
+    AddWatchers(WRITE_WATCHER, false);
+  }
+}
+
+void
+UnixSocketImpl::OnConnected()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
+
+  if (!SetSocketFlags(GetFd())) {
     NS_WARNING("Cannot set socket flags!");
     FireSocketError();
     return;
   }
 
-  if (!mConnector->SetUp(mFd)) {
+  if (!mConnector->SetUp(GetFd())) {
     NS_WARNING("Could not set up socket!");
     FireSocketError();
     return;
   }
 
   nsRefPtr<OnSocketEventTask> t =
     new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
   NS_DispatchToMainThread(t);
-  mConnectionStatus = SOCKET_CONNECTED;
+
+  AddWatchers(READ_WATCHER, true);
+  if (!mOutgoingQ.IsEmpty()) {
+    AddWatchers(WRITE_WATCHER, false);
+  }
+}
+
+void
+UnixSocketImpl::OnListening()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_LISTENING);
 
-  SetUpIO();
+  if (!mConnector->SetUpListenSocket(GetFd())) {
+    NS_WARNING("Could not set up listen socket!");
+    FireSocketError();
+    return;
+  }
+
+  AddWatchers(READ_WATCHER, true);
+}
+
+void
+UnixSocketImpl::OnError(const char* aFunction, int aErrno)
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+
+  UnixFdWatcher::OnError(aFunction, aErrno);
+  FireSocketError();
 }
 
-bool
-UnixSocketImpl::SetSocketFlags()
+void
+UnixSocketImpl::OnSocketCanReceiveWithoutBlocking()
 {
-  // Set socket addr to be reused even if kernel is still waiting to close
-  int n = 1;
-  setsockopt(mFd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
+
+  // Read all of the incoming data.
+  while (true) {
+    nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE));
+
+    ssize_t ret = read(GetFd(), incoming->mData, incoming->mSize);
+    if (ret <= 0) {
+      if (ret == -1) {
+        if (errno == EINTR) {
+          continue; // retry system call when interrupted
+        }
+        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+          return; // no data available: return and re-poll
+        }
+
+#ifdef DEBUG
+        NS_WARNING("Cannot read from network");
+#endif
+        // else fall through to error handling on other errno's
+      }
+
+      // We're done with our descriptors. Ensure that spurious events don't
+      // cause us to end up back here.
+      RemoveWatchers(READ_WATCHER|WRITE_WATCHER);
+      nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this);
+      NS_DispatchToMainThread(t);
+      return;
+    }
+
+    incoming->mSize = ret;
+    nsRefPtr<SocketReceiveTask> t =
+      new SocketReceiveTask(this, incoming.forget());
+    NS_DispatchToMainThread(t);
 
-  // Set close-on-exec bit.
-  int flags = fcntl(mFd, F_GETFD);
-  if (-1 == flags) {
-    return false;
+    // If ret is less than MAX_READ_SIZE, there's no
+    // more data in the socket for us to read now.
+    if (ret < ssize_t(MAX_READ_SIZE)) {
+      return;
+    }
   }
+}
+
+void
+UnixSocketImpl::OnSocketCanSendWithoutBlocking()
+{
+  MOZ_ASSERT(MessageLoopForIO::current() == GetIOLoop());
+  MOZ_ASSERT(GetConnectionStatus() == SOCKET_IS_CONNECTED);
 
-  flags |= FD_CLOEXEC;
-  if (-1 == fcntl(mFd, F_SETFD, flags)) {
-    return false;
+  // Try to write the bytes of mCurrentRilRawData.  If all were written, continue.
+  //
+  // Otherwise, save the byte position of the next byte to write
+  // within mCurrentWriteOffset, and request another write when the
+  // system won't block.
+  //
+  while (true) {
+    UnixSocketRawData* data;
+    if (mOutgoingQ.IsEmpty()) {
+      return;
+    }
+    data = mOutgoingQ.ElementAt(0);
+    const uint8_t *toWrite;
+    toWrite = data->mData;
+
+    while (data->mCurrentWriteOffset < data->mSize) {
+      ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
+      ssize_t written;
+      written = write (GetFd(), toWrite + data->mCurrentWriteOffset,
+                         write_amount);
+      if (written > 0) {
+        data->mCurrentWriteOffset += written;
+      }
+      if (written != write_amount) {
+        break;
+      }
+    }
+
+    if (data->mCurrentWriteOffset != data->mSize) {
+      AddWatchers(WRITE_WATCHER, false);
+      return;
+    }
+    mOutgoingQ.RemoveElementAt(0);
+    delete data;
   }
-
-  return true;
 }
 
 UnixSocketConsumer::UnixSocketConsumer() : mImpl(nullptr)
                                          , mConnectionStatus(SOCKET_DISCONNECTED)
                                          , mConnectTimestamp(0)
                                          , mConnectDelayMs(0)
 {
 }
@@ -733,176 +761,16 @@ UnixSocketConsumer::CloseSocket()
                                    new ShutdownSocketTask(mImpl));
 
   mImpl = nullptr;
 
   NotifyDisconnect();
 }
 
 void
-UnixSocketImpl::OnFileCanReadWithoutBlocking(int aFd)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(!mShuttingDownOnIOThread);
-
-  if (mConnectionStatus == SOCKET_CONNECTED) {
-    // Read all of the incoming data.
-    while (true) {
-      nsAutoPtr<UnixSocketRawData> incoming(new UnixSocketRawData(MAX_READ_SIZE));
-
-      ssize_t ret = read(aFd, incoming->mData, incoming->mSize);
-      if (ret <= 0) {
-        if (ret == -1) {
-          if (errno == EINTR) {
-            continue; // retry system call when interrupted
-          }
-          if (errno == EAGAIN || errno == EWOULDBLOCK) {
-            return; // no data available: return and re-poll
-          }
-
-#ifdef DEBUG
-          NS_WARNING("Cannot read from network");
-#endif
-          // else fall through to error handling on other errno's
-        }
-
-        // We're done with our descriptors. Ensure that spurious events don't
-        // cause us to end up back here.
-        mReadWatcher.StopWatchingFileDescriptor();
-        mWriteWatcher.StopWatchingFileDescriptor();
-        nsRefPtr<RequestClosingSocketTask> t = new RequestClosingSocketTask(this);
-        NS_DispatchToMainThread(t);
-        return;
-      }
-
-      incoming->mSize = ret;
-      nsRefPtr<SocketReceiveTask> t =
-        new SocketReceiveTask(this, incoming.forget());
-      NS_DispatchToMainThread(t);
-
-      // If ret is less than MAX_READ_SIZE, there's no
-      // more data in the socket for us to read now.
-      if (ret < ssize_t(MAX_READ_SIZE)) {
-        return;
-      }
-    }
-
-    MOZ_CRASH("We returned early");
-  } else if (mConnectionStatus == SOCKET_LISTENING) {
-    int client_fd = accept(mFd.get(), (struct sockaddr*)&mAddr, &mAddrSize);
-
-    if (client_fd < 0) {
-      return;
-    }
-
-    if (!mConnector->SetUp(client_fd)) {
-      NS_WARNING("Could not set up socket!");
-      return;
-    }
-
-    mReadWatcher.StopWatchingFileDescriptor();
-    mWriteWatcher.StopWatchingFileDescriptor();
-
-    mFd.reset(client_fd);
-    if (!SetSocketFlags()) {
-      return;
-    }
-
-    mIOLoop = nullptr;
-
-    nsRefPtr<OnSocketEventTask> t =
-      new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
-    NS_DispatchToMainThread(t);
-    mConnectionStatus = SOCKET_CONNECTED;
-
-    SetUpIO();
-  }
-}
-
-void
-UnixSocketImpl::OnFileCanWriteWithoutBlocking(int aFd)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-  MOZ_ASSERT(!mShuttingDownOnIOThread);
-
-  MOZ_ASSERT(aFd >= 0);
-  if (mConnectionStatus == SOCKET_CONNECTED) {
-    // Try to write the bytes of mCurrentRilRawData.  If all were written, continue.
-    //
-    // Otherwise, save the byte position of the next byte to write
-    // within mCurrentWriteOffset, and request another write when the
-    // system won't block.
-    //
-    while (true) {
-      UnixSocketRawData* data;
-      if (mOutgoingQ.IsEmpty()) {
-        return;
-      }
-      data = mOutgoingQ.ElementAt(0);
-      const uint8_t *toWrite;
-      toWrite = data->mData;
-
-      while (data->mCurrentWriteOffset < data->mSize) {
-        ssize_t write_amount = data->mSize - data->mCurrentWriteOffset;
-        ssize_t written;
-        written = write (aFd, toWrite + data->mCurrentWriteOffset,
-                         write_amount);
-        if (written > 0) {
-          data->mCurrentWriteOffset += written;
-        }
-        if (written != write_amount) {
-          break;
-        }
-      }
-
-      if (data->mCurrentWriteOffset != data->mSize) {
-        MessageLoopForIO::current()->WatchFileDescriptor(
-          aFd,
-          false,
-          MessageLoopForIO::WATCH_WRITE,
-          &mWriteWatcher,
-          this);
-        return;
-      }
-      mOutgoingQ.RemoveElementAt(0);
-      delete data;
-    }
-  } else if (mConnectionStatus == SOCKET_CONNECTING) {
-    int error, ret;
-    socklen_t len = sizeof(error);
-    ret = getsockopt(mFd.get(), SOL_SOCKET, SO_ERROR, &error, &len);
-
-    if (ret || error) {
-      NS_WARNING("getsockopt failure on async socket connect!");
-      FireSocketError();
-      return;
-    }
-
-    if (!SetSocketFlags()) {
-      NS_WARNING("Cannot set socket flags!");
-      FireSocketError();
-      return;
-    }
-
-    if (!mConnector->SetUp(mFd)) {
-      NS_WARNING("Could not set up socket!");
-      FireSocketError();
-      return;
-    }
-
-    nsRefPtr<OnSocketEventTask> t =
-      new OnSocketEventTask(this, OnSocketEventTask::CONNECT_SUCCESS);
-    NS_DispatchToMainThread(t);
-    mConnectionStatus = SOCKET_CONNECTED;
-
-    SetUpIO();
-  }
-}
-
-void
 UnixSocketConsumer::GetSocketAddr(nsAString& aAddrStr)
 {
   aAddrStr.Truncate();
   if (!mImpl || mConnectionStatus != SOCKET_CONNECTED) {
     NS_WARNING("No socket currently open!");
     return;
   }
   mImpl->GetSocketAddr(aAddrStr);
@@ -946,18 +814,18 @@ UnixSocketConsumer::ConnectSocket(UnixSo
   nsAutoPtr<UnixSocketConnector> connector(aConnector);
 
   if (mImpl) {
     NS_WARNING("Socket already connecting/connected!");
     return false;
   }
 
   nsCString addr(aAddress);
-  mImpl = new UnixSocketImpl(this, connector.forget(), addr, SOCKET_CONNECTING);
   MessageLoop* ioLoop = XRE_GetIOMessageLoop();
+  mImpl = new UnixSocketImpl(ioLoop, this, connector.forget(), addr);
   mConnectionStatus = SOCKET_CONNECTING;
   if (aDelayMs > 0) {
     SocketDelayedConnectTask* connectTask = new SocketDelayedConnectTask(mImpl);
     mImpl->SetDelayedConnectTask(connectTask);
     MessageLoop::current()->PostDelayedTask(FROM_HERE, connectTask, aDelayMs);
   } else {
     ioLoop->PostTask(FROM_HERE, new SocketConnectTask(mImpl));
   }
@@ -972,21 +840,21 @@ UnixSocketConsumer::ListenSocket(UnixSoc
 
   nsAutoPtr<UnixSocketConnector> connector(aConnector);
 
   if (mImpl) {
     NS_WARNING("Socket already connecting/connected!");
     return false;
   }
 
-  mImpl = new UnixSocketImpl(this, connector.forget(), EmptyCString(),
-                             SOCKET_LISTENING);
+  mImpl = new UnixSocketImpl(XRE_GetIOMessageLoop(), this, connector.forget(),
+                             EmptyCString());
   mConnectionStatus = SOCKET_LISTENING;
   XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
-                                   new SocketAcceptTask(mImpl));
+                                   new SocketListenTask(mImpl));
   return true;
 }
 
 uint32_t
 UnixSocketConsumer::CalculateConnectDelayMs() const
 {
   MOZ_ASSERT(NS_IsMainThread());
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5102,17 +5102,17 @@ nsRuleNode::ComputeDisplayData(void* aSt
                         "animIterationCount.num computed incorrectly");
       NS_ABORT_IF_FALSE(!canStoreInRuleTree,
                         "should have made canStoreInRuleTree false above");
       animation->SetIterationCount(parentDisplay->mAnimations[i].GetIterationCount());
     } else if (animIterationCount.unit == eCSSUnit_Initial ||
                animIterationCount.unit == eCSSUnit_Unset) {
       animation->SetIterationCount(1.0f);
     } else if (animIterationCount.list) {
-      switch(animIterationCount.list->mValue.GetUnit()) {
+      switch (animIterationCount.list->mValue.GetUnit()) {
         case eCSSUnit_Enumerated:
           NS_ABORT_IF_FALSE(animIterationCount.list->mValue.GetIntValue() ==
                               NS_STYLE_ANIMATION_ITERATION_COUNT_INFINITE,
                             "unexpected value");
           animation->SetIterationCount(NS_IEEEPositiveInfinity());
           break;
         case eCSSUnit_Number:
           animation->SetIterationCount(
@@ -8368,17 +8368,17 @@ nsRuleNode::ComputeSVGResetData(void* aS
     case eCSSUnit_Inherit:
       canStoreInRuleTree = false;
       svgReset->mFilters = parentSVGReset->mFilters;
       break;
     case eCSSUnit_List:
     case eCSSUnit_ListDep: {
       svgReset->mFilters.Clear();
       const nsCSSValueList* cur = filterValue->GetListValue();
-      while(cur) {
+      while (cur) {
         nsStyleFilter styleFilter;
         if (!SetStyleFilterToCSSValue(&styleFilter, cur->mValue, aContext,
                                       mPresContext, canStoreInRuleTree)) {
           svgReset->mFilters.Clear();
           break;
         }
         NS_ABORT_IF_FALSE(styleFilter.GetType() != NS_STYLE_FILTER_NONE,
                           "filter should be set");
--- a/services/common/Makefile.in
+++ b/services/common/Makefile.in
@@ -1,14 +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/.
 
 modules := \
-  hawk.js \
+  hawkclient.js \
+  hawkrequest.js \
   storageservice.js \
   stringbundle.js \
   tokenserverclient.js \
   utils.js \
   $(NULL)
 
 pp_modules := \
   async.js \
rename from services/common/hawk.js
rename to services/common/hawkclient.js
--- a/services/common/hawk.js
+++ b/services/common/hawkclient.js
@@ -26,17 +26,17 @@
 
 this.EXPORTED_SYMBOLS = ["HawkClient"];
 
 const {interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
-Cu.import("resource://services-common/rest.js");
+Cu.import("resource://services-common/hawkrequest.js");
 Cu.import("resource://gre/modules/Promise.jsm");
 
 /*
  * A general purpose client for making HAWK authenticated requests to a single
  * host.  Keeps track of the clock offset between the client and the host for
  * computation of the timestamp in the HAWK Authorization header.
  *
  * Clients should create one HawkClient object per each server they wish to
@@ -60,22 +60,28 @@ this.HawkClient.prototype = {
    *
    * @param restResponse
    *        A RESTResponse object from a RESTRequest
    *
    * @param errorString
    *        A string describing the error
    */
   _constructError: function(restResponse, errorString) {
-    return {
+    let errorObj = {
       error: errorString,
       message: restResponse.statusText,
       code: restResponse.status,
       errno: restResponse.status
     };
+    let retryAfter = restResponse.headers["retry-after"];
+    retryAfter = retryAfter ? parseInt(retryAfter) : retryAfter;
+    if (retryAfter) {
+      errorObj.retryAfter = retryAfter;
+    }
+    return errorObj;
   },
 
   /*
    *
    * Update clock offset by determining difference from date gives in the (RFC
    * 1123) Date header of a server response.  Because HAWK tolerates a window
    * of one minute of clock skew (so two minutes total since the skew can be
    * positive or negative), the simple method of calculating offset here is
new file mode 100644
--- /dev/null
+++ b/services/common/hawkrequest.js
@@ -0,0 +1,145 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+this.EXPORTED_SYMBOLS = [
+  "HAWKAuthenticatedRESTRequest",
+];
+
+Cu.import("resource://gre/modules/Preferences.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-common/rest.js");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CryptoUtils",
+                                  "resource://services-crypto/utils.js");
+
+const Prefs = new Preferences("services.common.rest.");
+
+/**
+ * Single-use HAWK-authenticated HTTP requests to RESTish resources.
+ *
+ * @param uri
+ *        (String) URI for the RESTRequest constructor
+ *
+ * @param credentials
+ *        (Object) Optional credentials for computing HAWK authentication
+ *        header.
+ *
+ * @param payloadObj
+ *        (Object) Optional object to be converted to JSON payload
+ *
+ * @param extra
+ *        (Object) Optional extra params for HAWK header computation.
+ *        Valid properties are:
+ *
+ *          now:                 <current time in milliseconds>,
+ *          localtimeOffsetMsec: <local clock offset vs server>
+ *
+ * extra.localtimeOffsetMsec is the value in milliseconds that must be added to
+ * the local clock to make it agree with the server's clock.  For instance, if
+ * the local clock is two minutes ahead of the server, the time offset in
+ * milliseconds will be -120000.
+ */
+
+this.HAWKAuthenticatedRESTRequest =
+ function HawkAuthenticatedRESTRequest(uri, credentials, extra={}) {
+  RESTRequest.call(this, uri);
+
+  this.credentials = credentials;
+  this.now = extra.now || Date.now();
+  this.localtimeOffsetMsec = extra.localtimeOffsetMsec || 0;
+  this._log.trace("local time, offset: " + this.now + ", " + (this.localtimeOffsetMsec));
+
+  // Expose for testing
+  this._intl = getIntl();
+};
+HAWKAuthenticatedRESTRequest.prototype = {
+  __proto__: RESTRequest.prototype,
+
+  dispatch: function dispatch(method, data, onComplete, onProgress) {
+    let contentType = "text/plain";
+    if (method == "POST" || method == "PUT") {
+      contentType = "application/json";
+    }
+    if (this.credentials) {
+      let options = {
+        now: this.now,
+        localtimeOffsetMsec: this.localtimeOffsetMsec,
+        credentials: this.credentials,
+        payload: data && JSON.stringify(data) || "",
+        contentType: contentType,
+      };
+      let header = CryptoUtils.computeHAWK(this.uri, method, options);
+      this.setHeader("Authorization", header.field);
+      this._log.trace("hawk auth header: " + header.field);
+    }
+
+    this.setHeader("Content-Type", contentType);
+
+    this.setHeader("Accept-Language", this._intl.accept_languages);
+
+    return RESTRequest.prototype.dispatch.call(
+      this, method, data, onComplete, onProgress
+    );
+  }
+};
+
+// With hawk request, we send the user's accepted-languages with each request.
+// To keep the number of times we read this pref at a minimum, maintain the
+// preference in a stateful object that notices and updates itself when the
+// pref is changed.
+this.Intl = function Intl() {
+  // We won't actually query the pref until the first time we need it
+  this._accepted = "";
+  this._everRead = false;
+  this._log = Log.repository.getLogger("Services.common.RESTRequest");
+  this._log.level = Log.Level[Prefs.get("log.logger.rest.request")];
+  this.init();
+};
+
+this.Intl.prototype = {
+  init: function() {
+    Services.prefs.addObserver("intl.accept_languages", this, false);
+  },
+
+  uninit: function() {
+    Services.prefs.removeObserver("intl.accept_languages", this);
+  },
+
+  observe: function(subject, topic, data) {
+    this.readPref();
+  },
+
+  readPref: function() {
+    this._everRead = true;
+    try {
+      this._accepted = Services.prefs.getComplexValue(
+        "intl.accept_languages", Ci.nsIPrefLocalizedString).data;
+    } catch (err) {
+      this._log.error("Error reading intl.accept_languages pref: " + CommonUtils.exceptionStr(err));
+    }
+  },
+
+  get accept_languages() {
+    if (!this._everRead) {
+      this.readPref();
+    }
+    return this._accepted;
+  },
+};
+
+// Singleton getter for Intl, creating an instance only when we first need it.
+let intl = null;
+function getIntl() {
+  if (!intl) {
+    intl = new Intl();
+  }
+  return intl;
+}
+
--- a/services/common/rest.js
+++ b/services/common/rest.js
@@ -5,17 +5,16 @@
 #ifndef MERGED_COMPARTMENT
 
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 this.EXPORTED_SYMBOLS = [
   "RESTRequest",
   "RESTResponse",
   "TokenAuthenticatedRESTRequest",
-  "HAWKAuthenticatedRESTRequest",
 ];
 
 #endif
 
 Cu.import("resource://gre/modules/Preferences.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
@@ -720,80 +719,8 @@ TokenAuthenticatedRESTRequest.prototype 
     this.setHeader("Authorization", sig.getHeader());
 
     return RESTRequest.prototype.dispatch.call(
       this, method, data, onComplete, onProgress
     );
   },
 };
 
-/**
- * Single-use HAWK-authenticated HTTP requests to RESTish resources.
- *
- * @param uri
- *        (String) URI for the RESTRequest constructor
- *
- * @param credentials
- *        (Object) Optional credentials for computing HAWK authentication
- *        header.
- *
- * @param payloadObj
- *        (Object) Optional object to be converted to JSON payload
- *
- * @param extra
- *        (Object) Optional extra params for HAWK header computation.
- *        Valid properties are:
- *
- *          now:                 <current time in milliseconds>,
- *          localtimeOffsetMsec: <local clock offset vs server>
- *
- * extra.localtimeOffsetMsec is the value in milliseconds that must be added to
- * the local clock to make it agree with the server's clock.  For instance, if
- * the local clock is two minutes ahead of the server, the time offset in
- * milliseconds will be -120000.
- */
-this.HAWKAuthenticatedRESTRequest =
- function HawkAuthenticatedRESTRequest(uri, credentials, extra={}) {
-  RESTRequest.call(this, uri);
-
-  this.credentials = credentials;
-  this.now = extra.now || Date.now();
-  this.localtimeOffsetMsec = extra.localtimeOffsetMsec || 0;
-  this._log.trace("local time, offset: " + this.now + ", " + (this.localtimeOffsetMsec));
-};
-HAWKAuthenticatedRESTRequest.prototype = {
-  __proto__: RESTRequest.prototype,
-
-  dispatch: function dispatch(method, data, onComplete, onProgress) {
-    let contentType = "text/plain";
-    if (method == "POST" || method == "PUT") {
-      contentType = "application/json";
-    }
-    if (this.credentials) {
-      let options = {
-        now: this.now,
-        localtimeOffsetMsec: this.localtimeOffsetMsec,
-        credentials: this.credentials,
-        payload: data && JSON.stringify(data) || "",
-        contentType: contentType,
-      };
-      let header = CryptoUtils.computeHAWK(this.uri, method, options);
-      this.setHeader("Authorization", header.field);
-      this._log.trace("hawk auth header: " + header.field);
-    }
-
-    this.setHeader("Content-Type", contentType);
-
-    try {
-      let acceptLanguage = Services.prefs.getComplexValue(
-          "intl.accept_languages", Ci.nsIPrefLocalizedString).data;
-      if (acceptLanguage) {
-        this.setHeader("Accept-Language", acceptLanguage);
-      }
-    } catch (err) {
-      this._log.error("Error reading intl.accept_languages pref: " + CommonUtils.exceptionStr(err));
-    }
-
-    return RESTRequest.prototype.dispatch.call(
-      this, method, data, onComplete, onProgress
-    );
-  }
-};
rename from services/common/tests/unit/test_hawk.js
rename to services/common/tests/unit/test_hawkclient.js
--- a/services/common/tests/unit/test_hawk.js
+++ b/services/common/tests/unit/test_hawkclient.js
@@ -1,15 +1,15 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 Cu.import("resource://gre/modules/Promise.jsm");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 
 const SECOND_MS = 1000;
 const MINUTE_MS = SECOND_MS * 60;
 const HOUR_MS = MINUTE_MS * 60;
 
 const TEST_CREDS = {
   id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
   key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
new file mode 100644
--- /dev/null
+++ b/services/common/tests/unit/test_hawkrequest.js
@@ -0,0 +1,203 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+Cu.import("resource://gre/modules/Log.jsm");
+Cu.import("resource://services-common/utils.js");
+Cu.import("resource://services-common/hawkrequest.js");
+
+function do_register_cleanup() {
+  Services.prefs.resetUserPrefs();
+
+  // remove the pref change listener
+  let hawk = new HAWKAuthenticatedRESTRequest("https://example.com");
+  hawk._intl.uninit();
+}
+
+function run_test() {
+  Log.repository.getLogger("Services.Common.RESTRequest").level =
+    Log.Level.Trace;
+  initTestLogging("Trace");
+
+  run_next_test();
+}
+
+
+add_test(function test_intl_accept_language() {
+  let testCount = 0;
+  let languages = [
+    "zu-NP;vo",     // Nepalese dialect of Zulu, defaulting to Volap√ľk
+    "fa-CG;ik",     // Congolese dialect of Farsei, defaulting to Inupiaq
+  ];
+
+  function setLanguage(lang) {
+    let acceptLanguage = Cc["@mozilla.org/supports-string;1"]
+                           .createInstance(Ci.nsISupportsString);
+    acceptLanguage.data = lang;
+    Services.prefs.setComplexValue(
+      "intl.accept_languages", Ci.nsISupportsString, acceptLanguage);
+  }
+
+  let hawk = new HAWKAuthenticatedRESTRequest("https://example.com");
+
+  Services.prefs.addObserver("intl.accept_languages", nextTest, false);
+  setLanguage(languages[testCount]);
+
+  function nextTest() {
+    CommonUtils.nextTick(function() {
+      if (testCount < 2) {
+        do_check_eq(hawk._intl.accept_languages, languages[testCount]);
+
+        testCount += 1;
+        setLanguage(languages[testCount]);
+        nextTest();
+        return;
+      }
+      Services.prefs.removeObserver("intl.accept_languages", nextTest);
+      run_next_test();
+      return;
+    });
+  }
+});
+
+add_test(function test_hawk_authenticated_request() {
+  let onProgressCalled = false;
+  let postData = {your: "data"};
+
+  // An arbitrary date - Feb 2, 1971.  It ends in a bunch of zeroes to make our
+  // computation with the hawk timestamp easier, since hawk throws away the
+  // millisecond values.
+  let then = 34329600000;
+
+  let clockSkew = 120000;
+  let timeOffset = -1 * clockSkew;
+  let localTime = then + clockSkew;
+
+  // Set the accept-languages pref to the Nepalese dialect of Zulu.
+  let acceptLanguage = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
+  acceptLanguage.data = 'zu-NP'; // omit trailing ';', which our HTTP libs snip
+  Services.prefs.setComplexValue('intl.accept_languages', Ci.nsISupportsString, acceptLanguage);
+
+  let credentials = {
+    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
+    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
+    algorithm: "sha256"
+  };
+
+  let server = httpd_setup({
+    "/elysium": function(request, response) {
+      do_check_true(request.hasHeader("Authorization"));
+
+      // check that the header timestamp is our arbitrary system date, not
+      // today's date.  Note that hawk header timestamps are in seconds, not
+      // milliseconds.
+      let authorization = request.getHeader("Authorization");
+      let tsMS = parseInt(/ts="(\d+)"/.exec(authorization)[1], 10) * 1000;
+      do_check_eq(tsMS, then);
+
+      // This testing can be a little wonky. In an environment where
+      //   pref("intl.accept_languages") === 'en-US, en'
+      // the header is sent as:
+      //   'en-US,en;q=0.5'
+      // hence our fake value for acceptLanguage.
+      let lang = request.getHeader("Accept-Language");
+      do_check_eq(lang, acceptLanguage);
+
+      let message = "yay";
+      response.setStatusLine(request.httpVersion, 200, "OK");
+      response.bodyOutputStream.write(message, message.length);
+    }
+  });
+
+  function onProgress() {
+    onProgressCalled = true;
+  }
+
+  function onComplete(error) {
+    do_check_eq(200, this.response.status);
+    do_check_eq(this.response.body, "yay");
+    do_check_true(onProgressCalled);
+
+    Services.prefs.resetUserPrefs();
+    let pref = Services.prefs.getComplexValue(
+      "intl.accept_languages", Ci.nsIPrefLocalizedString);
+    do_check_neq(acceptLanguage.data, pref.data);
+
+    server.stop(run_next_test);
+  }
+
+  let url = server.baseURI + "/elysium";
+  let extra = {
+    now: localTime,
+    localtimeOffsetMsec: timeOffset
+  };
+
+  let request = new HAWKAuthenticatedRESTRequest(url, credentials, extra);
+
+  // Allow hawk._intl to respond to the language pref change
+  CommonUtils.nextTick(function() {
+    request.post(postData, onComplete, onProgress);
+  });
+});
+
+add_test(function test_hawk_language_pref_changed() {
+  let languages = [
+    "zu-NP",        // Nepalese dialect of Zulu
+    "fa-CG",        // Congolese dialect of Farsi
+  ];
+
+  let credentials = {
+    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
+    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
+    algorithm: "sha256",
+  };
+
+  function setLanguage(lang) {
+    let acceptLanguage = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
+    acceptLanguage.data = lang;
+    Services.prefs.setComplexValue("intl.accept_languages", Ci.nsISupportsString, acceptLanguage);
+  }
+
+  let server = httpd_setup({
+    "/foo": function(request, response) {
+      do_check_eq(languages[1], request.getHeader("Accept-Language"));
+
+      response.setStatusLine(request.httpVersion, 200, "OK");
+    },
+  });
+
+  let url = server.baseURI + "/foo";
+  let postData = {};
+  let request;
+
+  setLanguage(languages[0]);
+
+  // A new request should create the stateful object for tracking the current
+  // language.
+  request = new HAWKAuthenticatedRESTRequest(url, credentials);
+  CommonUtils.nextTick(testFirstLanguage);
+
+  function testFirstLanguage() {
+    do_check_eq(languages[0], request._intl.accept_languages);
+
+    // Change the language pref ...
+    setLanguage(languages[1]); 
+    CommonUtils.nextTick(testRequest);
+  }
+
+  function testRequest() {
+    // Change of language pref should be picked up, which we can see on the
+    // server by inspecting the request headers.
+    request = new HAWKAuthenticatedRESTRequest(url, credentials);
+    request.post({}, function(error) {
+      do_check_null(error);
+      do_check_eq(200, this.response.status);
+
+      Services.prefs.resetUserPrefs();
+
+      server.stop(run_next_test);
+    });
+  }
+});
+
--- a/services/common/tests/unit/test_restrequest.js
+++ b/services/common/tests/unit/test_restrequest.js
@@ -1,18 +1,18 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
+"use strict";
+
 Cu.import("resource://gre/modules/NetUtil.jsm");
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://services-common/rest.js");
 Cu.import("resource://services-common/utils.js");
 
-//DEBUG = true;
-
 function run_test() {
   Log.repository.getLogger("Services.Common.RESTRequest").level =
     Log.Level.Trace;
   initTestLogging("Trace");
 
   run_next_test();
 }
 
@@ -833,84 +833,8 @@ add_test(function test_not_sending_cooki
   res.get(function (error) {
     do_check_null(error);
     do_check_true(this.response.success);
     do_check_eq("COOKIE!", this.response.body);
     server.stop(run_next_test);
   });
 });
 
-add_test(function test_hawk_authenticated_request() {
-  do_test_pending();
-
-  let onProgressCalled = false;
-  let postData = {your: "data"};
-
-  // An arbitrary date - Feb 2, 1971.  It ends in a bunch of zeroes to make our
-  // computation with the hawk timestamp easier, since hawk throws away the
-  // millisecond values.
-  let then = 34329600000;
-
-  let clockSkew = 120000;
-  let timeOffset = -1 * clockSkew;
-  let localTime = then + clockSkew;
-
-  // Set the accept-languages pref to the Nepalese dialect of Zulu.
-  let acceptLanguage = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
-  acceptLanguage.data = 'zu-NP'; // omit trailing ';', which our HTTP libs snip
-  Services.prefs.setComplexValue('intl.accept_languages', Ci.nsISupportsString, acceptLanguage);
-
-  let credentials = {
-    id: "eyJleHBpcmVzIjogMTM2NTAxMDg5OC4x",
-    key: "qTZf4ZFpAMpMoeSsX3zVRjiqmNs=",
-    algorithm: "sha256"
-  };
-
-  let server = httpd_setup({
-    "/elysium": function(request, response) {
-      do_check_true(request.hasHeader("Authorization"));
-
-      // check that the header timestamp is our arbitrary system date, not
-      // today's date.  Note that hawk header timestamps are in seconds, not
-      // milliseconds.
-      let authorization = request.getHeader("Authorization");
-      let tsMS = parseInt(/ts="(\d+)"/.exec(authorization)[1], 10) * 1000;
-      do_check_eq(tsMS, then);
-
-      // This testing can be a little wonky. In an environment where
-      //   pref("intl.accept_languages") === 'en-US, en'
-      // the header is sent as:
-      //   'en-US,en;q=0.5'
-      // hence our fake value for acceptLanguage.
-      let lang = request.getHeader('Accept-Language');
-      do_check_eq(lang, acceptLanguage);
-
-      let message = "yay";
-      response.setStatusLine(request.httpVersion, 200, "OK");
-      response.bodyOutputStream.write(message, message.length);
-    }
-  });
-
-  function onProgress() {
-    onProgressCalled = true;
-  }
-
-  function onComplete(error) {
-    do_check_eq(200, this.response.status);
-    do_check_eq(this.response.body, "yay");
-    do_check_true(onProgressCalled);
-    do_test_finished();
-    server.stop(run_next_test);
-  }
-
-  let url = server.baseURI + "/elysium";
-  let extra = {
-    now: localTime,
-    localtimeOffsetMsec: timeOffset
-  };
-  let request = new HAWKAuthenticatedRESTRequest(url, credentials, extra);
-  request.post(postData, onComplete, onProgress);
-
-  Services.prefs.resetUserPrefs();
-  let pref = Services.prefs.getComplexValue('intl.accept_languages',
-                                            Ci.nsIPrefLocalizedString);
-  do_check_neq(acceptLanguage.data, pref.data);
-});
--- a/services/common/tests/unit/xpcshell.ini
+++ b/services/common/tests/unit/xpcshell.ini
@@ -20,17 +20,18 @@ firefox-appdir = browser
 [test_utils_stackTrace.js]
 [test_utils_utf8.js]
 [test_utils_uuid.js]
 
 [test_async_chain.js]
 [test_async_querySpinningly.js]
 [test_bagheera_server.js]
 [test_bagheera_client.js]
-[test_hawk.js]
+[test_hawkclient.js]
+[test_hawkrequest.js]
 [test_observers.js]
 [test_restrequest.js]
 [test_tokenauthenticatedrequest.js]
 
 # Storage service APIs
 [test_storageservice_bso.js]
 [test_storageservice_client.js]
 # Bug 969624: Intermittent fail on Android 2.3 emulator
--- a/services/fxaccounts/FxAccountsClient.jsm
+++ b/services/fxaccounts/FxAccountsClient.jsm
@@ -5,33 +5,37 @@
 this.EXPORTED_SYMBOLS = ["FxAccountsClient"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 Cu.import("resource://gre/modules/Log.jsm");
 Cu.import("resource://gre/modules/Promise.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://services-common/utils.js");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 Cu.import("resource://gre/modules/Credentials.jsm");
 
 let _host = "https://api.accounts.firefox.com/v1"
 try {
   _host = Services.prefs.getCharPref("identity.fxaccounts.auth.uri");
 } catch(keepDefault) {}
 
 const HOST = _host;
 this.FxAccountsClient = function(host = HOST) {
   this.host = host;
 
   // The FxA auth server expects requests to certain endpoints to be authorized
   // using Hawk.
   this.hawk = new HawkClient(host);
+
+  // Manage server backoff state. C.f.
+  // https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#backoff-protocol
+  this.backoffError = null;
 };
 
 this.FxAccountsClient.prototype = {
 
   /**
    * Return client clock offset, in milliseconds, as determined by hawk client.
    * Provided because callers should not have to know about hawk
    * implementation.
@@ -301,16 +305,20 @@ this.FxAccountsClient.prototype = {
     return {
       algorithm: "sha256",
       key: out.slice(32, 64),
       extra: out.slice(64),
       id: CommonUtils.bytesAsHex(out.slice(0, 32))
     };
   },
 
+  _clearBackoff: function() {
+      this.backoffError = null;
+  },
+
   /**
    * A general method for sending raw API calls to the FxA auth server.
    * All request bodies and responses are JSON.
    *
    * @param path
    *        API endpoint path
    * @param method
    *        The HTTP request method
@@ -327,29 +335,47 @@ this.FxAccountsClient.prototype = {
    *          "error": "Bad Request", // string description of the error type
    *          "message": "the value of salt is not allowed to be undefined",
    *          "info": "https://docs.dev.lcip.og/errors/1234" // link to more info on the error
    *        }
    */
   _request: function hawkRequest(path, method, credentials, jsonPayload) {
     let deferred = Promise.defer();
 
+    // We were asked to back off.
+    if (this.backoffError) {
+      log.debug("Received new request during backoff, re-rejecting.");
+      deferred.reject(this.backoffError);
+      return deferred.promise;
+    }
+
     this.hawk.request(path, method, credentials, jsonPayload).then(
       (responseText) => {
         try {
           let response = JSON.parse(responseText);
           deferred.resolve(response);
         } catch (err) {
           log.error("json parse error on response: " + responseText);
           deferred.reject({error: err});
         }
       },
 
       (error) => {
         log.error("error " + method + "ing " + path + ": " + JSON.stringify(error));
+        if (error.retryAfter) {
+          log.debug("Received backoff response; caching error as flag.");
+          this.backoffError = error;
+          // Schedule clearing of cached-error-as-flag.
+          CommonUtils.namedTimer(
+            this._clearBackoff,
+            error.retryAfter * 1000,
+            this,
+            "fxaBackoffTimer"
+           );
+	}
         deferred.reject(error);
       }
     );
 
     return deferred.promise;
   },
 };
 
--- a/services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
+++ b/services/fxaccounts/tests/mochitest/test_invalidEmailCase.html
@@ -24,17 +24,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript;version=1.8">
 
 SimpleTest.waitForExplicitFinish();
 
 Components.utils.import("resource://gre/modules/Promise.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/FxAccounts.jsm");
 Components.utils.import("resource://gre/modules/FxAccountsClient.jsm");
-Components.utils.import("resource://services-common/hawk.js");
+Components.utils.import("resource://services-common/hawkclient.js");
 
 const TEST_SERVER =
   "http://mochi.test:8888/chrome/services/fxaccounts/tests/mochitest/file_invalidEmailCase.sjs?path=";
 
 let MockStorage = function() {
   this.data = null;
 };
 MockStorage.prototype = Object.freeze({
--- a/services/fxaccounts/tests/xpcshell/test_client.js
+++ b/services/fxaccounts/tests/xpcshell/test_client.js
@@ -97,16 +97,63 @@ add_task(function test_500_error() {
   } catch (e) {
     do_check_eq(500, e.code);
     do_check_eq("Internal Server Error", e.message);
   }
 
   yield deferredStop(server);
 });
 
+add_task(function test_backoffError() {
+  let method = "GET";
+  let server = httpd_setup({
+    "/retryDelay": function(request, response) {
+      response.setHeader("Retry-After", "30");
+      response.setStatusLine(request.httpVersion, 429, "Client has sent too many requests");
+      let message = "<h1>Ooops!</h1>";
+      response.bodyOutputStream.write(message, message.length);
+    },
+    "/duringDelayIShouldNotBeCalled": function(request, response) {
+      response.setStatusLine(request.httpVersion, 200, "OK");
+      let jsonMessage = "{\"working\": \"yes\"}";
+      response.bodyOutputStream.write(jsonMessage, jsonMessage.length);
+    },
+  });
+
+  let client = new FxAccountsClient(server.baseURI);
+
+  // Retry-After header sets client.backoffError
+  do_check_eq(client.backoffError, null);
+  try {
+    yield client._request("/retryDelay", method);
+  } catch (e) {
+    do_check_eq(429, e.code);
+    do_check_eq(30, e.retryAfter);
+    do_check_neq(typeof(client.fxaBackoffTimer), "undefined");
+    do_check_neq(client.backoffError, null);
+  }
+  // While delay is in effect, client short-circuits any requests
+  // and re-rejects with previous error.
+  try {
+    yield client._request("/duringDelayIShouldNotBeCalled", method);
+    throw new Error("I should not be reached");
+  } catch (e) {
+    do_check_eq(e.retryAfter, 30);
+    do_check_eq(e.message, "Client has sent too many requests");
+    do_check_neq(client.backoffError, null);
+  }
+  // Once timer fires, client nulls error out and HTTP calls work again.
+  client._clearBackoff();
+  let result = yield client._request("/duringDelayIShouldNotBeCalled", method);
+  do_check_eq(client.backoffError, null);
+  do_check_eq(result.working, "yes");
+
+  yield deferredStop(server);
+});
+
 add_task(function test_signUp() {
   let creationMessage = JSON.stringify({
     uid: "uid",
     sessionToken: "sessionToken",
     keyFetchToken: "keyFetchToken"
   });
   let errorMessage = JSON.stringify({code: 400, errno: 101, error: "account exists"});
   let created = false;
--- a/services/sync/tests/unit/test_browserid_identity.js
+++ b/services/sync/tests/unit/test_browserid_identity.js
@@ -3,17 +3,17 @@
 
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://services-sync/browserid_identity.js");
 Cu.import("resource://services-sync/rest.js");
 Cu.import("resource://services-sync/util.js");
 Cu.import("resource://services-common/utils.js");
 Cu.import("resource://services-crypto/utils.js");
 Cu.import("resource://testing-common/services/sync/utils.js");
-Cu.import("resource://services-common/hawk.js");
+Cu.import("resource://services-common/hawkclient.js");
 Cu.import("resource://gre/modules/FxAccounts.jsm");
 Cu.import("resource://gre/modules/FxAccountsClient.jsm");
 Cu.import("resource://gre/modules/FxAccountsCommon.js");
 
 const SECOND_MS = 1000;
 const MINUTE_MS = SECOND_MS * 60;
 const HOUR_MS = MINUTE_MS * 60;
 
--- a/testing/mozbase/mozlog/mozlog/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/__init__.py
@@ -4,21 +4,21 @@
 
 """
 Mozlog aims to standardize log formatting within Mozilla.
 
 It simply wraps Python's logging_ module and adds a few convenience methods
 for logging test results and events.
 
 The structured submodule takes a different approach and implements a
-JSON-based logging protocol designed for recording test results.
-"""
+JSON-based logging protocol designed for recording test results."""
 
 from logger import *
 from loglistener import LogMessageServer
 from loggingmixin import LoggingMixin
 
 try:
     import structured
 except ImportError:
     # Structured logging doesn't work on python 2.6 which is still used on some
     # legacy test machines; https://bugzilla.mozilla.org/show_bug.cgi?id=864866
     pass
+
--- a/testing/mozbase/mozlog/mozlog/structured/commandline.py
+++ b/testing/mozbase/mozlog/mozlog/structured/commandline.py
@@ -10,16 +10,17 @@ import handlers
 import formatters
 
 log_formatters = {
     'raw': (formatters.JSONFormatter, "Raw structured log messages"),
     'unittest': (formatters.UnittestFormatter, "Unittest style output"),
     'xunit': (formatters.XUnitFormatter, "xUnit compatible XML"),
     'html': (formatters.HTMLFormatter, "HTML report"),
     'mach': (formatters.MachFormatter, "Uncolored mach-like output"),
+    'mach_terminal': (formatters.MachTerminalFormatter, "Colored mach-like output for use in a tty"),
 }
 
 
 def log_file(name):
     if name == "-":
         return sys.stdout
     else:
         return open(name, "w")
@@ -37,44 +38,45 @@ def add_logging_group(parser):
                    options added.
     """
     group = parser.add_argument_group("Output Logging",
                                       description="Options for logging output.\n"
                                       "Each option represents a possible logging format "
                                       "and takes a filename to write that format to, "
                                       "or '-' to write to stdout.")
     for name, (cls, help_str) in log_formatters.iteritems():
-        group.add_argument("--log-" + name, type=log_file,
+        group.add_argument("--log-" + name, action="append", type=log_file,
                            help=help_str)
 
 
 def setup_logging(suite, args, defaults):
     """
     Configure a structuredlogger based on command line arguments.
 
     :param suite: The name of the testsuite being run
-    :param args: The Namespace object produced by argparse from parsing
-                 command line arguments from a parser with logging arguments.
+    :param args: A dictionary of {argument_name:value} produced from
+                 parsing the command line arguments for the application
     :param defaults: A dictionary of {formatter name: output stream} to apply
                      when there is no logging supplied on the command line.
 
     :rtype: StructuredLogger
     """
     logger = StructuredLogger(suite)
     prefix = "log_"
     found = False
     found_stdout_logger = False
-    for name, value in args.iteritems():
-        if name.startswith(prefix) and value is not None:
-            found = True
-            if value == sys.stdout:
-                found_stdout_logger = True
-            formatter_cls = log_formatters[name[len(prefix):]][0]
-            logger.add_handler(handlers.StreamHandler(stream=value,
-                                                      formatter=formatter_cls()))
+    for name, values in args.iteritems():
+        if name.startswith(prefix) and values is not None:
+            for value in values:
+                found = True
+                if value == sys.stdout:
+                    found_stdout_logger = True
+                formatter_cls = log_formatters[name[len(prefix):]][0]
+                logger.add_handler(handlers.StreamHandler(stream=value,
+                                                          formatter=formatter_cls()))
 
     #If there is no user-specified logging, go with the default options
     if not found:
         for name, value in defaults.iteritems():
             formatter_cls = log_formatters[name][0]
             logger.add_handler(handlers.StreamHandler(stream=value,
                                                       formatter=formatter_cls()))
 
--- a/testing/mozbase/mozlog/mozlog/structured/formatters/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/structured/formatters/__init__.py
@@ -3,9 +3,10 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 import json
 from unittest import UnittestFormatter
 from xunit import XUnitFormatter
 from html import HTMLFormatter
 from machformatter import MachFormatter, MachTerminalFormatter
 
-JSONFormatter = lambda: json.dumps
+def JSONFormatter():
+    return lambda x: json.dumps(x) + "\n"
--- a/testing/mozbase/mozlog/mozlog/structured/formatters/html/html.py
+++ b/testing/mozbase/mozlog/mozlog/structured/formatters/html/html.py
@@ -1,14 +1,15 @@
 #!/usr/bin/env 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/.
 
 import sys
+import json
 import datetime
 import os
 
 from .. import base
 
 from collections import defaultdict
 
 html = None
--- a/testing/mozbase/mozlog/mozlog/structured/formatters/machformatter.py
+++ b/testing/mozbase/mozlog/mozlog/structured/formatters/machformatter.py
@@ -24,17 +24,17 @@ class BaseMachFormatter(base.BaseFormatt
         self.last_time = None
 
     def __call__(self, data):
         s = base.BaseFormatter.__call__(self, data)
         if s is not None:
             return "%s %s\n" % (self.generic_formatter(data), s)
 
     def _get_test_id(self, data):
-        test_id = data["test"]
+        test_id = data.get("test")
         if isinstance(test_id, list):
             test_id = tuple(test_id)
         return test_id
 
     def generic_formatter(self, data):
         return "%s: %s" % (data["action"].upper(), data["thread"])
 
     def suite_start(self, data):
@@ -57,22 +57,23 @@ class BaseMachFormatter(base.BaseFormatt
 
         return "Harness status %s%s. Subtests passed %i/%i. Unexpected %i" % (
             data["status"], expected_str, subtests["pass"],
             subtests["count"], unexpected)
 
     def test_status(self, data):
         test = self._get_test_id(data)
         if test not in self.status_buffer:
-            self.buffer[test] = {"count": 0, "unexpected": 0, "pass": 0}
-        self.buffer[test]["count"] += 1
+            self.status_buffer[test] = {"count": 0, "unexpected": 0, "pass": 0}
+        self.status_buffer[test]["count"] += 1
+
         if "expected" in data:
-            self.buffer[test]["unexpected"] += 1
+            self.status_buffer[test]["unexpected"] += 1
         if data["status"] == "PASS":
-            self.buffer[test]["pass"] += 1
+            self.status_buffer[test]["pass"] += 1
 
     def process_output(self, data):
         return '"%s" (pid:%s command:%s)' % (data["data"],
                                              data["process"],
                                              data["command"])
 
     def log(self, data):
         return "%s %s" % (data["level"], data["message"])
@@ -127,19 +128,19 @@ class MachTerminalFormatter(BaseMachForm
         BaseMachFormatter.__init__(self,
                                    start_time=start_time,
                                    write_interval=write_interval,
                                    write_times=write_times)
 
     def __call__(self, data):
         s = BaseMachFormatter.__call__(self, data)
         if s is not None:
-            t = self.terminal.blue(format_seconds(self._time(entry)))
+            t = self.terminal.blue(format_seconds(self._time(data)))
 
-            return '%s %s' % (t, self._colorize(entry, s))
+            return '%s %s' % (t, self._colorize(data, s))
 
     def _colorize(self, data, s):
         if self.terminal is None:
             return s
 
         subtests = self._get_subtest_data(data)
 
         color = None
@@ -150,15 +151,17 @@ class MachTerminalFormatter(BaseMachForm
                 color = self.terminal.green
             else:
                 color = self.terminal.red
         elif data["action"] in ("suite_start", "suite_end", "test_start"):
             color = self.terminal.yellow
 
         if color is not None:
             result = color(s[:len_action]) + s[len_action:]
+        else:
+            result = s
 
         return result
 
 if __name__ == "__main__":
     base.format_file(sys.stdin,
                      handlers.StreamHandler(stream=sys.stdout,
                                             formatter=MachFormatter()))
--- a/testing/mozbase/mozlog/mozlog/structured/handlers/__init__.py
+++ b/testing/mozbase/mozlog/mozlog/structured/handlers/__init__.py
@@ -1,14 +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/.
 
 from threading import Lock
 
+from ..structuredlog import log_levels
+
 
 class BaseHandler(object):
     def __init__(self, formatter=str):
         self.formatter = formatter
         self.filters = []
 
     def add_filter(self, filter_func):
         self.filters.append(filter_func)
--- a/testing/mozbase/mozlog/mozlog/structured/structuredlog.py
+++ b/testing/mozbase/mozlog/mozlog/structured/structuredlog.py
@@ -99,22 +99,25 @@ class StructuredLogger(object):
         all_data = {"action": action,
                     "time": int(time.time() * 1000),
                     "thread": current_thread().name,
                     "pid": current_process().pid,
                     "source": self.name}
         all_data.update(data)
         return all_data
 
-    def suite_start(self, tests):
+    def suite_start(self, tests, run_info=None):
         """Log a suite_start message
 
         :param tests: List of test identifiers that will be run in the suite.
         """
-        self._log_data("suite_start", {"tests": tests})
+        data = {"tests": tests}
+        if run_info is not None:
+            data["run_info"] = run_info
+        self._log_data("suite_start", data)
 
     def suite_end(self):
         """Log a suite_end message"""
         self._log_data("suite_end")
 
     def test_start(self, test):
         """Log a test_start message
 
@@ -166,18 +169,17 @@ class StructuredLogger(object):
             data["message"] = message
         if expected != data["status"]:
             data["expected"] = expected
         if extra is not None:
             data["extra"] = extra
         self._log_data("test_end", data)
 
     def process_output(self, process, data, command=None):
-        """
-        Log output from a managed process.
+        """Log output from a managed process.
 
         :param process: A unique identifier for the process producing the output
                         (typically the pid)
         :param data: The output to log
         :param command: A string representing the full command line used to start
                         the process.
         """
         data = {"process": process, "data": data}
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -1948,17 +1948,17 @@ TransactionItemCache.prototype = {
   get siteURI()
     this._siteURI || null,
   set index(v)
     this._index = (parseInt(v) >= 0 ? v : null),
   // Index can be 0.
   get index()
     this._index != null ? this._index : PlacesUtils.bookmarks.DEFAULT_INDEX,
   set annotations(v)
-    this._annotations = Array.isArray(v) ? JSON.parse(JSON.stringify(v)) : null,
+    this._annotations = Array.isArray(v) ? Cu.cloneInto(v, {}) : null,
   get annotations()
     this._annotations || null,
   set tags(v)
     this._tags = (v && Array.isArray(v) ? Array.slice(v) : null),
   get tags()
     this._tags || null,
 };
 
--- a/toolkit/devtools/Loader.jsm
+++ b/toolkit/devtools/Loader.jsm
@@ -53,16 +53,17 @@ BuiltinProvider.prototype = {
         "source-map": SourceMap,
       },
       paths: {
         // When you add a line to this mapping, don't forget to make a
         // corresponding addition to the SrcdirProvider mapping below as well.
         "": "resource://gre/modules/commonjs/",
         "main": "resource:///modules/devtools/main.js",
         "devtools": "resource:///modules/devtools",
+        "devtools/toolkit": "resource://gre/modules/devtools",
         "devtools/server": "resource://gre/modules/devtools/server",
         "devtools/toolkit/webconsole": "resource://gre/modules/devtools/toolkit/webconsole",
         "devtools/app-actor-front": "resource://gre/modules/devtools/app-actor-front.js",
         "devtools/styleinspector/css-logic": "resource://gre/modules/devtools/styleinspector/css-logic",
         "devtools/css-color": "resource://gre/modules/devtools/css-color",
         "devtools/output-parser": "resource://gre/modules/devtools/output-parser",
         "devtools/touch-events": "resource://gre/modules/devtools/touch-events",
         "devtools/client": "resource://gre/modules/devtools/client",
@@ -101,16 +102,17 @@ SrcdirProvider.prototype = {
   load: function() {
     let srcdir = Services.prefs.getComplexValue("devtools.loader.srcdir",
                                                 Ci.nsISupportsString);
     srcdir = OS.Path.normalize(srcdir.data.trim());
     let devtoolsDir = OS.Path.join(srcdir, "browser", "devtools");
     let toolkitDir = OS.Path.join(srcdir, "toolkit", "devtools");
     let mainURI = this.fileURI(OS.Path.join(devtoolsDir, "main.js"));
     let devtoolsURI = this.fileURI(devtoolsDir);
+    let toolkitURI = this.fileURI(toolkitDir);
     let serverURI = this.fileURI(OS.Path.join(toolkitDir, "server"));
     let webconsoleURI = this.fileURI(OS.Path.join(toolkitDir, "webconsole"));
     let appActorURI = this.fileURI(OS.Path.join(toolkitDir, "apps", "app-actor-front.js"));
     let cssLogicURI = this.fileURI(OS.Path.join(toolkitDir, "styleinspector", "css-logic"));
     let cssColorURI = this.fileURI(OS.Path.join(toolkitDir, "css-color"));
     let outputParserURI = this.fileURI(OS.Path.join(toolkitDir, "output-parser"));
     let touchEventsURI = this.fileURI(OS.Path.join(toolkitDir, "touch-events"));
     let clientURI = this.fileURI(OS.Path.join(toolkitDir, "client"));
@@ -122,16 +124,17 @@ SrcdirProvider.prototype = {
       modules: {
         "toolkit/loader": loader,
         "source-map": SourceMap,
       },
       paths: {
         "": "resource://gre/modules/commonjs/",
         "main": mainURI,
         "devtools": devtoolsURI,
+        "devtools/toolkit": toolkitURI,
         "devtools/server": serverURI,
         "devtools/toolkit/webconsole": webconsoleURI,
         "devtools/app-actor-front": appActorURI,
         "devtools/styleinspector/css-logic": cssLogicURI,
         "devtools/css-color": cssColorURI,
         "devtools/output-parser": outputParserURI,
         "devtools/touch-events": touchEventsURI,
         "devtools/client": clientURI,
--- a/toolkit/devtools/apps/Devices.jsm
+++ b/toolkit/devtools/apps/Devices.jsm
@@ -1,15 +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/. */
 
 "use strict";
 
-Components.utils.import("resource:///modules/devtools/shared/event-emitter.js");
+Components.utils.import("resource://gre/modules/devtools/event-emitter.js");
 
 const EXPORTED_SYMBOLS = ["Devices"];
 
 let addonInstalled = false;
 
 const Devices = {
   _devices: {},
 
--- a/toolkit/devtools/apps/Simulator.jsm
+++ b/toolkit/devtools/apps/Simulator.jsm
@@ -1,15 +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/. */
 
 "use strict";
 
-Components.utils.import("resource:///modules/devtools/shared/event-emitter.js");
+Components.utils.import("resource://gre/modules/devtools/event-emitter.js");
 
 const EXPORTED_SYMBOLS = ["Simulator"];
 
 const Simulator = {
   _simulators: {},
 
   register: function (version, simulator) {
     this._simulators[version] = simulator;
--- a/toolkit/devtools/client/connection-manager.js
+++ b/toolkit/devtools/client/connection-manager.js
@@ -3,17 +3,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/. */
 
 "use strict";
 
 const {Cc, Ci, Cu} = require("chrome");
 const {setTimeout, clearTimeout} = require('sdk/timers');
-const EventEmitter = require("devtools/shared/event-emitter");
+const EventEmitter = require("devtools/toolkit/event-emitter");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-client.jsm");
 Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
 
 /**
  * Connection Manager.
  *
--- a/toolkit/devtools/client/dbg-client.jsm
+++ b/toolkit/devtools/client/dbg-client.jsm
@@ -474,32 +474,31 @@ DebuggerClient.prototype = {
    * @param array aListeners
    *        The console listeners you want to start.
    * @param function aOnResponse
    *        Called with the response packet and a WebConsoleClient
    *        instance (which will be undefined on error).
    */
   attachConsole:
   function (aConsoleActor, aListeners, aOnResponse) {
-    if (this._consoleClients.has(aConsoleActor)) {
-      setTimeout(() => aOnResponse({}, this._consoleClients.get(aConsoleActor)), 0);
-      return;
-    }
-
     let packet = {
       to: aConsoleActor,
       type: "startListeners",
       listeners: aListeners,
     };
 
     this.request(packet, (aResponse) => {
       let consoleClient;
       if (!aResponse.error) {
-        consoleClient = new WebConsoleClient(this, aConsoleActor);
-        this._consoleClients.set(aConsoleActor, consoleClient);
+        if (this._consoleClients.has(aConsoleActor)) {
+          consoleClient = this._consoleClients.get(aConsoleActor);
+        } else {
+          consoleClient = new WebConsoleClient(this, aConsoleActor);
+          this._consoleClients.set(aConsoleActor, consoleClient);
+        }
       }
       aOnResponse(aResponse, consoleClient);
     });
   },
 
   /**
    * Attach to a global-scoped thread actor for chrome debugging.
    *
rename from browser/devtools/shared/event-emitter.js
rename to toolkit/devtools/event-emitter.js
--- a/toolkit/devtools/server/actors/webbrowser.js
+++ b/toolkit/devtools/server/actors/webbrowser.js
@@ -1040,17 +1040,17 @@ BrowserAddonActor.prototype = {
  * is resumed before the navigation begins.
  *
  * @param BrowserTabActor aBrowserTabActor
  *        The tab actor associated with this listener.
  */
 function DebuggerProgressListener(aBrowserTabActor) {
   this._tabActor = aBrowserTabActor;
   this._tabActor._tabbrowser.addProgressListener(this);
-  let EventEmitter = devtools.require("devtools/shared/event-emitter");
+  let EventEmitter = devtools.require("devtools/toolkit/event-emitter");
   EventEmitter.decorate(this);
 }
 
 DebuggerProgressListener.prototype = {
   onStateChange:
   makeInfallible(function DPL_onStateChange(aProgress, aRequest, aFlag, aStatus) {
     let isStart = aFlag & Ci.nsIWebProgressListener.STATE_START;
     let isStop = aFlag & Ci.nsIWebProgressListener.STATE_STOP;
--- a/toolkit/devtools/tests/mochitest/chrome.ini
+++ b/toolkit/devtools/tests/mochitest/chrome.ini
@@ -1,1 +1,2 @@
+[test_eventemitter_basic.html]
 [test_loader_paths.html]
rename from browser/devtools/shared/test/browser_eventemitter_basic.js
rename to toolkit/devtools/tests/mochitest/test_eventemitter_basic.html
--- a/browser/devtools/shared/test/browser_eventemitter_basic.js
+++ b/toolkit/devtools/tests/mochitest/test_eventemitter_basic.html
@@ -1,154 +1,179 @@
-/* Any copyright is dedicated to the Public Domain.
-   http://creativecommons.org/publicdomain/zero/1.0/ */
+<!DOCTYPE html>
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
 
-"use strict";
+<html>
 
-const promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}).Promise;
-const EventEmitter = Cu.import("resource:///modules/devtools/shared/event-emitter.js", {}).EventEmitter;
+  <head>
+    <meta charset="utf8">
+    <title></title>
 
-function test() {
-  waitForExplicitFinish();
-
-  testEmitter();
-  testEmitter({});
+    <script type="application/javascript"
+            src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+    <link rel="stylesheet" type="text/css"
+          href="chrome://mochikit/content/tests/SimpleTest/test.css">
+  </head>
 
-  Task.spawn(testPromise).then(null, ok.bind(null, false)).then(finish);
-}
+  <body>
 
-function testEmitter(aObject) {
-  let emitter;
+    <script type="application/javascript;version=1.8">
+      "use strict";
 
-  if (aObject) {
-    emitter = aObject;
-    EventEmitter.decorate(emitter);
-  } else {
-    emitter = new EventEmitter();
-  }
+      const { utils: Cu } = Components;
+      const { Promise: promise } =
+        Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {});
+      const { EventEmitter } =
+        Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
+      const { Task } = Cu.import("resource://gre/modules/Task.jsm", {});
 
-  ok(emitter, "We have an event emitter");
+      SimpleTest.waitForExplicitFinish();
 
-  emitter.on("next", next);
-  emitter.emit("next", "abc", "def");
+      testEmitter();
+      testEmitter({});
+
+      Task.spawn(testPromise)
+          .then(null, ok.bind(null, false))
+          .then(SimpleTest.finish);
 
-  let beenHere1 = false;
-  function next(eventName, str1, str2) {
-    is(eventName, "next", "Got event");
-    is(str1, "abc", "Argument 1 is correct");
-    is(str2, "def", "Argument 2 is correct");
+      function testEmitter(aObject) {
+        let emitter;
 
-    ok(!beenHere1, "first time in next callback");
-    beenHere1 = true;
+        if (aObject) {
+          emitter = aObject;
+          EventEmitter.decorate(emitter);
+        } else {
+          emitter = new EventEmitter();
+        }
 
-    emitter.off("next", next);
+        ok(emitter, "We have an event emitter");
 
-    emitter.emit("next");
+        emitter.on("next", next);
+        emitter.emit("next", "abc", "def");
 
-    emitter.once("onlyonce", onlyOnce);
-
-    emitter.emit("onlyonce");
-    emitter.emit("onlyonce");
-  }
+        let beenHere1 = false;
+        function next(eventName, str1, str2) {
+          is(eventName, "next", "Got event");
+          is(str1, "abc", "Argument 1 is correct");
+          is(str2, "def", "Argument 2 is correct");
 
-  let beenHere2 = false;
-  function onlyOnce() {
-    ok(!beenHere2, "\"once\" listner has been called once");
-    beenHere2 = true;
-    emitter.emit("onlyonce");
+          ok(!beenHere1, "first time in next callback");
+          beenHere1 = true;
 
-    killItWhileEmitting();
-  }
+          emitter.off("next", next);
+
+          emitter.emit("next");
+
+          emitter.once("onlyonce", onlyOnce);
 
-  function killItWhileEmitting() {
-    function c1() {
-      ok(true, "c1 called");
-    }
-    function c2() {
-      ok(true, "c2 called");
-      emitter.off("tick", c3);
-    }
-    function c3() {
-      ok(false, "c3 should not be called");
-    }
-    function c4() {
-      ok(true, "c4 called");
-    }
+          emitter.emit("onlyonce");
+          emitter.emit("onlyonce");
+        }
+
+        let beenHere2 = false;
+        function onlyOnce() {
+          ok(!beenHere2, "\"once\" listner has been called once");
+          beenHere2 = true;
+          emitter.emit("onlyonce");
+
+          killItWhileEmitting();
+        }
 
-    emitter.on("tick", c1);
-    emitter.on("tick", c2);
-    emitter.on("tick", c3);
-    emitter.on("tick", c4);
-
-    emitter.emit("tick");
-
-    offAfterOnce();
-  }
+        function killItWhileEmitting() {
+          function c1() {
+            ok(true, "c1 called");
+          }
+          function c2() {
+            ok(true, "c2 called");
+            emitter.off("tick", c3);
+          }
+          function c3() {
+            ok(false, "c3 should not be called");
+          }
+          function c4() {
+            ok(true, "c4 called");
+          }
 
-  function offAfterOnce() {
-    let enteredC1 = false;
+          emitter.on("tick", c1);
+          emitter.on("tick", c2);
+          emitter.on("tick", c3);
+          emitter.on("tick", c4);
 
-    function c1() {
-      enteredC1 = true;
-    }
-
-    emitter.once("oao", c1);
-    emitter.off("oao", c1);
+          emitter.emit("tick");
 
-    emitter.emit("oao");
+          offAfterOnce();
+        }
 
-    ok(!enteredC1, "c1 should not be called");
-  }
-}
+        function offAfterOnce() {
+          let enteredC1 = false;
 
-function testPromise() {
-  let emitter = new EventEmitter();
-  let p = emitter.once("thing");
+          function c1() {
+            enteredC1 = true;
+          }
 
-  // Check that the promise is only resolved once event though we
-  // emit("thing") more than once
-  let firstCallbackCalled = false;
-  let check1 = p.then(arg => {
-    is(firstCallbackCalled, false, "first callback called only once");
-    firstCallbackCalled = true;
-    is(arg, "happened", "correct arg in promise");
-    return "rval from c1";
-  });
+          emitter.once("oao", c1);
+          emitter.off("oao", c1);
+
+          emitter.emit("oao");
+
+          ok(!enteredC1, "c1 should not be called");
+        }
+      }
+
+      function testPromise() {
+        let emitter = new EventEmitter();
+        let p = emitter.once("thing");
 
-  emitter.emit("thing", "happened", "ignored");
+        // Check that the promise is only resolved once event though we
+        // emit("thing") more than once
+        let firstCallbackCalled = false;
+        let check1 = p.then(arg => {
+          is(firstCallbackCalled, false, "first callback called only once");
+          firstCallbackCalled = true;
+          is(arg, "happened", "correct arg in promise");
+          return "rval from c1";
+        });
+
+        emitter.emit("thing", "happened", "ignored");
 
-  // Check that the promise is resolved asynchronously
-  let secondCallbackCalled = false;
-  let check2 = p.then(arg => {
-    ok(true, "second callback called");
-    is(arg, "happened", "correct arg in promise");
-    secondCallbackCalled = true;
-    is(arg, "happened", "correct arg in promise (a second time)");
-    return "rval from c2";
-  });
+        // Check that the promise is resolved asynchronously
+        let secondCallbackCalled = false;
+        let check2 = p.then(arg => {
+          ok(true, "second callback called");
+          is(arg, "happened", "correct arg in promise");
+          secondCallbackCalled = true;
+          is(arg, "happened", "correct arg in promise (a second time)");
+          return "rval from c2";
+        });
 
-  // Shouldn't call any of the above listeners
-  emitter.emit("thing", "trashinate");
-
-  // Check that we can still separate events with different names
-  // and that it works with no parameters
-  let pfoo = emitter.once("foo");
-  let pbar = emitter.once("bar");
+        // Shouldn't call any of the above listeners
+        emitter.emit("thing", "trashinate");
 
-  let check3 = pfoo.then(arg => {
-    ok(arg === undefined, "no arg for foo event");
-    return "rval from c3";
-  });
+        // Check that we can still separate events with different names
+        // and that it works with no parameters
+        let pfoo = emitter.once("foo");
+        let pbar = emitter.once("bar");
 
-  pbar.then(() => {
-    ok(false, "pbar should not be called");
-  });
+        let check3 = pfoo.then(arg => {
+          ok(arg === undefined, "no arg for foo event");
+          return "rval from c3";
+        });
+
+        pbar.then(() => {
+          ok(false, "pbar should not be called");
+        });
 
-  emitter.emit("foo");
+        emitter.emit("foo");
 
-  is(secondCallbackCalled, false, "second callback not called yet");
+        is(secondCallbackCalled, false, "second callback not called yet");
 
-  return promise.all([ check1, check2, check3 ]).then(args => {
-    is(args[0], "rval from c1", "callback 1 done good");
-    is(args[1], "rval from c2", "callback 2 done good");
-    is(args[2], "rval from c3", "callback 3 done good");
-  });
-}
+        return promise.all([ check1, check2, check3 ]).then(args => {
+          is(args[0], "rval from c1", "callback 1 done good");
+          is(args[1], "rval from c2", "callback 2 done good");
+          is(args[2], "rval from c3", "callback 3 done good");
+        });
+      }
+    </script>
+  </body>
+</html>
--- a/toolkit/modules/TelemetryTimestamps.jsm
+++ b/toolkit/modules/TelemetryTimestamps.jsm
@@ -1,14 +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/. */
 
 this.EXPORTED_SYMBOLS = ["TelemetryTimestamps"];
 
+const Cu = Components.utils;
+
 /**
  * This module's purpose is to collect timestamps for important
  * application-specific events.
  *
  * The TelemetryPing component attaches the timestamps stored by this module to
  * the telemetry submission, substracting the process lifetime so that the times
  * are relative to process startup. The overall goal is to produce a basic
  * timeline of the startup process.
@@ -41,12 +43,12 @@ this.TelemetryTimestamps = {
   },
 
   /**
    * Returns a JS object containing all of the timeStamps as properties (can be
    * easily serialized to JSON). Used by TelemetryPing to retrieve the data
    * to attach to the telemetry submission.
    */
   get: function TT_get() {
-    // Return a copy of the object by passing it through JSON.
-    return JSON.parse(JSON.stringify(timeStamps));
+    // Return a copy of the object.
+    return Cu.cloneInto(timeStamps, {});
   }
 };
--- a/widget/gonk/nativewindow/FakeSurfaceComposer.cpp
+++ b/widget/gonk/nativewindow/FakeSurfaceComposer.cpp
@@ -54,16 +54,22 @@ sp<IGraphicBufferAlloc> FakeSurfaceCompo
 }
 
 sp<IBinder> FakeSurfaceComposer::createDisplay(const String8& displayName,
         bool secure)
 {
     return nullptr;
 }
 
+#if ANDROID_VERSION >= 19
+void FakeSurfaceComposer::destroyDisplay(const sp<IBinder>& display)
+{
+}
+#endif
+
 sp<IBinder> FakeSurfaceComposer::getBuiltInDisplay(int32_t id) {
     return nullptr;
 }
 
 void FakeSurfaceComposer::setTransactionState(
         const Vector<ComposerState>& state,
         const Vector<DisplayState>& displays,
         uint32_t flags)
@@ -86,16 +92,25 @@ sp<IDisplayEventConnection> FakeSurfaceC
 status_t FakeSurfaceComposer::captureScreen(const sp<IBinder>& display,
         const sp<IGraphicBufferProducer>& producer,
         uint32_t reqWidth, uint32_t reqHeight,
         uint32_t minLayerZ, uint32_t maxLayerZ,
         bool isCpuConsumer) {
     return INVALID_OPERATION;
 }
 
+#if ANDROID_VERSION >= 19
+status_t FakeSurfaceComposer::captureScreen(const sp<IBinder>& display,
+    const sp<IGraphicBufferProducer>& producer,
+    uint32_t reqWidth, uint32_t reqHeight,
+    uint32_t minLayerZ, uint32_t maxLayerZ) {
+    return INVALID_OPERATION;
+}
+#endif
+
 void FakeSurfaceComposer::blank(const sp<IBinder>& display) {
 }
 
 void FakeSurfaceComposer::unblank(const sp<IBinder>& display) {
 }
 
 status_t FakeSurfaceComposer::getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) {
     return INVALID_OPERATION;
--- a/widget/gonk/nativewindow/FakeSurfaceComposer.h
+++ b/widget/gonk/nativewindow/FakeSurfaceComposer.h
@@ -40,16 +40,21 @@ class FakeSurfaceComposer : public Binde
 public:
     static char const* getServiceName() {
         return "FakeSurfaceComposer";
     }
 
     // Instantiate MediaResourceManagerService and register to service manager.
     // If service manager is not present, wait until service manager becomes present.
     static  void instantiate();
+#if ANDROID_VERSION >= 19
+    virtual void destroyDisplay(const sp<android::IBinder>& display);
+    virtual status_t captureScreen(const sp<IBinder>& display, const sp<IGraphicBufferProducer>& producer,
+            uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ, uint32_t maxLayerZ);
+#endif
 
 private:
     FakeSurfaceComposer();
     // We're reference counted, never destroy FakeSurfaceComposer directly
     virtual ~FakeSurfaceComposer();
 
     /* ------------------------------------------------------------------------
      * ISurfaceComposer interface
--- a/widget/gonk/nativewindow/GonkBufferQueue.h
+++ b/widget/gonk/nativewindow/GonkBufferQueue.h
@@ -1,662 +1,20 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- * Copyright (C) 2013 Mozilla Foundation
+/* Copyright 2013 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
+ *     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.
  */
 
-#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_H
-#define NATIVEWINDOW_GONKBUFFERQUEUE_H
-
-#include <gui/IGraphicBufferAlloc.h>
-#if ANDROID_VERSION == 17
-#include <gui/ISurfaceTexture.h>
-#else
-#include <gui/IGraphicBufferProducer.h>
-#endif
-
-#include <ui/Fence.h>
-#include <ui/GraphicBuffer.h>
-
-#include <utils/String8.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-#include "mozilla/layers/LayersSurfaces.h"
-
-#if ANDROID_VERSION == 17
-#define IGraphicBufferProducer ISurfaceTexture
-#endif
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-#if ANDROID_VERSION == 17
-class GonkBufferQueue : public BnSurfaceTexture {
-#else
-class GonkBufferQueue : public BnGraphicBufferProducer {
-#endif
-    typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
-
-public:
-    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
-    enum { NUM_BUFFER_SLOTS = 32 };
-    enum { NO_CONNECTED_API = 0 };
-    enum { INVALID_BUFFER_SLOT = -1 };
-    enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE };
-
-    // When in async mode we reserve two slots in order to guarantee that the
-    // producer and consumer can run asynchronously.
-    enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 };
-
-    // ConsumerListener is the interface through which the GonkBufferQueue notifies
-    // the consumer of events that the consumer may wish to react to.  Because
-    // the consumer will generally have a mutex that is locked during calls from
-    // the consumer to the GonkBufferQueue, these calls from the GonkBufferQueue to the
-    // consumer *MUST* be called only when the GonkBufferQueue mutex is NOT locked.
-    struct ConsumerListener : public virtual RefBase {
-        // onFrameAvailable is called from queueBuffer each time an additional
-        // frame becomes available for consumption. This means that frames that
-        // are queued while in asynchronous mode only trigger the callback if no
-        // previous frames are pending. Frames queued while in synchronous mode
-        // always trigger the callback.
-        //
-        // This is called without any lock held and can be called concurrently
-        // by multiple threads.
-        virtual void onFrameAvailable() = 0;
-
-        // onBuffersReleased is called to notify the buffer consumer that the
-        // GonkBufferQueue has released its references to one or more GraphicBuffers
-        // contained in its slots.  The buffer consumer should then call
-        // GonkBufferQueue::getReleasedBuffers to retrieve the list of buffers
-        //
-        // This is called without any lock held and can be called concurrently
-        // by multiple threads.
-        virtual void onBuffersReleased() = 0;
-    };
-
-    // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak
-    // reference to the actual consumer object.  It forwards all calls to that
-    // consumer object so long as it exists.
-    //
-    // This class exists to avoid having a circular reference between the
-    // GonkBufferQueue object and the consumer object.  The reason this can't be a weak
-    // reference in the GonkBufferQueue class is because we're planning to expose the
-    // consumer side of a GonkBufferQueue as a binder interface, which doesn't support
-    // weak references.
-    class ProxyConsumerListener : public GonkBufferQueue::ConsumerListener {
-    public:
-
-        ProxyConsumerListener(const wp<GonkBufferQueue::ConsumerListener>& consumerListener);
-        virtual ~ProxyConsumerListener();
-        virtual void onFrameAvailable();
-        virtual void onBuffersReleased();
-
-    private:
-
-        // mConsumerListener is a weak reference to the ConsumerListener.  This is
-        // the raison d'etre of ProxyConsumerListener.
-        wp<GonkBufferQueue::ConsumerListener> mConsumerListener;
-    };
-
-
-    // GonkBufferQueue manages a pool of gralloc memory slots to be used by
-    // producers and consumers. allowSynchronousMode specifies whether or not
-    // synchronous mode can be enabled by the producer. allocator is used to
-    // allocate all the needed gralloc buffers.
-    GonkBufferQueue(bool allowSynchronousMode = true,
-            const sp<IGraphicBufferAlloc>& allocator = NULL);
-    virtual ~GonkBufferQueue();
-
-    // Query native window attributes.  The "what" values are enumerated in
-    // window.h (e.g. NATIVE_WINDOW_FORMAT).
-    virtual int query(int what, int* value);
-
-    // setBufferCount updates the number of available buffer slots.  If this
-    // method succeeds, buffer slots will be both unallocated and owned by
-    // the GonkBufferQueue object (i.e. they are not owned by the producer or
-    // consumer).
-    //
-    // This will fail if the producer has dequeued any buffers, or if
-    // bufferCount is invalid.  bufferCount must generally be a value
-    // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS
-    // (inclusive).  It may also be set to zero (the default) to indicate
-    // that the producer does not wish to set a value.  The minimum value
-    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-    // ...).
-    //
-    // This may only be called by the producer.  The consumer will be told
-    // to discard buffers through the onBuffersReleased callback.
-    virtual status_t setBufferCount(int bufferCount);
-
-    // requestBuffer returns the GraphicBuffer for slot N.
-    //
-    // In normal operation, this is called the first time slot N is returned
-    // by dequeueBuffer.  It must be called again if dequeueBuffer returns
-    // flags indicating that previously-returned buffers are no longer valid.
-    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
-
-    // dequeueBuffer gets the next buffer slot index for the producer to use.
-    // If a buffer slot is available then that slot index is written to the
-    // location pointed to by the buf argument and a status of OK is returned.
-    // If no slot is available then a status of -EBUSY is returned and buf is
-    // unmodified.
-    //
-    // The fence parameter will be updated to hold the fence associated with
-    // the buffer. The contents of the buffer must not be overwritten until the
-    // fence signals. If the fence is Fence::NO_FENCE, the buffer may be
-    // written immediately.
-    //
-    // The width and height parameters must be no greater than the minimum of
-    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
-    // An error due to invalid dimensions might not be reported until
-    // updateTexImage() is called.  If width and height are both zero, the
-    // default values specified by setDefaultBufferSize() are used instead.
-    //
-    // The pixel formats are enumerated in graphics.h, e.g.
-    // HAL_PIXEL_FORMAT_RGBA_8888.  If the format is 0, the default format
-    // will be used.
-    //
-    // The usage argument specifies gralloc buffer usage flags.  The values
-    // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER.  These
-    // will be merged with the usage flags specified by setConsumerUsageBits.
-    //
-    // The return value may be a negative error value or a non-negative
-    // collection of flags.  If the flags are set, the return values are
-    // valid, but additional actions must be performed.
-    //
-    // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the
-    // producer must discard cached GraphicBuffer references for the slot
-    // returned in buf.
-    // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer
-    // must discard cached GraphicBuffer references for all slots.
-    //
-    // In both cases, the producer will need to call requestBuffer to get a
-    // GraphicBuffer handle for the returned slot.
-#if ANDROID_VERSION == 17
-    virtual status_t dequeueBuffer(int *buf, sp<Fence>& fence,
-            uint32_t width, uint32_t height, uint32_t format, uint32_t usage) {
-        return dequeueBuffer(buf, &fence, width, height, format, usage);
-    }
-#endif
-
-    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence,
-            uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
-
-    // queueBuffer returns a filled buffer to the GonkBufferQueue.
-    //
-    // Additional data is provided in the QueueBufferInput struct.  Notably,
-    // a timestamp must be provided for the buffer. The timestamp is in
-    // nanoseconds, and must be monotonically increasing. Its other semantics
-    // (zero point, etc) are producer-specific and should be documented by the
-    // producer.
-    //
-    // The caller may provide a fence that signals when all rendering
-    // operations have completed.  Alternatively, NO_FENCE may be used,
-    // indicating that the buffer is ready immediately.
-    //
-    // Some values are returned in the output struct: the current settings
-    // for default width and height, the current transform hint, and the
-    // number of queued buffers.
-    virtual status_t queueBuffer(int buf,
-            const QueueBufferInput& input, QueueBufferOutput* output);
-
-    // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't
-    // queue it for use by the consumer.
-    //
-    // The buffer will not be overwritten until the fence signals.  The fence
-    // will usually be the one obtained from dequeueBuffer.
-#if ANDROID_VERSION == 17
-    virtual void cancelBuffer(int buf, sp<Fence> fence);
-#else
-    virtual void cancelBuffer(int buf, const sp<Fence>& fence);
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19
+# include "GonkBufferQueueKK.h"
+#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
+# include "GonkBufferQueueJB.h"
 #endif
-
-    // setSynchronousMode sets whether dequeueBuffer is synchronous or
-    // asynchronous. In synchronous mode, dequeueBuffer blocks until
-    // a buffer is available, the currently bound buffer can be dequeued and
-    // queued buffers will be acquired in order.  In asynchronous mode,
-    // a queued buffer may be replaced by a subsequently queued buffer.
-    //
-    // The default mode is asynchronous.
-    virtual status_t setSynchronousMode(bool enabled);
-
-    // connect attempts to connect a producer API to the GonkBufferQueue.  This
-    // must be called before any other IGraphicBufferProducer methods are
-    // called except for getAllocator.  A consumer must already be connected.
-    //
-    // This method will fail if connect was previously called on the
-    // GonkBufferQueue and no corresponding disconnect call was made (i.e. if
-    // it's still connected to a producer).
-    //
-    // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
-    virtual status_t connect(int api, QueueBufferOutput* output);
-
-    // disconnect attempts to disconnect a producer API from the GonkBufferQueue.
-    // Calling this method will cause any subsequent calls to other
-    // IGraphicBufferProducer methods to fail except for getAllocator and connect.
-    // Successfully calling connect after this will allow the other methods to
-    // succeed again.
-    //
-    // This method will fail if the the GonkBufferQueue is not currently
-    // connected to the specified producer API.
-    virtual status_t disconnect(int api);
-
-    // dump our state in a String
-    virtual void dump(String8& result) const;
-    virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
-
-    // public facing structure for BufferSlot
-    struct BufferItem {
-
-        BufferItem()
-         :
-           mSurfaceDescriptor(SurfaceDescriptor()),
-           mTransform(0),
-           mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
-           mTimestamp(0),
-           mFrameNumber(0),
-           mBuf(INVALID_BUFFER_SLOT) {
-             mCrop.makeInvalid();
-        }
-        // mGraphicBuffer points to the buffer allocated for this slot, or is NULL
-        // if the buffer in this slot has been acquired in the past (see
-        // BufferSlot.mAcquireCalled).
-        sp<GraphicBuffer> mGraphicBuffer;
-
-        // mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
-        SurfaceDescriptor mSurfaceDescriptor;
-
-        // mCrop is the current crop rectangle for this buffer slot.
-        Rect mCrop;
-
-        // mTransform is the current transform flags for this buffer slot.
-        uint32_t mTransform;
-
-        // mScalingMode is the current scaling mode for this buffer slot.
-        uint32_t mScalingMode;
-
-        // mTimestamp is the current timestamp for this buffer slot. This gets
-        // to set by queueBuffer each time this slot is queued.
-        int64_t mTimestamp;
-
-        // mFrameNumber is the number of the queued frame for this slot.
-        uint64_t mFrameNumber;
-
-        // mBuf is the slot index of this buffer
-        int mBuf;
-
-        // mFence is a fence that will signal when the buffer is idle.
-        sp<Fence> mFence;
-    };
-
-    // The following public functions are the consumer-facing interface
-
-    // acquireBuffer attempts to acquire ownership of the next pending buffer in
-    // the GonkBufferQueue.  If no buffer is pending then it returns -EINVAL.  If a
-    // buffer is successfully acquired, the information about the buffer is
-    // returned in BufferItem.  If the buffer returned had previously been
-    // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
-    // NULL and it is assumed that the consumer still holds a reference to the
-    // buffer.
-    status_t acquireBuffer(BufferItem *buffer);
-
-    // releaseBuffer releases a buffer slot from the consumer back to the
-    // GonkBufferQueue.  This may be done while the buffer's contents are still
-    // being accessed.  The fence will signal when the buffer is no longer
-    // in use.
-    //
-    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
-    // any references to the just-released buffer that it might have, as if it
-    // had received a onBuffersReleased() call with a mask set for the released
-    // buffer.
-    //
-    // Note that the dependencies on EGL will be removed once we switch to using
-    // the Android HW Sync HAL.
-    status_t releaseBuffer(int buf, const sp<Fence>& releaseFence);
-
-    // consumerConnect connects a consumer to the GonkBufferQueue.  Only one
-    // consumer may be connected, and when that consumer disconnects the
-    // GonkBufferQueue is placed into the "abandoned" state, causing most
-    // interactions with the GonkBufferQueue by the producer to fail.
-    //
-    // consumer may not be NULL.
-    status_t consumerConnect(const sp<ConsumerListener>& consumer);
-
-    // consumerDisconnect disconnects a consumer from the GonkBufferQueue. All
-    // buffers will be freed and the GonkBufferQueue is placed in the "abandoned"
-    // state, causing most interactions with the GonkBufferQueue by the producer to
-    // fail.
-    status_t consumerDisconnect();
-
-    // getReleasedBuffers sets the value pointed to by slotMask to a bit mask
-    // indicating which buffer slots have been released by the GonkBufferQueue
-    // but have not yet been released by the consumer.
-    //
-    // This should be called from the onBuffersReleased() callback.
-    status_t getReleasedBuffers(uint32_t* slotMask);
-
-    // setDefaultBufferSize is used to set the size of buffers returned by
-    // dequeueBuffer when a width and height of zero is requested.  Default
-    // is 1x1.
-    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
-
-    // setDefaultMaxBufferCount sets the default value for the maximum buffer
-    // count (the initial default is 2). If the producer has requested a
-    // buffer count using setBufferCount, the default buffer count will only
-    // take effect if the producer sets the count back to zero.
-    //
-    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
-    status_t setDefaultMaxBufferCount(int bufferCount);
-
-    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
-    // be acquired by the consumer at one time (default 1).  This call will
-    // fail if a producer is connected to the GonkBufferQueue.
-    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
-
-    // isSynchronousMode returns whether the GonkBufferQueue is currently in
-    // synchronous mode.
-    bool isSynchronousMode() const;
-
-    // setConsumerName sets the name used in logging
-    void setConsumerName(const String8& name);
-
-    // setDefaultBufferFormat allows the GonkBufferQueue to create
-    // GraphicBuffers of a defaultFormat if no format is specified
-    // in dequeueBuffer.  Formats are enumerated in graphics.h; the
-    // initial default is HAL_PIXEL_FORMAT_RGBA_8888.
-    status_t setDefaultBufferFormat(uint32_t defaultFormat);
-
-    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
-    // These are merged with the bits passed to dequeueBuffer.  The values are
-    // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
-    status_t setConsumerUsageBits(uint32_t usage);
-
-    // setTransformHint bakes in rotation to buffers so overlays can be used.
-    // The values are enumerated in window.h, e.g.
-    // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
-    status_t setTransformHint(uint32_t hint);
-
-    int getGeneration();
-
-    SurfaceDescriptor *getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
-
-private:
-    // releaseBufferFreeListUnlocked releases the resources in the freeList;
-    // this must be called with mMutex unlocked.
-    void releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>& freeList);
-
-    // freeBufferLocked frees the GraphicBuffer and sync resources for the
-    // given slot.
-    //void freeBufferLocked(int index);
-
-    // freeAllBuffersLocked frees the GraphicBuffer and sync resources for
-    // all slots.
-    //void freeAllBuffersLocked();
-    void freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList);
-
-    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
-    // that will be used if the producer does not override the buffer slot
-    // count.  The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
-    // The initial default is 2.
-    status_t setDefaultMaxBufferCountLocked(int count);
-
-    // getMinBufferCountLocked returns the minimum number of buffers allowed
-    // given the current GonkBufferQueue state.
-    int getMinMaxBufferCountLocked() const;
-
-    // getMinUndequeuedBufferCountLocked returns the minimum number of buffers
-    // that must remain in a state other than DEQUEUED.
-    int getMinUndequeuedBufferCountLocked() const;
-
-    // getMaxBufferCountLocked returns the maximum number of buffers that can
-    // be allocated at once.  This value depends upon the following member
-    // variables:
-    //
-    //      mSynchronousMode
-    //      mMaxAcquiredBufferCount
-    //      mDefaultMaxBufferCount
-    //      mOverrideMaxBufferCount
-    //
-    // Any time one of these member variables is changed while a producer is
-    // connected, mDequeueCondition must be broadcast.
-    int getMaxBufferCountLocked() const;
-
-    struct BufferSlot {
-
-        BufferSlot()
-        : mSurfaceDescriptor(SurfaceDescriptor()),
-          mBufferState(BufferSlot::FREE),
-          mRequestBufferCalled(false),
-          mTransform(0),
-          mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
-          mTimestamp(0),
-          mFrameNumber(0),
-          mAcquireCalled(false),
-          mNeedsCleanupOnRelease(false) {
-            mCrop.makeInvalid();
-        }
-
-        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
-        // if no buffer has been allocated.
-        sp<GraphicBuffer> mGraphicBuffer;
-
-        // mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
-        SurfaceDescriptor mSurfaceDescriptor;
-
-        // BufferState represents the different states in which a buffer slot
-        // can be.  All slots are initially FREE.
-        enum BufferState {
-            // FREE indicates that the buffer is available to be dequeued
-            // by the producer.  The buffer may be in use by the consumer for
-            // a finite time, so the buffer must not be modified until the
-            // associated fence is signaled.
-            //
-            // The slot is "owned" by GonkBufferQueue.  It transitions to DEQUEUED
-            // when dequeueBuffer is called.
-            FREE = 0,
-
-            // DEQUEUED indicates that the buffer has been dequeued by the
-            // producer, but has not yet been queued or canceled.  The
-            // producer may modify the buffer's contents as soon as the
-            // associated ready fence is signaled.
-            //
-            // The slot is "owned" by the producer.  It can transition to
-            // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
-            DEQUEUED = 1,
-
-            // QUEUED indicates that the buffer has been filled by the
-            // producer and queued for use by the consumer.  The buffer
-            // contents may continue to be modified for a finite time, so
-            // the contents must not be accessed until the associated fence
-            // is signaled.
-            //
-            // The slot is "owned" by GonkBufferQueue.  It can transition to
-            // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
-            // queued in asynchronous mode).
-            QUEUED = 2,
-
-            // ACQUIRED indicates that the buffer has been acquired by the
-            // consumer.  As with QUEUED, the contents must not be accessed
-            // by the consumer until the fence is signaled.
-            //
-            // The slot is "owned" by the consumer.  It transitions to FREE
-            // when releaseBuffer is called.
-            ACQUIRED = 3
-        };
-
-        // mBufferState is the current state of this buffer slot.
-        BufferState mBufferState;
-
-        // mRequestBufferCalled is used for validating that the producer did
-        // call requestBuffer() when told to do so. Technically this is not
-        // needed but useful for debugging and catching producer bugs.
-        bool mRequestBufferCalled;
-
-        // mCrop is the current crop rectangle for this buffer slot.
-        Rect mCrop;
-
-        // mTransform is the current transform flags for this buffer slot.
-        // (example: NATIVE_WINDOW_TRANSFORM_ROT_90)
-        uint32_t mTransform;
-
-        // mScalingMode is the current scaling mode for this buffer slot.
-        // (example: NATIVE_WINDOW_SCALING_MODE_FREEZE)
-        uint32_t mScalingMode;
-
-        // mTimestamp is the current timestamp for this buffer slot. This gets
-        // to set by queueBuffer each time this slot is queued.
-        int64_t mTimestamp;
-
-        // mFrameNumber is the number of the queued frame for this slot.  This
-        // is used to dequeue buffers in LRU order (useful because buffers
-        // may be released before their release fence is signaled).
-        uint64_t mFrameNumber;
-
-        // mEglFence is the EGL sync object that must signal before the buffer
-        // associated with this buffer slot may be dequeued. It is initialized
-        // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a
-        // new sync object in releaseBuffer.  (This is deprecated in favor of
-        // mFence, below.)
-        //EGLSyncKHR mEglFence;
-
-        // mFence is a fence which will signal when work initiated by the
-        // previous owner of the buffer is finished. When the buffer is FREE,
-        // the fence indicates when the consumer has finished reading
-        // from the buffer, or when the producer has finished writing if it
-        // called cancelBuffer after queueing some writes. When the buffer is
-        // QUEUED, it indicates when the producer has finished filling the
-        // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been
-        // passed to the consumer or producer along with ownership of the
-        // buffer, and mFence is set to NO_FENCE.
-        sp<Fence> mFence;
-
-        // Indicates whether this buffer has been seen by a consumer yet
-        bool mAcquireCalled;
-
-        // Indicates whether this buffer needs to be cleaned up by the
-        // consumer.  This is set when a buffer in ACQUIRED state is freed.
-        // It causes releaseBuffer to return STALE_BUFFER_SLOT.
-        bool mNeedsCleanupOnRelease;
-    };
-
-    // mSlots is the array of buffer slots that must be mirrored on the
-    // producer side. This allows buffer ownership to be transferred between
-    // the producer and consumer without sending a GraphicBuffer over binder.
-    // The entire array is initialized to NULL at construction time, and
-    // buffers are allocated for a slot when requestBuffer is called with
-    // that slot's index.
-    BufferSlot mSlots[NUM_BUFFER_SLOTS];
-
-    // mDefaultWidth holds the default width of allocated buffers. It is used
-    // in dequeueBuffer() if a width and height of zero is specified.
-    uint32_t mDefaultWidth;
-
-    // mDefaultHeight holds the default height of allocated buffers. It is used
-    // in dequeueBuffer() if a width and height of zero is specified.
-    uint32_t mDefaultHeight;
-
-    // mMaxAcquiredBufferCount is the number of buffers that the consumer may
-    // acquire at one time.  It defaults to 1 and can be changed by the
-    // consumer via the setMaxAcquiredBufferCount method, but this may only be
-    // done when no producer is connected to the GonkBufferQueue.
-    //
-    // This value is used to derive the value returned for the
-    // MIN_UNDEQUEUED_BUFFERS query by the producer.
-    int mMaxAcquiredBufferCount;
-
-    // mDefaultMaxBufferCount is the default limit on the number of buffers
-    // that will be allocated at one time.  This default limit is set by the
-    // consumer.  The limit (as opposed to the default limit) may be
-    // overridden by the producer.
-    int mDefaultMaxBufferCount;
-
-    // mOverrideMaxBufferCount is the limit on the number of buffers that will
-    // be allocated at one time. This value is set by the image producer by
-    // calling setBufferCount. The default is zero, which means the producer
-    // doesn't care about the number of buffers in the pool. In that case
-    // mDefaultMaxBufferCount is used as the limit.
-    int mOverrideMaxBufferCount;
-
-    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
-    // allocate new GraphicBuffer objects.
-    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
-
-    // mConsumerListener is used to notify the connected consumer of
-    // asynchronous events that it may wish to react to.  It is initially set
-    // to NULL and is written by consumerConnect and consumerDisconnect.
-    sp<ConsumerListener> mConsumerListener;
-
-    // mSynchronousMode whether we're in synchronous mode or not
-    bool mSynchronousMode;
-
-    // mAllowSynchronousMode whether we allow synchronous mode or not.  Set
-    // when the GonkBufferQueue is created (by the consumer).
-    const bool mAllowSynchronousMode;
-
-    // mConnectedApi indicates the producer API that is currently connected
-    // to this GonkBufferQueue.  It defaults to NO_CONNECTED_API (= 0), and gets
-    // updated by the connect and disconnect methods.
-    int mConnectedApi;
-
-    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
-    mutable Condition mDequeueCondition;
-
-    // mQueue is a FIFO of queued buffers used in synchronous mode
-    typedef Vector<int> Fifo;
-    Fifo mQueue;
-
-    // mAbandoned indicates that the GonkBufferQueue will no longer be used to
-    // consume image buffers pushed to it using the IGraphicBufferProducer
-    // interface.  It is initialized to false, and set to true in the
-    // consumerDisconnect method.  A GonkBufferQueue that has been abandoned will
-    // return the NO_INIT error from all IGraphicBufferProducer methods
-    // capable of returning an error.
-    bool mAbandoned;
-
-    // mConsumerName is a string used to identify the GonkBufferQueue in log
-    // messages.  It is set by the setConsumerName method.
-    String8 mConsumerName;
-
-    // mMutex is the mutex used to prevent concurrent access to the member
-    // variables of GonkBufferQueue objects. It must be locked whenever the
-    // member variables are accessed.
-    mutable Mutex mMutex;
-
-    // mFrameCounter is the free running counter, incremented on every
-    // successful queueBuffer call.
-    uint64_t mFrameCounter;
-
-    // mBufferHasBeenQueued is true once a buffer has been queued.  It is
-    // reset when something causes all buffers to be freed (e.g. changing the
-    // buffer count).
-    bool mBufferHasBeenQueued;
-
-    // mDefaultBufferFormat can be set so it will override
-    // the buffer format when it isn't specified in dequeueBuffer
-    uint32_t mDefaultBufferFormat;
-
-    // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers
-    uint32_t mConsumerUsageBits;
-
-    // mTransformHint is used to optimize for screen rotations
-    uint32_t mTransformHint;
-
-    // mGeneration is the current generation of buffer slots
-    uint32_t mGeneration;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_GUI_BUFFERQUEUE_H
rename from widget/gonk/nativewindow/GonkBufferQueue.cpp
rename to widget/gonk/nativewindow/GonkBufferQueueJB.cpp
--- a/widget/gonk/nativewindow/GonkBufferQueue.cpp
+++ b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp
@@ -21,17 +21,17 @@
 
 #define GL_GLEXT_PROTOTYPES
 #define EGL_EGLEXT_PROTOTYPES
 
 #include <utils/Log.h>
 
 #include "mozilla/layers/ImageBridgeChild.h"
 
-#include "GonkBufferQueue.h"
+#include "GonkBufferQueueJB.h"
 
 // Macros for including the GonkBufferQueue name in log messages
 #define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
 #define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
 #define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
 #define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
 #define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
 
copy from widget/gonk/nativewindow/GonkBufferQueue.h
copy to widget/gonk/nativewindow/GonkBufferQueueJB.h
--- a/widget/gonk/nativewindow/GonkBufferQueue.h
+++ b/widget/gonk/nativewindow/GonkBufferQueueJB.h
@@ -10,18 +10,18 @@
  *
  * 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.
  */
 
-#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_H
-#define NATIVEWINDOW_GONKBUFFERQUEUE_H
+#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_JB_H
+#define NATIVEWINDOW_GONKBUFFERQUEUE_JB_H
 
 #include <gui/IGraphicBufferAlloc.h>
 #if ANDROID_VERSION == 17
 #include <gui/ISurfaceTexture.h>
 #else
 #include <gui/IGraphicBufferProducer.h>
 #endif
 
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueKK.cpp
@@ -0,0 +1,1287 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * 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.
+ */
+
+#define LOG_TAG "GonkBufferQueue"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define LOG_NDEBUG 0
+
+#define GL_GLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+#include <utils/CallStack.h>
+#include <cutils/compiler.h>
+#include "mozilla/layers/ImageBridgeChild.h"
+#include "GonkBufferQueueKK.h"
+
+// Macros for including the GonkBufferQueue name in log messages
+#define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
+#define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
+#define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
+#define ATRACE_BUFFER_INDEX(index)
+
+using namespace mozilla;
+using namespace mozilla::gfx;
+using namespace mozilla::layers;
+
+namespace android {
+
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
+
+static const char* scalingModeName(int scalingMode) {
+    switch (scalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE";
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW";
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP";
+        default: return "Unknown";
+    }
+}
+
+GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode,
+        const sp<IGraphicBufferAlloc>& allocator) :
+    mDefaultWidth(1),
+    mDefaultHeight(1),
+    mMaxAcquiredBufferCount(1),
+    mDefaultMaxBufferCount(2),
+    mOverrideMaxBufferCount(0),
+//    mSynchronousMode(true), // GonkBufferQueue always works in sync mode.
+    mConsumerControlledByApp(false),
+    mDequeueBufferCannotBlock(false),
+    mUseAsyncBuffer(true),
+    mConnectedApi(NO_CONNECTED_API),
+    mAbandoned(false),
+    mFrameCounter(0),
+    mBufferHasBeenQueued(false),
+    mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888),
+    mConsumerUsageBits(0),
+    mTransformHint(0),
+    mGeneration(0)
+{
+    // Choose a name using the PID and a process-unique ID.
+    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+
+    ST_LOGV("GonkBufferQueue");
+}
+
+GonkBufferQueue::~GonkBufferQueue() {
+    ST_LOGV("~GonkBufferQueue");
+}
+
+status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) {
+    if (count < 2 || count > NUM_BUFFER_SLOTS)
+        return BAD_VALUE;
+
+    mDefaultMaxBufferCount = count;
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+void GonkBufferQueue::setConsumerName(const String8& name) {
+    Mutex::Autolock lock(mMutex);
+    mConsumerName = name;
+}
+
+status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) {
+    Mutex::Autolock lock(mMutex);
+    mDefaultBufferFormat = defaultFormat;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) {
+    Mutex::Autolock lock(mMutex);
+    mConsumerUsageBits = usage;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setTransformHint(uint32_t hint) {
+    ST_LOGV("setTransformHint: %02x", hint);
+    Mutex::Autolock lock(mMutex);
+    mTransformHint = hint;
+    return NO_ERROR;
+}
+
+int GonkBufferQueue::getGeneration() {
+    return mGeneration;
+}
+
+mozilla::layers::SurfaceDescriptor*
+GonkBufferQueue::getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer)
+{
+    Mutex::Autolock _l(mMutex);
+    if (buffer == NULL) {
+        ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer");
+        return nullptr;
+    }
+
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) {
+            return &mSlots[i].mSurfaceDescriptor;
+        }
+    }
+    ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle);
+    return nullptr;
+}
+
+status_t GonkBufferQueue::setBufferCount(int bufferCount) {
+    ST_LOGV("setBufferCount: count=%d", bufferCount);
+
+    sp<IConsumerListener> listener;
+    nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
+    {
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!");
+            return NO_INIT;
+        }
+        if (bufferCount > NUM_BUFFER_SLOTS) {
+            ST_LOGE("setBufferCount: bufferCount too large (max %d)",
+                    NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
+        }
+
+        // Error out if the user has dequeued buffers
+        for (int i=0 ; i<NUM_BUFFER_SLOTS; i++) {
+            if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
+                ST_LOGE("setBufferCount: client owns some buffers");
+                return -EINVAL;
+            }
+        }
+
+        if (bufferCount == 0) {
+            mOverrideMaxBufferCount = 0;
+            mDequeueCondition.broadcast();
+            return NO_ERROR;
+        }
+
+        // fine to assume async to false before we're setting the buffer count
+        const int minBufferSlots = getMinMaxBufferCountLocked(false);
+        if (bufferCount < minBufferSlots) {
+            ST_LOGE("setBufferCount: requested buffer count (%d) is less than "
+                    "minimum (%d)", bufferCount, minBufferSlots);
+            return BAD_VALUE;
+        }
+
+        // here we're guaranteed that the client doesn't have dequeued buffers
+        // and will release all of its buffer references.  We don't clear the
+        // queue, however, so currently queued buffers still get displayed.
+        // XXX: Should this use drainQueueAndFreeBuffersLocked instead?
+        freeAllBuffersLocked(freeList);
+        mOverrideMaxBufferCount = bufferCount;
+        mDequeueCondition.broadcast();
+        listener = mConsumerListener;
+    } // scope for lock
+    releaseBufferFreeListUnlocked(freeList);
+
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return NO_ERROR;
+}
+
+int GonkBufferQueue::query(int what, int* outValue)
+{
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("query: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    int value;
+    switch (what) {
+    case NATIVE_WINDOW_WIDTH:
+        value = mDefaultWidth;
+        break;
+    case NATIVE_WINDOW_HEIGHT:
+        value = mDefaultHeight;
+        break;
+    case NATIVE_WINDOW_FORMAT:
+        value = mDefaultBufferFormat;
+        break;
+    case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
+        value = getMinUndequeuedBufferCount(false);
+        break;
+    case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND:
+        value = (mQueue.size() >= 2);
+        break;
+    case NATIVE_WINDOW_CONSUMER_USAGE_BITS:
+        value = mConsumerUsageBits;
+        break;
+    default:
+        return BAD_VALUE;
+    }
+    outValue[0] = value;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
+    ATRACE_CALL();
+    ST_LOGV("requestBuffer: slot=%d", slot);
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+    if (slot < 0 || slot >= NUM_BUFFER_SLOTS) {
+        ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d",
+                NUM_BUFFER_SLOTS, slot);
+        return BAD_VALUE;
+    } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) {
+        ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)",
+                slot, mSlots[slot].mBufferState);
+        return BAD_VALUE;
+    }
+    mSlots[slot].mRequestBufferCalled = true;
+    *buf = mSlots[slot].mGraphicBuffer;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp<Fence>* outFence, bool async,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+    ATRACE_CALL();
+    ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
+
+    if ((w && !h) || (!w && h)) {
+        ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
+        return BAD_VALUE;
+    }
+
+    status_t returnFlags(OK);
+    int buf = INVALID_BUFFER_SLOT;
+    uint32_t generation;
+    SurfaceDescriptor descOld;
+
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
+        generation = mGeneration;
+
+        if (format == 0) {
+            format = mDefaultBufferFormat;
+        }
+        // turn on usage bits the consumer requested
+        usage |= mConsumerUsageBits;
+
+        int found = -1;
+        bool tryAgain = true;
+        while (tryAgain) {
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!");
+                return NO_INIT;
+            }
+
+            const int maxBufferCount = getMaxBufferCountLocked(async);
+            if (async && mOverrideMaxBufferCount) {
+                // FIXME: some drivers are manually setting the buffer-count (which they
+                // shouldn't), so we do this extra test here to handle that case.
+                // This is TEMPORARY, until we get this fixed.
+                if (mOverrideMaxBufferCount < maxBufferCount) {
+                    ST_LOGE("dequeueBuffer: async mode is invalid with buffercount override");
+                    return BAD_VALUE;
+                }
+            }
+
+            // Free up any buffers that are in slots beyond the max buffer
+            // count.
+            //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+            //    assert(mSlots[i].mBufferState == BufferSlot::FREE);
+            //    if (mSlots[i].mGraphicBuffer != NULL) {
+            //        freeBufferLocked(i);
+            //        returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
+            //    }
+            //}
+
+            // look for a free buffer to give to the client
+            found = INVALID_BUFFER_SLOT;
+            int dequeuedCount = 0;
+            int acquiredCount = 0;
+            for (int i = 0; i < maxBufferCount; i++) {
+                const int state = mSlots[i].mBufferState;
+                switch (state) {
+                    case BufferSlot::DEQUEUED:
+                    dequeuedCount++;
+                        break;
+                    case BufferSlot::ACQUIRED:
+                        acquiredCount++;
+                        break;
+                    case BufferSlot::FREE:
+                    /* We return the oldest of the free buffers to avoid
+                     * stalling the producer if possible.  This is because
+                     * the consumer may still have pending reads of the
+                     * buffers in flight.
+                     */
+                    if ((found < 0) ||
+                            mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
+                        found = i;
+                    }
+                        break;
+                }
+            }
+
+            // clients are not allowed to dequeue more than one buffer
+            // if they didn't set a buffer count.
+            if (!mOverrideMaxBufferCount && dequeuedCount) {
+                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
+                        "setting the buffer count");
+                return -EINVAL;
+            }
+
+            // See whether a buffer has been queued since the last
+            // setBufferCount so we know whether to perform the min undequeued
+            // buffers check below.
+            if (mBufferHasBeenQueued) {
+                // make sure the client is not trying to dequeue more buffers
+                // than allowed.
+                const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1);
+                const int minUndequeuedCount = getMinUndequeuedBufferCount(async);
+                if (newUndequeuedCount < minUndequeuedCount) {
+                    ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) "
+                            "exceeded (dequeued=%d undequeudCount=%d)",
+                            minUndequeuedCount, dequeuedCount,
+                            newUndequeuedCount);
+                    return -EBUSY;
+                }
+            }
+
+            // If no buffer is found, wait for a buffer to be released or for
+            // the max buffer count to change.
+            tryAgain = found == INVALID_BUFFER_SLOT;
+            if (tryAgain) {
+                // return an error if we're in "cannot block" mode (producer and consumer
+                // are controlled by the application) -- however, the consumer is allowed
+                // to acquire briefly an extra buffer (which could cause us to have to wait here)
+                // and that's okay because we know the wait will be brief (it happens
+                // if we dequeue a buffer while the consumer has acquired one but not released
+                // the old one yet -- for e.g.: see GLConsumer::updateTexImage()).
+                if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) {
+                    ST_LOGE("dequeueBuffer: would block! returning an error instead.");
+                    return WOULD_BLOCK;
+                }
+                mDequeueCondition.wait(mMutex);
+            }
+        }
+
+
+        if (found == INVALID_BUFFER_SLOT) {
+            // This should not happen.
+            ST_LOGE("dequeueBuffer: no available buffer slots");
+            return -EBUSY;
+        }
+
+        buf = found;
+        *outBuf = found;
+
+        const bool useDefaultSize = !w && !h;
+        if (useDefaultSize) {
+            // use the default size
+            w = mDefaultWidth;
+            h = mDefaultHeight;
+        }
+
+        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+        if ((buffer == NULL) ||
+            (uint32_t(buffer->width)  != w) ||
+            (uint32_t(buffer->height) != h) ||
+            (uint32_t(buffer->format) != format) ||
+            ((uint32_t(buffer->usage) & usage) != usage))
+        {
+            mSlots[buf].mAcquireCalled = false;
+            mSlots[buf].mGraphicBuffer = NULL;
+            mSlots[buf].mRequestBufferCalled = false;
+            mSlots[buf].mFence = Fence::NO_FENCE;
+            descOld = mSlots[buf].mSurfaceDescriptor;
+            mSlots[buf].mSurfaceDescriptor = SurfaceDescriptor();
+
+            returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION;
+        }
+
+
+        if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) {
+            ST_LOGE("dequeueBuffer: about to return a NULL fence from mSlot. "
+                    "buf=%d, w=%d, h=%d, format=%d",
+                    buf, buffer->width, buffer->height, buffer->format);
+        }
+        *outFence = mSlots[buf].mFence;
+        mSlots[buf].mFence = Fence::NO_FENCE;
+    }  // end lock scope
+
+    SurfaceDescriptor desc;
+    ImageBridgeChild* ibc;
+    sp<GraphicBuffer> graphicBuffer;
+    if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+        status_t error;
+        ibc = ImageBridgeChild::GetSingleton();
+        ST_LOGD("dequeueBuffer: about to alloc surface descriptor");
+        ibc->AllocSurfaceDescriptorGralloc(IntSize(w, h),
+                                           format,
+                                           usage,
+                                           &desc);
+        // We can only use a gralloc buffer here.  If we didn't get
+        // one back, something went wrong.
+        ST_LOGD("dequeueBuffer: got surface descriptor");
+        if (SurfaceDescriptor::TSurfaceDescriptorGralloc != desc.type()) {
+            MOZ_ASSERT(SurfaceDescriptor::T__None == desc.type());
+            ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer");
+            return -ENOMEM;
+        }
+        graphicBuffer = GrallocBufferActor::GetFrom(desc.get_SurfaceDescriptorGralloc());
+        error = graphicBuffer->initCheck();
+        if (error != NO_ERROR) {
+            ST_LOGE("dequeueBuffer: createGraphicBuffer failed with error %d", error);
+            return error;
+        }
+
+        bool tooOld = false;
+        { // Scope for the lock
+            Mutex::Autolock lock(mMutex);
+
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+                return NO_INIT;
+            }
+
+            if (generation == mGeneration) {
+                mSlots[buf].mGraphicBuffer = graphicBuffer;
+                mSlots[buf].mSurfaceDescriptor = desc;
+                mSlots[buf].mSurfaceDescriptor.get_SurfaceDescriptorGralloc().external() = true;
+                ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf,
+                        mSlots[buf].mGraphicBuffer->handle);
+            } else {
+                tooOld = true;
+            }
+        }
+
+        if (IsSurfaceDescriptorValid(descOld)) {
+            ibc->DeallocSurfaceDescriptorGralloc(descOld);
+        }
+
+        if (tooOld) {
+            ibc->DeallocSurfaceDescriptorGralloc(desc);
+        }
+    }
+
+    ST_LOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf,
+            mSlots[*outBuf].mFrameNumber,
+            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
+
+    return returnFlags;
+}
+
+status_t GonkBufferQueue::queueBuffer(int buf,
+        const QueueBufferInput& input, QueueBufferOutput* output) {
+    ATRACE_CALL();
+
+    Rect crop;
+    uint32_t transform;
+    int scalingMode;
+    int64_t timestamp;
+    bool isAutoTimestamp;
+    bool async;
+    sp<Fence> fence;
+
+    input.deflate(&timestamp, &isAutoTimestamp, &crop, &scalingMode, &transform,
+             &async, &fence);
+
+    if (fence == NULL) {
+        ST_LOGE("queueBuffer: fence is NULL");
+        return BAD_VALUE;
+    }
+
+    ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x "
+            "scale=%s",
+            buf, timestamp, crop.left, crop.top, crop.right, crop.bottom,
+            transform, scalingModeName(scalingMode));
+
+    switch (scalingMode) {
+        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
+        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
+        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
+            break;
+        default:
+            ST_LOGE("unknown scaling mode: %d", scalingMode);
+            return -EINVAL;
+    }
+
+    sp<IConsumerListener> listener;
+
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!");
+            return NO_INIT;
+        }
+
+        const int maxBufferCount = getMaxBufferCountLocked(async);
+        if (async && mOverrideMaxBufferCount) {
+            // FIXME: some drivers are manually setting the buffer-count (which they
+            // shouldn't), so we do this extra test here to handle that case.
+            // This is TEMPORARY, until we get this fixed.
+            if (mOverrideMaxBufferCount < maxBufferCount) {
+                ST_LOGE("queueBuffer: async mode is invalid with buffercount override");
+                return BAD_VALUE;
+            }
+        }
+        if (buf < 0 || buf >= maxBufferCount) {
+            ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d",
+                    maxBufferCount, buf);
+            return -EINVAL;
+        } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+            ST_LOGE("queueBuffer: slot %d is not owned by the client "
+                    "(state=%d)", buf, mSlots[buf].mBufferState);
+            return -EINVAL;
+        } else if (!mSlots[buf].mRequestBufferCalled) {
+            ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
+                    "buffer", buf);
+            return -EINVAL;
+        }
+
+        ST_LOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] "
+                "tr=%#x scale=%s",
+                buf, mFrameCounter + 1, timestamp,
+                crop.left, crop.top, crop.right, crop.bottom,
+                transform, scalingModeName(scalingMode));
+
+        const sp<GraphicBuffer>& graphicBuffer(mSlots[buf].mGraphicBuffer);
+        Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
+        Rect croppedCrop;
+        crop.intersect(bufferRect, &croppedCrop);
+        if (croppedCrop != crop) {
+            ST_LOGE("queueBuffer: crop rect is not contained within the "
+                    "buffer in slot %d", buf);
+            return -EINVAL;
+        }
+
+        mSlots[buf].mFence = fence;
+        mSlots[buf].mBufferState = BufferSlot::QUEUED;
+        mFrameCounter++;
+        mSlots[buf].mFrameNumber = mFrameCounter;
+
+        BufferItem item;
+        item.mAcquireCalled = mSlots[buf].mAcquireCalled;
+        item.mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+        item.mCrop = crop;
+        item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
+        item.mTransformToDisplayInverse = bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY);
+        item.mScalingMode = scalingMode;
+        item.mTimestamp = timestamp;
+        item.mIsAutoTimestamp = isAutoTimestamp;
+        item.mFrameNumber = mFrameCounter;
+        item.mBuf = buf;
+        item.mFence = fence;
+        item.mIsDroppable = mDequeueBufferCannotBlock || async;
+
+        if (mQueue.empty()) {
+            // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and
+            // simply queue this buffer.
+            mQueue.push_back(item);
+            listener = mConsumerListener;
+        } else {
+            // when the queue is not empty, we need to look at the front buffer
+            // state and see if we need to replace it.
+            Fifo::iterator front(mQueue.begin());
+            if (front->mIsDroppable) {
+                // buffer slot currently queued is marked free if still tracked
+                if (stillTracking(front)) {
+                    mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
+                    // reset the frame number of the freed buffer so that it is the first in
+                    // line to be dequeued again.
+                    mSlots[front->mBuf].mFrameNumber = 0;
+                }
+                // and we record the new buffer in the queued list
+                *front = item;
+            } else {
+                mQueue.push_back(item);
+                listener = mConsumerListener;
+            }
+        }
+
+        mBufferHasBeenQueued = true;
+        mDequeueCondition.broadcast();
+
+        output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint,
+                mQueue.size());
+
+    } // scope for the lock
+
+    // call back without lock held
+    if (listener != 0) {
+        listener->onFrameAvailable();
+    }
+    return NO_ERROR;
+}
+
+void GonkBufferQueue::cancelBuffer(int buf, const sp<Fence>& fence) {
+    ATRACE_CALL();
+    ST_LOGV("cancelBuffer: slot=%d", buf);
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!");
+        return;
+    }
+
+    if (buf < 0 || buf >= NUM_BUFFER_SLOTS) {
+        ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d",
+                NUM_BUFFER_SLOTS, buf);
+        return;
+    } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) {
+        ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)",
+                buf, mSlots[buf].mBufferState);
+        return;
+    } else if (fence == NULL) {
+        ST_LOGE("cancelBuffer: fence is NULL");
+        return;
+    }
+    mSlots[buf].mBufferState = BufferSlot::FREE;
+    mSlots[buf].mFrameNumber = 0;
+    mSlots[buf].mFence = fence;
+    mDequeueCondition.broadcast();
+}
+
+
+status_t GonkBufferQueue::connect(const sp<IBinder>& token,
+        int api, bool producerControlledByApp, QueueBufferOutput* output) {
+    ATRACE_CALL();
+    ST_LOGV("connect: api=%d producerControlledByApp=%s", api,
+            producerControlledByApp ? "true" : "false");
+    Mutex::Autolock lock(mMutex);
+
+retry:
+    if (mAbandoned) {
+        ST_LOGE("connect: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    if (mConsumerListener == NULL) {
+        ST_LOGE("connect: GonkBufferQueue has no consumer!");
+        return NO_INIT;
+    }
+
+    if (mConnectedApi != NO_CONNECTED_API) {
+        ST_LOGE("connect: already connected (cur=%d, req=%d)",
+                mConnectedApi, api);
+        return -EINVAL;
+    }
+
+    // If we disconnect and reconnect quickly, we can be in a state where our slots are
+    // empty but we have many buffers in the queue.  This can cause us to run out of
+    // memory if we outrun the consumer.  Wait here if it looks like we have too many
+    // buffers queued up.
+    int maxBufferCount = getMaxBufferCountLocked(false);    // worst-case, i.e. largest value
+    if (mQueue.size() > (size_t) maxBufferCount) {
+        // TODO: make this bound tighter?
+        ST_LOGV("queue size is %d, waiting", mQueue.size());
+        mDequeueCondition.wait(mMutex);
+        goto retry;
+    }
+
+    int err = NO_ERROR;
+    switch (api) {
+        case NATIVE_WINDOW_API_EGL:
+        case NATIVE_WINDOW_API_CPU:
+        case NATIVE_WINDOW_API_MEDIA:
+        case NATIVE_WINDOW_API_CAMERA:
+            mConnectedApi = api;
+            output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size());
+
+            // set-up a death notification so that we can disconnect
+            // automatically when/if the remote producer dies.
+            if (token != NULL && token->remoteBinder() != NULL) {
+                status_t err = token->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
+                if (err == NO_ERROR) {
+                    mConnectedProducerToken = token;
+                } else {
+                    ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err);
+                }
+            }
+            break;
+        default:
+            err = -EINVAL;
+            break;
+    }
+
+    mBufferHasBeenQueued = false;
+    mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp;
+
+    return err;
+}
+
+void GonkBufferQueue::binderDied(const wp<IBinder>& who) {
+    // If we're here, it means that a producer we were connected to died.
+    // We're GUARANTEED that we still are connected to it because it has no other way
+    // to get disconnected -- or -- we wouldn't be here because we're removing this
+    // callback upon disconnect. Therefore, it's okay to read mConnectedApi without
+    // synchronization here.
+    int api = mConnectedApi;
+    this->disconnect(api);
+}
+
+status_t GonkBufferQueue::disconnect(int api) {
+    ATRACE_CALL();
+    ST_LOGV("disconnect: api=%d", api);
+
+    int err = NO_ERROR;
+    sp<IConsumerListener> listener;
+    nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
+
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
+
+        if (mAbandoned) {
+            // it is not really an error to disconnect after the surface
+            // has been abandoned, it should just be a no-op.
+            return NO_ERROR;
+        }
+
+        switch (api) {
+            case NATIVE_WINDOW_API_EGL:
+            case NATIVE_WINDOW_API_CPU:
+            case NATIVE_WINDOW_API_MEDIA:
+            case NATIVE_WINDOW_API_CAMERA:
+                if (mConnectedApi == api) {
+                    freeAllBuffersLocked(freeList);
+                    mConnectedApi = NO_CONNECTED_API;
+                    mDequeueCondition.broadcast();
+                    listener = mConsumerListener;
+                } else {
+                    ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)",
+                            mConnectedApi, api);
+                    err = -EINVAL;
+                }
+                break;
+            default:
+                ST_LOGE("disconnect: unknown API %d", api);
+                err = -EINVAL;
+                break;
+        }
+    }
+    releaseBufferFreeListUnlocked(freeList);
+
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+
+    return err;
+}
+
+void GonkBufferQueue::dump(String8& result, const char* prefix) const {
+    Mutex::Autolock _l(mMutex);
+
+    String8 fifo;
+    int fifoSize = 0;
+    Fifo::const_iterator i(mQueue.begin());
+    while (i != mQueue.end()) {
+        fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], "
+                "xform=0x%02x, time=%#llx, scale=%s\n",
+                i->mBuf, i->mGraphicBuffer.get(),
+                i->mCrop.left, i->mCrop.top, i->mCrop.right,
+                i->mCrop.bottom, i->mTransform, i->mTimestamp,
+                scalingModeName(i->mScalingMode)
+                );
+        i++;
+        fifoSize++;
+    }
+
+
+    result.appendFormat(
+            "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
+            "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n",
+            prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth,
+            mDefaultHeight, mDefaultBufferFormat, mTransformHint,
+            fifoSize, fifo.string());
+
+    struct {
+        const char * operator()(int state) const {
+            switch (state) {
+                case BufferSlot::DEQUEUED: return "DEQUEUED";
+                case BufferSlot::QUEUED: return "QUEUED";
+                case BufferSlot::FREE: return "FREE";
+                case BufferSlot::ACQUIRED: return "ACQUIRED";
+                default: return "Unknown";
+            }
+        }
+    } stateName;
+
+    // just trim the free buffers to not spam the dump
+    int maxBufferCount = 0;
+    for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) {
+        const BufferSlot& slot(mSlots[i]);
+        if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) {
+            maxBufferCount = i+1;
+            break;
+        }
+    }
+
+    for (int i=0 ; i<maxBufferCount ; i++) {
+        const BufferSlot& slot(mSlots[i]);
+        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+        result.appendFormat(
+            "%s%s[%02d:%p] state=%-8s",
+                prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(),
+                stateName(slot.mBufferState)
+        );
+
+        if (buf != NULL) {
+            result.appendFormat(
+                    ", %p [%4ux%4u:%4u,%3X]",
+                    buf->handle, buf->width, buf->height, buf->stride,
+                    buf->format);
+        }
+        result.append("\n");
+    }
+}
+
+void GonkBufferQueue::releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>& freeList)
+{
+    // This function MUST ONLY be called with mMutex unlocked; else there
+    // is a risk of deadlock with the ImageBridge thread.
+
+    ST_LOGD("releaseBufferFreeListUnlocked: E");
+    ImageBridgeChild *ibc = ImageBridgeChild::GetSingleton();
+
+    for (uint32_t i = 0; i < freeList.Length(); ++i) {
+        ibc->DeallocSurfaceDescriptorGralloc(freeList[i]);
+    }
+
+    freeList.Clear();
+    ST_LOGD("releaseBufferFreeListUnlocked: X");
+}
+
+void GonkBufferQueue::freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList)
+{
+    ALOGW_IF(!mQueue.isEmpty(),
+            "freeAllBuffersLocked called but mQueue is not empty");
+    ++mGeneration;
+    mQueue.clear();
+    mBufferHasBeenQueued = false;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].mGraphicBuffer.get() && mSlots[i].mBufferState != BufferSlot::ACQUIRED) {
+            SurfaceDescriptor* desc = freeList.AppendElement();
+            *desc = mSlots[i].mSurfaceDescriptor;
+        }
+        mSlots[i].mGraphicBuffer = 0;
+        mSlots[i].mSurfaceDescriptor = SurfaceDescriptor();
+        if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
+            mSlots[i].mNeedsCleanupOnRelease = true;
+        }
+        mSlots[i].mBufferState = BufferSlot::FREE;
+        mSlots[i].mFrameNumber = 0;
+        mSlots[i].mAcquireCalled = false;
+        // destroy fence as GonkBufferQueue now takes ownership
+        mSlots[i].mFence = Fence::NO_FENCE;
+    }
+}
+
+status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) {
+    ATRACE_CALL();
+    Mutex::Autolock _l(mMutex);
+
+    // Check that the consumer doesn't currently have the maximum number of
+    // buffers acquired.  We allow the max buffer count to be exceeded by one
+    // buffer, so that the consumer can successfully set up the newly acquired
+    // buffer before releasing the old one.
+    int numAcquiredBuffers = 0;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) {
+            numAcquiredBuffers++;
+        }
+    }
+    if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) {
+        ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)",
+                numAcquiredBuffers, mMaxAcquiredBufferCount);
+        return INVALID_OPERATION;
+    }
+
+    // check if queue is empty
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    if (mQueue.empty()) {
+        return NO_BUFFER_AVAILABLE;
+    }
+
+    Fifo::iterator front(mQueue.begin());
+
+    // If expectedPresent is specified, we may not want to return a buffer yet.
+    // If it's specified and there's more than one buffer queued, we may
+    // want to drop a buffer.
+    if (expectedPresent != 0) {
+        const int MAX_REASONABLE_NSEC = 1000000000ULL;  // 1 second
+
+        // The "expectedPresent" argument indicates when the buffer is expected
+        // to be presented on-screen.  If the buffer's desired-present time
+        // is earlier (less) than expectedPresent, meaning it'll be displayed
+        // on time or possibly late if we show it ASAP, we acquire and return
+        // it.  If we don't want to display it until after the expectedPresent
+        // time, we return PRESENT_LATER without acquiring it.
+        //
+        // To be safe, we don't defer acquisition if expectedPresent is
+        // more than one second in the future beyond the desired present time
+        // (i.e. we'd be holding the buffer for a long time).
+        //
+        // NOTE: code assumes monotonic time values from the system clock are
+        // positive.
+
+        // Start by checking to see if we can drop frames.  We skip this check
+        // if the timestamps are being auto-generated by Surface -- if the
+        // app isn't generating timestamps explicitly, they probably don't
+        // want frames to be discarded based on them.
+        while (mQueue.size() > 1 && !mQueue[0].mIsAutoTimestamp) {
+            // If entry[1] is timely, drop entry[0] (and repeat).  We apply
+            // an additional criteria here: we only drop the earlier buffer if
+            // our desiredPresent falls within +/- 1 second of the expected
+            // present.  Otherwise, bogus desiredPresent times (e.g. 0 or
+            // a small relative timestamp), which normally mean "ignore the
+            // timestamp and acquire immediately", would cause us to drop
+            // frames.
+            //
+            // We may want to add an additional criteria: don't drop the
+            // earlier buffer if entry[1]'s fence hasn't signaled yet.
+            //
+            // (Vector front is [0], back is [size()-1])
+            const BufferItem& bi(mQueue[1]);
+            nsecs_t desiredPresent = bi.mTimestamp;
+            if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC ||
+                    desiredPresent > expectedPresent) {
+                // This buffer is set to display in the near future, or
+                // desiredPresent is garbage.  Either way we don't want to
+                // drop the previous buffer just to get this on screen sooner.
+                ST_LOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld",
+                        desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                        systemTime(CLOCK_MONOTONIC));
+                break;
+            }
+            ST_LOGV("pts drop: queue1des=%lld expect=%lld size=%d",
+                    desiredPresent, expectedPresent, mQueue.size());
+            if (stillTracking(front)) {
+                // front buffer is still in mSlots, so mark the slot as free
+                mSlots[front->mBuf].mBufferState = BufferSlot::FREE;
+            }
+            mQueue.erase(front);
+            front = mQueue.begin();
+        }
+
+        // See if the front buffer is due.
+        nsecs_t desiredPresent = front->mTimestamp;
+        if (desiredPresent > expectedPresent &&
+                desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) {
+            ST_LOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld",
+                    desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                    systemTime(CLOCK_MONOTONIC));
+            return PRESENT_LATER;
+        }
+
+        ST_LOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld",
+                desiredPresent, expectedPresent, desiredPresent - expectedPresent,
+                systemTime(CLOCK_MONOTONIC));
+    }
+
+    int buf = front->mBuf;
+    buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+    buffer->mSurfaceDescriptor = mSlots[buf].mSurfaceDescriptor;
+    buffer->mFrameNumber = mSlots[buf].mFrameNumber;
+    buffer->mBuf = buf;
+    buffer->mFence = mSlots[buf].mFence;
+    ATRACE_BUFFER_INDEX(buf);
+
+    ST_LOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }",
+            front->mBuf, front->mFrameNumber,
+            front->mGraphicBuffer->handle);
+    // if front buffer still being tracked update slot state
+    if (stillTracking(front)) {
+        mSlots[buf].mAcquireCalled = true;
+        mSlots[buf].mNeedsCleanupOnRelease = false;
+        mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+        mSlots[buf].mFence = Fence::NO_FENCE;
+    }
+
+    // If the buffer has previously been acquired by the consumer, set
+    // mGraphicBuffer to NULL to avoid unnecessarily remapping this
+    // buffer on the consumer side.
+    //if (buffer->mAcquireCalled) {
+    //    buffer->mGraphicBuffer = NULL;
+    //}
+
+    mQueue.erase(front);
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::releaseBuffer(int buf, uint64_t frameNumber, const sp<Fence>& fence) {
+    ATRACE_CALL();
+
+    if (buf == INVALID_BUFFER_SLOT || fence == NULL) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mMutex);
+
+    // If the frame number has changed because buffer has been reallocated,
+    // we can ignore this releaseBuffer for the old buffer.
+    //if (frameNumber != mSlots[buf].mFrameNumber) {
+    //    return STALE_BUFFER_SLOT;
+    //}
+
+
+    // Internal state consistency checks:
+    // Make sure this buffers hasn't been queued while we were owning it (acquired)
+    Fifo::iterator front(mQueue.begin());
+    Fifo::const_iterator const end(mQueue.end());
+    while (front != end) {
+        if (front->mBuf == buf) {
+            LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been "
+                    "acquired", mConsumerName.string(), frameNumber, buf);
+            break; // never reached
+        }
+        front++;
+    }
+
+    // The buffer can now only be released if its in the acquired state
+    if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[buf].mFence = fence;
+        mSlots[buf].mBufferState = BufferSlot::FREE;
+    } else if (mSlots[buf].mNeedsCleanupOnRelease) {
+        ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState);
+        mSlots[buf].mNeedsCleanupOnRelease = false;
+        return STALE_BUFFER_SLOT;
+    } else {
+        ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState);
+        return -EINVAL;
+    }
+
+    mDequeueCondition.broadcast();
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::consumerConnect(const sp<IConsumerListener>& consumerListener,
+        bool controlledByApp) {
+    ST_LOGV("consumerConnect controlledByApp=%s",
+            controlledByApp ? "true" : "false");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+    if (consumerListener == NULL) {
+        ST_LOGE("consumerConnect: consumerListener may not be NULL");
+        return BAD_VALUE;
+    }
+
+    mConsumerListener = consumerListener;
+    mConsumerControlledByApp = controlledByApp;
+
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::consumerDisconnect() {
+    ST_LOGV("consumerDisconnect");
+    nsAutoTArray<SurfaceDescriptor, NUM_BUFFER_SLOTS> freeList;
+    {
+        Mutex::Autolock lock(mMutex);
+
+        if (mConsumerListener == NULL) {
+            ST_LOGE("consumerDisconnect: No consumer is connected!");
+            return -EINVAL;
+        }
+
+        mAbandoned = true;
+        mConsumerListener = NULL;
+        mQueue.clear();
+        freeAllBuffersLocked(freeList);
+    }
+    releaseBufferFreeListUnlocked(freeList);
+    mDequeueCondition.broadcast();
+
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) {
+    ST_LOGV("getReleasedBuffers");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!");
+        return NO_INIT;
+    }
+
+    uint32_t mask = 0;
+    for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
+        if (!mSlots[i].mAcquireCalled) {
+            mask |= 1 << i;
+        }
+    }
+
+    // Remove buffers in flight (on the queue) from the mask where acquire has
+    // been called, as the consumer will not receive the buffer address, so
+    // it should not free these slots.
+    Fifo::iterator front(mQueue.begin());
+    while (front != mQueue.end()) {
+        if (front->mAcquireCalled)
+            mask &= ~(1 << front->mBuf);
+        front++;
+    }
+
+    *slotMask = mask;
+
+    ST_LOGV("getReleasedBuffers: returning mask %#x", mask);
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
+    if (!w || !h) {
+        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
+                w, h);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mDefaultWidth = w;
+    mDefaultHeight = h;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    return setDefaultMaxBufferCountLocked(bufferCount);
+}
+
+status_t GonkBufferQueue::disableAsyncBuffer() {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    if (mConsumerListener != NULL) {
+        ST_LOGE("disableAsyncBuffer: consumer already connected!");
+        return INVALID_OPERATION;
+    }
+    mUseAsyncBuffer = false;
+    return NO_ERROR;
+}
+
+status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    ATRACE_CALL();
+    Mutex::Autolock lock(mMutex);
+    if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) {
+        ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d",
+                maxAcquiredBuffers);
+        return BAD_VALUE;
+    }
+    if (mConnectedApi != NO_CONNECTED_API) {
+        return INVALID_OPERATION;
+    }
+    mMaxAcquiredBufferCount = maxAcquiredBuffers;
+    return NO_ERROR;
+}
+
+int GonkBufferQueue::getMinUndequeuedBufferCount(bool async) const {
+    // if dequeueBuffer is allowed to error out, we don't have to
+    // add an extra buffer.
+    if (!mUseAsyncBuffer)
+        return mMaxAcquiredBufferCount;
+
+    // we're in async mode, or we want to prevent the app to
+    // deadlock itself, we throw-in an extra buffer to guarantee it.
+    if (mDequeueBufferCannotBlock || async)
+        return mMaxAcquiredBufferCount + 1;
+
+    return mMaxAcquiredBufferCount;
+}
+
+int GonkBufferQueue::getMinMaxBufferCountLocked(bool async) const {
+    return getMinUndequeuedBufferCount(async) + 1;
+}
+
+int GonkBufferQueue::getMaxBufferCountLocked(bool async) const {
+    int minMaxBufferCount = getMinMaxBufferCountLocked(async);
+
+    int maxBufferCount = mDefaultMaxBufferCount;
+    if (maxBufferCount < minMaxBufferCount) {
+        maxBufferCount = minMaxBufferCount;
+    }
+    if (mOverrideMaxBufferCount != 0) {
+        assert(mOverrideMaxBufferCount >= minMaxBufferCount);
+        maxBufferCount = mOverrideMaxBufferCount;
+    }
+
+    // Any buffers that are dequeued by the producer or sitting in the queue
+    // waiting to be consumed need to have their slots preserved.  Such
+    // buffers will temporarily keep the max buffer count up until the slots
+    // no longer need to be preserved.
+    for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) {
+        BufferSlot::BufferState state = mSlots[i].mBufferState;
+        if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) {
+            maxBufferCount = i + 1;
+        }
+    }
+
+    return maxBufferCount;
+}
+
+bool GonkBufferQueue::stillTracking(const BufferItem *item) const {
+    const BufferSlot &slot = mSlots[item->mBuf];
+
+    ST_LOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, "
+            "slot: { slot=%d/%llu, buffer=%p }",
+            item->mBuf, item->mFrameNumber,
+            (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0),
+            item->mBuf, slot.mFrameNumber,
+            (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0));
+
+    // Compare item with its original buffer slot.  We can check the slot
+    // as the buffer would not be moved to a different slot by the producer.
+    return (slot.mGraphicBuffer != NULL &&
+            item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle);
+}
+
+GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener(
+        const wp<ConsumerListener>& consumerListener):
+        mConsumerListener(consumerListener) {}
+
+GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {}
+
+void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onFrameAvailable();
+    }
+}
+
+void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() {
+    sp<ConsumerListener> listener(mConsumerListener.promote());
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+}
+
+}; // namespace android
new file mode 100644
--- /dev/null
+++ b/widget/gonk/nativewindow/GonkBufferQueueKK.h
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 Mozilla Foundation
+ *
+ * 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.
+ */
+
+#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_KK_H
+#define NATIVEWINDOW_GONKBUFFERQUEUE_KK_H
+
+#include <gui/IConsumerListener.h>
+#include <gui/IGraphicBufferAlloc.h>
+#include <gui/IGraphicBufferProducer.h>
+#include "IGonkGraphicBufferConsumer.h"
+
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#include "mozilla/layers/LayersSurfaces.h"
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class GonkBufferQueue : public BnGraphicBufferProducer,
+                    public BnGonkGraphicBufferConsumer,
+                    private IBinder::DeathRecipient {
+    typedef mozilla::layers::SurfaceDescriptor SurfaceDescriptor;
+
+public:
+    enum { MIN_UNDEQUEUED_BUFFERS = 2 };
+    enum { NUM_BUFFER_SLOTS = 32 };
+    enum { NO_CONNECTED_API = 0 };
+    enum { INVALID_BUFFER_SLOT = -1 };
+    enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE, PRESENT_LATER };
+
+    // When in async mode we reserve two slots in order to guarantee that the
+    // producer and consumer can run asynchronously.
+    enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 };
+
+    // for backward source compatibility
+    typedef ::android::ConsumerListener ConsumerListener;
+
+    // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak
+    // reference to the actual consumer object.  It forwards all calls to that
+    // consumer object so long as it exists.
+    //
+    // This class exists to avoid having a circular reference between the
+    // GonkBufferQueue object and the consumer object.  The reason this can't be a weak
+    // reference in the GonkBufferQueue class is because we're planning to expose the
+    // consumer side of a GonkBufferQueue as a binder interface, which doesn't support
+    // weak references.
+    class ProxyConsumerListener : public BnConsumerListener {
+    public:
+        ProxyConsumerListener(const wp<ConsumerListener>& consumerListener);
+        virtual ~ProxyConsumerListener();
+        virtual void onFrameAvailable();
+        virtual void onBuffersReleased();
+    private:
+        // mConsumerListener is a weak reference to the IConsumerListener.  This is
+        // the raison d'etre of ProxyConsumerListener.
+        wp<ConsumerListener> mConsumerListener;
+    };
+
+
+    // BufferQueue manages a pool of gralloc memory slots to be used by
+    // producers and consumers. allocator is used to allocate all the
+    // needed gralloc buffers.
+    GonkBufferQueue(bool allowSynchronousMode = true,
+            const sp<IGraphicBufferAlloc>& allocator = NULL);
+    virtual ~GonkBufferQueue();
+
+    /*
+     * IBinder::DeathRecipient interface
+     */
+
+    virtual void binderDied(const wp<IBinder>& who);
+
+    /*
+     * IGraphicBufferProducer interface
+     */
+
+    // Query native window attributes.  The "what" values are enumerated in
+    // window.h (e.g. NATIVE_WINDOW_FORMAT).
+    virtual int query(int what, int* value);
+
+    // setBufferCount updates the number of available buffer slots.  If this
+    // method succeeds, buffer slots will be both unallocated and owned by
+    // the GonkBufferQueue object (i.e. they are not owned by the producer or
+    // consumer).
+    //
+    // This will fail if the producer has dequeued any buffers, or if
+    // bufferCount is invalid.  bufferCount must generally be a value
+    // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS
+    // (inclusive).  It may also be set to zero (the default) to indicate
+    // that the producer does not wish to set a value.  The minimum value
+    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+    // ...).
+    //
+    // This may only be called by the producer.  The consumer will be told
+    // to discard buffers through the onBuffersReleased callback.
+    virtual status_t setBufferCount(int bufferCount);
+
+    // requestBuffer returns the GraphicBuffer for slot N.
+    //
+    // In normal operation, this is called the first time slot N is returned
+    // by dequeueBuffer.  It must be called again if dequeueBuffer returns
+    // flags indicating that previously-returned buffers are no longer valid.
+    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
+
+    // dequeueBuffer gets the next buffer slot index for the producer to use.
+    // If a buffer slot is available then that slot index is written to the
+    // location pointed to by the buf argument and a status of OK is returned.
+    // If no slot is available then a status of -EBUSY is returned and buf is
+    // unmodified.
+    //
+    // The fence parameter will be updated to hold the fence associated with
+    // the buffer. The contents of the buffer must not be overwritten until the
+    // fence signals. If the fence is Fence::NO_FENCE, the buffer may be
+    // written immediately.
+    //
+    // The width and height parameters must be no greater than the minimum of
+    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+    // An error due to invalid dimensions might not be reported until
+    // updateTexImage() is called.  If width and height are both zero, the
+    // default values specified by setDefaultBufferSize() are used instead.
+    //
+    // The pixel formats are enumerated in graphics.h, e.g.
+    // HAL_PIXEL_FORMAT_RGBA_8888.  If the format is 0, the default format
+    // will be used.
+    //
+    // The usage argument specifies gralloc buffer usage flags.  The values
+    // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER.  These
+    // will be merged with the usage flags specified by setConsumerUsageBits.
+    //
+    // The return value may be a negative error value or a non-negative
+    // collection of flags.  If the flags are set, the return values are
+    // valid, but additional actions must be performed.
+    //
+    // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the
+    // producer must discard cached GraphicBuffer references for the slot
+    // returned in buf.
+    // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer
+    // must discard cached GraphicBuffer references for all slots.
+    //
+    // In both cases, the producer will need to call requestBuffer to get a
+    // GraphicBuffer handle for the returned slot.
+    virtual status_t dequeueBuffer(int *buf, sp<Fence>* fence, bool async,
+            uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+
+    // queueBuffer returns a filled buffer to the GonkBufferQueue.
+    //
+    // Additional data is provided in the QueueBufferInput struct.  Notably,
+    // a timestamp must be provided for the buffer. The timestamp is in
+    // nanoseconds, and must be monotonically increasing. Its other semantics
+    // (zero point, etc) are producer-specific and should be documented by the
+    // producer.
+    //
+    // The caller may provide a fence that signals when all rendering
+    // operations have completed.  Alternatively, NO_FENCE may be used,
+    // indicating that the buffer is ready immediately.
+    //
+    // Some values are returned in the output struct: the current settings
+    // for default width and height, the current transform hint, and the
+    // number of queued buffers.
+    virtual status_t queueBuffer(int buf,
+            const QueueBufferInput& input, QueueBufferOutput* output);
+
+    // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't
+    // queue it for use by the consumer.
+    //
+    // The buffer will not be overwritten until the fence signals.  The fence
+    // will usually be the one obtained from dequeueBuffer.
+    virtual void cancelBuffer(int buf, const sp<Fence>& fence);
+
+    // connect attempts to connect a producer API to the GonkBufferQueue.  This
+    // must be called before any other IGraphicBufferProducer methods are
+    // called except for getAllocator.  A consumer must already be connected.
+    //
+    // This method will fail if connect was previously called on the
+    // GonkBufferQueue and no corresponding disconnect call was made (i.e. if
+    // it's still connected to a producer).
+    //
+    // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU).
+    virtual status_t connect(const sp<IBinder>& token,
+            int api, bool producerControlledByApp, QueueBufferOutput* output);
+
+    // disconnect attempts to disconnect a producer API from the GonkBufferQueue.
+    // Calling this method will cause any subsequent calls to other
+    // IGraphicBufferProducer methods to fail except for getAllocator and connect.
+    // Successfully calling connect after this will allow the other methods to
+    // succeed again.
+    //
+    // This method will fail if the the GonkBufferQueue is not currently
+    // connected to the specified producer API.
+    virtual status_t disconnect(int api);
+
+    /*
+     * IGraphicBufferConsumer interface
+     */
+
+    // acquireBuffer attempts to acquire ownership of the next pending buffer in
+    // the GonkBufferQueue.  If no buffer is pending then it returns -EINVAL.  If a
+    // buffer is successfully acquired, the information about the buffer is
+    // returned in BufferItem.  If the buffer returned had previously been
+    // acquired then the BufferItem::mGraphicBuffer field of buffer is set to
+    // NULL and it is assumed that the consumer still holds a reference to the
+    // buffer.
+    //
+    // If presentWhen is nonzero, it indicates the time when the buffer will
+    // be displayed on screen.  If the buffer's timestamp is farther in the
+    // future, the buffer won't be acquired, and PRESENT_LATER will be
+    // returned.  The presentation time is in nanoseconds, and the time base
+    // is CLOCK_MONOTONIC.
+    virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen);
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // GonkBufferQueue.  This may be done while the buffer's contents are still
+    // being accessed.  The fence will signal when the buffer is no longer
+    // in use. frameNumber is used to indentify the exact buffer returned.
+    //
+    // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free
+    // any references to the just-released buffer that it might have, as if it
+    // had received a onBuffersReleased() call with a mask set for the released
+    // buffer.
+    //
+    // Note that the dependencies on EGL will be removed once we switch to using
+    // the Android HW Sync HAL.
+    virtual status_t releaseBuffer(int buf, uint64_t frameNumber,
+                    const sp<Fence>& releaseFence);
+
+    // consumerConnect connects a consumer to the GonkBufferQueue.  Only one
+    // consumer may be connected, and when that consumer disconnects the
+    // GonkBufferQueue is placed into the "abandoned" state, causing most
+    // interactions with the GonkBufferQueue by the producer to fail.
+    // controlledByApp indicates whether the consumer is controlled by
+    // the application.
+    //
+    // consumer may not be NULL.
+    virtual status_t consumerConnect(const sp<IConsumerListener>& consumer, bool controlledByApp);
+
+    // consumerDisconnect disconnects a consumer from the GonkBufferQueue. All
+    // buffers will be freed and the GonkBufferQueue is placed in the "abandoned"
+    // state, causing most interactions with the GonkBufferQueue by the producer to
+    // fail.
+    virtual status_t consumerDisconnect();
+
+    // getReleasedBuffers sets the value pointed to by slotMask to a bit mask
+    // indicating which buffer slots have been released by the GonkBufferQueue
+    // but have not yet been released by the consumer.
+    //
+    // This should be called from the onBuffersReleased() callback.
+    virtual status_t getReleasedBuffers(uint32_t* slotMask);
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // dequeueBuffer when a width and height of zero is requested.  Default
+    // is 1x1.
+    virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+
+    // setDefaultMaxBufferCount sets the default value for the maximum buffer
+    // count (the initial default is 2). If the producer has requested a
+    // buffer count using setBufferCount, the default buffer count will only
+    // take effect if the producer sets the count back to zero.
+    //
+    // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    virtual status_t setDefaultMaxBufferCount(int bufferCount);
+
+    // disableAsyncBuffer disables the extra buffer used in async mode
+    // (when both producer and consumer have set their "isControlledByApp"
+    // flag) and has dequeueBuffer() return WOULD_BLOCK instead.
+    //
+    // This can only be called before consumerConnect().
+    virtual status_t disableAsyncBuffer();
+
+    // setMaxAcquiredBufferCount sets the maximum number of buffers that can
+    // be acquired by the consumer at one time (default 1).  This call will
+    // fail if a producer is connected to the GonkBufferQueue.
+    virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+    // setConsumerName sets the name used in logging
+    virtual void setConsumerName(const String8& name);
+
+    // setDefaultBufferFormat allows the GonkBufferQueue to create
+    // GraphicBuffers of a defaultFormat if no format is specified
+    // in dequeueBuffer.  Formats are enumerated in graphics.h; the
+    // initial default is HAL_PIXEL_FORMAT_RGBA_8888.
+    virtual status_t setDefaultBufferFormat(uint32_t defaultFormat);
+
+    // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer.
+    // These are merged with the bits passed to dequeueBuffer.  The values are
+    // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0.
+    virtual status_t setConsumerUsageBits(uint32_t usage);
+
+    // setTransformHint bakes in rotation to buffers so overlays can be used.
+    // The values are enumerated in window.h, e.g.
+    // NATIVE_WINDOW_TRANSFORM_ROT_90.  The default is 0 (no transform).
+    virtual status_t setTransformHint(uint32_t hint);
+
+    // dump our state in a String
+    virtual void dump(String8& result, const char* prefix) const;
+
+    int getGeneration();
+    SurfaceDescriptor *getSurfaceDescriptorFromBuffer(ANativeWindowBuffer* buffer);
+
+private:
+    // releaseBufferFreeListUnlocked releases the resources in the freeList;
+    // this must be called with mMutex unlocked.
+    void releaseBufferFreeListUnlocked(nsTArray<SurfaceDescriptor>& freeList);
+
+    // freeBufferLocked frees the GraphicBuffer and sync resources for the
+    // given slot.
+    //void freeBufferLocked(int index);
+
+    // freeAllBuffersLocked frees the GraphicBuffer and sync resources for
+    // all slots.
+    //void freeAllBuffersLocked();
+    void freeAllBuffersLocked(nsTArray<SurfaceDescriptor>& freeList);
+
+    // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots
+    // that will be used if the producer does not override the buffer slot
+    // count.  The count must be between 2 and NUM_BUFFER_SLOTS, inclusive.
+    // The initial default is 2.
+    status_t setDefaultMaxBufferCountLocked(int count);
+
+    // getMinUndequeuedBufferCount returns the minimum number of buffers
+    // that must remain in a state other than DEQUEUED.
+    // The async parameter tells whether we're in asynchronous mode.
+    int getMinUndequeuedBufferCount(bool async) const;
+
+    // getMinBufferCountLocked returns the minimum number of buffers allowed
+    // given the current GonkBufferQueue state.
+    // The async parameter tells whether we're in asynchronous mode.
+    int getMinMaxBufferCountLocked(bool async) const;
+
+    // getMaxBufferCountLocked returns the maximum number of buffers that can
+    // be allocated at once.  This value depends upon the following member
+    // variables:
+    //
+    //      mDequeueBufferCannotBlock
+    //      mMaxAcquiredBufferCount
+    //      mDefaultMaxBufferCount
+    //      mOverrideMaxBufferCount
+    //      async parameter
+    //
+    // Any time one of these member variables is changed while a producer is
+    // connected, mDequeueCondition must be broadcast.
+    int getMaxBufferCountLocked(bool async) const;
+
+    // stillTracking returns true iff the buffer item is still being tracked
+    // in one of the slots.
+    bool stillTracking(const BufferItem *item) const;
+
+    struct BufferSlot {
+
+        BufferSlot()
+        : mSurfaceDescriptor(SurfaceDescriptor()),
+          mBufferState(BufferSlot::FREE),
+          mRequestBufferCalled(false),
+          mFrameNumber(0),
+          mAcquireCalled(false),
+          mNeedsCleanupOnRelease(false) {
+        }
+
+        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+        // if no buffer has been allocated.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mSurfaceDescriptor is the token to remotely allocated GraphicBuffer.
+        SurfaceDescriptor mSurfaceDescriptor;
+
+        // BufferState represents the different states in which a buffer slot
+        // can be.  All slots are initially FREE.
+        enum BufferState {
+            // FREE indicates that the buffer is available to be dequeued
+            // by the producer.  The buffer may be in use by the consumer for
+            // a finite time, so the buffer must not be modified until the
+            // associated fence is signaled.
+            //
+            // The slot is "owned" by GonkBufferQueue.  It transitions to DEQUEUED
+            // when dequeueBuffer is called.
+            FREE = 0,
+
+            // DEQUEUED indicates that the buffer has been dequeued by the
+            // producer, but has not yet been queued or canceled.  The
+            // producer may modify the buffer's contents as soon as the
+            // associated ready fence is signaled.
+            //
+            // The slot is "owned" by the producer.  It can transition to
+            // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer).
+            DEQUEUED = 1,
+
+            // QUEUED indicates that the buffer has been filled by the
+            // producer and queued for use by the consumer.  The buffer
+            // contents may continue to be modified for a finite time, so
+            // the contents must not be accessed until the associated fence
+            // is signaled.
+            //
+            // The slot is "owned" by GonkBufferQueue.  It can transition to
+            // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is
+            // queued in asynchronous mode).
+            QUEUED = 2,
+
+            // ACQUIRED indicates that the buffer has been acquired by the
+            // consumer.  As with QUEUED, the contents must not be accessed
+            // by the consumer until the fence is signaled.
+            //
+            // The slot is "owned" by the consumer.  It transitions to FREE
+            // when releaseBuffer is called.
+            ACQUIRED = 3
+        };
+
+        // mBufferState is the current state of this buffer slot.
+        BufferState mBufferState;
+
+        // mRequestBufferCalled is used for validating that the producer did
+        // call requestBuffer() when told to do so. Technically this is not
+        // needed but useful for debugging and catching producer bugs.
+        bool mRequestBufferCalled;
+
+        // mFrameNumber is the number of the queued frame for this slot.  This
+        // is used to dequeue buffers in LRU order (useful because buffers
+        // may be released before their rele