Merge mozilla-central to mozilla-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Wed, 30 Dec 2015 12:15:55 +0100
changeset 277885 b493cf33851fc44f9fef8179bc88969f10df3ff6
parent 277831 f916b88c87b50619d9b05599f5d2581b84f6d557 (current diff)
parent 277884 c690c50b2b543b420803e8192d6e08e06b20e0a3 (diff)
child 277886 ee4446a2c02a04f6fba9c6ba573ab45445997277
push id69628
push usercbook@mozilla.com
push dateWed, 30 Dec 2015 11:16:09 +0000
treeherdermozilla-inbound@b493cf33851f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone46.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 mozilla-central to mozilla-inbound
browser/components/pocket/Pocket.jsm
browser/components/pocket/jar.mn
browser/components/pocket/main.js
browser/components/pocket/moz.build
browser/components/pocket/panels/css/firasans.css
browser/components/pocket/panels/css/normalize.css
browser/components/pocket/panels/css/saved.css
browser/components/pocket/panels/css/signup.css
browser/components/pocket/panels/fonts/FiraSans-Regular.woff
browser/components/pocket/panels/img/pocketerror@1x.png
browser/components/pocket/panels/img/pocketerror@2x.png
browser/components/pocket/panels/img/pocketlogo@1x.png
browser/components/pocket/panels/img/pocketlogo@2x.png
browser/components/pocket/panels/img/pocketlogosolo@1x.png
browser/components/pocket/panels/img/pocketlogosolo@2x.png
browser/components/pocket/panels/img/pocketmenuitem16.png
browser/components/pocket/panels/img/pocketmenuitem16@2x.png
browser/components/pocket/panels/img/pocketsignup_button@1x.png
browser/components/pocket/panels/img/pocketsignup_button@2x.png
browser/components/pocket/panels/img/pocketsignup_devices@1x.png
browser/components/pocket/panels/img/pocketsignup_devices@2x.png
browser/components/pocket/panels/img/pocketsignup_hero@1x.png
browser/components/pocket/panels/img/pocketsignup_hero@2x.png
browser/components/pocket/panels/img/signup_firefoxlogo@1x.png
browser/components/pocket/panels/img/signup_firefoxlogo@2x.png
browser/components/pocket/panels/img/signup_help@1x.png
browser/components/pocket/panels/img/signup_help@2x.png
browser/components/pocket/panels/img/signup_or@1x.png
browser/components/pocket/panels/img/signup_or@2x.png
browser/components/pocket/panels/img/tag_close@1x.png
browser/components/pocket/panels/img/tag_close@2x.png
browser/components/pocket/panels/img/tag_closeactive@1x.png
browser/components/pocket/panels/img/tag_closeactive@2x.png
browser/components/pocket/panels/js/messages.js
browser/components/pocket/panels/js/saved.js
browser/components/pocket/panels/js/signup.js
browser/components/pocket/panels/js/tmpl.js
browser/components/pocket/panels/js/vendor/handlebars.runtime.js
browser/components/pocket/panels/js/vendor/jquery-2.1.1.min.js
browser/components/pocket/panels/js/vendor/jquery.tokeninput.min.js
browser/components/pocket/panels/license.txt
browser/components/pocket/panels/saved.html
browser/components/pocket/panels/signup.html
browser/components/pocket/panels/tmpl/saved_premiumextras.handlebars
browser/components/pocket/panels/tmpl/saved_premiumshell.handlebars
browser/components/pocket/panels/tmpl/saved_shell.handlebars
browser/components/pocket/panels/tmpl/signup_shell.handlebars
browser/components/pocket/panels/tmpl/signupstoryboard_shell.handlebars
browser/components/pocket/pktApi.js
browser/locales/en-US/chrome/browser/browser-pocket.properties
devtools/client/memory/components/frame.js
mobile/android/base/lint.xml
testing/docker/builder/REGISTRY
testing/docker/builder/VERSION
toolkit/themes/shared/reader/pocket.svg
--- a/b2g/config/aries/sources.xml
+++ b/b2g/config/aries/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
@@ -134,17 +134,17 @@
   <!-- Platform common things -->
   <project name="device-shinano-common" path="device/sony/shinano-common" remote="b2g" revision="03f7deda712e213aabf79eb657bd902497e3b201"/>
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="2501e5940ba69ece7654ff85611c76ae5bda299c"/>
   <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="da1273d39b3b940b3b2a5bc5fdb81c521d74caa3"/>
   <project name="init_sh" path="external/init_sh" remote="b2g" revision="feb58d2b397e45ead9b904d5c4d9255df408db56"/>
   <project name="platform_bionic" path="bionic" remote="b2g" revision="3e85c4683c121530c1c3a48c696a569bf5f587e2"/>
   <project name="platform_external_bluetooth_bluedroid" path="external/bluetooth/bluedroid" remote="b2g" revision="70f536bd97d901b96b94669ae1aa2fd0fb54b258"/>
-  <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="b2g" revision="2d017f975f4542c6d23b226ec172b9b30383c31c"/>
+  <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="b2g" revision="2a52bd77d2ca0cefbf02acc6863492d16b6ccfec"/>
   <project name="platform_external_libnfc-pn547" path="external/libnfc-pn547" remote="b2g" revision="5bb999b84b8adc14f6bea004d523ba258dea8188"/>
   <project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="5b71e40213f650459e95d35b6f14af7e88d8ab62"/>
   <project name="platform_frameworks_av" path="frameworks/av" remote="b2g" revision="5d5bcc83d6c32874701f0df78ed1119e006bd10a"/>
   <project name="platform/frameworks/base" path="frameworks/base" revision="da8e6bc53c8bc669da0bb627904d08aa293f2497"/>
   <project name="platform/frameworks/native" path="frameworks/native" revision="a46a9f1ac0ed5662d614c277cbb14eb3f332f365"/>
   <project name="platform/hardware/libhardware" path="hardware/libhardware" revision="7196881a0e9dd7bfbbcf0af64c8064e70f0fa094"/>
   <project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="15a9b66de9b7d84c7ea63df3a834f095bca9e493"/>
   <project name="platform/hardware/qcom/audio" path="hardware/qcom/audio" revision="8d7676dfb68ee0cd069affedd5d1e97316a184ba"/>
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk-specific things and forks -->
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator-l/sources.xml
+++ b/b2g/config/emulator-l/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk-specific things and forks -->
   <project name="platform_bionic" path="bionic" remote="b2g" revision="e2b3733ba3fa5e3f404e983d2e4142b1f6b1b846"/>
   <project name="platform_build" path="build" remote="b2g" revision="1b0db93fb6b870b03467aff50d6419771ba0d88c">
     <copyfile dest="Makefile" src="core/root.mk"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
-        "git_revision": "63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23", 
+        "git_revision": "1899109c9fd9b9e2244155c4b9e966c0a48368fc", 
         "remote": "https://git.mozilla.org/releases/gaia.git", 
         "branch": ""
     }, 
-    "revision": "9cfeee1568995b5cf0f58db8924baff387871876", 
+    "revision": "cfb223aa835d5bf17ec0fd03f873b6788a149edb", 
     "repo_path": "integration/gaia-central"
 }
--- a/b2g/config/nexus-4-kk/sources.xml
+++ b/b2g/config/nexus-4-kk/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="660169a3d7e034a892359e39135e8c2785a6ad6f">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
--- a/b2g/config/nexus-5-l/sources.xml
+++ b/b2g/config/nexus-5-l/sources.xml
@@ -16,17 +16,17 @@
   <remote fetch="https://git.mozilla.org/external/linaro" name="linaro"/>
   <!--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"/>
   <!--
     B2G repositories for all targets
     -->
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="63c3a57ad9935b9c61057a29ee27a1c6ed6a9e23"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="1899109c9fd9b9e2244155c4b9e966c0a48368fc"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="4a962bdab532e18f53e9d2d114c349983262c6b7"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="99c333dab00ed79baff9e1cf76b320aee8e1c123"/>
   <project name="platform_hardware_libhardware_moz" path="hardware/libhardware_moz" remote="b2g" revision="fdf3a143dc777e5f9d33a88373af7ea161d3b440"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -643,19 +643,19 @@
 @RESPATH@/components/XULStore.manifest
 @RESPATH@/components/Webapps.js
 @RESPATH@/components/Webapps.manifest
 @RESPATH@/components/AppsService.js
 @RESPATH@/components/AppsService.manifest
 @RESPATH@/components/Push.js
 @RESPATH@/components/Push.manifest
 #ifdef MOZ_SIMPLEPUSH
-@RESPATH@/components/PushComponents.js
+@RESPATH@/components/PushServiceLauncher.js
 #else
-@RESPATH@/components/PushServiceLauncher.js
+@RESPATH@/components/PushComponents.js
 #endif
 
 @RESPATH@/components/InterAppComm.manifest
 @RESPATH@/components/InterAppCommService.js
 @RESPATH@/components/InterAppConnection.js
 @RESPATH@/components/InterAppMessagePort.js
 
 @RESPATH@/components/nsDOMIdentity.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1606,23 +1606,16 @@ pref("dom.ipc.reportProcessHangs", true)
 pref("browser.reader.detectedFirstArticle", false);
 // Don't limit how many nodes we care about on desktop:
 pref("reader.parse-node-limit", 0);
 
 // On desktop, we want the URLs to be included here for ease of debugging,
 // and because (normally) these errors are not persisted anywhere.
 pref("reader.errors.includeURLs", true);
 
-pref("browser.pocket.enabled", true);
-pref("browser.pocket.api", "api.getpocket.com");
-pref("browser.pocket.site", "getpocket.com");
-pref("browser.pocket.oAuthConsumerKey", "40249-e88c401e1b1f2242d9e441c4");
-pref("browser.pocket.useLocaleList", true);
-pref("browser.pocket.enabledLocales", "cs de en-GB en-US en-ZA es-ES es-MX fr hu it ja ja-JP-mac ko nl pl pt-BR pt-PT ru zh-CN zh-TW");
-
 pref("view_source.tab", true);
 
 pref("dom.serviceWorkers.enabled", true);
 pref("dom.serviceWorkers.interception.enabled", true);
 pref("dom.serviceWorkers.openWindow.enabled", true);
 
 #ifndef RELEASE_BUILD
 // Enable Push API.
--- a/browser/base/content/browser-context.inc
+++ b/browser/base/content/browser-context.inc
@@ -74,20 +74,16 @@
       <menuitem id="context-sharelink"
                 label="&shareLink.label;"
                 accesskey="&shareLink.accesskey;"
                 oncommand="gContextMenu.shareLink();"/>
       <menuitem id="context-savelink"
                 label="&saveLinkCmd.label;"
                 accesskey="&saveLinkCmd.accesskey;"
                 oncommand="gContextMenu.saveLink();"/>
-      <menuitem id="context-savelinktopocket"
-                label="&saveLinkToPocketCmd.label;"
-                accesskey="&saveLinkToPocketCmd.accesskey;"
-                oncommand="gContextMenu.saveLinkToPocket();"/>
       <menu id="context-marklinkMenu" label="&social.marklinkMenu.label;"
             accesskey="&social.marklinkMenu.accesskey;">
         <menupopup/>
       </menu>
       <menuitem id="context-copyemail"
                 label="&copyEmailCmd.label;"
                 accesskey="&copyEmailCmd.accesskey;"
                 oncommand="gContextMenu.copyEmail();"/>
@@ -265,20 +261,16 @@
       <menuitem id="context-sharepage"
                 label="&sharePageCmd.label;"
                 accesskey="&sharePageCmd.accesskey;"
                 oncommand="SocialShare.sharePage();"/>
       <menuitem id="context-savepage"
                 label="&savePageCmd.label;"
                 accesskey="&savePageCmd.accesskey2;"
                 oncommand="gContextMenu.savePageAs();"/>
-      <menuitem id="context-pocket"
-                label="&saveToPocketCmd.label;"
-                accesskey="&saveToPocketCmd.accesskey;"
-                oncommand="gContextMenu.savePageToPocket();"/>
       <menu id="context-markpageMenu" label="&social.markpageMenu.label;"
             accesskey="&social.markpageMenu.accesskey;">
         <menupopup/>
       </menu>
       <menuseparator id="context-sep-viewbgimage"/>
       <menuitem id="context-viewbgimage"
                 label="&viewBGImageCmd.label;"
                 accesskey="&viewBGImageCmd.accesskey;"
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -408,31 +408,24 @@
 #ifndef XP_MACOSX
                placespopup="true"
 #endif
                context="placesContext"
                openInTabs="children"
                oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
                onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
                onpopupshowing="BookmarkingUI.onMainMenuPopupShowing(event);
-                               BookmarkingUI.updatePocketItemVisibility('menu_');
                                if (!this.parentNode._placesView)
                                  new PlacesMenu(event, 'place:folder=BOOKMARKS_MENU');"
                tooltip="bhTooltip" popupsinherittooltip="true">
       <menuitem id="bookmarksShowAll"
                 label="&showAllBookmarks2.label;"
                 command="Browser:ShowAllBookmarks"
                 key="manBookmarkKb"/>
       <menuseparator id="organizeBookmarksSeparator"/>
-      <menuitem id="menu_pocket" label="&pocketMenuitem.label;"
-#ifndef XP_MACOSX
-                class="menuitem-iconic"
-#endif
-                oncommand="openUILink(Pocket.listURL, event);"/>
-      <menuseparator id="menu_pocketSeparator"/>
       <menuitem id="menu_bookmarkThisPage"
                 command="Browser:AddBookmarkAs"
                 observes="bookmarkThisPageBroadcaster"
                 key="addBookmarkAsKb"/>
       <menuitem id="subscribeToPageMenuitem"
 #ifndef XP_MACOSX
                 class="menuitem-iconic"
 #endif
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1549,22 +1549,16 @@ var BookmarkingUI = {
     }
   },
 
   onMainMenuPopupShowing: function BUI_onMainMenuPopupShowing(event) {
     this._updateBookmarkPageMenuItem();
     PlacesCommandHook.updateBookmarkAllTabsCommand();
   },
 
-  updatePocketItemVisibility: function BUI_updatePocketItemVisibility(prefix) {
-    let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button");
-    document.getElementById(prefix + "pocket").hidden = hidden;
-    document.getElementById(prefix + "pocketSeparator").hidden = hidden;
-  },
-
   _showBookmarkedNotification: function BUI_showBookmarkedNotification() {
     function getCenteringTransformForRects(rectToPosition, referenceRect) {
       let topDiff = referenceRect.top - rectToPosition.top;
       let leftDiff = referenceRect.left - rectToPosition.left;
       let heightDiff = referenceRect.height - rectToPosition.height;
       let widthDiff = referenceRect.width - rectToPosition.width;
       return [(leftDiff + .5 * widthDiff) + "px", (topDiff + .5 * heightDiff) + "px"];
     }
@@ -1676,17 +1670,16 @@ var BookmarkingUI = {
       case "ViewHiding":
         this.onPanelMenuViewHiding(aEvent);
         break;
     }
   },
 
   onPanelMenuViewShowing: function BUI_onViewShowing(aEvent) {
     this._updateBookmarkPageMenuItem();
-    this.updatePocketItemVisibility("panelMenu_");
     // Update checked status of the toolbar toggle.
     let viewToolbar = document.getElementById("panelMenu_viewBookmarksToolbar");
     let personalToolbar = document.getElementById("PersonalToolbar");
     if (personalToolbar.collapsed)
       viewToolbar.removeAttribute("checked");
     else
       viewToolbar.setAttribute("checked", "true");
     // Get all statically placed buttons to supply them with keyboard shortcuts.
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -1343,19 +1343,18 @@ SocialMarks = {
     }
   },
 
   getProviders: function() {
     // only rely on providers that the user has placed in the UI somewhere. This
     // also means that populateToolbarPalette must be called prior to using this
     // method, otherwise you get a big fat zero. For our use case with context
     // menu's, this is ok.
-    let tbh = this._toolbarHelper;
     return [p for (p of Social.providers) if (p.markURL &&
-                                              document.getElementById(tbh.idFromOrigin(p.origin)))];
+                                              document.getElementById(this._toolbarHelper.idFromOrigin(p.origin)))];
   },
 
   populateContextMenu: function() {
     // only show a selection if enabled and there is more than one
     let providers = this.getProviders();
 
     // remove all previous entries by class
     let menus = [m for (m of document.getElementsByClassName("context-socialmarks"))];
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -48,47 +48,16 @@ XPCOMUtils.defineLazyServiceGetter(this,
                                    "mozIAsyncFavicons");
 XPCOMUtils.defineLazyServiceGetter(this, "gDNSService",
                                    "@mozilla.org/network/dns-service;1",
                                    "nsIDNSService");
 XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
                                    "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
-                                  "resource:///modules/Pocket.jsm");
-
-// Can't use XPCOMUtils for these because the scripts try to define the variables
-// on window, and so the defineProperty inside defineLazyGetter fails.
-Object.defineProperty(window, "pktApi", {
-  get: function() {
-    // Avoid this getter running again:
-    delete window.pktApi;
-    Services.scriptloader.loadSubScript("chrome://browser/content/pocket/pktApi.js", window);
-    return window.pktApi;
-  },
-  configurable: true,
-  enumerable: true
-});
-
-function pktUIGetter(prop) {
-  return {
-    get: function() {
-      // Avoid either of these getters running again:
-      delete window.pktUI;
-      delete window.pktUIMessaging;
-      Services.scriptloader.loadSubScript("chrome://browser/content/pocket/main.js", window);
-      return window[prop];
-    },
-    configurable: true,
-    enumerable: true
-  };
-}
-Object.defineProperty(window, "pktUI", pktUIGetter("pktUI"));
-Object.defineProperty(window, "pktUIMessaging", pktUIGetter("pktUIMessaging"));
 
 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
   return Services.strings.createBundle('chrome://browser/locale/browser.properties');
 });
 
 const nsIWebNavigation = Ci.nsIWebNavigation;
 
 var gLastBrowserCharset = null;
@@ -7092,16 +7061,19 @@ var gIdentityHandler = {
       host = this.getEffectiveHost();
     } catch (e) {
       // Some URIs might have no hosts.
     }
 
     // Fallback for special protocols.
     if (!host) {
       host = this._uri.specIgnoringRef;
+      // Special URIs without a host (eg, about:) should crop the end so
+      // the protocol can be seen.
+      crop = "end";
     }
 
     // Fill in the CA name if we have a valid TLS certificate.
     if (this._isSecure) {
       verifier = this._identityBox.tooltipText;
     }
 
     // Fill in organization information if we have a valid EV certificate.
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -615,19 +615,19 @@
            to the default placements of buttons in CustomizableUI.jsm, so the
            customization code doesn't get confused.
       -->
     <toolbar id="nav-bar"
              aria-label="&navbarCmd.label;"
              fullscreentoolbar="true" mode="icons" customizable="true"
              iconsize="small"
 #ifdef MOZ_DEV_EDITION
-             defaultset="urlbar-container,search-container,developer-button,bookmarks-menu-button,pocket-button,downloads-button,home-button,loop-button"
+             defaultset="urlbar-container,search-container,developer-button,bookmarks-menu-button,downloads-button,home-button,loop-button"
 #else
-             defaultset="urlbar-container,search-container,bookmarks-menu-button,pocket-button,downloads-button,home-button,loop-button"
+             defaultset="urlbar-container,search-container,bookmarks-menu-button,downloads-button,home-button,loop-button"
 #endif
              customizationtarget="nav-bar-customization-target"
              overflowable="true"
              overflowbutton="nav-bar-overflow-button"
              overflowtarget="widget-overflow-list"
              overflowpanel="widget-overflow"
              context="toolbar-context-menu">
 
@@ -793,38 +793,32 @@
           <menupopup id="BMB_bookmarksPopup"
                      class="cui-widget-panel cui-widget-panelview cui-widget-panelWithFooter PanelUI-subView"
                      placespopup="true"
                      context="placesContext"
                      openInTabs="children"
                      oncommand="BookmarksEventHandler.onCommand(event, this.parentNode._placesView);"
                      onclick="BookmarksEventHandler.onClick(event, this.parentNode._placesView);"
                      onpopupshowing="BookmarkingUI.onPopupShowing(event);
-                                     BookmarkingUI.updatePocketItemVisibility('BMB_');
                                      BookmarkingUI.attachPlacesView(event, this);"
                      tooltip="bhTooltip" popupsinherittooltip="true">
             <menuitem id="BMB_viewBookmarksSidebar"
                       class="subviewbutton"
                       label="&viewBookmarksSidebar2.label;"
                       type="checkbox"
                       oncommand="SidebarUI.toggle('viewBookmarksSidebar');">
               <observes element="viewBookmarksSidebar" attribute="checked"/>
             </menuitem>
             <!-- NB: temporary solution for bug 985024, this should go away soon. -->
             <menuitem id="BMB_bookmarksShowAllTop"
                       class="menuitem-iconic subviewbutton"
                       label="&showAllBookmarks2.label;"
                       command="Browser:ShowAllBookmarks"
                       key="manBookmarkKb"/>
             <menuseparator/>
-            <menuitem id="BMB_pocket"
-                      class="menuitem-iconic bookmark-item subviewbutton"
-                      label="&pocketMenuitem.label;"
-                      oncommand="openUILink(Pocket.listURL, event);"/>
-            <menuseparator id="BMB_pocketSeparator"/>
             <menuitem id="BMB_subscribeToPageMenuitem"
 #ifndef XP_MACOSX
                       class="menuitem-iconic subviewbutton"
 #else
                       class="subviewbutton"
 #endif
                       label="&subscribeToPageMenuitem.label;"
                       oncommand="return FeedHandler.subscribeToFeed(null, event);"
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -6,20 +6,16 @@
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
 Components.utils.import("resource://gre/modules/LoginManagerContextMenu.jsm");
 Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 
-XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
-  "resource:///modules/CustomizableUI.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
-  "resource:///modules/Pocket.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
   "resource://gre/modules/LoginHelper.jsm");
 
 var gContextMenuContentData = null;
 
 function nsContextMenu(aXulMenu, aIsShift) {
   this.shouldDisplay = true;
   this.initMenu(aXulMenu, aIsShift);
@@ -211,35 +207,16 @@ nsContextMenu.prototype = {
     // SimpleServiceDiscovery.services), but SimpleServiceDiscovery is guaranteed
     // to be already loaded, since we load it on startup in nsBrowserGlue,
     // and CastingApps isn't, so check SimpleServiceDiscovery.services first
     // to avoid needing to load CastingApps.jsm if we don't need to.
     shouldShowCast = shouldShowCast && this.mediaURL &&
                      SimpleServiceDiscovery.services.length > 0 &&
                      CastingApps.getServicesForVideo(this.target).length > 0;
     this.setItemAttr("context-castvideo", "disabled", !shouldShowCast);
-
-    this.initPocketItems();
-  },
-
-  initPocketItems: function CM_initPocketItems() {
-    var showSaveCurrentPageToPocket = !(this.onTextInput || this.onLink ||
-                                        this.isContentSelected || this.onImage ||
-                                        this.onCanvas || this.onVideo || this.onAudio);
-    let targetURI = (this.onSaveableLink || this.onPlainTextLink) ? this.linkURI : this.browser.currentURI;
-    let canPocket = CustomizableUI.getPlacementOfWidget("pocket-button") &&
-                    window.pktApi && window.pktApi.isUserLoggedIn();
-    canPocket = canPocket && (targetURI.schemeIs("http") || targetURI.schemeIs("https") ||
-                              (targetURI.schemeIs("about") && ReaderMode.getOriginalUrl(targetURI.spec)));
-    canPocket = canPocket && window.gBrowser && this.browser.getTabBrowser() == window.gBrowser;
-
-    this.showItem("context-pocket", canPocket && showSaveCurrentPageToPocket);
-    let showSaveLinkToPocket = canPocket && !showSaveCurrentPageToPocket &&
-                               (this.onSaveableLink || this.onPlainTextLink);
-    this.showItem("context-savelinktopocket", showSaveLinkToPocket);
   },
 
   initViewItems: function CM_initViewItems() {
     // View source is always OK, unless in directory listing.
     this.showItem("context-viewpartialsource-selection",
                   this.isContentSelected);
     this.showItem("context-viewpartialsource-mathml",
                   this.onMathML && !this.isContentSelected);
@@ -1716,24 +1693,16 @@ nsContextMenu.prototype = {
   shareSelect: function CM_shareSelect() {
     SocialShare.sharePage(null, { url: this.browser.currentURI.spec, text: this.textSelected }, this.target);
   },
 
   savePageAs: function CM_savePageAs() {
     saveBrowser(this.browser);
   },
 
-  saveLinkToPocket: function CM_saveLinkToPocket() {
-    Pocket.savePage(this.browser, this.linkURL);
-  },
-
-  savePageToPocket: function CM_saveToPocket() {
-    Pocket.savePage(this.browser, this.browser.currentURI.spec, this.browser.contentTitle);
-  },
-
   printFrame: function CM_printFrame() {
     PrintUtils.printWindow(this.frameOuterWindowID, this.browser);
   },
 
   switchPageDirection: function CM_switchPageDirection() {
     this.browser.messageManager.sendAsyncMessage("SwitchDocumentDirection");
   },
 
--- a/browser/base/content/test/social/browser_addons.js
+++ b/browser/base/content/test/social/browser_addons.js
@@ -7,25 +7,25 @@ var manifest = {
   sidebarURL: "https://example.com/browser/browser/base/content/test/social/social_sidebar_empty.html",
   iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png"
 };
 var manifest2 = { // used for testing install
   name: "provider 2",
   origin: "https://test1.example.com",
   sidebarURL: "https://test1.example.com/browser/browser/base/content/test/social/social_sidebar_empty.html",
   iconURL: "https://test1.example.com/browser/browser/base/content/test/general/moz.png",
-  version: 1
+  version: "1.0"
 };
 var manifestUpgrade = { // used for testing install
   name: "provider 3",
   origin: "https://test2.example.com",
   sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html",
   workerURL: "https://test2.example.com/browser/browser/base/content/test/social/social_worker.js",
   iconURL: "https://test2.example.com/browser/browser/base/content/test/general/moz.png",
-  version: 1
+  version: "1.0"
 };
 
 function test() {
   waitForExplicitFinish();
 
   let prefname = getManifestPrefname(manifest);
   // ensure that manifest2 is NOT showing as builtin
   is(SocialService.getOriginActivationType(manifest.origin), "foreign", "manifest is foreign");
--- a/browser/base/content/test/social/browser_share.js
+++ b/browser/base/content/test/social/browser_share.js
@@ -43,17 +43,16 @@ function test() {
     Services.prefs.clearUserPref("social.share.activationPanelEnabled");
   });
   runSocialTests(tests, undefined, function(next) {
     let shareButton = SocialShare.shareButton;
     if (shareButton) {
       CustomizableUI.removeWidgetFromArea("social-share-button", CustomizableUI.AREA_NAVBAR)
       shareButton.remove();
     }
-    ok(CustomizableUI.inDefaultState, "Should start in default state.");
     next();
   });
 }
 
 var corpus = [
   {
     url: baseURL+"opengraph/opengraph.html",
     options: {
--- a/browser/base/content/test/social/browser_social_contextmenu.js
+++ b/browser/base/content/test/social/browser_social_contextmenu.js
@@ -8,17 +8,17 @@ var manifest = { // used for testing ins
   name: "provider test1",
   origin: "https://test1.example.com",
   workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
   markURL: "https://test1.example.com/browser/browser/base/content/test/social/social_mark.html?url=%{url}",
   markedIcon: "https://test1.example.com/browser/browser/base/content/test/social/unchecked.jpg",
   unmarkedIcon: "https://test1.example.com/browser/browser/base/content/test/social/checked.jpg",
 
   iconURL: "https://test1.example.com/browser/browser/base/content/test/general/moz.png",
-  version: 1
+  version: "1.0"
 };
 
 function test() {
   waitForExplicitFinish();
 
   runSocialTestWithProvider(manifest, function (finishcb) {
     runSocialTests(tests, undefined, undefined, function () {
       finishcb();
--- a/browser/base/content/test/social/browser_social_marks.js
+++ b/browser/base/content/test/social/browser_social_marks.js
@@ -8,35 +8,30 @@ var manifest2 = { // used for testing in
   name: "provider test1",
   origin: "https://test1.example.com",
   workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
   markURL: "https://test1.example.com/browser/browser/base/content/test/social/social_mark.html?url=%{url}",
   markedIcon: "https://test1.example.com/browser/browser/base/content/test/social/unchecked.jpg",
   unmarkedIcon: "https://test1.example.com/browser/browser/base/content/test/social/checked.jpg",
 
   iconURL: "https://test1.example.com/browser/browser/base/content/test/general/moz.png",
-  version: 1
+  version: "1.0"
 };
 var manifest3 = { // used for testing install
   name: "provider test2",
   origin: "https://test2.example.com",
   sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html",
   iconURL: "https://test2.example.com/browser/browser/base/content/test/general/moz.png",
-  version: 1
+  version: "1.0"
 };
 
 function test() {
   waitForExplicitFinish();
 
-  runSocialTests(tests, undefined, undefined, function () {
-    // Bug 1232207 - something breaks this on aurora on most platforms
-    // ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish");
-    CustomizableUI.reset();
-    finish();
-  });
+  runSocialTests(tests, undefined, undefined, finish);
 }
 
 var tests = {
   testButtonDisabledOnActivate: function(next) {
     // starting on about:blank page, share should be visible but disabled when
     // adding provider
     is(gBrowser.selectedBrowser.currentURI.spec, "about:blank");
     SocialService.addProvider(manifest2, function(provider) {
--- a/browser/base/content/test/social/browser_social_marks_context.js
+++ b/browser/base/content/test/social/browser_social_marks_context.js
@@ -3,28 +3,24 @@ var SocialService = Cu.import("resource:
 function makeMarkProvider(origin) {
   return { // used for testing install
     name: "mark provider " + origin,
     origin: "https://" + origin + ".example.com",
     markURL: "https://" + origin + ".example.com/browser/browser/base/content/test/social/social_mark.html?url=%{url}",
     markedIcon: "https://" + origin + ".example.com/browser/browser/base/content/test/social/unchecked.jpg",
     unmarkedIcon: "https://" + origin + ".example.com/browser/browser/base/content/test/social/checked.jpg",
     iconURL: "https://" + origin + ".example.com/browser/browser/base/content/test/general/moz.png",
-    version: 1
+    version: "1.0"
   }
 }
 
 function test() {
   waitForExplicitFinish();
 
-  runSocialTests(tests, undefined, undefined, function () {
-    ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish");
-    CustomizableUI.reset();
-    finish();
-  });
+  runSocialTests(tests, undefined, undefined, finish);
 }
 
 var tests = {
   testContextSubmenu: function(next) {
     // install 4 providers to test that the menu's are added as submenus
     let manifests = [
       makeMarkProvider("sub1.test1"),
       makeMarkProvider("sub2.test1"),
--- a/browser/base/content/test/social/browser_social_status.js
+++ b/browser/base/content/test/social/browser_social_status.js
@@ -12,24 +12,24 @@ var manifest = { // builtin provider
   iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png"
 };
 var manifest2 = { // used for testing install
   name: "provider test1",
   origin: "https://test1.example.com",
   workerURL: "https://test1.example.com/browser/browser/base/content/test/social/social_worker.js",
   statusURL: "https://test1.example.com/browser/browser/base/content/test/social/social_panel.html",
   iconURL: "https://test1.example.com/browser/browser/base/content/test/general/moz.png",
-  version: 1
+  version: "1.0"
 };
 var manifest3 = { // used for testing install
   name: "provider test2",
   origin: "https://test2.example.com",
   sidebarURL: "https://test2.example.com/browser/browser/base/content/test/social/social_sidebar.html",
   iconURL: "https://test2.example.com/browser/browser/base/content/test/general/moz.png",
-  version: 1
+  version: "1.0"
 };
 
 
 function openWindowAndWaitForInit(callback) {
   let topic = "browser-delayed-startup-finished";
   let w = OpenBrowserWindow();
   Services.obs.addObserver(function providerSet(subject, topic, data) {
     Services.obs.removeObserver(providerSet, topic);
@@ -40,17 +40,16 @@ function openWindowAndWaitForInit(callba
 function test() {
   waitForExplicitFinish();
 
   runSocialTestWithProvider(manifest, function (finishcb) {
     runSocialTests(tests, undefined, undefined, function () {
       Services.prefs.clearUserPref("social.remote-install.enabled");
       // just in case the tests failed, clear these here as well
       Services.prefs.clearUserPref("social.whitelist");
-      ok(CustomizableUI.inDefaultState, "Should be in the default state when we finish");
       CustomizableUI.reset();
       finishcb();
     });
   });
 }
 
 var tests = {
   testNoButtonOnEnable: function(next) {
--- a/browser/base/content/test/social/social_activate.html
+++ b/browser/base/content/test/social/social_activate.html
@@ -17,17 +17,17 @@ var data = {
   "statusURL": "/browser/browser/base/content/test/social/social_panel.html",
   "postActivationURL": "/browser/browser/base/content/test/social/social_postActivation.html",
 
   // should be available for display purposes
   "description": "A short paragraph about this provider",
   "author": "Shane Caraveo, Mozilla",
 
   // optional
-  "version": 1
+  "version": "1.0"
 }
 
 function activate(node) {
   node.setAttribute("data-service", JSON.stringify(data));
   var event = new CustomEvent("ActivateSocialFeature");
   node.dispatchEvent(event);
 }
 
--- a/browser/base/content/test/social/social_activate_basic.html
+++ b/browser/base/content/test/social/social_activate_basic.html
@@ -15,17 +15,17 @@ var data = {
   "sidebarURL": "/browser/browser/base/content/test/social/social_sidebar_empty.html",
   "postActivationURL": "/browser/browser/base/content/test/social/social_postActivation.html",
 
   // should be available for display purposes
   "description": "A short paragraph about this provider",
   "author": "Shane Caraveo, Mozilla",
 
   // optional
-  "version": 1
+  "version": "1.0"
 }
 
 function activate(node) {
   node.setAttribute("data-service", JSON.stringify(data));
   var event = new CustomEvent("ActivateSocialFeature");
   node.dispatchEvent(event);
 }
 
--- a/browser/base/content/test/social/social_worker.js
+++ b/browser/base/content/test/social/social_worker.js
@@ -121,17 +121,17 @@ onconnect = function(e) {
         break;
       case "worker.update":
         updatingManifest = true;
         apiPort.postMessage({topic: 'social.manifest-get'});
         break;
       case "social.manifest":
         if (updatingManifest) {
           updatingManifest = false;
-          event.data.data.version = 2;
+          event.data.data.version = "2.0";
           apiPort.postMessage({topic: 'social.manifest-set', data: event.data.data});
         } else if (testPort) {
           testPort.postMessage({topic:"social.manifest", data: event.data.data});
         }
         break;
     }
   }
 }
--- a/browser/components/about/AboutRedirector.cpp
+++ b/browser/components/about/AboutRedirector.cpp
@@ -121,28 +121,16 @@ static RedirEntry kRedirMap[] = {
     // Shares an IndexedDB origin with about:loopconversation.
     "loopconversation" },
   { "reader", "chrome://global/content/reader/aboutReader.html",
     nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
     nsIAboutModule::ALLOW_SCRIPT |
     nsIAboutModule::URI_MUST_LOAD_IN_CHILD |
     nsIAboutModule::MAKE_UNLINKABLE |
     nsIAboutModule::HIDE_FROM_ABOUTABOUT },
-  {
-    "pocket-saved", "chrome://browser/content/pocket/panels/saved.html",
-    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
-    nsIAboutModule::ALLOW_SCRIPT |
-    nsIAboutModule::HIDE_FROM_ABOUTABOUT |
-    nsIAboutModule::MAKE_UNLINKABLE },
-  {
-    "pocket-signup", "chrome://browser/content/pocket/panels/signup.html",
-    nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
-    nsIAboutModule::ALLOW_SCRIPT |
-    nsIAboutModule::HIDE_FROM_ABOUTABOUT |
-    nsIAboutModule::MAKE_UNLINKABLE },
 };
 static const int kRedirTotal = ArrayLength(kRedirMap);
 
 static nsAutoCString
 GetAboutModuleName(nsIURI *aURI)
 {
   nsAutoCString path;
   aURI->GetPath(path);
--- a/browser/components/build/nsModule.cpp
+++ b/browser/components/build/nsModule.cpp
@@ -112,18 +112,16 @@ static const mozilla::Module::ContractID
 #ifdef MOZ_SERVICES_HEALTHREPORT
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "healthreport", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #endif
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "customizing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "debugging", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "looppanel", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "loopconversation", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
     { NS_ABOUT_MODULE_CONTRACTID_PREFIX "reader", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-saved", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
-    { NS_ABOUT_MODULE_CONTRACTID_PREFIX "pocket-signup", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
 #if defined(XP_WIN)
     { NS_IEHISTORYENUMERATOR_CONTRACTID, &kNS_WINIEHISTORYENUMERATOR_CID },
     { NS_EDGEREADINGLISTEXTRACTOR_CONTRACTID, &kNS_EDGEREADINGLISTEXTRACTOR_CID },
 #elif defined(XP_MACOSX)
     { NS_SHELLSERVICE_CONTRACTID, &kNS_SHELLSERVICE_CID },
 #endif
     { nullptr }
 };
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -51,25 +51,26 @@ const kSubviewEvents = [
   "ViewShowing",
   "ViewHiding"
 ];
 
 /**
  * The current version. We can use this to auto-add new default widgets as necessary.
  * (would be const but isn't because of testing purposes)
  */
-var kVersion = 5;
+var kVersion = 6;
 
 /**
  * Buttons removed from built-ins by version they were removed. kVersion must be
  * bumped any time a new id is added to this. Use the button id as key, and
  * version the button is removed in as the value.  e.g. "pocket-button": 5
  */
 var ObsoleteBuiltinButtons = {
-  "loop-button": 5
+  "loop-button": 5,
+  "pocket-button": 6
 };
 
 /**
  * gPalette is a map of every widget that CustomizableUI.jsm knows about, keyed
  * on their IDs.
  */
 var gPalette = new Map();
 
@@ -217,25 +218,16 @@ var CustomizableUIInternal = {
       "developer-button",
 #endif
       "bookmarks-menu-button",
       "downloads-button",
       "home-button",
       "loop-button",
     ];
 
-    // Insert the Pocket button after the bookmarks button if it's present.
-    for (let widgetDefinition of CustomizableWidgets) {
-      if (widgetDefinition.id == "pocket-button") {
-        let idx = navbarPlacements.indexOf("bookmarks-menu-button") + 1;
-        navbarPlacements.splice(idx, 0, widgetDefinition.id);
-        break;
-      }
-    }
-
     if (Services.prefs.getBoolPref(kPrefWebIDEInNavbar)) {
       navbarPlacements.push("webide-button");
     }
 
     this.registerArea(CustomizableUI.AREA_NAVBAR, {
       legacy: true,
       type: CustomizableUI.TYPE_TOOLBAR,
       overflowable: true,
@@ -3468,18 +3460,18 @@ this.CustomizableUI = {
    *     position: 42 // the index in the placements array corresponding to
    *                  // your widget.
    *   }
    *
    *   OR
    *
    *   null // if the widget is not placed anywhere (ie in the palette)
    */
-  getPlacementOfWidget: function(aWidgetId) {
-    return CustomizableUIInternal.getPlacementOfWidget(aWidgetId, true);
+  getPlacementOfWidget: function(aWidgetId, aOnlyRegistered=true, aDeadAreas=false) {
+    return CustomizableUIInternal.getPlacementOfWidget(aWidgetId, aOnlyRegistered, aDeadAreas);
   },
   /**
    * Check if a widget can be removed from the area it's in.
    *
    * Note that if you're wanting to move the widget somewhere, you should
    * generally be checking canWidgetMoveToArea, because that will return
    * true if the widget is already in the area where you want to move it (!).
    *
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -13,28 +13,22 @@ Cu.import("resource://gre/modules/XPCOMU
 XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
   "resource:///modules/BrowserUITelemetry.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
   "resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUIUtils",
   "resource:///modules/PlacesUIUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "RecentlyClosedTabsAndWindowsMenuUtils",
   "resource:///modules/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
-  "resource:///modules/Pocket.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShortcutUtils",
   "resource://gre/modules/ShortcutUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "CharsetMenu",
   "resource://gre/modules/CharsetMenu.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
-  "resource://gre/modules/AddonManager.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
-  "resource://gre/modules/SocialService.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "SyncedTabs",
   "resource://services-sync/SyncedTabs.jsm");
 
 XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() {
   const kCharsetBundle = "chrome://global/locale/charsetMenu.properties";
   return Services.strings.createBundle(kCharsetBundle);
 });
 XPCOMUtils.defineLazyGetter(this, "BrandBundle", function() {
@@ -1220,78 +1214,16 @@ if (Services.prefs.getBoolPref("privacy.
     },
     onViewHiding: function(aEvent) {
       let forgetButton = aEvent.target.querySelector("#PanelUI-panic-view-button");
       forgetButton.removeEventListener("command", this);
     },
   });
 }
 
-if (Services.prefs.getBoolPref("browser.pocket.enabled")) {
-  let isEnabledForLocale = true;
-  if (Services.prefs.getBoolPref("browser.pocket.useLocaleList")) {
-    let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"]
-                           .getService(Ci.nsIXULChromeRegistry);
-    let browserLocale = chromeRegistry.getSelectedLocale("browser");
-    let enabledLocales = [];
-    try {
-      enabledLocales = Services.prefs.getCharPref("browser.pocket.enabledLocales").split(' ');
-    } catch (ex) {
-      Cu.reportError(ex);
-    }
-    isEnabledForLocale = enabledLocales.indexOf(browserLocale) != -1;
-  }
-
-  if (isEnabledForLocale) {
-    let pocketButton = {
-      id: "pocket-button",
-      defaultArea: CustomizableUI.AREA_NAVBAR,
-      introducedInVersion: "pref",
-      type: "view",
-      viewId: "PanelUI-pocketView",
-      // Use forwarding functions here to avoid loading Pocket.jsm on startup:
-      onViewShowing: function() {
-        return Pocket.onPanelViewShowing.apply(this, arguments);
-      },
-      onViewHiding: function() {
-        return Pocket.onPanelViewHiding.apply(this, arguments);
-      },
-
-      // If the user has the "classic" Pocket add-on installed, use that instead
-      // and destroy the widget.
-      conditionalDestroyPromise: new Promise(resolve => {
-        AddonManager.getAddonByID("isreaditlater@ideashower.com", addon => {
-          resolve(addon && addon.isActive);
-        });
-      }),
-    };
-
-    CustomizableWidgets.push(pocketButton);
-    CustomizableUI.addListener(pocketButton);
-
-    // Uninstall the Pocket social provider if it exists, but only if we haven't
-    // already uninstalled it in this manner.  That way the user can reinstall
-    // it if they prefer it without its being uninstalled every time they start
-    // the browser.
-    let origin = "https://getpocket.com";
-    SocialService.getProvider(origin, provider => {
-      if (provider) {
-        let pref = "social.backup.getpocket-com";
-        if (!Services.prefs.prefHasUserValue(pref)) {
-          let str = Cc["@mozilla.org/supports-string;1"].
-                    createInstance(Ci.nsISupportsString);
-          str.data = JSON.stringify(provider.manifest);
-          Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str);
-          SocialService.uninstallProvider(origin, () => {});
-        }
-      }
-    });
-  }
-}
-
 #ifdef E10S_TESTING_ONLY
 var e10sDisabled = false;
 #ifdef XP_MACOSX
 // On OS X, "Disable Hardware Acceleration" also disables OMTC and forces
 // a fallback to Basic Layers. This is incompatible with e10s.
 e10sDisabled |= Services.prefs.getBoolPref("layers.acceleration.disabled");
 #endif
 
--- a/browser/components/customizableui/content/panelUI.inc.xul
+++ b/browser/components/customizableui/content/panelUI.inc.xul
@@ -186,20 +186,16 @@
     <panelview id="PanelUI-bookmarks" flex="1" class="PanelUI-subView">
       <label value="&bookmarksMenu.label;" class="panel-subview-header"/>
       <vbox class="panel-subview-body">
         <toolbarbutton id="panelMenuBookmarkThisPage"
                        class="subviewbutton"
                        observes="bookmarkThisPageBroadcaster"
                        command="Browser:AddBookmarkAs"
                        onclick="PanelUI.hide();"/>
-        <toolbarseparator id="panelMenu_pocketSeparator"/>
-        <toolbarbutton id="panelMenu_pocket" label="&pocketMenuitem.label;"
-                       class="subviewbutton cui-withicon"
-                       oncommand="openUILink(Pocket.listURL, event);"/>
         <toolbarseparator/>
         <toolbarbutton id="panelMenu_viewBookmarksSidebar"
                        label="&viewBookmarksSidebar2.label;"
                        class="subviewbutton"
                        key="viewBookmarksSidebarKb"
                        oncommand="SidebarUI.toggle('viewBookmarksSidebar'); PanelUI.hide();">
           <observes element="viewBookmarksSidebar" attribute="checked"/>
         </toolbarbutton>
@@ -305,22 +301,16 @@
 
           <label id="PanelUI-panic-warning">&panicButton.view.undoWarning;</label>
         </vbox>
         <button id="PanelUI-panic-view-button"
                 label="&panicButton.view.forgetButton;"/>
       </vbox>
     </panelview>
 
-    <panelview id="PanelUI-pocketView" flex="1">
-      <vbox class="panel-subview-body">
-      </vbox>
-    </panelview>
-
-
   </panelmultiview>
   <!-- These menupopups are located here to prevent flickering,
        see bug 492960 comment 20. -->
   <menupopup id="customizationPanelItemContextMenu">
     <menuitem oncommand="gCustomizeMode.addToToolbar(document.popupNode)"
               closemenu="single"
               class="customize-context-moveToToolbar"
               accesskey="&customizeMenu.moveToToolbar.accesskey;"
--- a/browser/components/moz.build
+++ b/browser/components/moz.build
@@ -10,17 +10,16 @@ DIRS += [
     'customizableui',
     'dirprovider',
     'downloads',
     'extensions',
     'feeds',
     'migration',
     'newtab',
     'places',
-    'pocket',
     'preferences',
     'privatebrowsing',
     'search',
     'sessionstore',
     'shell',
     'selfsupport',
     'uitour',
     'translation',
deleted file mode 100644
--- a/browser/components/pocket/jar.mn
+++ /dev/null
@@ -1,48 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-browser.jar:
-  content/browser/pocket/main.js
-  content/browser/pocket/pktApi.js
-  content/browser/pocket/panels/saved.html       (panels/saved.html)
-  content/browser/pocket/panels/signup.html      (panels/signup.html)
-  content/browser/pocket/panels/css/normalize.css       (panels/css/normalize.css)
-  content/browser/pocket/panels/css/firasans.css        (panels/css/firasans.css)
-  content/browser/pocket/panels/css/saved.css           (panels/css/saved.css)
-  content/browser/pocket/panels/css/signup.css           (panels/css/signup.css)
-  content/browser/pocket/panels/fonts/FiraSans-Regular.woff (panels/fonts/FiraSans-Regular.woff)
-  content/browser/pocket/panels/img/pocketerror@1x.png             (panels/img/pocketerror@1x.png)
-  content/browser/pocket/panels/img/pocketerror@2x.png             (panels/img/pocketerror@2x.png)
-  content/browser/pocket/panels/img/pocketlogo@1x.png              (panels/img/pocketlogo@1x.png)
-  content/browser/pocket/panels/img/pocketlogo@2x.png              (panels/img/pocketlogo@2x.png)
-  content/browser/pocket/panels/img/pocketlogosolo@1x.png          (panels/img/pocketlogosolo@1x.png)
-  content/browser/pocket/panels/img/pocketlogosolo@2x.png          (panels/img/pocketlogosolo@2x.png)
-  content/browser/pocket/panels/img/pocketmenuitem16.png           (panels/img/pocketmenuitem16.png)
-  content/browser/pocket/panels/img/pocketmenuitem16@2x.png        (panels/img/pocketmenuitem16@2x.png)
-  content/browser/pocket/panels/img/pocketsignup_button@1x.png     (panels/img/pocketsignup_button@1x.png)
-  content/browser/pocket/panels/img/pocketsignup_button@2x.png     (panels/img/pocketsignup_button@2x.png)
-  content/browser/pocket/panels/img/pocketsignup_devices@1x.png    (panels/img/pocketsignup_devices@1x.png)
-  content/browser/pocket/panels/img/pocketsignup_devices@2x.png    (panels/img/pocketsignup_devices@2x.png)
-  content/browser/pocket/panels/img/pocketsignup_hero@1x.png       (panels/img/pocketsignup_hero@1x.png)
-  content/browser/pocket/panels/img/pocketsignup_hero@2x.png       (panels/img/pocketsignup_hero@2x.png)
-  content/browser/pocket/panels/img/signup_firefoxlogo@1x.png      (panels/img/signup_firefoxlogo@1x.png)
-  content/browser/pocket/panels/img/signup_firefoxlogo@2x.png      (panels/img/signup_firefoxlogo@2x.png)
-  content/browser/pocket/panels/img/signup_help@1x.png             (panels/img/signup_help@1x.png)
-  content/browser/pocket/panels/img/signup_help@2x.png             (panels/img/signup_help@2x.png)
-  content/browser/pocket/panels/img/tag_close@1x.png               (panels/img/tag_close@1x.png)
-  content/browser/pocket/panels/img/tag_close@2x.png               (panels/img/tag_close@2x.png)
-  content/browser/pocket/panels/img/tag_closeactive@1x.png         (panels/img/tag_closeactive@1x.png)
-  content/browser/pocket/panels/img/tag_closeactive@2x.png         (panels/img/tag_closeactive@2x.png)
-  content/browser/pocket/panels/js/messages.js                     (panels/js/messages.js)
-  content/browser/pocket/panels/js/saved.js                        (panels/js/saved.js)
-  content/browser/pocket/panels/js/signup.js                       (panels/js/signup.js)
-  content/browser/pocket/panels/js/tmpl.js                         (panels/js/tmpl.js)
-  content/browser/pocket/panels/js/vendor/jquery-2.1.1.min.js      (panels/js/vendor/jquery-2.1.1.min.js)
-  content/browser/pocket/panels/js/vendor/handlebars.runtime.js    (panels/js/vendor/handlebars.runtime.js)
-  content/browser/pocket/panels/js/vendor/jquery.tokeninput.min.js (panels/js/vendor/jquery.tokeninput.min.js)
-  content/browser/pocket/panels/tmpl/saved_premiumextras.handlebars (panels/tmpl/saved_premiumextras.handlebars)
-  content/browser/pocket/panels/tmpl/saved_premiumshell.handlebars (panels/tmpl/saved_premiumshell.handlebars)
-  content/browser/pocket/panels/tmpl/saved_shell.handlebars        (panels/tmpl/saved_shell.handlebars)
-  content/browser/pocket/panels/tmpl/signup_shell.handlebars       (panels/tmpl/signup_shell.handlebars)
-  content/browser/pocket/panels/tmpl/signupstoryboard_shell.handlebars (panels/tmpl/signupstoryboard_shell.handlebars)
deleted file mode 100644
--- a/browser/components/pocket/moz.build
+++ /dev/null
@@ -1,7 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-JAR_MANIFESTS += ['jar.mn']
-
-EXTRA_JS_MODULES += ['Pocket.jsm']
--- a/browser/components/uitour/test/browser_UITour_availableTargets.js
+++ b/browser/components/uitour/test/browser_UITour_availableTargets.js
@@ -4,35 +4,17 @@
 "use strict";
 
 var gTestTab;
 var gContentAPI;
 var gContentWindow;
 
 var hasWebIDE = Services.prefs.getBoolPref("devtools.webide.widget.enabled");
 
-var hasPocket = false;
-if (Services.prefs.getBoolPref("browser.pocket.enabled")) {
-  let isEnabledForLocale = true;
-  if (Services.prefs.getBoolPref("browser.pocket.useLocaleList")) {
-    let chromeRegistry = Cc["@mozilla.org/chrome/chrome-registry;1"]
-                           .getService(Ci.nsIXULChromeRegistry);
-    let browserLocale = chromeRegistry.getSelectedLocale("browser");
-    let enabledLocales = [];
-    try {
-      enabledLocales = Services.prefs.getCharPref("browser.pocket.enabledLocales").split(' ');
-    } catch (ex) {
-      Cu.reportError(ex);
-    }
-    isEnabledForLocale = enabledLocales.indexOf(browserLocale) != -1;
-  }
-  if (isEnabledForLocale) {
-    hasPocket = true;
-  }
-}
+var hasPocket = Services.prefs.getBoolPref("extensions.pocket.enabled");
 
 function test() {
   requestLongerTimeout(2);
   UITourTest();
 }
 
 var tests = [
   function test_availableTargets(done) {
--- a/browser/components/uitour/test/browser_UITour_pocket.js
+++ b/browser/components/uitour/test/browser_UITour_pocket.js
@@ -57,17 +57,17 @@ function checkPanelIsHidden(aPanel) {
   if (aPanel.parentElement) {
     is_hidden(aPanel);
   } else {
     ok(!aPanel.parentElement, "Widget panel should have been removed");
   }
   is(button.hasAttribute("open"), false, "Pocket button should know that the panel is closed");
 }
 
-if (Services.prefs.getBoolPref("browser.pocket.enabled")) {
+if (Services.prefs.getBoolPref("extensions.pocket.enabled")) {
   let placement = CustomizableUI.getPlacementOfWidget("pocket-button");
 
   // Add the button to the nav-bar by default.
   if (!placement || placement.area != CustomizableUI.AREA_NAVBAR) {
     CustomizableUI.addWidgetToArea("pocket-button", CustomizableUI.AREA_NAVBAR);
   }
   registerCleanupFunction(() => {
     CustomizableUI.reset();
--- a/browser/extensions/moz.build
+++ b/browser/extensions/moz.build
@@ -2,10 +2,11 @@
 # 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/.
 
 DIRS += [
     'loop',
     'pdfjs',
+    'pocket',
     'shumway',
 ]
--- a/browser/extensions/pdfjs/README.mozilla
+++ b/browser/extensions/pdfjs/README.mozilla
@@ -1,3 +1,3 @@
 This is the pdf.js project output, https://github.com/mozilla/pdf.js
 
-Current extension version is: 1.3.110
+Current extension version is: 1.3.142
--- a/browser/extensions/pdfjs/content/build/pdf.js
+++ b/browser/extensions/pdfjs/content/build/pdf.js
@@ -7,26 +7,27 @@
  *     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.
  */
-/*jshint globalstrict: false */
-/* globals PDFJS */
+/* jshint globalstrict: false */
+/* globals PDFJS, global */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
-  (typeof window !== 'undefined' ? window : this).PDFJS = {};
+  (typeof window !== 'undefined' ? window :
+   typeof global !== 'undefined' ? global : this).PDFJS = {};
 }
 
-PDFJS.version = '1.3.110';
-PDFJS.build = '42beb0c';
+PDFJS.version = '1.3.142';
+PDFJS.build = 'e8db825';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 
 
 (function (root, factory) {
@@ -53,16 +54,84 @@ PDFJS.build = '42beb0c';
   exports.globalScope = globalScope;
   exports.isWorker = isWorker;
   exports.PDFJS = globalScope.PDFJS;
 }));
 
 
 (function (root, factory) {
   {
+    factory((root.pdfjsDisplayDOMUtils = {}), root.pdfjsSharedGlobal);
+  }
+}(this, function (exports, sharedGlobal) {
+
+var PDFJS = sharedGlobal.PDFJS;
+
+/**
+ * Optimised CSS custom property getter/setter.
+ * @class
+ */
+var CustomStyle = (function CustomStyleClosure() {
+
+  // As noted on: http://www.zachstronaut.com/posts/2009/02/17/
+  //              animate-css-transforms-firefox-webkit.html
+  // in some versions of IE9 it is critical that ms appear in this list
+  // before Moz
+  var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
+  var _cache = {};
+
+  function CustomStyle() {}
+
+  CustomStyle.getProp = function get(propName, element) {
+    // check cache only when no element is given
+    if (arguments.length === 1 && typeof _cache[propName] === 'string') {
+      return _cache[propName];
+    }
+
+    element = element || document.documentElement;
+    var style = element.style, prefixed, uPropName;
+
+    // test standard property first
+    if (typeof style[propName] === 'string') {
+      return (_cache[propName] = propName);
+    }
+
+    // capitalize
+    uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
+
+    // test vendor specific properties
+    for (var i = 0, l = prefixes.length; i < l; i++) {
+      prefixed = prefixes[i] + uPropName;
+      if (typeof style[prefixed] === 'string') {
+        return (_cache[propName] = prefixed);
+      }
+    }
+
+    //if all fails then set to undefined
+    return (_cache[propName] = 'undefined');
+  };
+
+  CustomStyle.setProp = function set(propName, element, str) {
+    var prop = this.getProp(propName);
+    if (prop !== 'undefined') {
+      element.style[prop] = str;
+    }
+  };
+
+  return CustomStyle;
+})();
+
+PDFJS.CustomStyle = CustomStyle;
+
+exports.CustomStyle = CustomStyle;
+}));
+
+
+(function (root, factory) {
+  {
     factory((root.pdfjsSharedUtil = {}), root.pdfjsSharedGlobal);
   }
 }(this, function (exports, sharedGlobal) {
 
 var PDFJS = sharedGlobal.PDFJS;
 var globalScope = sharedGlobal.globalScope;
 
 var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
@@ -1400,434 +1469,688 @@ exports.stringToPDFString = stringToPDFS
 exports.stringToUTF8String = stringToUTF8String;
 exports.utf8StringToString = utf8StringToString;
 exports.warn = warn;
 }));
 
 
 (function (root, factory) {
   {
-    factory((root.pdfjsDisplayDOMUtils = {}), root.pdfjsSharedGlobal);
-  }
-}(this, function (exports, sharedGlobal) {
-
-var PDFJS = sharedGlobal.PDFJS;
-
-/**
- * Optimised CSS custom property getter/setter.
- * @class
- */
-var CustomStyle = (function CustomStyleClosure() {
-
-  // As noted on: http://www.zachstronaut.com/posts/2009/02/17/
-  //              animate-css-transforms-firefox-webkit.html
-  // in some versions of IE9 it is critical that ms appear in this list
-  // before Moz
-  var prefixes = ['ms', 'Moz', 'Webkit', 'O'];
-  var _cache = {};
-
-  function CustomStyle() {}
-
-  CustomStyle.getProp = function get(propName, element) {
-    // check cache only when no element is given
-    if (arguments.length === 1 && typeof _cache[propName] === 'string') {
-      return _cache[propName];
-    }
-
-    element = element || document.documentElement;
-    var style = element.style, prefixed, uPropName;
-
-    // test standard property first
-    if (typeof style[propName] === 'string') {
-      return (_cache[propName] = propName);
-    }
-
-    // capitalize
-    uPropName = propName.charAt(0).toUpperCase() + propName.slice(1);
-
-    // test vendor specific properties
-    for (var i = 0, l = prefixes.length; i < l; i++) {
-      prefixed = prefixes[i] + uPropName;
-      if (typeof style[prefixed] === 'string') {
-        return (_cache[propName] = prefixed);
-      }
-    }
-
-    //if all fails then set to undefined
-    return (_cache[propName] = 'undefined');
-  };
-
-  CustomStyle.setProp = function set(propName, element, str) {
-    var prop = this.getProp(propName);
-    if (prop !== 'undefined') {
-      element.style[prop] = str;
-    }
-  };
-
-  return CustomStyle;
-})();
-
-PDFJS.CustomStyle = CustomStyle;
-
-exports.CustomStyle = CustomStyle;
-}));
-
-
-(function (root, factory) {
-  {
     factory((root.pdfjsDisplayAnnotationLayer = {}), root.pdfjsSharedUtil,
       root.pdfjsDisplayDOMUtils);
   }
 }(this, function (exports, sharedUtil, displayDOMUtils) {
 
 var AnnotationBorderStyleType = sharedUtil.AnnotationBorderStyleType;
 var AnnotationType = sharedUtil.AnnotationType;
 var Util = sharedUtil.Util;
-var isExternalLinkTargetSet = sharedUtil.Util;
+var isExternalLinkTargetSet = sharedUtil.isExternalLinkTargetSet;
 var LinkTargetStringMap = sharedUtil.LinkTargetStringMap;
 var warn = sharedUtil.warn;
 var CustomStyle = displayDOMUtils.CustomStyle;
 
-var ANNOT_MIN_SIZE = 10; // px
-
-var AnnotationLayer = (function AnnotationLayerClosure() {
-  // TODO(mack): This dupes some of the logic in CanvasGraphics.setFont()
-  function setTextStyles(element, item, fontObj) {
-    var style = element.style;
-    style.fontSize = item.fontSize + 'px';
-    style.direction = item.fontDirection < 0 ? 'rtl': 'ltr';
-
-    if (!fontObj) {
-      return;
+/**
+ * @typedef {Object} AnnotationElementParameters
+ * @property {Object} data
+ * @property {HTMLDivElement} layer
+ * @property {PDFPage} page
+ * @property {PageViewport} viewport
+ * @property {IPDFLinkService} linkService
+ */
+
+/**
+ * @class
+ * @alias AnnotationElementFactory
+ */
+function AnnotationElementFactory() {}
+AnnotationElementFactory.prototype =
+    /** @lends AnnotationElementFactory.prototype */ {
+  /**
+   * @param {AnnotationElementParameters} parameters
+   * @returns {AnnotationElement}
+   */
+  create: function AnnotationElementFactory_create(parameters) {
+    var subtype = parameters.data.annotationType;
+
+    switch (subtype) {
+      case AnnotationType.LINK:
+        return new LinkAnnotationElement(parameters);
+
+      case AnnotationType.TEXT:
+        return new TextAnnotationElement(parameters);
+
+      case AnnotationType.WIDGET:
+        return new WidgetAnnotationElement(parameters);
+
+      case AnnotationType.POPUP:
+        return new PopupAnnotationElement(parameters);
+
+      case AnnotationType.UNDERLINE:
+        return new UnderlineAnnotationElement(parameters);
+
+      default:
+        throw new Error('Unimplemented annotation type "' + subtype + '"');
     }
-
-    style.fontWeight = fontObj.black ?
-      (fontObj.bold ? 'bolder' : 'bold') :
-      (fontObj.bold ? 'bold' : 'normal');
-    style.fontStyle = fontObj.italic ? 'italic' : 'normal';
-
-    var fontName = fontObj.loadedName;
-    var fontFamily = fontName ? '"' + fontName + '", ' : '';
-    // Use a reasonable default font if the font doesn't specify a fallback
-    var fallbackName = fontObj.fallbackName || 'Helvetica, sans-serif';
-    style.fontFamily = fontFamily + fallbackName;
   }
-
-  function getContainer(data, page, viewport) {
-    var container = document.createElement('section');
-    var width = data.rect[2] - data.rect[0];
-    var height = data.rect[3] - data.rect[1];
-
-    container.setAttribute('data-annotation-id', data.id);
-
-    data.rect = Util.normalizeRect([
-      data.rect[0],
-      page.view[3] - data.rect[1] + page.view[1],
-      data.rect[2],
-      page.view[3] - data.rect[3] + page.view[1]
-    ]);
-
-    CustomStyle.setProp('transform', container,
-                        'matrix(' + viewport.transform.join(',') + ')');
-    CustomStyle.setProp('transformOrigin', container,
-                        -data.rect[0] + 'px ' + -data.rect[1] + 'px');
-
-    if (data.borderStyle.width > 0) {
-      container.style.borderWidth = data.borderStyle.width + 'px';
-      if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
-        // Underline styles only have a bottom border, so we do not need
-        // to adjust for all borders. This yields a similar result as
-        // Adobe Acrobat/Reader.
-        width = width - 2 * data.borderStyle.width;
-        height = height - 2 * data.borderStyle.width;
-      }
-
-      var horizontalRadius = data.borderStyle.horizontalCornerRadius;
-      var verticalRadius = data.borderStyle.verticalCornerRadius;
-      if (horizontalRadius > 0 || verticalRadius > 0) {
-        var radius = horizontalRadius + 'px / ' + verticalRadius + 'px';
-        CustomStyle.setProp('borderRadius', container, radius);
-      }
-
-      switch (data.borderStyle.style) {
-        case AnnotationBorderStyleType.SOLID:
-          container.style.borderStyle = 'solid';
-          break;
-
-        case AnnotationBorderStyleType.DASHED:
-          container.style.borderStyle = 'dashed';
-          break;
-
-        case AnnotationBorderStyleType.BEVELED:
-          warn('Unimplemented border style: beveled');
-          break;
-
-        case AnnotationBorderStyleType.INSET:
-          warn('Unimplemented border style: inset');
-          break;
-
-        case AnnotationBorderStyleType.UNDERLINE:
-          container.style.borderBottomStyle = 'solid';
-          break;
-
-        default:
-          break;
-      }
-
-      if (data.color) {
-        container.style.borderColor =
-          Util.makeCssRgb(data.color[0] | 0,
-                          data.color[1] | 0,
-                          data.color[2] | 0);
-      } else {
-        // Transparent (invisible) border, so do not draw it at all.
-        container.style.borderWidth = 0;
-      }
-    }
-
-    container.style.left = data.rect[0] + 'px';
-    container.style.top = data.rect[1] + 'px';
-
-    container.style.width = width + 'px';
-    container.style.height = height + 'px';
-
-    return container;
-  }
-
-  function getHtmlElementForTextWidgetAnnotation(item, page, viewport) {
-    var container = getContainer(item, page, viewport);
-
-    var content = document.createElement('div');
-    content.textContent = item.fieldValue;
-    var textAlignment = item.textAlignment;
-    content.style.textAlign = ['left', 'center', 'right'][textAlignment];
-    content.style.verticalAlign = 'middle';
-    content.style.display = 'table-cell';
-
-    var fontObj = item.fontRefName ?
-      page.commonObjs.getData(item.fontRefName) : null;
-    setTextStyles(content, item, fontObj);
-
-    container.appendChild(content);
-
-    return container;
+};
+
+/**
+ * @class
+ * @alias AnnotationElement
+ */
+var AnnotationElement = (function AnnotationElementClosure() {
+  function AnnotationElement(parameters) {
+    this.data = parameters.data;
+    this.layer = parameters.layer;
+    this.page = parameters.page;
+    this.viewport = parameters.viewport;
+    this.linkService = parameters.linkService;
+
+    this.container = this._createContainer();
   }
 
-  function getHtmlElementForTextAnnotation(item, page, viewport) {
-    var rect = item.rect;
-
-    // sanity check because of OOo-generated PDFs
-    if ((rect[3] - rect[1]) < ANNOT_MIN_SIZE) {
-      rect[3] = rect[1] + ANNOT_MIN_SIZE;
-    }
-    if ((rect[2] - rect[0]) < ANNOT_MIN_SIZE) {
-      rect[2] = rect[0] + (rect[3] - rect[1]); // make it square
-    }
-
-    var container = getContainer(item, page, viewport);
-    container.className = 'annotText';
-
-    var image  = document.createElement('img');
-    image.style.height = container.style.height;
-    image.style.width = container.style.width;
-    var iconName = item.name;
-    image.src = PDFJS.imageResourcesPath + 'annotation-' +
-      iconName.toLowerCase() + '.svg';
-    image.alt = '[{{type}} Annotation]';
-    image.dataset.l10nId = 'text_annotation_type';
-    image.dataset.l10nArgs = JSON.stringify({type: iconName});
-
-    var contentWrapper = document.createElement('div');
-    contentWrapper.className = 'annotTextContentWrapper';
-    contentWrapper.style.left = Math.floor(rect[2] - rect[0] + 5) + 'px';
-    contentWrapper.style.top = '-10px';
-
-    var content = document.createElement('div');
-    content.className = 'annotTextContent';
-    content.setAttribute('hidden', true);
-
-    var i, ii;
-    if (item.hasBgColor && item.color) {
-      var color = item.color;
-
-      // Enlighten the color (70%)
-      var BACKGROUND_ENLIGHT = 0.7;
-      var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0];
-      var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1];
-      var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2];
-      content.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0);
-    }
-
-    var title = document.createElement('h1');
-    var text = document.createElement('p');
-    title.textContent = item.title;
-
-    if (!item.content && !item.title) {
-      content.setAttribute('hidden', true);
-    } else {
-      var e = document.createElement('span');
-      var lines = item.content.split(/(?:\r\n?|\n)/);
-      for (i = 0, ii = lines.length; i < ii; ++i) {
-        var line = lines[i];
-        e.appendChild(document.createTextNode(line));
-        if (i < (ii - 1)) {
-          e.appendChild(document.createElement('br'));
+  AnnotationElement.prototype = /** @lends AnnotationElement.prototype */ {
+    /**
+     * Create an empty container for the annotation's HTML element.
+     *
+     * @private
+     * @memberof AnnotationElement
+     * @returns {HTMLSectionElement}
+     */
+    _createContainer: function AnnotationElement_createContainer() {
+      var data = this.data, page = this.page, viewport = this.viewport;
+      var container = document.createElement('section');
+      var width = data.rect[2] - data.rect[0];
+      var height = data.rect[3] - data.rect[1];
+
+      container.setAttribute('data-annotation-id', data.id);
+
+      // Do *not* modify `data.rect`, since that will corrupt the annotation
+      // position on subsequent calls to `_createContainer` (see issue 6804).
+      var rect = Util.normalizeRect([
+        data.rect[0],
+        page.view[3] - data.rect[1] + page.view[1],
+        data.rect[2],
+        page.view[3] - data.rect[3] + page.view[1]
+      ]);
+
+      CustomStyle.setProp('transform', container,
+                          'matrix(' + viewport.transform.join(',') + ')');
+      CustomStyle.setProp('transformOrigin', container,
+                          -rect[0] + 'px ' + -rect[1] + 'px');
+
+      if (data.borderStyle.width > 0) {
+        container.style.borderWidth = data.borderStyle.width + 'px';
+        if (data.borderStyle.style !== AnnotationBorderStyleType.UNDERLINE) {
+          // Underline styles only have a bottom border, so we do not need
+          // to adjust for all borders. This yields a similar result as
+          // Adobe Acrobat/Reader.
+          width = width - 2 * data.borderStyle.width;
+          height = height - 2 * data.borderStyle.width;
+        }
+
+        var horizontalRadius = data.borderStyle.horizontalCornerRadius;
+        var verticalRadius = data.borderStyle.verticalCornerRadius;
+        if (horizontalRadius > 0 || verticalRadius > 0) {
+          var radius = horizontalRadius + 'px / ' + verticalRadius + 'px';
+          CustomStyle.setProp('borderRadius', container, radius);
+        }
+
+        switch (data.borderStyle.style) {
+          case AnnotationBorderStyleType.SOLID:
+            container.style.borderStyle = 'solid';
+            break;
+
+          case AnnotationBorderStyleType.DASHED:
+            container.style.borderStyle = 'dashed';
+            break;
+
+          case AnnotationBorderStyleType.BEVELED:
+            warn('Unimplemented border style: beveled');
+            break;
+
+          case AnnotationBorderStyleType.INSET:
+            warn('Unimplemented border style: inset');
+            break;
+
+          case AnnotationBorderStyleType.UNDERLINE:
+            container.style.borderBottomStyle = 'solid';
+            break;
+
+          default:
+            break;
+        }
+
+        if (data.color) {
+          container.style.borderColor =
+            Util.makeCssRgb(data.color[0] | 0,
+                            data.color[1] | 0,
+                            data.color[2] | 0);
+        } else {
+          // Transparent (invisible) border, so do not draw it at all.
+          container.style.borderWidth = 0;
         }
       }
-      text.appendChild(e);
-
-      var pinned = false;
-
-      var showAnnotation = function showAnnotation(pin) {
-        if (pin) {
-          pinned = true;
-        }
-        if (content.hasAttribute('hidden')) {
-          container.style.zIndex += 1;
-          content.removeAttribute('hidden');
-        }
-      };
-
-      var hideAnnotation = function hideAnnotation(unpin) {
-        if (unpin) {
-          pinned = false;
-        }
-        if (!content.hasAttribute('hidden') && !pinned) {
-          container.style.zIndex -= 1;
-          content.setAttribute('hidden', true);
-        }
-      };
-
-      var toggleAnnotation = function toggleAnnotation() {
-        if (pinned) {
-          hideAnnotation(true);
+
+      container.style.left = rect[0] + 'px';
+      container.style.top = rect[1] + 'px';
+
+      container.style.width = width + 'px';
+      container.style.height = height + 'px';
+
+      return container;
+    },
+
+    /**
+     * Render the annotation's HTML element in the empty container.
+     *
+     * @public
+     * @memberof AnnotationElement
+     */
+    render: function AnnotationElement_render() {
+      throw new Error('Abstract method AnnotationElement.render called');
+    }
+  };
+
+  return AnnotationElement;
+})();
+
+/**
+ * @class
+ * @alias LinkAnnotationElement
+ */
+var LinkAnnotationElement = (function LinkAnnotationElementClosure() {
+  function LinkAnnotationElement(parameters) {
+    AnnotationElement.call(this, parameters);
+  }
+
+  Util.inherit(LinkAnnotationElement, AnnotationElement, {
+    /**
+     * Render the link annotation's HTML element in the empty container.
+     *
+     * @public
+     * @memberof LinkAnnotationElement
+     * @returns {HTMLSectionElement}
+     */
+    render: function LinkAnnotationElement_render() {
+      this.container.className = 'linkAnnotation';
+
+      var link = document.createElement('a');
+      link.href = link.title = this.data.url || '';
+
+      if (this.data.url && isExternalLinkTargetSet()) {
+        link.target = LinkTargetStringMap[PDFJS.externalLinkTarget];
+      }
+
+      // Strip referrer from the URL.
+      if (this.data.url) {
+        link.rel = PDFJS.externalLinkRel;
+      }
+
+      if (!this.data.url) {
+        if (this.data.action) {
+          this._bindNamedAction(link, this.data.action);
         } else {
-          showAnnotation(true);
+          this._bindLink(link, ('dest' in this.data) ? this.data.dest : null);
         }
-      };
-
-      image.addEventListener('click', function image_clickHandler() {
-        toggleAnnotation();
-      }, false);
-      image.addEventListener('mouseover', function image_mouseOverHandler() {
-        showAnnotation();
-      }, false);
-      image.addEventListener('mouseout', function image_mouseOutHandler() {
-        hideAnnotation();
-      }, false);
-
-      content.addEventListener('click', function content_clickHandler() {
-        hideAnnotation(true);
-      }, false);
-    }
-
-    content.appendChild(title);
-    content.appendChild(text);
-    contentWrapper.appendChild(content);
-    container.appendChild(image);
-    container.appendChild(contentWrapper);
-
-    return container;
-  }
-
-  function getHtmlElementForLinkAnnotation(item, page, viewport, linkService) {
-    function bindLink(link, dest) {
-      link.href = linkService.getDestinationHash(dest);
-      link.onclick = function annotationsLayerBuilderLinksOnclick() {
-        if (dest) {
-          linkService.navigateTo(dest);
+      }
+
+      this.container.appendChild(link);
+      return this.container;
+    },
+
+    /**
+     * Bind internal links to the link element.
+     *
+     * @private
+     * @param {Object} link
+     * @param {Object} destination
+     * @memberof LinkAnnotationElement
+     */
+    _bindLink: function LinkAnnotationElement_bindLink(link, destination) {
+      var self = this;
+
+      link.href = this.linkService.getDestinationHash(destination);
+      link.onclick = function() {
+        if (destination) {
+          self.linkService.navigateTo(destination);
         }
         return false;
       };
-      if (dest) {
+      if (destination) {
         link.className = 'internalLink';
       }
-    }
-
-    function bindNamedAction(link, action) {
-      link.href = linkService.getAnchorUrl('');
-      link.onclick = function annotationsLayerBuilderNamedActionOnClick() {
-        linkService.executeNamedAction(action);
+    },
+
+    /**
+     * Bind named actions to the link element.
+     *
+     * @private
+     * @param {Object} link
+     * @param {Object} action
+     * @memberof LinkAnnotationElement
+     */
+    _bindNamedAction:
+        function LinkAnnotationElement_bindNamedAction(link, action) {
+      var self = this;
+
+      link.href = this.linkService.getAnchorUrl('');
+      link.onclick = function() {
+        self.linkService.executeNamedAction(action);
         return false;
       };
       link.className = 'internalLink';
     }
-
-    var container = getContainer(item, page, viewport);
-    container.className = 'annotLink';
-
-    var link = document.createElement('a');
-    link.href = link.title = item.url || '';
-
-    if (item.url && isExternalLinkTargetSet()) {
-      link.target = LinkTargetStringMap[PDFJS.externalLinkTarget];
+  });
+
+  return LinkAnnotationElement;
+})();
+
+/**
+ * @class
+ * @alias TextAnnotationElement
+ */
+var TextAnnotationElement = (function TextAnnotationElementClosure() {
+  function TextAnnotationElement(parameters) {
+    AnnotationElement.call(this, parameters);
+  }
+
+  Util.inherit(TextAnnotationElement, AnnotationElement, {
+    /**
+     * Render the text annotation's HTML element in the empty container.
+     *
+     * @public
+     * @memberof TextAnnotationElement
+     * @returns {HTMLSectionElement}
+     */
+    render: function TextAnnotationElement_render() {
+      this.container.className = 'textAnnotation';
+
+      var image = document.createElement('img');
+      image.style.height = this.container.style.height;
+      image.style.width = this.container.style.width;
+      image.src = PDFJS.imageResourcesPath + 'annotation-' +
+        this.data.name.toLowerCase() + '.svg';
+      image.alt = '[{{type}} Annotation]';
+      image.dataset.l10nId = 'text_annotation_type';
+      image.dataset.l10nArgs = JSON.stringify({type: this.data.name});
+
+      if (!this.data.hasPopup) {
+        var popupElement = new PopupElement({
+          container: this.container,
+          trigger: image,
+          color: this.data.color,
+          title: this.data.title,
+          contents: this.data.contents,
+          hideWrapper: true
+        });
+        var popup = popupElement.render();
+
+        // Position the popup next to the Text annotation's container.
+        popup.style.left = image.style.width;
+
+        this.container.appendChild(popup);
+      }
+
+      this.container.appendChild(image);
+      return this.container;
+    }
+  });
+
+  return TextAnnotationElement;
+})();
+
+/**
+ * @class
+ * @alias WidgetAnnotationElement
+ */
+var WidgetAnnotationElement = (function WidgetAnnotationElementClosure() {
+  function WidgetAnnotationElement(parameters) {
+    AnnotationElement.call(this, parameters);
+  }
+
+  Util.inherit(WidgetAnnotationElement, AnnotationElement, {
+    /**
+     * Render the widget annotation's HTML element in the empty container.
+     *
+     * @public
+     * @memberof WidgetAnnotationElement
+     * @returns {HTMLSectionElement}
+     */
+    render: function WidgetAnnotationElement_render() {
+      var content = document.createElement('div');
+      content.textContent = this.data.fieldValue;
+      var textAlignment = this.data.textAlignment;
+      content.style.textAlign = ['left', 'center', 'right'][textAlignment];
+      content.style.verticalAlign = 'middle';
+      content.style.display = 'table-cell';
+
+      var font = (this.data.fontRefName ?
+        this.page.commonObjs.getData(this.data.fontRefName) : null);
+      this._setTextStyle(content, font);
+
+      this.container.appendChild(content);
+      return this.container;
+    },
+
+    /**
+     * Apply text styles to the text in the element.
+     *
+     * @private
+     * @param {HTMLDivElement} element
+     * @param {Object} font
+     * @memberof WidgetAnnotationElement
+     */
+    _setTextStyle:
+        function WidgetAnnotationElement_setTextStyle(element, font) {
+      // TODO: This duplicates some of the logic in CanvasGraphics.setFont().
+      var style = element.style;
+      style.fontSize = this.data.fontSize + 'px';
+      style.direction = (this.data.fontDirection < 0 ? 'rtl': 'ltr');
+
+      if (!font) {
+        return;
+      }
+
+      style.fontWeight = (font.black ?
+        (font.bold ? '900' : 'bold') :
+        (font.bold ? 'bold' : 'normal'));
+      style.fontStyle = (font.italic ? 'italic' : 'normal');
+
+      // Use a reasonable default font if the font doesn't specify a fallback.
+      var fontFamily = font.loadedName ? '"' + font.loadedName + '", ' : '';
+      var fallbackName = font.fallbackName || 'Helvetica, sans-serif';
+      style.fontFamily = fontFamily + fallbackName;
     }
-
-    // Strip referrer
-    if (item.url) {
-      link.rel = PDFJS.externalLinkRel;
+  });
+
+  return WidgetAnnotationElement;
+})();
+
+/**
+ * @class
+ * @alias PopupAnnotationElement
+ */
+var PopupAnnotationElement = (function PopupAnnotationElementClosure() {
+  function PopupAnnotationElement(parameters) {
+    AnnotationElement.call(this, parameters);
+  }
+
+  Util.inherit(PopupAnnotationElement, AnnotationElement, {
+    /**
+     * Render the popup annotation's HTML element in the empty container.
+     *
+     * @public
+     * @memberof PopupAnnotationElement
+     * @returns {HTMLSectionElement}
+     */
+    render: function PopupAnnotationElement_render() {
+      this.container.className = 'popupAnnotation';
+
+      var selector = '[data-annotation-id="' + this.data.parentId + '"]';
+      var parentElement = this.layer.querySelector(selector);
+      if (!parentElement) {
+        return this.container;
+      }
+
+      var popup = new PopupElement({
+        container: this.container,
+        trigger: parentElement,
+        color: this.data.color,
+        title: this.data.title,
+        contents: this.data.contents
+      });
+
+      // Position the popup next to the parent annotation's container.
+      // PDF viewers ignore a popup annotation's rectangle.
+      var parentLeft = parseFloat(parentElement.style.left);
+      var parentWidth = parseFloat(parentElement.style.width);
+      CustomStyle.setProp('transformOrigin', this.container,
+                          -(parentLeft + parentWidth) + 'px -' +
+                          parentElement.style.top);
+      this.container.style.left = (parentLeft + parentWidth) + 'px';
+
+      this.container.appendChild(popup.render());
+      return this.container;
     }
-
-    if (!item.url) {
-      if (item.action) {
-        bindNamedAction(link, item.action);
+  });
+
+  return PopupAnnotationElement;
+})();
+
+/**
+ * @class
+ * @alias PopupElement
+ */
+var PopupElement = (function PopupElementClosure() {
+  var BACKGROUND_ENLIGHT = 0.7;
+
+  function PopupElement(parameters) {
+    this.container = parameters.container;
+    this.trigger = parameters.trigger;
+    this.color = parameters.color;
+    this.title = parameters.title;
+    this.contents = parameters.contents;
+    this.hideWrapper = parameters.hideWrapper || false;
+
+    this.pinned = false;
+  }
+
+  PopupElement.prototype = /** @lends PopupElement.prototype */ {
+    /**
+     * Render the popup's HTML element.
+     *
+     * @public
+     * @memberof PopupElement
+     * @returns {HTMLSectionElement}
+     */
+    render: function PopupElement_render() {
+      var wrapper = document.createElement('div');
+      wrapper.className = 'popupWrapper';
+
+      // For Popup annotations we hide the entire section because it contains
+      // only the popup. However, for Text annotations without a separate Popup
+      // annotation, we cannot hide the entire container as the image would
+      // disappear too. In that special case, hiding the wrapper suffices.
+      this.hideElement = (this.hideWrapper ? wrapper : this.container);
+      this.hideElement.setAttribute('hidden', true);
+
+      var popup = document.createElement('div');
+      popup.className = 'popup';
+
+      var color = this.color;
+      if (color) {
+        // Enlighten the color.
+        var r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0];
+        var g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1];
+        var b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2];
+        popup.style.backgroundColor = Util.makeCssRgb(r | 0, g | 0, b | 0);
+      }
+
+      var contents = this._formatContents(this.contents);
+      var title = document.createElement('h1');
+      title.textContent = this.title;
+
+      // Attach the event listeners to the trigger element.
+      this.trigger.addEventListener('click', this._toggle.bind(this));
+      this.trigger.addEventListener('mouseover', this._show.bind(this, false));
+      this.trigger.addEventListener('mouseout', this._hide.bind(this, false));
+      popup.addEventListener('click', this._hide.bind(this, true));
+
+      popup.appendChild(title);
+      popup.appendChild(contents);
+      wrapper.appendChild(popup);
+      return wrapper;
+    },
+
+    /**
+     * Format the contents of the popup by adding newlines where necessary.
+     *
+     * @private
+     * @param {string} contents
+     * @memberof PopupElement
+     * @returns {HTMLParagraphElement}
+     */
+    _formatContents: function PopupElement_formatContents(contents) {
+      var p = document.createElement('p');
+      var lines = contents.split(/(?:\r\n?|\n)/);
+      for (var i = 0, ii = lines.length; i < ii; ++i) {
+        var line = lines[i];
+        p.appendChild(document.createTextNode(line));
+        if (i < (ii - 1)) {
+          p.appendChild(document.createElement('br'));
+        }
+      }
+      return p;
+    },
+
+    /**
+     * Toggle the visibility of the popup.
+     *
+     * @private
+     * @memberof PopupElement
+     */
+    _toggle: function PopupElement_toggle() {
+      if (this.pinned) {
+        this._hide(true);
       } else {
-        bindLink(link, ('dest' in item) ? item.dest : null);
+        this._show(true);
+      }
+    },
+
+    /**
+     * Show the popup.
+     *
+     * @private
+     * @param {boolean} pin
+     * @memberof PopupElement
+     */
+    _show: function PopupElement_show(pin) {
+      if (pin) {
+        this.pinned = true;
+      }
+      if (this.hideElement.hasAttribute('hidden')) {
+        this.hideElement.removeAttribute('hidden');
+        this.container.style.zIndex += 1;
+      }
+    },
+
+    /**
+     * Hide the popup.
+     *
+     * @private
+     * @param {boolean} unpin
+     * @memberof PopupElement
+     */
+    _hide: function PopupElement_hide(unpin) {
+      if (unpin) {
+        this.pinned = false;
+      }
+      if (!this.hideElement.hasAttribute('hidden') && !this.pinned) {
+        this.hideElement.setAttribute('hidden', true);
+        this.container.style.zIndex -= 1;
       }
     }
-
-    container.appendChild(link);
-
-    return container;
-  }
-
-  function getHtmlElement(data, page, viewport, linkService) {
-    switch (data.annotationType) {
-      case AnnotationType.WIDGET:
-        return getHtmlElementForTextWidgetAnnotation(data, page, viewport);
-      case AnnotationType.TEXT:
-        return getHtmlElementForTextAnnotation(data, page, viewport);
-      case AnnotationType.LINK:
-        return getHtmlElementForLinkAnnotation(data, page, viewport,
-                                               linkService);
-      default:
-        throw new Error('Unsupported annotationType: ' + data.annotationType);
-    }
+  };
+
+  return PopupElement;
+})();
+
+/**
+ * @class
+ * @alias UnderlineAnnotationElement
+ */
+var UnderlineAnnotationElement = (
+    function UnderlineAnnotationElementClosure() {
+  function UnderlineAnnotationElement(parameters) {
+    AnnotationElement.call(this, parameters);
   }
 
-  function render(viewport, div, annotations, page, linkService) {
-    for (var i = 0, ii = annotations.length; i < ii; i++) {
-      var data = annotations[i];
-      if (!data || !data.hasHtml) {
-        continue;
-      }
-
-      var element = getHtmlElement(data, page, viewport, linkService);
-      div.appendChild(element);
+  Util.inherit(UnderlineAnnotationElement, AnnotationElement, {
+    /**
+     * Render the underline annotation's HTML element in the empty container.
+     *
+     * @public
+     * @memberof UnderlineAnnotationElement
+     * @returns {HTMLSectionElement}
+     */
+    render: function UnderlineAnnotationElement_render() {
+      this.container.className = 'underlineAnnotation';
+      return this.container;
     }
-  }
-
-  function update(viewport, div, annotations) {
-    for (var i = 0, ii = annotations.length; i < ii; i++) {
-      var data = annotations[i];
-      var element = div.querySelector(
-        '[data-annotation-id="' + data.id + '"]');
-      if (element) {
-        CustomStyle.setProp('transform', element,
-          'matrix(' + viewport.transform.join(',') + ')');
-      }
+  });
+
+  return UnderlineAnnotationElement;
+})();
+
+/**
+ * @typedef {Object} AnnotationLayerParameters
+ * @property {PageViewport} viewport
+ * @property {HTMLDivElement} div
+ * @property {Array} annotations
+ * @property {PDFPage} page
+ * @property {IPDFLinkService} linkService
+ */
+
+/**
+ * @class
+ * @alias AnnotationLayer
+ */
+var AnnotationLayer = (function AnnotationLayerClosure() {
+  return {
+    /**
+     * Render a new annotation layer with all annotation elements.
+     *
+     * @public
+     * @param {AnnotationLayerParameters} parameters
+     * @memberof AnnotationLayer
+     */
+    render: function AnnotationLayer_render(parameters) {
+      var annotationElementFactory = new AnnotationElementFactory();
+
+      for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {
+        var data = parameters.annotations[i];
+        if (!data || !data.hasHtml) {
+          continue;
+        }
+
+        var properties = {
+          data: data,
+          layer: parameters.div,
+          page: parameters.page,
+          viewport: parameters.viewport,
+          linkService: parameters.linkService
+        };
+        var element = annotationElementFactory.create(properties);
+        parameters.div.appendChild(element.render());
+      }
+    },
+
+    /**
+     * Update the annotation elements on existing annotation layer.
+     *
+     * @public
+     * @param {AnnotationLayerParameters} parameters
+     * @memberof AnnotationLayer
+     */
+    update: function AnnotationLayer_update(parameters) {
+      for (var i = 0, ii = parameters.annotations.length; i < ii; i++) {
+        var data = parameters.annotations[i];
+        var element = parameters.div.querySelector(
+          '[data-annotation-id="' + data.id + '"]');
+        if (element) {
+          CustomStyle.setProp('transform', element,
+            'matrix(' + parameters.viewport.transform.join(',') + ')');
+        }
+      }
+      parameters.div.removeAttribute('hidden');
     }
-    div.removeAttribute('hidden');
-  }
-
-  return {
-    render: render,
-    update: update
   };
 })();
+
 PDFJS.AnnotationLayer = AnnotationLayer;
 
 exports.AnnotationLayer = AnnotationLayer;
 }));
 
 
 (function (root, factory) {
   {
@@ -2080,21 +2403,25 @@ var Metadata = PDFJS.Metadata = (functio
 })();
 
 exports.Metadata = Metadata;
 }));
 
 
 (function (root, factory) {
   {
-    factory((root.pdfjsDisplayTextLayer = {}), root.pdfjsSharedUtil);
+    factory((root.pdfjsDisplayTextLayer = {}), root.pdfjsSharedUtil,
+      root.pdfjsDisplayDOMUtils, root.pdfjsSharedGlobal);
   }
-}(this, function (exports, sharedUtil) {
-
+}(this, function (exports, sharedUtil, displayDOMUtils, sharedGlobal) {
+
+var Util = sharedUtil.Util;
 var createPromiseCapability = sharedUtil.createPromiseCapability;
+var CustomStyle = displayDOMUtils.CustomStyle;
+var PDFJS = sharedGlobal.PDFJS;
 
 /**
  * Text layer render parameters.
  *
  * @typedef {Object} TextLayerRenderParameters
  * @property {TextContent} textContent - Text content to render (the object is
  *   returned by the page's getTextContent() method).
  * @property {HTMLElement} container - HTML element that will contain text runs.
@@ -2118,17 +2445,17 @@ var renderTextLayer = (function renderTe
   function appendText(textDivs, viewport, geom, styles) {
     var style = styles[geom.fontName];
     var textDiv = document.createElement('div');
     textDivs.push(textDiv);
     if (isAllWhitespace(geom.str)) {
       textDiv.dataset.isWhitespace = true;
       return;
     }
-    var tx = PDFJS.Util.transform(viewport.transform, geom.transform);
+    var tx = Util.transform(viewport.transform, geom.transform);
     var angle = Math.atan2(tx[1], tx[0]);
     if (style.vertical) {
       angle += Math.PI / 2;
     }
     var fontHeight = Math.sqrt((tx[2] * tx[2]) + (tx[3] * tx[3]));
     var fontAscent = fontHeight;
     if (style.ascent) {
       fontAscent = style.ascent * fontAscent;
@@ -2222,17 +2549,17 @@ var renderTextLayer = (function renderTe
         } else {
           transform = '';
         }
         var rotation = textDiv.dataset.angle;
         if (rotation) {
           transform = 'rotate(' + rotation + 'deg) ' + transform;
         }
         if (transform) {
-          PDFJS.CustomStyle.setProp('transform' , textDiv, transform);
+          CustomStyle.setProp('transform' , textDiv, transform);
         }
       }
     }
     capability.resolve();
   }
 
   /**
    * Text layer rendering task.
@@ -4977,16 +5304,20 @@ var CanvasGraphics = (function CanvasGra
         this.ctx.drawImage(groupCtx.canvas, 0, 0);
       }
       this.restore();
     },
 
     beginAnnotations: function CanvasGraphics_beginAnnotations() {
       this.save();
       this.current = new CanvasExtraState();
+
+      if (this.baseTransform) {
+        this.ctx.setTransform.apply(this.ctx, this.baseTransform);
+      }
     },
 
     endAnnotations: function CanvasGraphics_endAnnotations() {
       this.restore();
     },
 
     beginAnnotation: function CanvasGraphics_beginAnnotation(rect, transform,
                                                              matrix) {
@@ -5395,16 +5726,18 @@ var FontFaceObject = displayFontLoader.F
 var FontLoader = displayFontLoader.FontLoader;
 var CanvasGraphics = displayCanvas.CanvasGraphics;
 var createScratchCanvas = displayCanvas.createScratchCanvas;
 var PDFJS = sharedGlobal.PDFJS;
 var globalScope = sharedGlobal.globalScope;
 
 var DEFAULT_RANGE_CHUNK_SIZE = 65536; // 2^16 = 65536
 
+  var fakeWorkerFilesLoader = null;
+
 /**
  * The maximum allowed image size in total pixels e.g. width * height. Images
  * above this value will not be drawn. Use -1 for no limit.
  * @var {number}
  */
 PDFJS.maxImageSize = (PDFJS.maxImageSize === undefined ?
                       -1 : PDFJS.maxImageSize);
 
@@ -5743,17 +6076,17 @@ PDFJS.getDocument = function getDocument
       if (task.destroyed) {
         throw new Error('Loading aborted');
       }
       var messageHandler = new MessageHandler(docId, workerId, worker.port);
       messageHandler.send('Ready', null);
       var transport = new WorkerTransport(messageHandler, task, rangeTransport);
       task._transport = transport;
     });
-  }, task._capability.reject);
+  }).catch(task._capability.reject);
 
   return task;
 };
 
 /**
  * Starts fetching of specified PDF document/data.
  * @param {PDFWorker} worker
  * @param {Object} source
@@ -6513,17 +6846,20 @@ var PDFWorker = (function PDFWorkerClosu
 
   // Loads worker code into main thread.
   function setupFakeWorkerGlobal() {
     if (!PDFJS.fakeWorkerFilesLoadedCapability) {
       PDFJS.fakeWorkerFilesLoadedCapability = createPromiseCapability();
       // In the developer build load worker_loader which in turn loads all the
       // other files and resolves the promise. In production only the
       // pdf.worker.js file is needed.
-      Util.loadScript(PDFJS.workerSrc, function() {
+      var loader = fakeWorkerFilesLoader || function (callback) {
+        Util.loadScript(PDFJS.workerSrc, callback);
+      };
+      loader(function () {
         PDFJS.fakeWorkerFilesLoadedCapability.resolve();
       });
     }
     return PDFJS.fakeWorkerFilesLoadedCapability.promise;
   }
 
   function PDFWorker(name) {
     this.name = name;
@@ -6561,17 +6897,16 @@ var PDFWorker = (function PDFWorkerClosu
           error('No PDFJS.workerSrc specified');
         }
 
         try {
           // Some versions of FF can't create a worker on localhost, see:
           // https://bugzilla.mozilla.org/show_bug.cgi?id=683280
           var worker = new Worker(workerSrc);
           var messageHandler = new MessageHandler('main', 'worker', worker);
-
           messageHandler.on('test', function PDFWorker_test(data) {
             if (this.destroyed) {
               this._readyCapability.reject(new Error('Worker was destroyed'));
               messageHandler.destroy();
               worker.terminate();
               return; // worker was destroyed
             }
             var supportTypedArray = data && data.supportTypedArray;
@@ -6592,39 +6927,65 @@ var PDFWorker = (function PDFWorkerClosu
 
           messageHandler.on('console_log', function (data) {
             console.log.apply(console, data);
           });
           messageHandler.on('console_error', function (data) {
             console.error.apply(console, data);
           });
 
-          var testObj = new Uint8Array([PDFJS.postMessageTransfers ? 255 : 0]);
-          // Some versions of Opera throw a DATA_CLONE_ERR on serializing the
-          // typed array. Also, checking if we can use transfers.
-          try {
-            messageHandler.send('test', testObj, [testObj.buffer]);
-          } catch (ex) {
-            info('Cannot use postMessage transfers');
-            testObj[0] = 0;
-            messageHandler.send('test', testObj);
-          }
+          messageHandler.on('ready', function (data) {
+            if (this.destroyed) {
+              this._readyCapability.reject(new Error('Worker was destroyed'));
+              messageHandler.destroy();
+              worker.terminate();
+              return; // worker was destroyed
+            }
+            try {
+              sendTest();
+            } catch (e)  {
+              // We need fallback to a faked worker.
+              this._setupFakeWorker();
+            }
+          }.bind(this));
+
+          var sendTest = function () {
+            var testObj = new Uint8Array(
+              [PDFJS.postMessageTransfers ? 255 : 0]);
+            // Some versions of Opera throw a DATA_CLONE_ERR on serializing the
+            // typed array. Also, checking if we can use transfers.
+            try {
+              messageHandler.send('test', testObj, [testObj.buffer]);
+            } catch (ex) {
+              info('Cannot use postMessage transfers');
+              testObj[0] = 0;
+              messageHandler.send('test', testObj);
+            }
+          };
+
+          // It might take time for worker to initialize (especially when AMD
+          // loader is used). We will try to send test immediately, and then
+          // when 'ready' message will arrive. The worker shall process only
+          // first received 'test'.
+          sendTest();
           return;
         } catch (e) {
           info('The worker has been disabled.');
         }
       }
       // Either workers are disabled, not supported or have thrown an exception.
       // Thus, we fallback to a faked worker.
       this._setupFakeWorker();
     },
 
     _setupFakeWorker: function PDFWorker_setupFakeWorker() {
-      warn('Setting up fake worker.');
-      globalScope.PDFJS.disableWorker = true;
+      if (!globalScope.PDFJS.disableWorker) {
+        warn('Setting up fake worker.');
+        globalScope.PDFJS.disableWorker = true;
+      }
 
       setupFakeWorkerGlobal().then(function () {
         if (this.destroyed) {
           this._readyCapability.reject(new Error('Worker was destroyed'));
           return;
         }
 
         // If we don't use a worker, just post/sendMessage to the main thread.
@@ -7414,20 +7775,12 @@ PDFJS.UnsupportedManager = (function Uns
 
 exports.getDocument = PDFJS.getDocument;
 exports.PDFDataRangeTransport = PDFDataRangeTransport;
 exports.PDFDocumentProxy = PDFDocumentProxy;
 exports.PDFPageProxy = PDFPageProxy;
 }));
 
 
-(function (root, factory) {
-  {
-    factory((root.pdfjsDisplaySVG = {}), root.pdfjsSharedUtil);
-  }
-}(this, function (exports, sharedUtil) {
-}));
-
-
 }).call((typeof window === 'undefined') ? this : window);
 
 
 
--- a/browser/extensions/pdfjs/content/build/pdf.worker.js
+++ b/browser/extensions/pdfjs/content/build/pdf.worker.js
@@ -7,1409 +7,36 @@
  *     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.
  */
-/*jshint globalstrict: false */
-/* globals PDFJS */
+/* jshint globalstrict: false */
+/* globals PDFJS, global */
 
 // Initializing PDFJS global object (if still undefined)
 if (typeof PDFJS === 'undefined') {
-  (typeof window !== 'undefined' ? window : this).PDFJS = {};
-}
-
-PDFJS.version = '1.3.110';
-PDFJS.build = '42beb0c';
+  (typeof window !== 'undefined' ? window :
+   typeof global !== 'undefined' ? global : this).PDFJS = {};
+}
+
+PDFJS.version = '1.3.142';
+PDFJS.build = 'e8db825';
 
 (function pdfjsWrapper() {
   // Use strict in our context only - users might not want it
   'use strict';
 
 
 
 (function (root, factory) {
   {
-    factory((root.pdfjsSharedGlobal = {}));
-  }
-}(this, function (exports) {
-
-  var globalScope = (typeof window !== 'undefined') ? window :
-                    (typeof global !== 'undefined') ? global :
-                    (typeof self !== 'undefined') ? self : this;
-
-  var isWorker = (typeof window === 'undefined');
-
-  // The global PDFJS object exposes the API
-  // In production, it will be declared outside a global wrapper
-  // In development, it will be declared here
-  if (!globalScope.PDFJS) {
-    globalScope.PDFJS = {};
-  }
-
-  globalScope.PDFJS.pdfBug = false;
-
-  exports.globalScope = globalScope;
-  exports.isWorker = isWorker;
-  exports.PDFJS = globalScope.PDFJS;
-}));
-
-
-(function (root, factory) {
-  {
-    factory((root.pdfjsSharedUtil = {}), root.pdfjsSharedGlobal);
-  }
-}(this, function (exports, sharedGlobal) {
-
-var PDFJS = sharedGlobal.PDFJS;
-var globalScope = sharedGlobal.globalScope;
-
-var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
-
-var TextRenderingMode = {
-  FILL: 0,
-  STROKE: 1,
-  FILL_STROKE: 2,
-  INVISIBLE: 3,
-  FILL_ADD_TO_PATH: 4,
-  STROKE_ADD_TO_PATH: 5,
-  FILL_STROKE_ADD_TO_PATH: 6,
-  ADD_TO_PATH: 7,
-  FILL_STROKE_MASK: 3,
-  ADD_TO_PATH_FLAG: 4
-};
-
-var ImageKind = {
-  GRAYSCALE_1BPP: 1,
-  RGB_24BPP: 2,
-  RGBA_32BPP: 3
-};
-
-var AnnotationType = {
-  TEXT: 1,
-  LINK: 2,
-  FREETEXT: 3,
-  LINE: 4,
-  SQUARE: 5,
-  CIRCLE: 6,
-  POLYGON: 7,
-  POLYLINE: 8,
-  HIGHLIGHT: 9,
-  UNDERLINE: 10,
-  SQUIGGLY: 11,
-  STRIKEOUT: 12,
-  STAMP: 13,
-  CARET: 14,
-  INK: 15,
-  POPUP: 16,
-  FILEATTACHMENT: 17,
-  SOUND: 18,
-  MOVIE: 19,
-  WIDGET: 20,
-  SCREEN: 21,
-  PRINTERMARK: 22,
-  TRAPNET: 23,
-  WATERMARK: 24,
-  THREED: 25,
-  REDACT: 26
-};
-
-var AnnotationFlag = {
-  INVISIBLE: 0x01,
-  HIDDEN: 0x02,
-  PRINT: 0x04,
-  NOZOOM: 0x08,
-  NOROTATE: 0x10,
-  NOVIEW: 0x20,
-  READONLY: 0x40,
-  LOCKED: 0x80,
-  TOGGLENOVIEW: 0x100,
-  LOCKEDCONTENTS: 0x200
-};
-
-var AnnotationBorderStyleType = {
-  SOLID: 1,
-  DASHED: 2,
-  BEVELED: 3,
-  INSET: 4,
-  UNDERLINE: 5
-};
-
-var StreamType = {
-  UNKNOWN: 0,
-  FLATE: 1,
-  LZW: 2,
-  DCT: 3,
-  JPX: 4,
-  JBIG: 5,
-  A85: 6,
-  AHX: 7,
-  CCF: 8,
-  RL: 9
-};
-
-var FontType = {
-  UNKNOWN: 0,
-  TYPE1: 1,
-  TYPE1C: 2,
-  CIDFONTTYPE0: 3,
-  CIDFONTTYPE0C: 4,
-  TRUETYPE: 5,
-  CIDFONTTYPE2: 6,
-  TYPE3: 7,
-  OPENTYPE: 8,
-  TYPE0: 9,
-  MMTYPE1: 10
-};
-
-PDFJS.VERBOSITY_LEVELS = {
-  errors: 0,
-  warnings: 1,
-  infos: 5
-};
-
-// All the possible operations for an operator list.
-var OPS = PDFJS.OPS = {
-  // Intentionally start from 1 so it is easy to spot bad operators that will be
-  // 0's.
-  dependency: 1,
-  setLineWidth: 2,
-  setLineCap: 3,
-  setLineJoin: 4,
-  setMiterLimit: 5,
-  setDash: 6,
-  setRenderingIntent: 7,
-  setFlatness: 8,
-  setGState: 9,
-  save: 10,
-  restore: 11,
-  transform: 12,
-  moveTo: 13,
-  lineTo: 14,
-  curveTo: 15,
-  curveTo2: 16,
-  curveTo3: 17,
-  closePath: 18,
-  rectangle: 19,
-  stroke: 20,
-  closeStroke: 21,
-  fill: 22,
-  eoFill: 23,
-  fillStroke: 24,
-  eoFillStroke: 25,
-  closeFillStroke: 26,
-  closeEOFillStroke: 27,
-  endPath: 28,
-  clip: 29,
-  eoClip: 30,
-  beginText: 31,
-  endText: 32,
-  setCharSpacing: 33,
-  setWordSpacing: 34,
-  setHScale: 35,
-  setLeading: 36,
-  setFont: 37,
-  setTextRenderingMode: 38,
-  setTextRise: 39,
-  moveText: 40,
-  setLeadingMoveText: 41,
-  setTextMatrix: 42,
-  nextLine: 43,
-  showText: 44,
-  showSpacedText: 45,
-  nextLineShowText: 46,
-  nextLineSetSpacingShowText: 47,
-  setCharWidth: 48,
-  setCharWidthAndBounds: 49,
-  setStrokeColorSpace: 50,
-  setFillColorSpace: 51,
-  setStrokeColor: 52,
-  setStrokeColorN: 53,
-  setFillColor: 54,
-  setFillColorN: 55,
-  setStrokeGray: 56,
-  setFillGray: 57,
-  setStrokeRGBColor: 58,
-  setFillRGBColor: 59,
-  setStrokeCMYKColor: 60,
-  setFillCMYKColor: 61,
-  shadingFill: 62,
-  beginInlineImage: 63,
-  beginImageData: 64,
-  endInlineImage: 65,
-  paintXObject: 66,
-  markPoint: 67,
-  markPointProps: 68,
-  beginMarkedContent: 69,
-  beginMarkedContentProps: 70,
-  endMarkedContent: 71,
-  beginCompat: 72,
-  endCompat: 73,
-  paintFormXObjectBegin: 74,
-  paintFormXObjectEnd: 75,
-  beginGroup: 76,
-  endGroup: 77,
-  beginAnnotations: 78,
-  endAnnotations: 79,
-  beginAnnotation: 80,
-  endAnnotation: 81,
-  paintJpegXObject: 82,
-  paintImageMaskXObject: 83,
-  paintImageMaskXObjectGroup: 84,
-  paintImageXObject: 85,
-  paintInlineImageXObject: 86,
-  paintInlineImageXObjectGroup: 87,
-  paintImageXObjectRepeat: 88,
-  paintImageMaskXObjectRepeat: 89,
-  paintSolidColorImageMask: 90,
-  constructPath: 91
-};
-
-// A notice for devs. These are good for things that are helpful to devs, such
-// as warning that Workers were disabled, which is important to devs but not
-// end users.
-function info(msg) {
-  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
-    console.log('Info: ' + msg);
-  }
-}
-
-// Non-fatal warnings.
-function warn(msg) {
-  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
-    console.log('Warning: ' + msg);
-  }
-}
-
-// Deprecated API function -- treated as warnings.
-function deprecated(details) {
-  warn('Deprecated API usage: ' + details);
-}
-
-// Fatal errors that should trigger the fallback UI and halt execution by
-// throwing an exception.
-function error(msg) {
-  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) {
-    console.log('Error: ' + msg);
-    console.log(backtrace());
-  }
-  throw new Error(msg);
-}
-
-function backtrace() {
-  try {
-    throw new Error();
-  } catch (e) {
-    return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
-  }
-}
-
-function assert(cond, msg) {
-  if (!cond) {
-    error(msg);
-  }
-}
-
-var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
-  unknown: 'unknown',
-  forms: 'forms',
-  javaScript: 'javaScript',
-  smask: 'smask',
-  shadingPattern: 'shadingPattern',
-  font: 'font'
-};
-
-// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
-// absolute URL, it will be returned as is.
-function combineUrl(baseUrl, url) {
-  if (!url) {
-    return baseUrl;
-  }
-  if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
-    return url;
-  }
-  var i;
-  if (url.charAt(0) === '/') {
-    // absolute path
-    i = baseUrl.indexOf('://');
-    if (url.charAt(1) === '/') {
-      ++i;
-    } else {
-      i = baseUrl.indexOf('/', i + 3);
-    }
-    return baseUrl.substring(0, i) + url;
-  } else {
-    // relative path
-    var pathLength = baseUrl.length;
-    i = baseUrl.lastIndexOf('#');
-    pathLength = i >= 0 ? i : pathLength;
-    i = baseUrl.lastIndexOf('?', pathLength);
-    pathLength = i >= 0 ? i : pathLength;
-    var prefixLength = baseUrl.lastIndexOf('/', pathLength);
-    return baseUrl.substring(0, prefixLength + 1) + url;
-  }
-}
-
-// Validates if URL is safe and allowed, e.g. to avoid XSS.
-function isValidUrl(url, allowRelative) {
-  if (!url) {
-    return false;
-  }
-  // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
-  // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
-  var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url);
-  if (!protocol) {
-    return allowRelative;
-  }
-  protocol = protocol[0].toLowerCase();
-  switch (protocol) {
-    case 'http':
-    case 'https':
-    case 'ftp':
-    case 'mailto':
-    case 'tel':
-      return true;
-    default:
-      return false;
-  }
-}
-PDFJS.isValidUrl = isValidUrl;
-
-function shadow(obj, prop, value) {
-  Object.defineProperty(obj, prop, { value: value,
-                                     enumerable: true,
-                                     configurable: true,
-                                     writable: false });
-  return value;
-}
-PDFJS.shadow = shadow;
-
-var LinkTarget = PDFJS.LinkTarget = {
-  NONE: 0, // Default value.
-  SELF: 1,
-  BLANK: 2,
-  PARENT: 3,
-  TOP: 4,
-};
-var LinkTargetStringMap = [
-  '',
-  '_self',
-  '_blank',
-  '_parent',
-  '_top'
-];
-
-function isExternalLinkTargetSet() {
-  switch (PDFJS.externalLinkTarget) {
-    case LinkTarget.NONE:
-      return false;
-    case LinkTarget.SELF:
-    case LinkTarget.BLANK:
-    case LinkTarget.PARENT:
-    case LinkTarget.TOP:
-      return true;
-  }
-  warn('PDFJS.externalLinkTarget is invalid: ' + PDFJS.externalLinkTarget);
-  // Reset the external link target, to suppress further warnings.
-  PDFJS.externalLinkTarget = LinkTarget.NONE;
-  return false;
-}
-PDFJS.isExternalLinkTargetSet = isExternalLinkTargetSet;
-
-var PasswordResponses = PDFJS.PasswordResponses = {
-  NEED_PASSWORD: 1,
-  INCORRECT_PASSWORD: 2
-};
-
-var PasswordException = (function PasswordExceptionClosure() {
-  function PasswordException(msg, code) {
-    this.name = 'PasswordException';
-    this.message = msg;
-    this.code = code;
-  }
-
-  PasswordException.prototype = new Error();
-  PasswordException.constructor = PasswordException;
-
-  return PasswordException;
-})();
-PDFJS.PasswordException = PasswordException;
-
-var UnknownErrorException = (function UnknownErrorExceptionClosure() {
-  function UnknownErrorException(msg, details) {
-    this.name = 'UnknownErrorException';
-    this.message = msg;
-    this.details = details;
-  }
-
-  UnknownErrorException.prototype = new Error();
-  UnknownErrorException.constructor = UnknownErrorException;
-
-  return UnknownErrorException;
-})();
-PDFJS.UnknownErrorException = UnknownErrorException;
-
-var InvalidPDFException = (function InvalidPDFExceptionClosure() {
-  function InvalidPDFException(msg) {
-    this.name = 'InvalidPDFException';
-    this.message = msg;
-  }
-
-  InvalidPDFException.prototype = new Error();
-  InvalidPDFException.constructor = InvalidPDFException;
-
-  return InvalidPDFException;
-})();
-PDFJS.InvalidPDFException = InvalidPDFException;
-
-var MissingPDFException = (function MissingPDFExceptionClosure() {
-  function MissingPDFException(msg) {
-    this.name = 'MissingPDFException';
-    this.message = msg;
-  }
-
-  MissingPDFException.prototype = new Error();
-  MissingPDFException.constructor = MissingPDFException;
-
-  return MissingPDFException;
-})();
-PDFJS.MissingPDFException = MissingPDFException;
-
-var UnexpectedResponseException =
-    (function UnexpectedResponseExceptionClosure() {
-  function UnexpectedResponseException(msg, status) {
-    this.name = 'UnexpectedResponseException';
-    this.message = msg;
-    this.status = status;
-  }
-
-  UnexpectedResponseException.prototype = new Error();
-  UnexpectedResponseException.constructor = UnexpectedResponseException;
-
-  return UnexpectedResponseException;
-})();
-PDFJS.UnexpectedResponseException = UnexpectedResponseException;
-
-var NotImplementedException = (function NotImplementedExceptionClosure() {
-  function NotImplementedException(msg) {
-    this.message = msg;
-  }
-
-  NotImplementedException.prototype = new Error();
-  NotImplementedException.prototype.name = 'NotImplementedException';
-  NotImplementedException.constructor = NotImplementedException;
-
-  return NotImplementedException;
-})();
-
-var MissingDataException = (function MissingDataExceptionClosure() {
-  function MissingDataException(begin, end) {
-    this.begin = begin;
-    this.end = end;
-    this.message = 'Missing data [' + begin + ', ' + end + ')';
-  }
-
-  MissingDataException.prototype = new Error();
-  MissingDataException.prototype.name = 'MissingDataException';
-  MissingDataException.constructor = MissingDataException;
-
-  return MissingDataException;
-})();
-
-var XRefParseException = (function XRefParseExceptionClosure() {
-  function XRefParseException(msg) {
-    this.message = msg;
-  }
-
-  XRefParseException.prototype = new Error();
-  XRefParseException.prototype.name = 'XRefParseException';
-  XRefParseException.constructor = XRefParseException;
-
-  return XRefParseException;
-})();
-
-
-function bytesToString(bytes) {
-  assert(bytes !== null && typeof bytes === 'object' &&
-         bytes.length !== undefined, 'Invalid argument for bytesToString');
-  var length = bytes.length;
-  var MAX_ARGUMENT_COUNT = 8192;
-  if (length < MAX_ARGUMENT_COUNT) {
-    return String.fromCharCode.apply(null, bytes);
-  }
-  var strBuf = [];
-  for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
-    var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
-    var chunk = bytes.subarray(i, chunkEnd);
-    strBuf.push(String.fromCharCode.apply(null, chunk));
-  }
-  return strBuf.join('');
-}
-
-function stringToBytes(str) {
-  assert(typeof str === 'string', 'Invalid argument for stringToBytes');
-  var length = str.length;
-  var bytes = new Uint8Array(length);
-  for (var i = 0; i < length; ++i) {
-    bytes[i] = str.charCodeAt(i) & 0xFF;
-  }
-  return bytes;
-}
-
-function string32(value) {
-  return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
-                             (value >> 8) & 0xff, value & 0xff);
-}
-
-function log2(x) {
-  var n = 1, i = 0;
-  while (x > n) {
-    n <<= 1;
-    i++;
-  }
-  return i;
-}
-
-function readInt8(data, start) {
-  return (data[start] << 24) >> 24;
-}
-
-function readUint16(data, offset) {
-  return (data[offset] << 8) | data[offset + 1];
-}
-
-function readUint32(data, offset) {
-  return ((data[offset] << 24) | (data[offset + 1] << 16) |
-         (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
-}
-
-// Lazy test the endianness of the platform
-// NOTE: This will be 'true' for simulated TypedArrays
-function isLittleEndian() {
-  var buffer8 = new Uint8Array(2);
-  buffer8[0] = 1;
-  var buffer16 = new Uint16Array(buffer8.buffer);
-  return (buffer16[0] === 1);
-}
-
-Object.defineProperty(PDFJS, 'isLittleEndian', {
-  configurable: true,
-  get: function PDFJS_isLittleEndian() {
-    return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
-  }
-});
-
-  PDFJS.hasCanvasTypedArrays = true;
-
-var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
-
-var Util = PDFJS.Util = (function UtilClosure() {
-  function Util() {}
-
-  var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
-
-  // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
-  // creating many intermediate strings.
-  Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
-    rgbBuf[1] = r;
-    rgbBuf[3] = g;
-    rgbBuf[5] = b;
-    return rgbBuf.join('');
-  };
-
-  // Concatenates two transformation matrices together and returns the result.
-  Util.transform = function Util_transform(m1, m2) {
-    return [
-      m1[0] * m2[0] + m1[2] * m2[1],
-      m1[1] * m2[0] + m1[3] * m2[1],
-      m1[0] * m2[2] + m1[2] * m2[3],
-      m1[1] * m2[2] + m1[3] * m2[3],
-      m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
-      m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
-    ];
-  };
-
-  // For 2d affine transforms
-  Util.applyTransform = function Util_applyTransform(p, m) {
-    var xt = p[0] * m[0] + p[1] * m[2] + m[4];
-    var yt = p[0] * m[1] + p[1] * m[3] + m[5];
-    return [xt, yt];
-  };
-
-  Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
-    var d = m[0] * m[3] - m[1] * m[2];
-    var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
-    var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
-    return [xt, yt];
-  };
-
-  // Applies the transform to the rectangle and finds the minimum axially
-  // aligned bounding box.
-  Util.getAxialAlignedBoundingBox =
-    function Util_getAxialAlignedBoundingBox(r, m) {
-
-    var p1 = Util.applyTransform(r, m);
-    var p2 = Util.applyTransform(r.slice(2, 4), m);
-    var p3 = Util.applyTransform([r[0], r[3]], m);
-    var p4 = Util.applyTransform([r[2], r[1]], m);
-    return [
-      Math.min(p1[0], p2[0], p3[0], p4[0]),
-      Math.min(p1[1], p2[1], p3[1], p4[1]),
-      Math.max(p1[0], p2[0], p3[0], p4[0]),
-      Math.max(p1[1], p2[1], p3[1], p4[1])
-    ];
-  };
-
-  Util.inverseTransform = function Util_inverseTransform(m) {
-    var d = m[0] * m[3] - m[1] * m[2];
-    return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
-      (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
-  };
-
-  // Apply a generic 3d matrix M on a 3-vector v:
-  //   | a b c |   | X |
-  //   | d e f | x | Y |
-  //   | g h i |   | Z |
-  // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
-  // with v as [X,Y,Z]
-  Util.apply3dTransform = function Util_apply3dTransform(m, v) {
-    return [
-      m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
-      m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
-      m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
-    ];
-  };
-
-  // This calculation uses Singular Value Decomposition.
-  // The SVD can be represented with formula A = USV. We are interested in the
-  // matrix S here because it represents the scale values.
-  Util.singularValueDecompose2dScale =
-    function Util_singularValueDecompose2dScale(m) {
-
-    var transpose = [m[0], m[2], m[1], m[3]];
-
-    // Multiply matrix m with its transpose.
-    var a = m[0] * transpose[0] + m[1] * transpose[2];
-    var b = m[0] * transpose[1] + m[1] * transpose[3];
-    var c = m[2] * transpose[0] + m[3] * transpose[2];
-    var d = m[2] * transpose[1] + m[3] * transpose[3];
-
-    // Solve the second degree polynomial to get roots.
-    var first = (a + d) / 2;
-    var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
-    var sx = first + second || 1;
-    var sy = first - second || 1;
-
-    // Scale values are the square roots of the eigenvalues.
-    return [Math.sqrt(sx), Math.sqrt(sy)];
-  };
-
-  // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
-  // For coordinate systems whose origin lies in the bottom-left, this
-  // means normalization to (BL,TR) ordering. For systems with origin in the
-  // top-left, this means (TL,BR) ordering.
-  Util.normalizeRect = function Util_normalizeRect(rect) {
-    var r = rect.slice(0); // clone rect
-    if (rect[0] > rect[2]) {
-      r[0] = rect[2];
-      r[2] = rect[0];
-    }
-    if (rect[1] > rect[3]) {
-      r[1] = rect[3];
-      r[3] = rect[1];
-    }
-    return r;
-  };
-
-  // Returns a rectangle [x1, y1, x2, y2] corresponding to the
-  // intersection of rect1 and rect2. If no intersection, returns 'false'
-  // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
-  Util.intersect = function Util_intersect(rect1, rect2) {
-    function compare(a, b) {
-      return a - b;
-    }
-
-    // Order points along the axes
-    var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
-        orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
-        result = [];
-
-    rect1 = Util.normalizeRect(rect1);
-    rect2 = Util.normalizeRect(rect2);
-
-    // X: first and second points belong to different rectangles?
-    if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
-        (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
-      // Intersection must be between second and third points
-      result[0] = orderedX[1];
-      result[2] = orderedX[2];
-    } else {
-      return false;
-    }
-
-    // Y: first and second points belong to different rectangles?
-    if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
-        (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
-      // Intersection must be between second and third points
-      result[1] = orderedY[1];
-      result[3] = orderedY[2];
-    } else {
-      return false;
-    }
-
-    return result;
-  };
-
-  Util.sign = function Util_sign(num) {
-    return num < 0 ? -1 : 1;
-  };
-
-  Util.appendToArray = function Util_appendToArray(arr1, arr2) {
-    Array.prototype.push.apply(arr1, arr2);
-  };
-
-  Util.prependToArray = function Util_prependToArray(arr1, arr2) {
-    Array.prototype.unshift.apply(arr1, arr2);
-  };
-
-  Util.extendObj = function extendObj(obj1, obj2) {
-    for (var key in obj2) {
-      obj1[key] = obj2[key];
-    }
-  };
-
-  Util.getInheritableProperty = function Util_getInheritableProperty(dict,
-                                                                     name) {
-    while (dict && !dict.has(name)) {
-      dict = dict.get('Parent');
-    }
-    if (!dict) {
-      return null;
-    }
-    return dict.get(name);
-  };
-
-  Util.inherit = function Util_inherit(sub, base, prototype) {
-    sub.prototype = Object.create(base.prototype);
-    sub.prototype.constructor = sub;
-    for (var prop in prototype) {
-      sub.prototype[prop] = prototype[prop];
-    }
-  };
-
-  Util.loadScript = function Util_loadScript(src, callback) {
-    var script = document.createElement('script');
-    var loaded = false;
-    script.setAttribute('src', src);
-    if (callback) {
-      script.onload = function() {
-        if (!loaded) {
-          callback();
-        }
-        loaded = true;
-      };
-    }
-    document.getElementsByTagName('head')[0].appendChild(script);
-  };
-
-  return Util;
-})();
-
-/**
- * PDF page viewport created based on scale, rotation and offset.
- * @class
- * @alias PDFJS.PageViewport
- */
-var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
-  /**
-   * @constructor
-   * @private
-   * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
-   * @param scale {number} scale of the viewport.
-   * @param rotation {number} rotations of the viewport in degrees.
-   * @param offsetX {number} offset X
-   * @param offsetY {number} offset Y
-   * @param dontFlip {boolean} if true, axis Y will not be flipped.
-   */
-  function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
-    this.viewBox = viewBox;
-    this.scale = scale;
-    this.rotation = rotation;
-    this.offsetX = offsetX;
-    this.offsetY = offsetY;
-
-    // creating transform to convert pdf coordinate system to the normal
-    // canvas like coordinates taking in account scale and rotation
-    var centerX = (viewBox[2] + viewBox[0]) / 2;
-    var centerY = (viewBox[3] + viewBox[1]) / 2;
-    var rotateA, rotateB, rotateC, rotateD;
-    rotation = rotation % 360;
-    rotation = rotation < 0 ? rotation + 360 : rotation;
-    switch (rotation) {
-      case 180:
-        rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
-        break;
-      case 90:
-        rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
-        break;
-      case 270:
-        rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
-        break;
-      //case 0:
-      default:
-        rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
-        break;
-    }
-
-    if (dontFlip) {
-      rotateC = -rotateC; rotateD = -rotateD;
-    }
-
-    var offsetCanvasX, offsetCanvasY;
-    var width, height;
-    if (rotateA === 0) {
-      offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
-      offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
-      width = Math.abs(viewBox[3] - viewBox[1]) * scale;
-      height = Math.abs(viewBox[2] - viewBox[0]) * scale;
-    } else {
-      offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
-      offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
-      width = Math.abs(viewBox[2] - viewBox[0]) * scale;
-      height = Math.abs(viewBox[3] - viewBox[1]) * scale;
-    }
-    // creating transform for the following operations:
-    // translate(-centerX, -centerY), rotate and flip vertically,
-    // scale, and translate(offsetCanvasX, offsetCanvasY)
-    this.transform = [
-      rotateA * scale,
-      rotateB * scale,
-      rotateC * scale,
-      rotateD * scale,
-      offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
-      offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
-    ];
-
-    this.width = width;
-    this.height = height;
-    this.fontScale = scale;
-  }
-  PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
-    /**
-     * Clones viewport with additional properties.
-     * @param args {Object} (optional) If specified, may contain the 'scale' or
-     * 'rotation' properties to override the corresponding properties in
-     * the cloned viewport.
-     * @returns {PDFJS.PageViewport} Cloned viewport.
-     */
-    clone: function PageViewPort_clone(args) {
-      args = args || {};
-      var scale = 'scale' in args ? args.scale : this.scale;
-      var rotation = 'rotation' in args ? args.rotation : this.rotation;
-      return new PageViewport(this.viewBox.slice(), scale, rotation,
-                              this.offsetX, this.offsetY, args.dontFlip);
-    },
-    /**
-     * Converts PDF point to the viewport coordinates. For examples, useful for
-     * converting PDF location into canvas pixel coordinates.
-     * @param x {number} X coordinate.
-     * @param y {number} Y coordinate.
-     * @returns {Object} Object that contains 'x' and 'y' properties of the
-     * point in the viewport coordinate space.
-     * @see {@link convertToPdfPoint}
-     * @see {@link convertToViewportRectangle}
-     */
-    convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
-      return Util.applyTransform([x, y], this.transform);
-    },
-    /**
-     * Converts PDF rectangle to the viewport coordinates.
-     * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
-     * @returns {Array} Contains corresponding coordinates of the rectangle
-     * in the viewport coordinate space.
-     * @see {@link convertToViewportPoint}
-     */
-    convertToViewportRectangle:
-      function PageViewport_convertToViewportRectangle(rect) {
-      var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
-      var br = Util.applyTransform([rect[2], rect[3]], this.transform);
-      return [tl[0], tl[1], br[0], br[1]];
-    },
-    /**
-     * Converts viewport coordinates to the PDF location. For examples, useful
-     * for converting canvas pixel location into PDF one.
-     * @param x {number} X coordinate.
-     * @param y {number} Y coordinate.
-     * @returns {Object} Object that contains 'x' and 'y' properties of the
-     * point in the PDF coordinate space.
-     * @see {@link convertToViewportPoint}
-     */
-    convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
-      return Util.applyInverseTransform([x, y], this.transform);
-    }
-  };
-  return PageViewport;
-})();
-
-var PDFStringTranslateTable = [
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
-  0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
-  0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
-  0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
-];
-
-function stringToPDFString(str) {
-  var i, n = str.length, strBuf = [];
-  if (str[0] === '\xFE' && str[1] === '\xFF') {
-    // UTF16BE BOM
-    for (i = 2; i < n; i += 2) {
-      strBuf.push(String.fromCharCode(
-        (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
-    }
-  } else {
-    for (i = 0; i < n; ++i) {
-      var code = PDFStringTranslateTable[str.charCodeAt(i)];
-      strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
-    }
-  }
-  return strBuf.join('');
-}
-
-function stringToUTF8String(str) {
-  return decodeURIComponent(escape(str));
-}
-
-function utf8StringToString(str) {
-  return unescape(encodeURIComponent(str));
-}
-
-function isEmptyObj(obj) {
-  for (var key in obj) {
-    return false;
-  }
-  return true;
-}
-
-function isBool(v) {
-  return typeof v === 'boolean';
-}
-
-function isInt(v) {
-  return typeof v === 'number' && ((v | 0) === v);
-}
-
-function isNum(v) {
-  return typeof v === 'number';
-}
-
-function isString(v) {
-  return typeof v === 'string';
-}
-
-function isArray(v) {
-  return v instanceof Array;
-}
-
-function isArrayBuffer(v) {
-  return typeof v === 'object' && v !== null && v.byteLength !== undefined;
-}
-
-/**
- * Promise Capability object.
- *
- * @typedef {Object} PromiseCapability
- * @property {Promise} promise - A promise object.
- * @property {function} resolve - Fullfills the promise.
- * @property {function} reject - Rejects the promise.
- */
-
-/**
- * Creates a promise capability object.
- * @alias PDFJS.createPromiseCapability
- *
- * @return {PromiseCapability} A capability object contains:
- * - a Promise, resolve and reject methods.
- */
-function createPromiseCapability() {
-  var capability = {};
-  capability.promise = new Promise(function (resolve, reject) {
-    capability.resolve = resolve;
-    capability.reject = reject;
-  });
-  return capability;
-}
-
-PDFJS.createPromiseCapability = createPromiseCapability;
-
-/**
- * Polyfill for Promises:
- * The following promise implementation tries to generally implement the
- * Promise/A+ spec. Some notable differences from other promise libaries are:
- * - There currently isn't a seperate deferred and promise object.
- * - Unhandled rejections eventually show an error if they aren't handled.
- *
- * Based off of the work in:
- * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
- */
-(function PromiseClosure() {
-  if (globalScope.Promise) {
-    // Promises existing in the DOM/Worker, checking presence of all/resolve
-    if (typeof globalScope.Promise.all !== 'function') {
-      globalScope.Promise.all = function (iterable) {
-        var count = 0, results = [], resolve, reject;
-        var promise = new globalScope.Promise(function (resolve_, reject_) {
-          resolve = resolve_;
-          reject = reject_;
-        });
-        iterable.forEach(function (p, i) {
-          count++;
-          p.then(function (result) {
-            results[i] = result;
-            count--;
-            if (count === 0) {
-              resolve(results);
-            }
-          }, reject);
-        });
-        if (count === 0) {
-          resolve(results);
-        }
-        return promise;
-      };
-    }
-    if (typeof globalScope.Promise.resolve !== 'function') {
-      globalScope.Promise.resolve = function (value) {
-        return new globalScope.Promise(function (resolve) { resolve(value); });
-      };
-    }
-    if (typeof globalScope.Promise.reject !== 'function') {
-      globalScope.Promise.reject = function (reason) {
-        return new globalScope.Promise(function (resolve, reject) {
-          reject(reason);
-        });
-      };
-    }
-    if (typeof globalScope.Promise.prototype.catch !== 'function') {
-      globalScope.Promise.prototype.catch = function (onReject) {
-        return globalScope.Promise.prototype.then(undefined, onReject);
-      };
-    }
-    return;
-  }
-  throw new Error('DOM Promise is not present');
-})();
-
-var StatTimer = (function StatTimerClosure() {
-  function rpad(str, pad, length) {
-    while (str.length < length) {
-      str += pad;
-    }
-    return str;
-  }
-  function StatTimer() {
-    this.started = {};
-    this.times = [];
-    this.enabled = true;
-  }
-  StatTimer.prototype = {
-    time: function StatTimer_time(name) {
-      if (!this.enabled) {
-        return;
-      }
-      if (name in this.started) {
-        warn('Timer is already running for ' + name);
-      }
-      this.started[name] = Date.now();
-    },
-    timeEnd: function StatTimer_timeEnd(name) {
-      if (!this.enabled) {
-        return;
-      }
-      if (!(name in this.started)) {
-        warn('Timer has not been started for ' + name);
-      }
-      this.times.push({
-        'name': name,
-        'start': this.started[name],
-        'end': Date.now()
-      });
-      // Remove timer from started so it can be called again.
-      delete this.started[name];
-    },
-    toString: function StatTimer_toString() {
-      var i, ii;
-      var times = this.times;
-      var out = '';
-      // Find the longest name for padding purposes.
-      var longest = 0;
-      for (i = 0, ii = times.length; i < ii; ++i) {
-        var name = times[i]['name'];
-        if (name.length > longest) {
-          longest = name.length;
-        }
-      }
-      for (i = 0, ii = times.length; i < ii; ++i) {
-        var span = times[i];
-        var duration = span.end - span.start;
-        out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
-      }
-      return out;
-    }
-  };
-  return StatTimer;
-})();
-
-PDFJS.createBlob = function createBlob(data, contentType) {
-  if (typeof Blob !== 'undefined') {
-    return new Blob([data], { type: contentType });
-  }
-  // Blob builder is deprecated in FF14 and removed in FF18.
-  var bb = new MozBlobBuilder();
-  bb.append(data);
-  return bb.getBlob(contentType);
-};
-
-PDFJS.createObjectURL = (function createObjectURLClosure() {
-  // Blob/createObjectURL is not available, falling back to data schema.
-  var digits =
-    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
-
-  return function createObjectURL(data, contentType) {
-    if (!PDFJS.disableCreateObjectURL &&
-        typeof URL !== 'undefined' && URL.createObjectURL) {
-      var blob = PDFJS.createBlob(data, contentType);
-      return URL.createObjectURL(blob);
-    }
-
-    var buffer = 'data:' + contentType + ';base64,';
-    for (var i = 0, ii = data.length; i < ii; i += 3) {
-      var b1 = data[i] & 0xFF;
-      var b2 = data[i + 1] & 0xFF;
-      var b3 = data[i + 2] & 0xFF;
-      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
-      var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
-      var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
-      buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
-    }
-    return buffer;
-  };
-})();
-
-function MessageHandler(sourceName, targetName, comObj) {
-  this.sourceName = sourceName;
-  this.targetName = targetName;
-  this.comObj = comObj;
-  this.callbackIndex = 1;
-  this.postMessageTransfers = true;
-  var callbacksCapabilities = this.callbacksCapabilities = {};
-  var ah = this.actionHandler = {};
-
-  this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) {
-    var data = event.data;
-    if (data.targetName !== this.sourceName) {
-      return;
-    }
-    if (data.isReply) {
-      var callbackId = data.callbackId;
-      if (data.callbackId in callbacksCapabilities) {
-        var callback = callbacksCapabilities[callbackId];
-        delete callbacksCapabilities[callbackId];
-        if ('error' in data) {
-          callback.reject(data.error);
-        } else {
-          callback.resolve(data.data);
-        }
-      } else {
-        error('Cannot resolve callback ' + callbackId);
-      }
-    } else if (data.action in ah) {
-      var action = ah[data.action];
-      if (data.callbackId) {
-        var sourceName = this.sourceName;
-        var targetName = data.sourceName;
-        Promise.resolve().then(function () {
-          return action[0].call(action[1], data.data);
-        }).then(function (result) {
-          comObj.postMessage({
-            sourceName: sourceName,
-            targetName: targetName,
-            isReply: true,
-            callbackId: data.callbackId,
-            data: result
-          });
-        }, function (reason) {
-          if (reason instanceof Error) {
-            // Serialize error to avoid "DataCloneError"
-            reason = reason + '';
-          }
-          comObj.postMessage({
-            sourceName: sourceName,
-            targetName: targetName,
-            isReply: true,
-            callbackId: data.callbackId,
-            error: reason
-          });
-        });
-      } else {
-        action[0].call(action[1], data.data);
-      }
-    } else {
-      error('Unknown action from worker: ' + data.action);
-    }
-  }.bind(this);
-  comObj.addEventListener('message', this._onComObjOnMessage);
-}
-
-MessageHandler.prototype = {
-  on: function messageHandlerOn(actionName, handler, scope) {
-    var ah = this.actionHandler;
-    if (ah[actionName]) {
-      error('There is already an actionName called "' + actionName + '"');
-    }
-    ah[actionName] = [handler, scope];
-  },
-  /**
-   * Sends a message to the comObj to invoke the action with the supplied data.
-   * @param {String} actionName Action to call.
-   * @param {JSON} data JSON data to send.
-   * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
-   */
-  send: function messageHandlerSend(actionName, data, transfers) {
-    var message = {
-      sourceName: this.sourceName,
-      targetName: this.targetName,
-      action: actionName,
-      data: data
-    };
-    this.postMessage(message, transfers);
-  },
-  /**
-   * Sends a message to the comObj to invoke the action with the supplied data.
-   * Expects that other side will callback with the response.
-   * @param {String} actionName Action to call.
-   * @param {JSON} data JSON data to send.
-   * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
-   * @returns {Promise} Promise to be resolved with response data.
-   */
-  sendWithPromise:
-    function messageHandlerSendWithPromise(actionName, data, transfers) {
-    var callbackId = this.callbackIndex++;
-    var message = {
-      sourceName: this.sourceName,
-      targetName: this.targetName,
-      action: actionName,
-      data: data,
-      callbackId: callbackId
-    };
-    var capability = createPromiseCapability();
-    this.callbacksCapabilities[callbackId] = capability;
-    try {
-      this.postMessage(message, transfers);
-    } catch (e) {
-      capability.reject(e);
-    }
-    return capability.promise;
-  },
-  /**
-   * Sends raw message to the comObj.
-   * @private
-   * @param message {Object} Raw message.
-   * @param transfers List of transfers/ArrayBuffers, or undefined.
-   */
-  postMessage: function (message, transfers) {
-    if (transfers && this.postMessageTransfers) {
-      this.comObj.postMessage(message, transfers);
-    } else {
-      this.comObj.postMessage(message);
-    }
-  },
-
-  destroy: function () {
-    this.comObj.removeEventListener('message', this._onComObjOnMessage);
-  }
-};
-
-function loadJpegStream(id, imageUrl, objs) {
-  var img = new Image();
-  img.onload = (function loadJpegStream_onloadClosure() {
-    objs.resolve(id, img);
-  });
-  img.onerror = (function loadJpegStream_onerrorClosure() {
-    objs.resolve(id, null);
-    warn('Error during JPEG image loading');
-  });
-  img.src = imageUrl;
-}
-
-exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX;
-exports.IDENTITY_MATRIX = IDENTITY_MATRIX;
-exports.OPS = OPS;
-exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES;
-exports.AnnotationBorderStyleType = AnnotationBorderStyleType;
-exports.AnnotationFlag = AnnotationFlag;
-exports.AnnotationType = AnnotationType;
-exports.FontType = FontType;
-exports.ImageKind = ImageKind;
-exports.InvalidPDFException = InvalidPDFException;
-exports.LinkTarget = LinkTarget;
-exports.LinkTargetStringMap = LinkTargetStringMap;
-exports.MessageHandler = MessageHandler;
-exports.MissingDataException = MissingDataException;
-exports.MissingPDFException = MissingPDFException;
-exports.NotImplementedException = NotImplementedException;
-exports.PasswordException = PasswordException;
-exports.PasswordResponses = PasswordResponses;
-exports.StatTimer = StatTimer;
-exports.StreamType = StreamType;
-exports.TextRenderingMode = TextRenderingMode;
-exports.UnexpectedResponseException = UnexpectedResponseException;
-exports.UnknownErrorException = UnknownErrorException;
-exports.Util = Util;
-exports.XRefParseException = XRefParseException;
-exports.assert = assert;
-exports.bytesToString = bytesToString;
-exports.combineUrl = combineUrl;
-exports.createPromiseCapability = createPromiseCapability;
-exports.deprecated = deprecated;
-exports.error = error;
-exports.info = info;
-exports.isArray = isArray;
-exports.isArrayBuffer = isArrayBuffer;
-exports.isBool = isBool;
-exports.isEmptyObj = isEmptyObj;
-exports.isExternalLinkTargetSet = isExternalLinkTargetSet;
-exports.isInt = isInt;
-exports.isNum = isNum;
-exports.isString = isString;
-exports.isValidUrl = isValidUrl;
-exports.loadJpegStream = loadJpegStream;
-exports.log2 = log2;
-exports.readInt8 = readInt8;
-exports.readUint16 = readUint16;
-exports.readUint32 = readUint32;
-exports.shadow = shadow;
-exports.string32 = string32;
-exports.stringToBytes = stringToBytes;
-exports.stringToPDFString = stringToPDFString;
-exports.stringToUTF8String = stringToUTF8String;
-exports.utf8StringToString = utf8StringToString;
-exports.warn = warn;
-}));
-
-
-(function (root, factory) {
-  {
     factory((root.pdfjsCoreArithmeticDecoder = {}));
   }
 }(this, function (exports) {
 
 /* This class implements the QM Coder decoding as defined in
  *   JPEG 2000 Part I Final Committee Draft Version 1.0
  *   Annex C.3 Arithmetic decoding procedure
  * available at http://www.jpeg.org/public/fcd15444-1.pdf
@@ -10089,16 +8716,43 @@ var Metrics = {
 };
 
 exports.Metrics = Metrics;
 }));
 
 
 (function (root, factory) {
   {
+    factory((root.pdfjsSharedGlobal = {}));
+  }
+}(this, function (exports) {
+
+  var globalScope = (typeof window !== 'undefined') ? window :
+                    (typeof global !== 'undefined') ? global :
+                    (typeof self !== 'undefined') ? self : this;
+
+  var isWorker = (typeof window === 'undefined');
+
+  // The global PDFJS object exposes the API
+  // In production, it will be declared outside a global wrapper
+  // In development, it will be declared here
+  if (!globalScope.PDFJS) {
+    globalScope.PDFJS = {};
+  }
+
+  globalScope.PDFJS.pdfBug = false;
+
+  exports.globalScope = globalScope;
+  exports.isWorker = isWorker;
+  exports.PDFJS = globalScope.PDFJS;
+}));
+
+
+(function (root, factory) {
+  {
     factory((root.pdfjsCoreBidi = {}), root.pdfjsSharedGlobal);
   }
 }(this, function (exports, sharedGlobal) {
 
 var PDFJS = sharedGlobal.PDFJS;
 
 var bidi = PDFJS.bidi = (function bidiClosure() {
   // Character types for symbols from 0000 to 00FF.
@@ -10507,16 +9161,1363 @@ var bidi = PDFJS.bidi = (function bidiCl
 })();
 
 exports.bidi = bidi;
 }));
 
 
 (function (root, factory) {
   {
+    factory((root.pdfjsSharedUtil = {}), root.pdfjsSharedGlobal);
+  }
+}(this, function (exports, sharedGlobal) {
+
+var PDFJS = sharedGlobal.PDFJS;
+var globalScope = sharedGlobal.globalScope;
+
+var FONT_IDENTITY_MATRIX = [0.001, 0, 0, 0.001, 0, 0];
+
+var TextRenderingMode = {
+  FILL: 0,
+  STROKE: 1,
+  FILL_STROKE: 2,
+  INVISIBLE: 3,
+  FILL_ADD_TO_PATH: 4,
+  STROKE_ADD_TO_PATH: 5,
+  FILL_STROKE_ADD_TO_PATH: 6,
+  ADD_TO_PATH: 7,
+  FILL_STROKE_MASK: 3,
+  ADD_TO_PATH_FLAG: 4
+};
+
+var ImageKind = {
+  GRAYSCALE_1BPP: 1,
+  RGB_24BPP: 2,
+  RGBA_32BPP: 3
+};
+
+var AnnotationType = {
+  TEXT: 1,
+  LINK: 2,
+  FREETEXT: 3,
+  LINE: 4,
+  SQUARE: 5,
+  CIRCLE: 6,
+  POLYGON: 7,
+  POLYLINE: 8,
+  HIGHLIGHT: 9,
+  UNDERLINE: 10,
+  SQUIGGLY: 11,
+  STRIKEOUT: 12,
+  STAMP: 13,
+  CARET: 14,
+  INK: 15,
+  POPUP: 16,
+  FILEATTACHMENT: 17,
+  SOUND: 18,
+  MOVIE: 19,
+  WIDGET: 20,
+  SCREEN: 21,
+  PRINTERMARK: 22,
+  TRAPNET: 23,
+  WATERMARK: 24,
+  THREED: 25,
+  REDACT: 26
+};
+
+var AnnotationFlag = {
+  INVISIBLE: 0x01,
+  HIDDEN: 0x02,
+  PRINT: 0x04,
+  NOZOOM: 0x08,
+  NOROTATE: 0x10,
+  NOVIEW: 0x20,
+  READONLY: 0x40,
+  LOCKED: 0x80,
+  TOGGLENOVIEW: 0x100,
+  LOCKEDCONTENTS: 0x200
+};
+
+var AnnotationBorderStyleType = {
+  SOLID: 1,
+  DASHED: 2,
+  BEVELED: 3,
+  INSET: 4,
+  UNDERLINE: 5
+};
+
+var StreamType = {
+  UNKNOWN: 0,
+  FLATE: 1,
+  LZW: 2,
+  DCT: 3,
+  JPX: 4,
+  JBIG: 5,
+  A85: 6,
+  AHX: 7,
+  CCF: 8,
+  RL: 9
+};
+
+var FontType = {
+  UNKNOWN: 0,
+  TYPE1: 1,
+  TYPE1C: 2,
+  CIDFONTTYPE0: 3,
+  CIDFONTTYPE0C: 4,
+  TRUETYPE: 5,
+  CIDFONTTYPE2: 6,
+  TYPE3: 7,
+  OPENTYPE: 8,
+  TYPE0: 9,
+  MMTYPE1: 10
+};
+
+PDFJS.VERBOSITY_LEVELS = {
+  errors: 0,
+  warnings: 1,
+  infos: 5
+};
+
+// All the possible operations for an operator list.
+var OPS = PDFJS.OPS = {
+  // Intentionally start from 1 so it is easy to spot bad operators that will be
+  // 0's.
+  dependency: 1,
+  setLineWidth: 2,
+  setLineCap: 3,
+  setLineJoin: 4,
+  setMiterLimit: 5,
+  setDash: 6,
+  setRenderingIntent: 7,
+  setFlatness: 8,
+  setGState: 9,
+  save: 10,
+  restore: 11,
+  transform: 12,
+  moveTo: 13,
+  lineTo: 14,
+  curveTo: 15,
+  curveTo2: 16,
+  curveTo3: 17,
+  closePath: 18,
+  rectangle: 19,
+  stroke: 20,
+  closeStroke: 21,
+  fill: 22,
+  eoFill: 23,
+  fillStroke: 24,
+  eoFillStroke: 25,
+  closeFillStroke: 26,
+  closeEOFillStroke: 27,
+  endPath: 28,
+  clip: 29,
+  eoClip: 30,
+  beginText: 31,
+  endText: 32,
+  setCharSpacing: 33,
+  setWordSpacing: 34,
+  setHScale: 35,
+  setLeading: 36,
+  setFont: 37,
+  setTextRenderingMode: 38,
+  setTextRise: 39,
+  moveText: 40,
+  setLeadingMoveText: 41,
+  setTextMatrix: 42,
+  nextLine: 43,
+  showText: 44,
+  showSpacedText: 45,
+  nextLineShowText: 46,
+  nextLineSetSpacingShowText: 47,
+  setCharWidth: 48,
+  setCharWidthAndBounds: 49,
+  setStrokeColorSpace: 50,
+  setFillColorSpace: 51,
+  setStrokeColor: 52,
+  setStrokeColorN: 53,
+  setFillColor: 54,
+  setFillColorN: 55,
+  setStrokeGray: 56,
+  setFillGray: 57,
+  setStrokeRGBColor: 58,
+  setFillRGBColor: 59,
+  setStrokeCMYKColor: 60,
+  setFillCMYKColor: 61,
+  shadingFill: 62,
+  beginInlineImage: 63,
+  beginImageData: 64,
+  endInlineImage: 65,
+  paintXObject: 66,
+  markPoint: 67,
+  markPointProps: 68,
+  beginMarkedContent: 69,
+  beginMarkedContentProps: 70,
+  endMarkedContent: 71,
+  beginCompat: 72,
+  endCompat: 73,
+  paintFormXObjectBegin: 74,
+  paintFormXObjectEnd: 75,
+  beginGroup: 76,
+  endGroup: 77,
+  beginAnnotations: 78,
+  endAnnotations: 79,
+  beginAnnotation: 80,
+  endAnnotation: 81,
+  paintJpegXObject: 82,
+  paintImageMaskXObject: 83,
+  paintImageMaskXObjectGroup: 84,
+  paintImageXObject: 85,
+  paintInlineImageXObject: 86,
+  paintInlineImageXObjectGroup: 87,
+  paintImageXObjectRepeat: 88,
+  paintImageMaskXObjectRepeat: 89,
+  paintSolidColorImageMask: 90,
+  constructPath: 91
+};
+
+// A notice for devs. These are good for things that are helpful to devs, such
+// as warning that Workers were disabled, which is important to devs but not
+// end users.
+function info(msg) {
+  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.infos) {
+    console.log('Info: ' + msg);
+  }
+}
+
+// Non-fatal warnings.
+function warn(msg) {
+  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.warnings) {
+    console.log('Warning: ' + msg);
+  }
+}
+
+// Deprecated API function -- treated as warnings.
+function deprecated(details) {
+  warn('Deprecated API usage: ' + details);
+}
+
+// Fatal errors that should trigger the fallback UI and halt execution by
+// throwing an exception.
+function error(msg) {
+  if (PDFJS.verbosity >= PDFJS.VERBOSITY_LEVELS.errors) {
+    console.log('Error: ' + msg);
+    console.log(backtrace());
+  }
+  throw new Error(msg);
+}
+
+function backtrace() {
+  try {
+    throw new Error();
+  } catch (e) {
+    return e.stack ? e.stack.split('\n').slice(2).join('\n') : '';
+  }
+}
+
+function assert(cond, msg) {
+  if (!cond) {
+    error(msg);
+  }
+}
+
+var UNSUPPORTED_FEATURES = PDFJS.UNSUPPORTED_FEATURES = {
+  unknown: 'unknown',
+  forms: 'forms',
+  javaScript: 'javaScript',
+  smask: 'smask',
+  shadingPattern: 'shadingPattern',
+  font: 'font'
+};
+
+// Combines two URLs. The baseUrl shall be absolute URL. If the url is an
+// absolute URL, it will be returned as is.
+function combineUrl(baseUrl, url) {
+  if (!url) {
+    return baseUrl;
+  }
+  if (/^[a-z][a-z0-9+\-.]*:/i.test(url)) {
+    return url;
+  }
+  var i;
+  if (url.charAt(0) === '/') {
+    // absolute path
+    i = baseUrl.indexOf('://');
+    if (url.charAt(1) === '/') {
+      ++i;
+    } else {
+      i = baseUrl.indexOf('/', i + 3);
+    }
+    return baseUrl.substring(0, i) + url;
+  } else {
+    // relative path
+    var pathLength = baseUrl.length;
+    i = baseUrl.lastIndexOf('#');
+    pathLength = i >= 0 ? i : pathLength;
+    i = baseUrl.lastIndexOf('?', pathLength);
+    pathLength = i >= 0 ? i : pathLength;
+    var prefixLength = baseUrl.lastIndexOf('/', pathLength);
+    return baseUrl.substring(0, prefixLength + 1) + url;
+  }
+}
+
+// Validates if URL is safe and allowed, e.g. to avoid XSS.
+function isValidUrl(url, allowRelative) {
+  if (!url) {
+    return false;
+  }
+  // RFC 3986 (http://tools.ietf.org/html/rfc3986#section-3.1)
+  // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+  var protocol = /^[a-z][a-z0-9+\-.]*(?=:)/i.exec(url);
+  if (!protocol) {
+    return allowRelative;
+  }
+  protocol = protocol[0].toLowerCase();
+  switch (protocol) {
+    case 'http':
+    case 'https':
+    case 'ftp':
+    case 'mailto':
+    case 'tel':
+      return true;
+    default:
+      return false;
+  }
+}
+PDFJS.isValidUrl = isValidUrl;
+
+function shadow(obj, prop, value) {
+  Object.defineProperty(obj, prop, { value: value,
+                                     enumerable: true,
+                                     configurable: true,
+                                     writable: false });
+  return value;
+}
+PDFJS.shadow = shadow;
+
+var LinkTarget = PDFJS.LinkTarget = {
+  NONE: 0, // Default value.
+  SELF: 1,
+  BLANK: 2,
+  PARENT: 3,
+  TOP: 4,
+};
+var LinkTargetStringMap = [
+  '',
+  '_self',
+  '_blank',
+  '_parent',
+  '_top'
+];
+
+function isExternalLinkTargetSet() {
+  switch (PDFJS.externalLinkTarget) {
+    case LinkTarget.NONE:
+      return false;
+    case LinkTarget.SELF:
+    case LinkTarget.BLANK:
+    case LinkTarget.PARENT:
+    case LinkTarget.TOP:
+      return true;
+  }
+  warn('PDFJS.externalLinkTarget is invalid: ' + PDFJS.externalLinkTarget);
+  // Reset the external link target, to suppress further warnings.
+  PDFJS.externalLinkTarget = LinkTarget.NONE;
+  return false;
+}
+PDFJS.isExternalLinkTargetSet = isExternalLinkTargetSet;
+
+var PasswordResponses = PDFJS.PasswordResponses = {
+  NEED_PASSWORD: 1,
+  INCORRECT_PASSWORD: 2
+};
+
+var PasswordException = (function PasswordExceptionClosure() {
+  function PasswordException(msg, code) {
+    this.name = 'PasswordException';
+    this.message = msg;
+    this.code = code;
+  }
+
+  PasswordException.prototype = new Error();
+  PasswordException.constructor = PasswordException;
+
+  return PasswordException;
+})();
+PDFJS.PasswordException = PasswordException;
+
+var UnknownErrorException = (function UnknownErrorExceptionClosure() {
+  function UnknownErrorException(msg, details) {
+    this.name = 'UnknownErrorException';
+    this.message = msg;
+    this.details = details;
+  }
+
+  UnknownErrorException.prototype = new Error();
+  UnknownErrorException.constructor = UnknownErrorException;
+
+  return UnknownErrorException;
+})();
+PDFJS.UnknownErrorException = UnknownErrorException;
+
+var InvalidPDFException = (function InvalidPDFExceptionClosure() {
+  function InvalidPDFException(msg) {
+    this.name = 'InvalidPDFException';
+    this.message = msg;
+  }
+
+  InvalidPDFException.prototype = new Error();
+  InvalidPDFException.constructor = InvalidPDFException;
+
+  return InvalidPDFException;
+})();
+PDFJS.InvalidPDFException = InvalidPDFException;
+
+var MissingPDFException = (function MissingPDFExceptionClosure() {
+  function MissingPDFException(msg) {
+    this.name = 'MissingPDFException';
+    this.message = msg;
+  }
+
+  MissingPDFException.prototype = new Error();
+  MissingPDFException.constructor = MissingPDFException;
+
+  return MissingPDFException;
+})();
+PDFJS.MissingPDFException = MissingPDFException;
+
+var UnexpectedResponseException =
+    (function UnexpectedResponseExceptionClosure() {
+  function UnexpectedResponseException(msg, status) {
+    this.name = 'UnexpectedResponseException';
+    this.message = msg;
+    this.status = status;
+  }
+
+  UnexpectedResponseException.prototype = new Error();
+  UnexpectedResponseException.constructor = UnexpectedResponseException;
+
+  return UnexpectedResponseException;
+})();
+PDFJS.UnexpectedResponseException = UnexpectedResponseException;
+
+var NotImplementedException = (function NotImplementedExceptionClosure() {
+  function NotImplementedException(msg) {
+    this.message = msg;
+  }
+
+  NotImplementedException.prototype = new Error();
+  NotImplementedException.prototype.name = 'NotImplementedException';
+  NotImplementedException.constructor = NotImplementedException;
+
+  return NotImplementedException;
+})();
+
+var MissingDataException = (function MissingDataExceptionClosure() {
+  function MissingDataException(begin, end) {
+    this.begin = begin;
+    this.end = end;
+    this.message = 'Missing data [' + begin + ', ' + end + ')';
+  }
+
+  MissingDataException.prototype = new Error();
+  MissingDataException.prototype.name = 'MissingDataException';
+  MissingDataException.constructor = MissingDataException;
+
+  return MissingDataException;
+})();
+
+var XRefParseException = (function XRefParseExceptionClosure() {
+  function XRefParseException(msg) {
+    this.message = msg;
+  }
+
+  XRefParseException.prototype = new Error();
+  XRefParseException.prototype.name = 'XRefParseException';
+  XRefParseException.constructor = XRefParseException;
+
+  return XRefParseException;
+})();
+
+
+function bytesToString(bytes) {
+  assert(bytes !== null && typeof bytes === 'object' &&
+         bytes.length !== undefined, 'Invalid argument for bytesToString');
+  var length = bytes.length;
+  var MAX_ARGUMENT_COUNT = 8192;
+  if (length < MAX_ARGUMENT_COUNT) {
+    return String.fromCharCode.apply(null, bytes);
+  }
+  var strBuf = [];
+  for (var i = 0; i < length; i += MAX_ARGUMENT_COUNT) {
+    var chunkEnd = Math.min(i + MAX_ARGUMENT_COUNT, length);
+    var chunk = bytes.subarray(i, chunkEnd);
+    strBuf.push(String.fromCharCode.apply(null, chunk));
+  }
+  return strBuf.join('');
+}
+
+function stringToBytes(str) {
+  assert(typeof str === 'string', 'Invalid argument for stringToBytes');
+  var length = str.length;
+  var bytes = new Uint8Array(length);
+  for (var i = 0; i < length; ++i) {
+    bytes[i] = str.charCodeAt(i) & 0xFF;
+  }
+  return bytes;
+}
+
+function string32(value) {
+  return String.fromCharCode((value >> 24) & 0xff, (value >> 16) & 0xff,
+                             (value >> 8) & 0xff, value & 0xff);
+}
+
+function log2(x) {
+  var n = 1, i = 0;
+  while (x > n) {
+    n <<= 1;
+    i++;
+  }
+  return i;
+}
+
+function readInt8(data, start) {
+  return (data[start] << 24) >> 24;
+}
+
+function readUint16(data, offset) {
+  return (data[offset] << 8) | data[offset + 1];
+}
+
+function readUint32(data, offset) {
+  return ((data[offset] << 24) | (data[offset + 1] << 16) |
+         (data[offset + 2] << 8) | data[offset + 3]) >>> 0;
+}
+
+// Lazy test the endianness of the platform
+// NOTE: This will be 'true' for simulated TypedArrays
+function isLittleEndian() {
+  var buffer8 = new Uint8Array(2);
+  buffer8[0] = 1;
+  var buffer16 = new Uint16Array(buffer8.buffer);
+  return (buffer16[0] === 1);
+}
+
+Object.defineProperty(PDFJS, 'isLittleEndian', {
+  configurable: true,
+  get: function PDFJS_isLittleEndian() {
+    return shadow(PDFJS, 'isLittleEndian', isLittleEndian());
+  }
+});
+
+  PDFJS.hasCanvasTypedArrays = true;
+
+var IDENTITY_MATRIX = [1, 0, 0, 1, 0, 0];
+
+var Util = PDFJS.Util = (function UtilClosure() {
+  function Util() {}
+
+  var rgbBuf = ['rgb(', 0, ',', 0, ',', 0, ')'];
+
+  // makeCssRgb() can be called thousands of times. Using |rgbBuf| avoids
+  // creating many intermediate strings.
+  Util.makeCssRgb = function Util_makeCssRgb(r, g, b) {
+    rgbBuf[1] = r;
+    rgbBuf[3] = g;
+    rgbBuf[5] = b;
+    return rgbBuf.join('');
+  };
+
+  // Concatenates two transformation matrices together and returns the result.
+  Util.transform = function Util_transform(m1, m2) {
+    return [
+      m1[0] * m2[0] + m1[2] * m2[1],
+      m1[1] * m2[0] + m1[3] * m2[1],
+      m1[0] * m2[2] + m1[2] * m2[3],
+      m1[1] * m2[2] + m1[3] * m2[3],
+      m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
+      m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
+    ];
+  };
+
+  // For 2d affine transforms
+  Util.applyTransform = function Util_applyTransform(p, m) {
+    var xt = p[0] * m[0] + p[1] * m[2] + m[4];
+    var yt = p[0] * m[1] + p[1] * m[3] + m[5];
+    return [xt, yt];
+  };
+
+  Util.applyInverseTransform = function Util_applyInverseTransform(p, m) {
+    var d = m[0] * m[3] - m[1] * m[2];
+    var xt = (p[0] * m[3] - p[1] * m[2] + m[2] * m[5] - m[4] * m[3]) / d;
+    var yt = (-p[0] * m[1] + p[1] * m[0] + m[4] * m[1] - m[5] * m[0]) / d;
+    return [xt, yt];
+  };
+
+  // Applies the transform to the rectangle and finds the minimum axially
+  // aligned bounding box.
+  Util.getAxialAlignedBoundingBox =
+    function Util_getAxialAlignedBoundingBox(r, m) {
+
+    var p1 = Util.applyTransform(r, m);
+    var p2 = Util.applyTransform(r.slice(2, 4), m);
+    var p3 = Util.applyTransform([r[0], r[3]], m);
+    var p4 = Util.applyTransform([r[2], r[1]], m);
+    return [
+      Math.min(p1[0], p2[0], p3[0], p4[0]),
+      Math.min(p1[1], p2[1], p3[1], p4[1]),
+      Math.max(p1[0], p2[0], p3[0], p4[0]),
+      Math.max(p1[1], p2[1], p3[1], p4[1])
+    ];
+  };
+
+  Util.inverseTransform = function Util_inverseTransform(m) {
+    var d = m[0] * m[3] - m[1] * m[2];
+    return [m[3] / d, -m[1] / d, -m[2] / d, m[0] / d,
+      (m[2] * m[5] - m[4] * m[3]) / d, (m[4] * m[1] - m[5] * m[0]) / d];
+  };
+
+  // Apply a generic 3d matrix M on a 3-vector v:
+  //   | a b c |   | X |
+  //   | d e f | x | Y |
+  //   | g h i |   | Z |
+  // M is assumed to be serialized as [a,b,c,d,e,f,g,h,i],
+  // with v as [X,Y,Z]
+  Util.apply3dTransform = function Util_apply3dTransform(m, v) {
+    return [
+      m[0] * v[0] + m[1] * v[1] + m[2] * v[2],
+      m[3] * v[0] + m[4] * v[1] + m[5] * v[2],
+      m[6] * v[0] + m[7] * v[1] + m[8] * v[2]
+    ];
+  };
+
+  // This calculation uses Singular Value Decomposition.
+  // The SVD can be represented with formula A = USV. We are interested in the
+  // matrix S here because it represents the scale values.
+  Util.singularValueDecompose2dScale =
+    function Util_singularValueDecompose2dScale(m) {
+
+    var transpose = [m[0], m[2], m[1], m[3]];
+
+    // Multiply matrix m with its transpose.
+    var a = m[0] * transpose[0] + m[1] * transpose[2];
+    var b = m[0] * transpose[1] + m[1] * transpose[3];
+    var c = m[2] * transpose[0] + m[3] * transpose[2];
+    var d = m[2] * transpose[1] + m[3] * transpose[3];
+
+    // Solve the second degree polynomial to get roots.
+    var first = (a + d) / 2;
+    var second = Math.sqrt((a + d) * (a + d) - 4 * (a * d - c * b)) / 2;
+    var sx = first + second || 1;
+    var sy = first - second || 1;
+
+    // Scale values are the square roots of the eigenvalues.
+    return [Math.sqrt(sx), Math.sqrt(sy)];
+  };
+
+  // Normalize rectangle rect=[x1, y1, x2, y2] so that (x1,y1) < (x2,y2)
+  // For coordinate systems whose origin lies in the bottom-left, this
+  // means normalization to (BL,TR) ordering. For systems with origin in the
+  // top-left, this means (TL,BR) ordering.
+  Util.normalizeRect = function Util_normalizeRect(rect) {
+    var r = rect.slice(0); // clone rect
+    if (rect[0] > rect[2]) {
+      r[0] = rect[2];
+      r[2] = rect[0];
+    }
+    if (rect[1] > rect[3]) {
+      r[1] = rect[3];
+      r[3] = rect[1];
+    }
+    return r;
+  };
+
+  // Returns a rectangle [x1, y1, x2, y2] corresponding to the
+  // intersection of rect1 and rect2. If no intersection, returns 'false'
+  // The rectangle coordinates of rect1, rect2 should be [x1, y1, x2, y2]
+  Util.intersect = function Util_intersect(rect1, rect2) {
+    function compare(a, b) {
+      return a - b;
+    }
+
+    // Order points along the axes
+    var orderedX = [rect1[0], rect1[2], rect2[0], rect2[2]].sort(compare),
+        orderedY = [rect1[1], rect1[3], rect2[1], rect2[3]].sort(compare),
+        result = [];
+
+    rect1 = Util.normalizeRect(rect1);
+    rect2 = Util.normalizeRect(rect2);
+
+    // X: first and second points belong to different rectangles?
+    if ((orderedX[0] === rect1[0] && orderedX[1] === rect2[0]) ||
+        (orderedX[0] === rect2[0] && orderedX[1] === rect1[0])) {
+      // Intersection must be between second and third points
+      result[0] = orderedX[1];
+      result[2] = orderedX[2];
+    } else {
+      return false;
+    }
+
+    // Y: first and second points belong to different rectangles?
+    if ((orderedY[0] === rect1[1] && orderedY[1] === rect2[1]) ||
+        (orderedY[0] === rect2[1] && orderedY[1] === rect1[1])) {
+      // Intersection must be between second and third points
+      result[1] = orderedY[1];
+      result[3] = orderedY[2];
+    } else {
+      return false;
+    }
+
+    return result;
+  };
+
+  Util.sign = function Util_sign(num) {
+    return num < 0 ? -1 : 1;
+  };
+
+  Util.appendToArray = function Util_appendToArray(arr1, arr2) {
+    Array.prototype.push.apply(arr1, arr2);
+  };
+
+  Util.prependToArray = function Util_prependToArray(arr1, arr2) {
+    Array.prototype.unshift.apply(arr1, arr2);
+  };
+
+  Util.extendObj = function extendObj(obj1, obj2) {
+    for (var key in obj2) {
+      obj1[key] = obj2[key];
+    }
+  };
+
+  Util.getInheritableProperty = function Util_getInheritableProperty(dict,
+                                                                     name) {
+    while (dict && !dict.has(name)) {
+      dict = dict.get('Parent');
+    }
+    if (!dict) {
+      return null;
+    }
+    return dict.get(name);
+  };
+
+  Util.inherit = function Util_inherit(sub, base, prototype) {
+    sub.prototype = Object.create(base.prototype);
+    sub.prototype.constructor = sub;
+    for (var prop in prototype) {
+      sub.prototype[prop] = prototype[prop];
+    }
+  };
+
+  Util.loadScript = function Util_loadScript(src, callback) {
+    var script = document.createElement('script');
+    var loaded = false;
+    script.setAttribute('src', src);
+    if (callback) {
+      script.onload = function() {
+        if (!loaded) {
+          callback();
+        }
+        loaded = true;
+      };
+    }
+    document.getElementsByTagName('head')[0].appendChild(script);
+  };
+
+  return Util;
+})();
+
+/**
+ * PDF page viewport created based on scale, rotation and offset.
+ * @class
+ * @alias PDFJS.PageViewport
+ */
+var PageViewport = PDFJS.PageViewport = (function PageViewportClosure() {
+  /**
+   * @constructor
+   * @private
+   * @param viewBox {Array} xMin, yMin, xMax and yMax coordinates.
+   * @param scale {number} scale of the viewport.
+   * @param rotation {number} rotations of the viewport in degrees.
+   * @param offsetX {number} offset X
+   * @param offsetY {number} offset Y
+   * @param dontFlip {boolean} if true, axis Y will not be flipped.
+   */
+  function PageViewport(viewBox, scale, rotation, offsetX, offsetY, dontFlip) {
+    this.viewBox = viewBox;
+    this.scale = scale;
+    this.rotation = rotation;
+    this.offsetX = offsetX;
+    this.offsetY = offsetY;
+
+    // creating transform to convert pdf coordinate system to the normal
+    // canvas like coordinates taking in account scale and rotation
+    var centerX = (viewBox[2] + viewBox[0]) / 2;
+    var centerY = (viewBox[3] + viewBox[1]) / 2;
+    var rotateA, rotateB, rotateC, rotateD;
+    rotation = rotation % 360;
+    rotation = rotation < 0 ? rotation + 360 : rotation;
+    switch (rotation) {
+      case 180:
+        rotateA = -1; rotateB = 0; rotateC = 0; rotateD = 1;
+        break;
+      case 90:
+        rotateA = 0; rotateB = 1; rotateC = 1; rotateD = 0;
+        break;
+      case 270:
+        rotateA = 0; rotateB = -1; rotateC = -1; rotateD = 0;
+        break;
+      //case 0:
+      default:
+        rotateA = 1; rotateB = 0; rotateC = 0; rotateD = -1;
+        break;
+    }
+
+    if (dontFlip) {
+      rotateC = -rotateC; rotateD = -rotateD;
+    }
+
+    var offsetCanvasX, offsetCanvasY;
+    var width, height;
+    if (rotateA === 0) {
+      offsetCanvasX = Math.abs(centerY - viewBox[1]) * scale + offsetX;
+      offsetCanvasY = Math.abs(centerX - viewBox[0]) * scale + offsetY;
+      width = Math.abs(viewBox[3] - viewBox[1]) * scale;
+      height = Math.abs(viewBox[2] - viewBox[0]) * scale;
+    } else {
+      offsetCanvasX = Math.abs(centerX - viewBox[0]) * scale + offsetX;
+      offsetCanvasY = Math.abs(centerY - viewBox[1]) * scale + offsetY;
+      width = Math.abs(viewBox[2] - viewBox[0]) * scale;
+      height = Math.abs(viewBox[3] - viewBox[1]) * scale;
+    }
+    // creating transform for the following operations:
+    // translate(-centerX, -centerY), rotate and flip vertically,
+    // scale, and translate(offsetCanvasX, offsetCanvasY)
+    this.transform = [
+      rotateA * scale,
+      rotateB * scale,
+      rotateC * scale,
+      rotateD * scale,
+      offsetCanvasX - rotateA * scale * centerX - rotateC * scale * centerY,
+      offsetCanvasY - rotateB * scale * centerX - rotateD * scale * centerY
+    ];
+
+    this.width = width;
+    this.height = height;
+    this.fontScale = scale;
+  }
+  PageViewport.prototype = /** @lends PDFJS.PageViewport.prototype */ {
+    /**
+     * Clones viewport with additional properties.
+     * @param args {Object} (optional) If specified, may contain the 'scale' or
+     * 'rotation' properties to override the corresponding properties in
+     * the cloned viewport.
+     * @returns {PDFJS.PageViewport} Cloned viewport.
+     */
+    clone: function PageViewPort_clone(args) {
+      args = args || {};
+      var scale = 'scale' in args ? args.scale : this.scale;
+      var rotation = 'rotation' in args ? args.rotation : this.rotation;
+      return new PageViewport(this.viewBox.slice(), scale, rotation,
+                              this.offsetX, this.offsetY, args.dontFlip);
+    },
+    /**
+     * Converts PDF point to the viewport coordinates. For examples, useful for
+     * converting PDF location into canvas pixel coordinates.
+     * @param x {number} X coordinate.
+     * @param y {number} Y coordinate.
+     * @returns {Object} Object that contains 'x' and 'y' properties of the
+     * point in the viewport coordinate space.
+     * @see {@link convertToPdfPoint}
+     * @see {@link convertToViewportRectangle}
+     */
+    convertToViewportPoint: function PageViewport_convertToViewportPoint(x, y) {
+      return Util.applyTransform([x, y], this.transform);
+    },
+    /**
+     * Converts PDF rectangle to the viewport coordinates.
+     * @param rect {Array} xMin, yMin, xMax and yMax coordinates.
+     * @returns {Array} Contains corresponding coordinates of the rectangle
+     * in the viewport coordinate space.
+     * @see {@link convertToViewportPoint}
+     */
+    convertToViewportRectangle:
+      function PageViewport_convertToViewportRectangle(rect) {
+      var tl = Util.applyTransform([rect[0], rect[1]], this.transform);
+      var br = Util.applyTransform([rect[2], rect[3]], this.transform);
+      return [tl[0], tl[1], br[0], br[1]];
+    },
+    /**
+     * Converts viewport coordinates to the PDF location. For examples, useful
+     * for converting canvas pixel location into PDF one.
+     * @param x {number} X coordinate.
+     * @param y {number} Y coordinate.
+     * @returns {Object} Object that contains 'x' and 'y' properties of the
+     * point in the PDF coordinate space.
+     * @see {@link convertToViewportPoint}
+     */
+    convertToPdfPoint: function PageViewport_convertToPdfPoint(x, y) {
+      return Util.applyInverseTransform([x, y], this.transform);
+    }
+  };
+  return PageViewport;
+})();
+
+var PDFStringTranslateTable = [
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0x2D8, 0x2C7, 0x2C6, 0x2D9, 0x2DD, 0x2DB, 0x2DA, 0x2DC, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014,
+  0x2013, 0x192, 0x2044, 0x2039, 0x203A, 0x2212, 0x2030, 0x201E, 0x201C,
+  0x201D, 0x2018, 0x2019, 0x201A, 0x2122, 0xFB01, 0xFB02, 0x141, 0x152, 0x160,
+  0x178, 0x17D, 0x131, 0x142, 0x153, 0x161, 0x17E, 0, 0x20AC
+];
+
+function stringToPDFString(str) {
+  var i, n = str.length, strBuf = [];
+  if (str[0] === '\xFE' && str[1] === '\xFF') {
+    // UTF16BE BOM
+    for (i = 2; i < n; i += 2) {
+      strBuf.push(String.fromCharCode(
+        (str.charCodeAt(i) << 8) | str.charCodeAt(i + 1)));
+    }
+  } else {
+    for (i = 0; i < n; ++i) {
+      var code = PDFStringTranslateTable[str.charCodeAt(i)];
+      strBuf.push(code ? String.fromCharCode(code) : str.charAt(i));
+    }
+  }
+  return strBuf.join('');
+}
+
+function stringToUTF8String(str) {
+  return decodeURIComponent(escape(str));
+}
+
+function utf8StringToString(str) {
+  return unescape(encodeURIComponent(str));
+}
+
+function isEmptyObj(obj) {
+  for (var key in obj) {
+    return false;
+  }
+  return true;
+}
+
+function isBool(v) {
+  return typeof v === 'boolean';
+}
+
+function isInt(v) {
+  return typeof v === 'number' && ((v | 0) === v);
+}
+
+function isNum(v) {
+  return typeof v === 'number';
+}
+
+function isString(v) {
+  return typeof v === 'string';
+}
+
+function isArray(v) {
+  return v instanceof Array;
+}
+
+function isArrayBuffer(v) {
+  return typeof v === 'object' && v !== null && v.byteLength !== undefined;
+}
+
+/**
+ * Promise Capability object.
+ *
+ * @typedef {Object} PromiseCapability
+ * @property {Promise} promise - A promise object.
+ * @property {function} resolve - Fullfills the promise.
+ * @property {function} reject - Rejects the promise.
+ */
+
+/**
+ * Creates a promise capability object.
+ * @alias PDFJS.createPromiseCapability
+ *
+ * @return {PromiseCapability} A capability object contains:
+ * - a Promise, resolve and reject methods.
+ */
+function createPromiseCapability() {
+  var capability = {};
+  capability.promise = new Promise(function (resolve, reject) {
+    capability.resolve = resolve;
+    capability.reject = reject;
+  });
+  return capability;
+}
+
+PDFJS.createPromiseCapability = createPromiseCapability;
+
+/**
+ * Polyfill for Promises:
+ * The following promise implementation tries to generally implement the
+ * Promise/A+ spec. Some notable differences from other promise libaries are:
+ * - There currently isn't a seperate deferred and promise object.
+ * - Unhandled rejections eventually show an error if they aren't handled.
+ *
+ * Based off of the work in:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=810490
+ */
+(function PromiseClosure() {
+  if (globalScope.Promise) {
+    // Promises existing in the DOM/Worker, checking presence of all/resolve
+    if (typeof globalScope.Promise.all !== 'function') {
+      globalScope.Promise.all = function (iterable) {
+        var count = 0, results = [], resolve, reject;
+        var promise = new globalScope.Promise(function (resolve_, reject_) {
+          resolve = resolve_;
+          reject = reject_;
+        });
+        iterable.forEach(function (p, i) {
+          count++;
+          p.then(function (result) {
+            results[i] = result;
+            count--;
+            if (count === 0) {
+              resolve(results);
+            }
+          }, reject);
+        });
+        if (count === 0) {
+          resolve(results);
+        }
+        return promise;
+      };
+    }
+    if (typeof globalScope.Promise.resolve !== 'function') {
+      globalScope.Promise.resolve = function (value) {
+        return new globalScope.Promise(function (resolve) { resolve(value); });
+      };
+    }
+    if (typeof globalScope.Promise.reject !== 'function') {
+      globalScope.Promise.reject = function (reason) {
+        return new globalScope.Promise(function (resolve, reject) {
+          reject(reason);
+        });
+      };
+    }
+    if (typeof globalScope.Promise.prototype.catch !== 'function') {
+      globalScope.Promise.prototype.catch = function (onReject) {
+        return globalScope.Promise.prototype.then(undefined, onReject);
+      };
+    }
+    return;
+  }
+  throw new Error('DOM Promise is not present');
+})();
+
+var StatTimer = (function StatTimerClosure() {
+  function rpad(str, pad, length) {
+    while (str.length < length) {
+      str += pad;
+    }
+    return str;
+  }
+  function StatTimer() {
+    this.started = {};
+    this.times = [];
+    this.enabled = true;
+  }
+  StatTimer.prototype = {
+    time: function StatTimer_time(name) {
+      if (!this.enabled) {
+        return;
+      }
+      if (name in this.started) {
+        warn('Timer is already running for ' + name);
+      }
+      this.started[name] = Date.now();
+    },
+    timeEnd: function StatTimer_timeEnd(name) {
+      if (!this.enabled) {
+        return;
+      }
+      if (!(name in this.started)) {
+        warn('Timer has not been started for ' + name);
+      }
+      this.times.push({
+        'name': name,
+        'start': this.started[name],
+        'end': Date.now()
+      });
+      // Remove timer from started so it can be called again.
+      delete this.started[name];
+    },
+    toString: function StatTimer_toString() {
+      var i, ii;
+      var times = this.times;
+      var out = '';
+      // Find the longest name for padding purposes.
+      var longest = 0;
+      for (i = 0, ii = times.length; i < ii; ++i) {
+        var name = times[i]['name'];
+        if (name.length > longest) {
+          longest = name.length;
+        }
+      }
+      for (i = 0, ii = times.length; i < ii; ++i) {
+        var span = times[i];
+        var duration = span.end - span.start;
+        out += rpad(span['name'], ' ', longest) + ' ' + duration + 'ms\n';
+      }
+      return out;
+    }
+  };
+  return StatTimer;
+})();
+
+PDFJS.createBlob = function createBlob(data, contentType) {
+  if (typeof Blob !== 'undefined') {
+    return new Blob([data], { type: contentType });
+  }
+  // Blob builder is deprecated in FF14 and removed in FF18.
+  var bb = new MozBlobBuilder();
+  bb.append(data);
+  return bb.getBlob(contentType);
+};
+
+PDFJS.createObjectURL = (function createObjectURLClosure() {
+  // Blob/createObjectURL is not available, falling back to data schema.
+  var digits =
+    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
+
+  return function createObjectURL(data, contentType) {
+    if (!PDFJS.disableCreateObjectURL &&
+        typeof URL !== 'undefined' && URL.createObjectURL) {
+      var blob = PDFJS.createBlob(data, contentType);
+      return URL.createObjectURL(blob);
+    }
+
+    var buffer = 'data:' + contentType + ';base64,';
+    for (var i = 0, ii = data.length; i < ii; i += 3) {
+      var b1 = data[i] & 0xFF;
+      var b2 = data[i + 1] & 0xFF;
+      var b3 = data[i + 2] & 0xFF;
+      var d1 = b1 >> 2, d2 = ((b1 & 3) << 4) | (b2 >> 4);
+      var d3 = i + 1 < ii ? ((b2 & 0xF) << 2) | (b3 >> 6) : 64;
+      var d4 = i + 2 < ii ? (b3 & 0x3F) : 64;
+      buffer += digits[d1] + digits[d2] + digits[d3] + digits[d4];
+    }
+    return buffer;
+  };
+})();
+
+function MessageHandler(sourceName, targetName, comObj) {
+  this.sourceName = sourceName;
+  this.targetName = targetName;
+  this.comObj = comObj;
+  this.callbackIndex = 1;
+  this.postMessageTransfers = true;
+  var callbacksCapabilities = this.callbacksCapabilities = {};
+  var ah = this.actionHandler = {};
+
+  this._onComObjOnMessage = function messageHandlerComObjOnMessage(event) {
+    var data = event.data;
+    if (data.targetName !== this.sourceName) {
+      return;
+    }
+    if (data.isReply) {
+      var callbackId = data.callbackId;
+      if (data.callbackId in callbacksCapabilities) {
+        var callback = callbacksCapabilities[callbackId];
+        delete callbacksCapabilities[callbackId];
+        if ('error' in data) {
+          callback.reject(data.error);
+        } else {
+          callback.resolve(data.data);
+        }
+      } else {
+        error('Cannot resolve callback ' + callbackId);
+      }
+    } else if (data.action in ah) {
+      var action = ah[data.action];
+      if (data.callbackId) {
+        var sourceName = this.sourceName;
+        var targetName = data.sourceName;
+        Promise.resolve().then(function () {
+          return action[0].call(action[1], data.data);
+        }).then(function (result) {
+          comObj.postMessage({
+            sourceName: sourceName,
+            targetName: targetName,
+            isReply: true,
+            callbackId: data.callbackId,
+            data: result
+          });
+        }, function (reason) {
+          if (reason instanceof Error) {
+            // Serialize error to avoid "DataCloneError"
+            reason = reason + '';
+          }
+          comObj.postMessage({
+            sourceName: sourceName,
+            targetName: targetName,
+            isReply: true,
+            callbackId: data.callbackId,
+            error: reason
+          });
+        });
+      } else {
+        action[0].call(action[1], data.data);
+      }
+    } else {
+      error('Unknown action from worker: ' + data.action);
+    }
+  }.bind(this);
+  comObj.addEventListener('message', this._onComObjOnMessage);
+}
+
+MessageHandler.prototype = {
+  on: function messageHandlerOn(actionName, handler, scope) {
+    var ah = this.actionHandler;
+    if (ah[actionName]) {
+      error('There is already an actionName called "' + actionName + '"');
+    }
+    ah[actionName] = [handler, scope];
+  },
+  /**
+   * Sends a message to the comObj to invoke the action with the supplied data.
+   * @param {String} actionName Action to call.
+   * @param {JSON} data JSON data to send.
+   * @param {Array} [transfers] Optional list of transfers/ArrayBuffers
+   */
+  send: function messageHandlerSend(actionName, data, transfers) {
+    var message = {
+      sourceName: this.sourceName,
+      targetName: this.targetName,
+      action: actionName,
+      data: data
+    };
+    this.postMessage(message, transfers);
+  },
+  /**
+   * Sends a message to the comObj to invoke the action with the supplied data.
+   * Expects that other side will callback with the response.
+   * @param {String} actionName Action to call.
+   * @param {JSON} data JSON data to send.
+   * @param {Array} [transfers] Optional list of transfers/ArrayBuffers.
+   * @returns {Promise} Promise to be resolved with response data.
+   */
+  sendWithPromise:
+    function messageHandlerSendWithPromise(actionName, data, transfers) {
+    var callbackId = this.callbackIndex++;
+    var message = {
+      sourceName: this.sourceName,
+      targetName: this.targetName,
+      action: actionName,
+      data: data,
+      callbackId: callbackId
+    };
+    var capability = createPromiseCapability();
+    this.callbacksCapabilities[callbackId] = capability;
+    try {
+      this.postMessage(message, transfers);
+    } catch (e) {
+      capability.reject(e);
+    }
+    return capability.promise;
+  },
+  /**
+   * Sends raw message to the comObj.
+   * @private
+   * @param message {Object} Raw message.
+   * @param transfers List of transfers/ArrayBuffers, or undefined.
+   */
+  postMessage: function (message, transfers) {
+    if (transfers && this.postMessageTransfers) {
+      this.comObj.postMessage(message, transfers);
+    } else {
+      this.comObj.postMessage(message);
+    }
+  },
+
+  destroy: function () {
+    this.comObj.removeEventListener('message', this._onComObjOnMessage);
+  }
+};
+
+function loadJpegStream(id, imageUrl, objs) {
+  var img = new Image();
+  img.onload = (function loadJpegStream_onloadClosure() {
+    objs.resolve(id, img);
+  });
+  img.onerror = (function loadJpegStream_onerrorClosure() {
+    objs.resolve(id, null);
+    warn('Error during JPEG image loading');
+  });
+  img.src = imageUrl;
+}
+
+exports.FONT_IDENTITY_MATRIX = FONT_IDENTITY_MATRIX;
+exports.IDENTITY_MATRIX = IDENTITY_MATRIX;
+exports.OPS = OPS;
+exports.UNSUPPORTED_FEATURES = UNSUPPORTED_FEATURES;
+exports.AnnotationBorderStyleType = AnnotationBorderStyleType;
+exports.AnnotationFlag = AnnotationFlag;
+exports.AnnotationType = AnnotationType;
+exports.FontType = FontType;
+exports.ImageKind = ImageKind;
+exports.InvalidPDFException = InvalidPDFException;
+exports.LinkTarget = LinkTarget;
+exports.LinkTargetStringMap = LinkTargetStringMap;
+exports.MessageHandler = MessageHandler;
+exports.MissingDataException = MissingDataException;
+exports.MissingPDFException = MissingPDFException;
+exports.NotImplementedException = NotImplementedException;
+exports.PasswordException = PasswordException;
+exports.PasswordResponses = PasswordResponses;
+exports.StatTimer = StatTimer;
+exports.StreamType = StreamType;
+exports.TextRenderingMode = TextRenderingMode;
+exports.UnexpectedResponseException = UnexpectedResponseException;
+exports.UnknownErrorException = UnknownErrorException;
+exports.Util = Util;
+exports.XRefParseException = XRefParseException;
+exports.assert = assert;
+exports.bytesToString = bytesToString;
+exports.combineUrl = combineUrl;
+exports.createPromiseCapability = createPromiseCapability;
+exports.deprecated = deprecated;
+exports.error = error;
+exports.info = info;
+exports.isArray = isArray;
+exports.isArrayBuffer = isArrayBuffer;
+exports.isBool = isBool;
+exports.isEmptyObj = isEmptyObj;
+exports.isExternalLinkTargetSet = isExternalLinkTargetSet;
+exports.isInt = isInt;
+exports.isNum = isNum;
+exports.isString = isString;
+exports.isValidUrl = isValidUrl;
+exports.loadJpegStream = loadJpegStream;
+exports.log2 = log2;
+exports.readInt8 = readInt8;
+exports.readUint16 = readUint16;
+exports.readUint32 = readUint32;
+exports.shadow = shadow;
+exports.string32 = string32;
+exports.stringToBytes = stringToBytes;
+exports.stringToPDFString = stringToPDFString;
+exports.stringToUTF8String = stringToUTF8String;
+exports.utf8StringToString = utf8StringToString;
+exports.warn = warn;
+}));
+
+
+(function (root, factory) {
+  {
     factory((root.pdfjsCoreChunkedStream = {}), root.pdfjsSharedUtil);
   }
 }(this, function (exports, sharedUtil) {
 
 var MissingDataException = sharedUtil.MissingDataException;
 var assert = sharedUtil.assert;
 var createPromiseCapability = sharedUtil.createPromiseCapability;
 var isInt = sharedUtil.isInt;
@@ -17380,16 +17381,17 @@ var PasswordResponses = sharedUtil.Passw
 var bytesToString = sharedUtil.bytesToString;
 var error = sharedUtil.error;
 var isInt = sharedUtil.isInt;
 var stringToBytes = sharedUtil.stringToBytes;
 var utf8StringToString = sharedUtil.utf8StringToString;
 var warn = sharedUtil.warn;
 var Name = corePrimitives.Name;
 var isName = corePrimitives.isName;
+var isDict = corePrimitives.isDict;
 var DecryptStream = coreStream.DecryptStream;
 
 var ARCFourCipher = (function ARCFourCipherClosure() {
   function ARCFourCipher(key) {
     this.a = 0;
     this.b = 0;
     var s = new Uint8Array(256);
     var i, j = 0, tmp, keyLength = key.length;
@@ -19263,17 +19265,37 @@ var CipherTransformFactory = (function C
     this.dict = dict;
     var algorithm = dict.get('V');
     if (!isInt(algorithm) ||
         (algorithm !== 1 && algorithm !== 2 && algorithm !== 4 &&
         algorithm !== 5)) {
       error('unsupported encryption algorithm');
     }
     this.algorithm = algorithm;
-    var keyLength = dict.get('Length') || 40;
+    var keyLength = dict.get('Length');
+    if (!keyLength) {
+      // Spec asks to rely on encryption dictionary's Length entry, however
+      // some PDFs don't have it. Trying to recover.
+      if (algorithm <= 3) {
+        // For 1 and 2 it's fixed to 40-bit, for 3 40-bit is a minimal value.
+        keyLength = 40;
+      } else {
+        // Trying to find default handler -- it usually has Length.
+        var cfDict = dict.get('CF');
+        var streamCryptoName = dict.get('StmF');
+        if (isDict(cfDict) && isName(streamCryptoName)) {
+          var handlerDict = cfDict.get(streamCryptoName.name);
+          keyLength = (handlerDict && handlerDict.get('Length')) || 128;
+          if (keyLength < 40) {
+            // Sometimes it's incorrect value of bits, generators specify bytes.
+            keyLength <<= 3;
+          }
+        }
+      }
+    }
     if (!isInt(keyLength) ||
         keyLength < 40 || (keyLength % 8) !== 0) {
       error('invalid key length');
     }
 
     // prepare keys
     var ownerPassword = stringToBytes(dict.get('O')).subarray(0, 32);
     var userPassword = stringToBytes(dict.get('U')).subarray(0, 32);
@@ -38224,18 +38246,16 @@ var warn = sharedUtil.warn;
 var Dict = corePrimitives.Dict;
 var isDict = corePrimitives.isDict;
 var isName = corePrimitives.isName;
 var Stream = coreStream.Stream;
 var ColorSpace = coreColorSpace.ColorSpace;
 var ObjectLoader = coreObj.ObjectLoader;
 var OperatorList = coreEvaluator.OperatorList;
 
-var DEFAULT_ICON_SIZE = 22; // px
-
 /**
  * @class
  * @alias AnnotationFactory
  */
 function AnnotationFactory() {}
 AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
   /**
    * @param {XRef} xref
@@ -38267,16 +38287,22 @@ AnnotationFactory.prototype = /** @lends
 
       case 'Widget':
         var fieldType = Util.getInheritableProperty(dict, 'FT');
         if (isName(fieldType) && fieldType.name === 'Tx') {
           return new TextWidgetAnnotation(parameters);
         }
         return new WidgetAnnotation(parameters);
 
+      case 'Popup':
+        return new PopupAnnotation(parameters);
+
+      case 'Underline':
+        return new UnderlineAnnotation(parameters);
+
       default:
         warn('Unimplemented annotation type "' + subtype + '", ' +
              'falling back to base annotation');
         return new Annotation(parameters);
     }
   }
 };
 
@@ -38332,17 +38358,17 @@ var Annotation = (function AnnotationClo
     this.setFlags(dict.get('F'));
     this.setRectangle(dict.get('Rect'));
     this.setColor(dict.get('C'));
     this.setBorderStyle(dict);
     this.appearance = getDefaultAppearance(dict);
 
     // Expose public properties using a data object.
     this.data = {};
-    this.data.id = params.ref.num;
+    this.data.id = params.ref.toString();
     this.data.subtype = dict.get('Subtype').name;
     this.data.annotationFlags = this.flags;
     this.data.rect = this.rectangle;
     this.data.color = this.color;
     this.data.borderStyle = this.borderStyle;
     this.data.hasAppearance = !!this.appearance;
   }
 
@@ -38811,39 +38837,45 @@ var TextWidgetAnnotation = (function Tex
         });
     }
   });
 
   return TextWidgetAnnotation;
 })();
 
 var TextAnnotation = (function TextAnnotationClosure() {
-  function TextAnnotation(params) {
-    Annotation.call(this, params);
-
-    var dict = params.dict;
-    var data = this.data;
-
-    var content = dict.get('Contents');
-    var title = dict.get('T');
-    data.annotationType = AnnotationType.TEXT;
-    data.content = stringToPDFString(content || '');
-    data.title = stringToPDFString(title || '');
-    data.hasHtml = true;
-
-    if (data.hasAppearance) {
-      data.name = 'NoIcon';
-    } else {
-      data.rect[1] = data.rect[3] - DEFAULT_ICON_SIZE;
-      data.rect[2] = data.rect[0] + DEFAULT_ICON_SIZE;
-      data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
-    }
-
-    if (dict.has('C')) {
-      data.hasBgColor = true;
+  var DEFAULT_ICON_SIZE = 22; // px
+
+  function TextAnnotation(parameters) {
+    Annotation.call(this, parameters);
+
+    this.data.annotationType = AnnotationType.TEXT;
+    this.data.hasHtml = true;
+
+    var dict = parameters.dict;
+    if (this.data.hasAppearance) {
+      this.data.name = 'NoIcon';
+    } else {
+      this.data.rect[1] = this.data.rect[3] - DEFAULT_ICON_SIZE;
+      this.data.rect[2] = this.data.rect[0] + DEFAULT_ICON_SIZE;
+      this.data.name = dict.has('Name') ? dict.get('Name').name : 'Note';
+    }
+
+    if (!dict.has('C')) {
+      // Fall back to the default background color.
+      this.data.color = null;
+    }
+
+    this.data.hasPopup = dict.has('Popup');
+    if (!this.data.hasPopup) {
+      // There is no associated Popup annotation, so the Text annotation
+      // must create its own popup.
+      this.data.title = stringToPDFString(dict.get('T') || '');
+      this.data.contents = stringToPDFString(dict.get('Contents') || '');
+      this.data.hasHtml = (this.data.title || this.data.contents);
     }
   }
 
   Util.inherit(TextAnnotation, Annotation, {});
 
   return TextAnnotation;
 })();
 
@@ -38918,16 +38950,65 @@ var LinkAnnotation = (function LinkAnnot
     return url;
   }
 
   Util.inherit(LinkAnnotation, Annotation, {});
 
   return LinkAnnotation;
 })();
 
+var PopupAnnotation = (function PopupAnnotationClosure() {
+  function PopupAnnotation(parameters) {
+    Annotation.call(this, parameters);
+
+    this.data.annotationType = AnnotationType.POPUP;
+
+    var dict = parameters.dict;
+    var parentItem = dict.get('Parent');
+    if (!parentItem) {
+      warn('Popup annotation has a missing or invalid parent annotation.');
+      return;
+    }
+
+    this.data.parentId = dict.getRaw('Parent').toString();
+    this.data.title = stringToPDFString(parentItem.get('T') || '');
+    this.data.contents = stringToPDFString(parentItem.get('Contents') || '');
+
+    if (!parentItem.has('C')) {
+      // Fall back to the default background color.
+      this.data.color = null;
+    } else {
+      this.setColor(parentItem.get('C'));
+      this.data.color = this.color;
+    }
+
+    this.data.hasHtml = (this.data.title || this.data.contents);
+  }
+
+  Util.inherit(PopupAnnotation, Annotation, {});
+
+  return PopupAnnotation;
+})();
+
+var UnderlineAnnotation = (function UnderlineAnnotationClosure() {
+  function UnderlineAnnotation(parameters) {
+    Annotation.call(this, parameters);
+
+    this.data.annotationType = AnnotationType.UNDERLINE;
+    this.data.hasHtml = true;
+
+    // PDF viewers completely ignore any border styles.
+    this.data.borderStyle.setWidth(0);
+  }
+
+  Util.inherit(UnderlineAnnotation, Annotation, {});
+
+  return UnderlineAnnotation;
+})();
+
 exports.Annotation = Annotation;
 exports.AnnotationBorderStyle = AnnotationBorderStyle;
 exports.AnnotationFactory = AnnotationFactory;
 }));
 
 
 (function (root, factory) {
   {
@@ -39781,17 +39862,23 @@ var WorkerTask = (function WorkerTaskClo
     }
   };
 
   return WorkerTask;
 })();
 
 var WorkerMessageHandler = PDFJS.WorkerMessageHandler = {
   setup: function wphSetup(handler, port) {
+    var testMessageProcessed = false;
     handler.on('test', function wphSetupTest(data) {
+      if (testMessageProcessed) {
+        return; // we already processed 'test' message once
+      }
+      testMessageProcessed = true;
+
       // check if Uint8Array can be sent to worker
       if (!(data instanceof Uint8Array)) {
         handler.send('test', 'main', false);
         return;
       }
       // making sure postMessage transfers are working
       var supportTransfers = data[0] === 255;
       handler.postMessageTransfers = supportTransfers;
@@ -40308,60 +40395,27 @@ var WorkerMessageHandler = PDFJS.WorkerM
     handler.on('Ready', function wphReady(data) {
       setupDoc(docParams);
       docParams = null; // we don't need docParams anymore -- saving memory.
     });
     return workerHandlerName;
   }
 };
 
-var consoleTimer = {};
-
-var workerConsole = {
-  log: function log() {
-    var args = Array.prototype.slice.call(arguments);
-    globalScope.postMessage({
-      targetName: 'main',
-      action: 'console_log',
-      data: args
-    });
-  },
-
-  error: function error() {
-    var args = Array.prototype.slice.call(arguments);
-    globalScope.postMessage({
-      targetName: 'main',
-      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' && typeof require === 'undefined') {
-  if (!('console' in globalScope)) {
-    globalScope.console = workerConsole;
-  }
+function initializeWorker() {
 
   var handler = new MessageHandler('worker', 'main', self);
   WorkerMessageHandler.setup(handler, self);
+  handler.send('ready', null);
+}
+
+// Worker thread (and not node.js)?
+if (typeof window === 'undefined' &&
+    !(typeof module !== 'undefined' && module.require)) {
+  initializeWorker();
 }
 
 exports.WorkerTask = WorkerTask;
 exports.WorkerMessageHandler = WorkerMessageHandler;
 }));
 
 
 }).call((typeof window === 'undefined') ? this : window);
--- a/browser/extensions/pdfjs/content/network.js
+++ b/browser/extensions/pdfjs/content/network.js
@@ -259,8 +259,9 @@ var NetworkManager = (function NetworkMa
       delete this.pendingRequests[xhrId];
       xhr.abort();
     }
   };
 
   return NetworkManager;
 })();
 
+
--- a/browser/extensions/pdfjs/content/web/viewer.css
+++ b/browser/extensions/pdfjs/content/web/viewer.css
@@ -76,62 +76,68 @@
   top: 0px;
 }
 
 
 .annotationLayer section {
   position: absolute;
 }
 
-.annotationLayer .annotLink > a:hover {
-  opacity: 0.2;
-  background: #ff0;
-  box-shadow: 0px 2px 10px #ff0;
-}
-
-.annotationLayer .annotText > img {
-  position: absolute;
-  cursor: pointer;
-}
-
-.annotationLayer .annotTextContentWrapper {
-  position: absolute;
-  width: 20em;
-}
-
-.annotationLayer .annotTextContent {
-  z-index: 200;
-  float: left;
-  max-width: 20em;
-  background-color: #FFFF99;
-  box-shadow: 0px 2px 5px #333;
-  border-radius: 2px;
-  padding: 0.6em;
-  cursor: pointer;
-}
-
-.annotationLayer .annotTextContent > h1 {
-  font-size: 1em;
-  border-bottom: 1px solid #000000;
-  padding-bottom: 0.2em;
-}
-
-.annotationLayer .annotTextContent > p {
-  padding-top: 0.2em;
-}
-
-.annotationLayer .annotLink > a {
+.annotationLayer .linkAnnotation > a {
   position: absolute;
   font-size: 1em;
   top: 0;
   left: 0;
   width: 100%;
   height: 100%;
 }
 
+.annotationLayer .linkAnnotation > a:hover {
+  opacity: 0.2;
+  background: #ff0;
+  box-shadow: 0px 2px 10px #ff0;
+}
+
+.annotationLayer .textAnnotation img {
+  position: absolute;
+  cursor: pointer;
+}
+
+.annotationLayer .popupWrapper {
+  position: absolute;
+  width: 20em;
+}
+
+.annotationLayer .popup {
+  position: absolute;
+  z-index: 200;
+  max-width: 20em;
+  background-color: #FFFF99;
+  box-shadow: 0px 2px 5px #333;
+  border-radius: 2px;
+  padding: 0.6em;
+  margin-left: 5px;
+  cursor: pointer;
+  word-wrap: break-word;
+}
+
+.annotationLayer .popup h1 {
+  font-size: 1em;
+  border-bottom: 1px solid #000000;
+  padding-bottom: 0.2em;
+}
+
+.annotationLayer .popup p {
+  padding-top: 0.2em;
+}
+
+.annotationLayer .underlineAnnotation {
+  cursor: pointer;
+}
+
 .pdfViewer .canvasWrapper {
   overflow: hidden;
 }
 
 .pdfViewer .page {
   direction: ltr;
   width: 816px;
   height: 1056px;
--- a/browser/extensions/pdfjs/content/web/viewer.js
+++ b/browser/extensions/pdfjs/content/web/viewer.js
@@ -29,20 +29,22 @@ var DEFAULT_URL = 'compressed.tracemonke
 var DEFAULT_SCALE_DELTA = 1.1;
 var MIN_SCALE = 0.25;
 var MAX_SCALE = 10.0;
 var SCALE_SELECT_CONTAINER_PADDING = 8;
 var SCALE_SELECT_PADDING = 22;
 var PAGE_NUMBER_LOADING_INDICATOR = 'visiblePageIsLoading';
 var DISABLE_AUTO_FETCH_LOADING_BAR_TIMEOUT = 5000;
 
-PDFJS.imageResourcesPath = './images/';
+function configure(PDFJS) {
+  PDFJS.imageResourcesPath = './images/';
   PDFJS.workerSrc = '../build/pdf.worker.js';
   PDFJS.cMapUrl = '../web/cmaps/';
   PDFJS.cMapPacked = true;
+}
 
 var mozL10n = document.mozL10n || document.webL10n;
 
 
 var CSS_UNITS = 96.0 / 72.0;
 var DEFAULT_SCALE_VALUE = 'auto';
 var DEFAULT_SCALE = 1.0;
 var UNKNOWN_SCALE = 0;
@@ -3434,51 +3436,49 @@ var TEXT_LAYER_RENDER_DELAY = 200; // ms
 /**
  * @typedef {Object} PDFPageViewOptions
  * @property {HTMLDivElement} container - The viewer element.
  * @property {number} id - The page unique ID (normally its number).
  * @property {number} scale - The page scale display.
  * @property {PageViewport} defaultViewport - The page viewport.
  * @property {PDFRenderingQueue} renderingQueue - The rendering queue object.
  * @property {IPDFTextLayerFactory} textLayerFactory
- * @property {IPDFAnnotationsLayerFactory} annotationsLayerFactory
+ * @property {IPDFAnnotationLayerFactory} annotationLayerFactory
  */
 
 /**
  * @class
  * @implements {IRenderableView}
  */
 var PDFPageView = (function PDFPageViewClosure() {
-  var CustomStyle = PDFJS.CustomStyle;
-
   /**
    * @constructs PDFPageView
    * @param {PDFPageViewOptions} options
    */
   function PDFPageView(options) {
     var container = options.container;
     var id = options.id;
     var scale = options.scale;
     var defaultViewport = options.defaultViewport;
     var renderingQueue = options.renderingQueue;
     var textLayerFactory = options.textLayerFactory;
-    var annotationsLayerFactory = options.annotationsLayerFactory;
+    var annotationLayerFactory = options.annotationLayerFactory;
 
     this.id = id;
     this.renderingId = 'page' + id;
 
     this.rotation = 0;
     this.scale = scale || DEFAULT_SCALE;
     this.viewport = defaultViewport;
     this.pdfPageRotate = defaultViewport.rotation;
     this.hasRestrictedScaling = false;
 
     this.renderingQueue = renderingQueue;
     this.textLayerFactory = textLayerFactory;
-    this.annotationsLayerFactory = annotationsLayerFactory;
+    this.annotationLayerFactory = annotationLayerFactory;
 
     this.renderingState = RenderingStates.INITIAL;
     this.resume = null;
 
     this.onBeforeDraw = null;
     this.onAfterDraw = null;
 
     this.textLayer = null;
@@ -3617,16 +3617,18 @@ var PDFPageView = (function PDFPageViewC
      */
     updatePosition: function PDFPageView_updatePosition() {
       if (this.textLayer) {
         this.textLayer.render(TEXT_LAYER_RENDER_DELAY);
       }
     },
 
     cssTransform: function PDFPageView_transform(canvas, redrawAnnotations) {
+      var CustomStyle = PDFJS.CustomStyle;
+
       // Scale canvas, canvas wrapper, and page container.
       var width = this.viewport.width;
       var height = this.viewport.height;
       var div = this.div;
       canvas.style.width = canvas.parentNode.style.width = div.style.width =
         Math.floor(width) + 'px';
       canvas.style.height = canvas.parentNode.style.height = div.style.height =
         Math.floor(height) + 'px';
@@ -3897,32 +3899,33 @@ var PDFPageView = (function PDFPageViewC
             );
           }
         },
         function pdfPageRenderError(error) {
           pageViewDrawCallback(error);
         }
       );
 
-      if (this.annotationsLayerFactory) {
+      if (this.annotationLayerFactory) {
         if (!this.annotationLayer) {
-          this.annotationLayer = this.annotationsLayerFactory.
-            createAnnotationsLayerBuilder(div, this.pdfPage);
+          this.annotationLayer = this.annotationLayerFactory.
+            createAnnotationLayerBuilder(div, this.pdfPage);
         }
         this.annotationLayer.render(this.viewport, 'display');
       }
       div.setAttribute('data-loaded', true);
 
       if (self.onBeforeDraw) {
         self.onBeforeDraw();
       }
       return promise;
     },
 
     beforePrint: function PDFPageView_beforePrint() {
+      var CustomStyle = PDFJS.CustomStyle;
       var pdfPage = this.pdfPage;
 
       var viewport = pdfPage.getViewport(1);
       // Use the same hack we use for high dpi displays for printing to get
       // better output until bug 811002 is fixed in FF.
       var PRINT_OUTPUT_SCALE = 2;
       var canvas = document.createElement('canvas');
 
@@ -4291,102 +4294,109 @@ DefaultTextLayerFactory.prototype = {
       pageIndex: pageIndex,
       viewport: viewport
     });
   }
 };
 
 
 /**
- * @typedef {Object} AnnotationsLayerBuilderOptions
+ * @typedef {Object} AnnotationLayerBuilderOptions
  * @property {HTMLDivElement} pageDiv
  * @property {PDFPage} pdfPage
  * @property {IPDFLinkService} linkService
  */
 
 /**
  * @class
  */
-var AnnotationsLayerBuilder = (function AnnotationsLayerBuilderClosure() {
+var AnnotationLayerBuilder = (function AnnotationLayerBuilderClosure() {
   /**
-   * @param {AnnotationsLayerBuilderOptions} options
-   * @constructs AnnotationsLayerBuilder
+   * @param {AnnotationLayerBuilderOptions} options
+   * @constructs AnnotationLayerBuilder
    */
-  function AnnotationsLayerBuilder(options) {
+  function AnnotationLayerBuilder(options) {
     this.pageDiv = options.pageDiv;
     this.pdfPage = options.pdfPage;
     this.linkService = options.linkService;
 
     this.div = null;
   }
 
-  AnnotationsLayerBuilder.prototype =
-      /** @lends AnnotationsLayerBuilder.prototype */ {
+  AnnotationLayerBuilder.prototype =
+      /** @lends AnnotationLayerBuilder.prototype */ {
 
     /**
      * @param {PageViewport} viewport
      * @param {string} intent (default value is 'display')
      */
-    render: function AnnotationsLayerBuilder_render(viewport, intent) {
+    render: function AnnotationLayerBuilder_render(viewport, intent) {
       var self = this;
       var parameters = {
         intent: (intent === undefined ? 'display' : intent),
       };
 
       this.pdfPage.getAnnotations(parameters).then(function (annotations) {
         viewport = viewport.clone({ dontFlip: true });
+        parameters = {
+          viewport: viewport,
+          div: self.div,
+          annotations: annotations,
+          page: self.pdfPage,
+          linkService: self.linkService
+        };
 
         if (self.div) {
           // If an annotationLayer already exists, refresh its children's
           // transformation matrices.
-          PDFJS.AnnotationLayer.update(viewport, self.div, annotations);
+          PDFJS.AnnotationLayer.update(parameters);
         } else {
           // Create an annotation layer div and render the annotations
           // if there is at least one annotation.
           if (annotations.length === 0) {
             return;
           }
 
           self.div = document.createElement('div');
           self.div.className = 'annotationLayer';
           self.pageDiv.appendChild(self.div);
-
-          PDFJS.AnnotationLayer.render(viewport, self.div, annotations,
-                                       self.pdfPage, self.linkService);
+          parameters.div = self.div;
+
+          PDFJS.AnnotationLayer.render(parameters);
           if (typeof mozL10n !== 'undefined') {
             mozL10n.translate(self.div);
           }
         }
       });
     },
 
-    hide: function AnnotationsLayerBuilder_hide() {
+    hide: function AnnotationLayerBuilder_hide() {
       if (!this.div) {
         return;
       }
       this.div.setAttribute('hidden', 'true');
     }
   };
 
-  return AnnotationsLayerBuilder;
+  return AnnotationLayerBuilder;
 })();
 
 /**
  * @constructor
- * @implements IPDFAnnotationsLayerFactory
+ * @implements IPDFAnnotationLayerFactory
  */
-function DefaultAnnotationsLayerFactory() {}
-DefaultAnnotationsLayerFactory.prototype = {
+function DefaultAnnotationLayerFactory() {}
+DefaultAnnotationLayerFactory.prototype = {
   /**
    * @param {HTMLDivElement} pageDiv
    * @param {PDFPage} pdfPage
-   * @returns {AnnotationsLayerBuilder}
+   * @returns {AnnotationLayerBuilder}
    */
-  createAnnotationsLayerBuilder: function (pageDiv, pdfPage) {
-    return new AnnotationsLayerBuilder({
+  createAnnotationLayerBuilder: function (pageDiv, pdfPage) {
+    return new AnnotationLayerBuilder({
       pageDiv: pageDiv,
       pdfPage: pdfPage,
       linkService: new SimpleLinkService(),
     });
   }
 };
 
 
@@ -4644,17 +4654,17 @@ var PDFViewer = (function pdfViewer() {
           }
           var pageView = new PDFPageView({
             container: this.viewer,
             id: pageNum,
             scale: scale,
             defaultViewport: viewport.clone(),
             renderingQueue: this.renderingQueue,
             textLayerFactory: textLayerFactory,
-            annotationsLayerFactory: this
+            annotationLayerFactory: this
           });
           bindOnAfterAndBeforeDraw(pageView);
           this._pages.push(pageView);
         }
 
         var linkService = this.linkService;
 
         // Fetch all the pages since the viewport is needed before printing
@@ -5101,20 +5111,20 @@ var PDFViewer = (function pdfViewer() {
         viewport: viewport,
         findController: this.isInPresentationMode ? null : this.findController
       });
     },
 
     /**
      * @param {HTMLDivElement} pageDiv
      * @param {PDFPage} pdfPage
-     * @returns {AnnotationsLayerBuilder}
+     * @returns {AnnotationLayerBuilder}
      */
-    createAnnotationsLayerBuilder: function (pageDiv, pdfPage) {
-      return new AnnotationsLayerBuilder({
+    createAnnotationLayerBuilder: function (pageDiv, pdfPage) {
+      return new AnnotationLayerBuilder({
         pageDiv: pageDiv,
         pdfPage: pdfPage,
         linkService: this.linkService
       });
     },
 
     setFindController: function (findController) {
       this.findController = findController;
@@ -7085,17 +7095,18 @@ var PDFViewerApplication = {
       return;
     }
     this.pdfPresentationMode.mouseScroll(delta);
   }
 };
 
 
 function webViewerLoad(evt) {
-  PDFViewerApplication.initialize().then(webViewerInitialized);
+    configure(PDFJS);
+    PDFViewerApplication.initialize().then(webViewerInitialized);
 }
 
 function webViewerInitialized() {
   var file = window.location.href.split('#')[0];
 
   document.getElementById('openFile').setAttribute('hidden', 'true');
   document.getElementById('secondaryOpenFile').setAttribute('hidden', 'true');
 
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/bootstrap.js
@@ -0,0 +1,502 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://services-common/utils.js");
+Cu.import("resource://gre/modules/Preferences.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+                                  "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
+                                  "resource:///modules/RecentWindow.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
+                                  "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
+                                  "resource://gre/modules/SocialService.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+                                  "resource://gre/modules/AddonManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
+                                  "resource://gre/modules/ReaderMode.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
+                                  "chrome://pocket/content/Pocket.jsm");
+XPCOMUtils.defineLazyGetter(this, "gPocketBundle", function() {
+  return Services.strings.createBundle("chrome://pocket/locale/pocket.properties");
+});
+
+
+const PREF_BRANCH = "extensions.pocket.";
+const PREFS = {
+  enabled: true, // bug 1229937, figure out ui tour support
+  api: "api.getpocket.com",
+  site: "getpocket.com",
+  oAuthConsumerKey: "40249-e88c401e1b1f2242d9e441c4"
+};
+
+function setDefaultPrefs() {
+  let branch = Services.prefs.getDefaultBranch(PREF_BRANCH);
+  for (let [key, val] in Iterator(PREFS)) {
+    switch (typeof val) {
+      case "boolean":
+        branch.setBoolPref(key, val);
+        break;
+      case "number":
+        branch.setIntPref(key, val);
+        break;
+      case "string":
+        branch.setCharPref(key, val);
+        break;
+    }
+  }
+}
+
+function* allBrowserWindows() {
+  var winEnum = Services.wm.getEnumerator("navigator:browser");
+  while (winEnum.hasMoreElements()) {
+    let win = winEnum.getNext();
+    // skip closed windows
+    if (win.closed)
+      continue;
+    yield win;
+  }
+}
+
+function createElementWithAttrs(document, type, attrs) {
+  let element = document.createElement(type);
+  Object.keys(attrs).forEach(function (attr) {
+    element.setAttribute(attr, attrs[attr]);
+  })
+  return element;
+}
+
+function CreatePocketWidget(reason) {
+  let id = "pocket-button"
+  let widget = CustomizableUI.getWidget(id);
+  // The widget is only null if we've created then destroyed the widget.
+  // Once we've actually called createWidget the provider will be set to
+  // PROVIDER_API.
+  if (widget && widget.provider == CustomizableUI.PROVIDER_API)
+    return;
+  // if upgrading from builtin version and the button was placed in ui,
+  // seenWidget will not be null
+  let seenWidget = CustomizableUI.getPlacementOfWidget("pocket-button", false, true);
+  let pocketButton = {
+    id: "pocket-button",
+    defaultArea: CustomizableUI.AREA_NAVBAR,
+    introducedInVersion: "pref",
+    type: "view",
+    viewId: "PanelUI-pocketView",
+    label: gPocketBundle.GetStringFromName("pocket-button.label"),
+    tooltiptext: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"),
+    // Use forwarding functions here to avoid loading Pocket.jsm on startup:
+    onViewShowing: function() {
+      return Pocket.onPanelViewShowing.apply(this, arguments);
+    },
+    onViewHiding: function() {
+      return Pocket.onPanelViewHiding.apply(this, arguments);
+    },
+    onBeforeCreated: function(doc) {
+      // Bug 1223127,CUI should make this easier to do.
+      if (doc.getElementById("PanelUI-pocketView"))
+        return;
+      let view = doc.createElement("panelview");
+      view.id = "PanelUI-pocketView";
+      let panel = doc.createElement("vbox");
+      panel.setAttribute("class", "panel-subview-body");
+      view.appendChild(panel);
+      doc.getElementById("PanelUI-multiView").appendChild(view);
+    }
+  };
+
+  CustomizableUI.createWidget(pocketButton);
+  CustomizableUI.addListener(pocketButton);
+  // placed is null if location is palette
+  let placed = CustomizableUI.getPlacementOfWidget("pocket-button");
+
+  // a first time install will always have placed the button somewhere, and will
+  // not have a placement prior to creating the widget. Thus, !seenWidget &&
+  // placed.
+  if (reason == ADDON_ENABLE && !seenWidget && placed) {
+    // initially place the button after the bookmarks button if it is in the UI
+    let widgets = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR);
+    let bmbtn = widgets.indexOf("bookmarks-menu-button");
+    if (bmbtn > -1) {
+      CustomizableUI.moveWidgetWithinArea("pocket-button", bmbtn + 1);
+    }
+  }
+
+  // Uninstall the Pocket social provider if it exists, but only if we haven't
+  // already uninstalled it in this manner.  That way the user can reinstall
+  // it if they prefer it without its being uninstalled every time they start
+  // the browser.
+  let origin = "https://getpocket.com";
+  SocialService.getProvider(origin, provider => {
+    if (provider) {
+      let pref = "social.backup.getpocket-com";
+      if (!Services.prefs.prefHasUserValue(pref)) {
+        let str = Cc["@mozilla.org/supports-string;1"].
+                  createInstance(Ci.nsISupportsString);
+        str.data = JSON.stringify(provider.manifest);
+        Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str);
+        SocialService.uninstallProvider(origin, () => {});
+      }
+    }
+  });
+
+};
+
+// PocketContextMenu
+// When the context menu is opened check if we need to build and enable pocket UI.
+var PocketContextMenu = {
+  init: function() {
+    Services.obs.addObserver(this, "on-build-contextmenu", false);
+  },
+  shutdown: function() {
+    Services.obs.removeObserver(this, "on-build-contextmenu");
+    // loop through windows and remove context menus
+    // iterate through all windows and add pocket to them
+    for (let win of allBrowserWindows()) {
+      let document = win.document;
+      for (let id in ["context-pocket", "context-savelinktopocket"]) {
+        let element = document.getElementById(id);
+        if (element)
+          element.remove();
+      }
+    }
+  },
+  observe: function(aSubject, aTopic, aData) {
+    let subject = aSubject.wrappedJSObject;;
+    let document = subject.menu.ownerDocument;
+    let window = document.defaultView;
+    let pocketEnabled = CustomizableUI.getPlacementOfWidget("pocket-button");
+
+    let showSaveCurrentPageToPocket = !(subject.onTextInput || subject.onLink ||
+                                        subject.isContentSelected || subject.onImage ||
+                                        subject.onCanvas || subject.onVideo || subject.onAudio);
+    let targetUrl = subject.onLink ? subject.linkUrl : subject.pageUrl;
+    let targetURI = Services.io.newURI(targetUrl, null, null);
+    let canPocket = pocketEnabled && (targetURI.schemeIs("http") || targetURI.schemeIs("https") ||
+                    (targetURI.schemeIs("about") && ReaderMode.getOriginalUrl(targetUrl)));
+
+    let showSaveLinkToPocket = canPocket && !showSaveCurrentPageToPocket && subject.onLink;
+
+    // create menu entries if necessary
+    let menu = document.getElementById("context-pocket");
+    if (!menu) {
+      menu = createElementWithAttrs(document, "menuitem", {
+        "id": "context-pocket",
+        "label": gPocketBundle.GetStringFromName("saveToPocketCmd.label"),
+        "accesskey": gPocketBundle.GetStringFromName("saveToPocketCmd.accesskey"),
+        "oncommand": "Pocket.savePage(gContextMenu.browser, gContextMenu.browser.currentURI.spec, gContextMenu.browser.contentTitle);"
+      });
+      let sibling = document.getElementById("context-savepage");
+      if (sibling.nextSibling) {
+        sibling.parentNode.insertBefore(menu, sibling.nextSibling);
+      } else {
+        sibling.parentNode.appendChild(menu);
+      }
+    }
+    menu.hidden = !(canPocket && showSaveCurrentPageToPocket);
+
+    menu = document.getElementById("context-savelinktopocket");
+    if (!menu) {
+      menu = createElementWithAttrs(document, "menuitem", {
+        "id": "context-savelinktopocket",
+        "label": gPocketBundle.GetStringFromName("saveLinkToPocketCmd.label"),
+        "accesskey": gPocketBundle.GetStringFromName("saveLinkToPocketCmd.accesskey"),
+        "oncommand": "Pocket.savePage(gContextMenu.browser, gContextMenu.linkURL);"
+      });
+      sibling = document.getElementById("context-savelink");
+      if (sibling.nextSibling) {
+        sibling.parentNode.insertBefore(menu, sibling.nextSibling);
+      } else {
+        sibling.parentNode.appendChild(menu);
+      }
+    }
+    menu.hidden = !showSaveLinkToPocket;
+  }
+}
+
+// PocketReader
+// Listen for reader mode setup and add our button to the reader toolbar
+var PocketReader = {
+  startup: function() {
+    let mm = Services.mm;
+    mm.addMessageListener("Reader:OnSetup", this);
+    mm.addMessageListener("Reader:Clicked-pocket-button", this);
+    mm.broadcastAsyncMessage("Reader:AddButton",
+                             { id: "pocket-button",
+                               title: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"),
+                               image: "chrome://pocket/content/panels/img/pocket.svg#pocket-mark" });
+  },
+  shutdown: function() {
+    let mm = Services.mm;
+    mm.removeMessageListener("Reader:OnSetup", this);
+    mm.removeMessageListener("Reader:Clicked-pocket-button", this);
+    mm.broadcastAsyncMessage("Reader:RemoveButton", { id: "pocket-button" });
+  },
+  receiveMessage: function(message) {
+    switch (message.name) {
+      case "Reader:OnSetup": {
+        // tell the reader about our button.  A chrome url here doesn't work, but
+        // we can use the resoure url.
+        message.target.messageManager.
+          sendAsyncMessage("Reader:AddButton", { id: "pocket-button",
+                                                 title: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"),
+                                                 image: "chrome://pocket/content/panels/img/pocket.svg#pocket-mark"});
+        break;
+      }
+      case "Reader:Clicked-pocket-button": {
+        let doc = message.target.ownerDocument;
+        let pocketWidget = doc.getElementById("pocket-button");
+        let placement = CustomizableUI.getPlacementOfWidget("pocket-button");
+        if (placement) {
+          if (placement.area == CustomizableUI.AREA_PANEL) {
+            doc.defaultView.PanelUI.show().then(function() {
+              // The DOM node might not exist yet if the panel wasn't opened before.
+              pocketWidget = doc.getElementById("pocket-button");
+              pocketWidget.doCommand();
+            });
+          } else {
+            pocketWidget.doCommand();
+          }
+        }
+        break;
+      }
+    }
+  }
+}
+
+
+function pktUIGetter(prop, window) {
+  return {
+    get: function() {
+      // delete any getters for properties loaded from main.js so we only load main.js once
+      delete window.pktUI;
+      delete window.pktUIMessaging;
+      Services.scriptloader.loadSubScript("chrome://pocket/content/main.js", window);
+      return window[prop];
+    },
+    configurable: true,
+    enumerable: true
+  };
+}
+
+var PocketOverlay = {
+  startup: function(reason) {
+    this.registerStylesheet();
+    CreatePocketWidget(reason);
+    Services.obs.addObserver(this,
+                             "browser-delayed-startup-finished",
+                             false);
+    CustomizableUI.addListener(this);
+    PocketContextMenu.init();
+    PocketReader.startup();
+
+    if (reason == ADDON_ENABLE) {
+      for (let win of allBrowserWindows()) {
+        this.setWindowScripts(win);
+        this.updateWindow(win);
+      }
+    }
+  },
+  shutdown: function(reason) {
+    CustomizableUI.removeListener(this);
+    for (let window of allBrowserWindows()) {
+      for (let id of ["panelMenu_pocket", "menu_pocket", "BMB_pocket",
+                      "panelMenu_pocketSeparator", "menu_pocketSeparator",
+                      "BMB_pocketSeparator"]) {
+        let element = window.document.getElementById(id);
+        if (element)
+          element.remove();
+      }
+      // remove script getters/objects
+      delete window.Pocket;
+      delete window.pktUI;
+      delete window.pktUIMessaging;
+    }
+    CustomizableUI.destroyWidget("pocket-button");
+    PocketContextMenu.shutdown();
+    PocketReader.shutdown();
+    this.unregisterStylesheet();
+  },
+  observe: function(aSubject, aTopic, aData) {
+    // new browser window, initialize the "overlay"
+    let window = aSubject;
+    this.setWindowScripts(window);
+    this.updateWindow(window);
+  },
+  setWindowScripts: function(window) {
+    XPCOMUtils.defineLazyModuleGetter(window, "Pocket",
+                                      "chrome://pocket/content/Pocket.jsm");
+    // Can't use XPCOMUtils for these because the scripts try to define the variables
+    // on window, and so the defineProperty inside defineLazyGetter fails.
+    Object.defineProperty(window, "pktUI", pktUIGetter("pktUI", window));
+    Object.defineProperty(window, "pktUIMessaging", pktUIGetter("pktUIMessaging", window));
+  },
+  // called for each window as it is opened
+  updateWindow: function(window) {
+    // insert our three menu items
+    let document = window.document;
+
+    // add to bookmarksMenu
+    let sib = document.getElementById("menu_bookmarkThisPage");
+    if (sib && !document.getElementById("menu_pocket")) {
+      let menu = createElementWithAttrs(document, "menuitem", {
+        "id": "menu_pocket",
+        "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
+        "class": "menuitem-iconic", // OSX only
+        "oncommand": "openUILink(Pocket.listURL, event);"
+      });
+      let sep = createElementWithAttrs(document, "menuseparator", {
+        "id": "menu_pocketSeparator"
+      });
+      sib.parentNode.insertBefore(menu, sib);
+      sib.parentNode.insertBefore(sep, sib);
+    }
+
+    // add to bookmarks-menu-button
+    sib = document.getElementById("BMB_subscribeToPageMenuitem");
+    if (sib && !document.getElementById("BMB_pocket")) {
+      let menu = createElementWithAttrs(document, "menuitem", {
+        "id": "BMB_pocket",
+        "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
+        "class": "menuitem-iconic bookmark-item subviewbutton",
+        "oncommand": "openUILink(Pocket.listURL, event);"
+      });
+      let sep = createElementWithAttrs(document, "menuseparator", {
+        "id": "BMB_pocketSeparator"
+      });
+      sib.parentNode.insertBefore(menu, sib);
+      sib.parentNode.insertBefore(sep, sib);
+    }
+
+    // add to PanelUI-bookmarks
+    sib = document.getElementById("panelMenuBookmarkThisPage");
+    if (sib && !document.getElementById("panelMenu_pocket")) {
+      let menu = createElementWithAttrs(document, "toolbarbutton", {
+        "id": "panelMenu_pocket",
+        "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
+        "class": "subviewbutton cui-withicon",
+        "oncommand": "openUILink(Pocket.listURL, event);"
+      });
+      let sep = createElementWithAttrs(document, "toolbarseparator", {
+        "id": "panelMenu_pocketSeparator"
+      });
+      // nextSibling is no-id toolbarseparator
+      // insert separator first then button
+      sib = sib.nextSibling;
+      sib.parentNode.insertBefore(sep, sib);
+      sib.parentNode.insertBefore(menu, sib);
+    }
+
+    this.updatePocketItemVisibility(document);
+  },
+  onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+    for (let win of allBrowserWindows()) {
+      this.updatePocketItemVisibility(win.document);
+    }
+  },
+  onWidgetRemoved: function(aWidgetId, aArea, aPosition) {
+    for (let win of allBrowserWindows()) {
+      this.updatePocketItemVisibility(win.document);
+    }
+  },
+  onWidgetReset: function(aNode, aContainer) {
+    // CUI was reset and doesn't respect default area for API widgets, place our
+    // widget back to the default area
+    // initially place the button after the bookmarks button if it is in the UI
+    let widgets = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR);
+    let bmbtn = widgets.indexOf("bookmarks-menu-button");
+    if (bmbtn > -1) {
+      CustomizableUI.addWidgetToArea("pocket-button", CustomizableUI.AREA_NAVBAR, bmbtn + 1);
+    } else {
+      CustomizableUI.addWidgetToArea("pocket-button", CustomizableUI.AREA_NAVBAR);
+    }
+  },
+  updatePocketItemVisibility: function(doc) {
+    let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button");
+    for (let prefix of ["panelMenu_", "menu_", "BMB_"]) {
+      let element = doc.getElementById(prefix + "pocket");
+      if (element) {
+        element.hidden = hidden;
+        doc.getElementById(prefix + "pocketSeparator").hidden = hidden;
+      }
+    }
+    // enable or disable reader button
+    if (hidden) {
+      PocketReader.shutdown();
+    } else {
+      PocketReader.startup();
+    }
+  },
+
+  registerStylesheet: function() {
+    let styleSheetService= Components.classes["@mozilla.org/content/style-sheet-service;1"]
+                                     .getService(Components.interfaces.nsIStyleSheetService);
+    let styleSheetURI = Services.io.newURI("chrome://pocket/skin/pocket.css", null, null);
+    styleSheetService.loadAndRegisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET);
+    styleSheetURI = Services.io.newURI("chrome://pocket-shared/skin/pocket.css", null, null);
+    styleSheetService.loadAndRegisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET);
+  },
+
+  unregisterStylesheet: function() {
+    let styleSheetService = Components.classes["@mozilla.org/content/style-sheet-service;1"]
+                                      .getService(Components.interfaces.nsIStyleSheetService);
+    let styleSheetURI = Services.io.newURI("chrome://pocket/skin/pocket.css", null, null);
+    if (styleSheetService.sheetRegistered(styleSheetURI, styleSheetService.AUTHOR_SHEET)) {
+      styleSheetService.unregisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET);
+    }
+    styleSheetURI = Services.io.newURI("chrome://pocket-shared/skin/pocket.css", null, null);
+    if (styleSheetService.sheetRegistered(styleSheetURI, styleSheetService.AUTHOR_SHEET)) {
+      styleSheetService.unregisterSheet(styleSheetURI, styleSheetService.AUTHOR_SHEET);
+    }
+  }
+
+}
+
+// use enabled pref as a way for tests (e.g. test_contextmenu.html) to disable
+// the addon when running.
+function prefObserver(aSubject, aTopic, aData) {
+  let enabled = Services.prefs.getBoolPref("extensions.pocket.enabled");
+  if (enabled)
+    PocketOverlay.startup(ADDON_ENABLE);
+  else
+    PocketOverlay.shutdown(ADDON_DISABLE);
+}
+
+function startup(data, reason) {
+  AddonManager.getAddonByID("isreaditlater@ideashower.com", addon => {
+    if (addon && addon.isActive)
+      return;
+    setDefaultPrefs();
+    // migrate enabled pref
+    if (Services.prefs.prefHasUserValue("browser.pocket.enabled")) {
+      Services.prefs.setBoolPref("extensions.pocket.enabled", Services.prefs.getBoolPref("browser.pocket.enabled"));
+      Services.prefs.clearUserPref("browser.pocket.enabled");
+    }
+    // watch pref change and enable/disable if necessary
+    Services.prefs.addObserver("extensions.pocket.enabled", prefObserver, false);
+    if (Services.prefs.prefHasUserValue("extensions.pocket.enabled") &&
+        !Services.prefs.getBoolPref("extensions.pocket.enabled"))
+      return;
+    PocketOverlay.startup(reason);
+  });
+}
+
+function shutdown(data, reason) {
+  // For speed sake, we should only do a shutdown if we're being disabled.
+  // On an app shutdown, just let it fade away...
+  if (reason == ADDON_DISABLE) {
+    Services.prefs.removeObserver("extensions.pocket.enabled", prefObserver);
+    PocketOverlay.shutdown(reason);
+  }
+}
+
+function install() {
+}
+
+function uninstall() {
+}
rename from browser/components/pocket/Pocket.jsm
rename to browser/extensions/pocket/content/Pocket.jsm
--- a/browser/components/pocket/Pocket.jsm
+++ b/browser/extensions/pocket/content/Pocket.jsm
@@ -11,17 +11,17 @@ Cu.import("resource://gre/modules/XPCOMU
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
   "resource:///modules/CustomizableUI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
   "resource://gre/modules/ReaderMode.jsm");
 
 var Pocket = {
-  get site() { return Services.prefs.getCharPref("browser.pocket.site"); },
+  get site() { return Services.prefs.getCharPref("extensions.pocket.site"); },
   get listURL() { return "https://" + Pocket.site + "/?src=ff_ext"; },
 
   /**
    * Functions related to the Pocket panel UI.
    */
   onPanelViewShowing(event) {
     let document = event.target.ownerDocument;
     let window = document.defaultView;
@@ -32,17 +32,17 @@ var Pocket = {
     Pocket._urlToSave = null;
     Pocket._titleToSave = null;
     // ViewShowing fires immediately before it creates the contents,
     // in lieu of an AfterViewShowing event, just spin the event loop.
     window.setTimeout(function() {
       if (urlToSave) {
         window.pktUI.tryToSaveUrl(urlToSave, titleToSave);
       } else {
-        window.pktUI.pocketButtonOnCommand();
+        window.pktUI.tryToSaveCurrentPage();
       }
 
       if (iframe.contentDocument &&
           iframe.contentDocument.readyState == "complete") {
         window.pktUI.pocketPanelDidShow();
       } else {
         // iframe didn't load yet. This seems to always be the case when in
         // the toolbar panel, but never the case for a subview.
rename from browser/components/pocket/main.js
rename to browser/extensions/pocket/content/main.js
--- a/browser/components/pocket/main.js
+++ b/browser/extensions/pocket/content/main.js
@@ -10,20 +10,20 @@
  * SOFTWARE
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
- * 
+ *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
- * 
+ *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
@@ -41,238 +41,79 @@
 // TODO : [needs clarificaiton from Fx] Move prefs within pktApi.s to sqlite or a local file so it's not editable (and is safer)
 // TODO : [nice to have] - Immediately save, buffer the actions in a local queue and send (so it works offline, works like our native extensions)
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
   "resource://gre/modules/PrivateBrowsingUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
   "resource://gre/modules/ReaderMode.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "pktApi",
+  "chrome://pocket/content/pktApi.jsm");
 
 var pktUI = (function() {
 
 	// -- Initialization (on startup and new windows) -- //
 	var inited = false;
 	var _currentPanelDidShow;
     var _currentPanelDidHide;
 	var _isHidden = false;
 	var _notificationTimeout;
 
     // Init panel id at 0. The first actual panel id will have the number 1 so
     // in case at some point any panel has the id 0 we know there is something
     // wrong
     var _panelId = 0;
 
-	var prefBranch = Services.prefs.getBranch("browser.pocket.settings.");
+	var prefBranch = Services.prefs.getBranch("extensions.pocket.settings.");
 
 	var overflowMenuWidth = 230;
 	var overflowMenuHeight = 475;
 	var savePanelWidth = 350;
 	var savePanelHeights = {collapsed: 153, expanded: 272};
 
-	/**
-     * Initalizes Pocket UI and panels
-     */
-	function onLoad() {
-		
-		if (inited)
-			return;
-		
-		// Install the button (Only on first run, if a user removes the button, you do not want to restore it)
-		// TODO, only do this if in a certain language
-		// TODO - Ask Mozilla what the best way is to have this update when a user restores browser defaults
-		// TODO - this needs to run only on a main window - if the first run happens on a window without the toolbar, then it will never try to run it again
-		if (!prefBranch.prefHasUserValue('installed')) {
-		
-			// If user has social add-on installed, uninstall it
-			if (Social.getManifestByOrigin("https://getpocket.com")) {
-				Social.uninstallProvider("https://getpocket.com", function(){ /* callback */ });
-			}
-			
-			// if user has legacy pkt add-on installed, flag it so we can handle it correctly
-			prefBranch.setBoolPref('hasLegacyExtension', hasLegacyExtension());
-		
-			var id = "pocket-menu-button";
-	        var toolbar = document.getElementById("nav-bar");
-			
-	        var before = null;
-			// Is the bookmarks button in the toolbar?
-			if (toolbar.currentSet.match("bookmarks-menu-button")) {
-	            var elem = document.getElementById("bookmarks-menu-button");
-	            if (elem)
-					before = elem.nextElementSibling;
-			}
-			// Otherwise, just add it to the end of the toolbar (because before is null)
-			
-        	toolbar.insertItem(id, before);
-	
-	        toolbar.setAttribute("currentset", toolbar.currentSet);
-	        document.persist(toolbar.id, "currentset");
-	        
-	        prefBranch.setBoolPref('installed', true);
-		}
-		
-		// Context Menu Event
-		document.getElementById('contentAreaContextMenu').addEventListener("popupshowing", contextOnPopupShowing, false);
-		
-		// Hide the extension based on certain criteria
-		hideIntegrationIfNeeded();
-		
-		inited = true;
-	}
-	
-	/**
-	 * Mark all Pocket integration chrome elements as hidden if certain criteria apply (ex: legacy Pocket extension users or unsupported languages)
-	 */
-	function hideIntegrationIfNeeded() {
-		
-		var hideIntegration = false;
-		
-		// Check if the user had the legacy extension the last time we looked
-		if (prefBranch.getBoolPref('hasLegacyExtension')) {
-			if (hasLegacyExtension()) {
-				hideIntegration = true; // they still have it, hide new native integration
-			}
-			else {
-				// if they originally had it, but no longer do, then we should remove the pref so we no longer have to check
-				prefBranch.setBoolPref('hasLegacyExtension', false);
-			}
-		}
-		
-		// TODO
-		// If language other than launch languages (en-US currently) {
-		//	hideIntegration = true;
-		//}
-		
-		// Hide the integration if needed
-		if (hideIntegration) {
-			// Note, we don't hide the context menus here, that's handled in contextOnPopupShowing
-			var elements = ['pocket-menu-button', 'BMB_openPocketWebapp'];
-			for(var i=0; i<elements.length; i++) {
-				document.getElementById(elements[i]).setAttribute('hidden', true);
-			}
-			
-			_isHidden = true;
-		}
-		else
-			_isHidden = false
-	}
-	
-	
 	// -- Event Handling -- //
-    
+
     /**
      * Event handler when Pocket toolbar button is pressed
      */
-    function pocketButtonOnCommand(event) {
-    
-    	tryToSaveCurrentPage();
-    
-    }
-    
+
     function pocketPanelDidShow(event) {
     	if (_currentPanelDidShow) {
     		_currentPanelDidShow(event);
         }
-    	
+
     }
-    
+
     function pocketPanelDidHide(event) {
     	if (_currentPanelDidHide) {
     		_currentPanelDidHide(event);
         }
-        
+
         // clear the panel
         getPanelFrame().setAttribute('src', 'about:blank');
     }
 
 
     /**
      * Event handler when Pocket bookmark bar entry is pressed
      */
      function pocketBookmarkBarOpenPocketCommand(event) {
         openTabWithUrl('https://getpocket.com/a/', true);
      }
 
-    /**
-     * Event handler when Pocket context menu button is presed
-     */
-
-	// Determine which context menus to show before it's shown
-	function contextOnPopupShowing() {
-
-		var saveLinkId = "PKT_context_saveLink";
-		var savePageId = "PKT_context_savePage";
-
-		if (isHidden()) {
-			gContextMenu.showItem(saveLinkId, false);
-			gContextMenu.showItem(savePageId, false);
-	    } else if ( (gContextMenu.onSaveableLink || ( gContextMenu.inDirList && gContextMenu.onLink )) ) {
-			gContextMenu.showItem(saveLinkId, true);
-			gContextMenu.showItem(savePageId, false);
-	    } else if (gContextMenu.isTextSelected) {
-			gContextMenu.showItem(saveLinkId, false);
-			gContextMenu.showItem(savePageId, false);
-	    } else if (!gContextMenu.onTextInput) {
-			gContextMenu.showItem(saveLinkId, false);
-			gContextMenu.showItem(savePageId, true);
-	    } else {
-			gContextMenu.showItem(saveLinkId, false);
-			gContextMenu.showItem(savePageId, false);
-	    }
-	}
-
-    function pocketContextSaveLinkOnCommand(event) {
-    	// TODO : Unsafe CPOW Usage when saving with Page context menu (Ask Mozilla for help with this one)
-        var linkNode = gContextMenu.target || document.popupNode;
-
-        // Get parent node in case of text nodes (old safari versions)
-        if (linkNode.nodeType == Node.TEXT_NODE) {
-            linkNode = linkNode.parentNode;
-        }
-
-        // If for some reason, it's not an element node, abort
-        if (linkNode.nodeType != Node.ELEMENT_NODE) {
-            return;
-        }
-
-        // Try to get a link element in the parent chain as we can be in the
-        // last child element
-        var currentElement = linkNode;
-        while (currentElement !== null) {
-            if (currentElement.nodeType == Node.ELEMENT_NODE &&
-                currentElement.nodeName.toLowerCase() == 'a')
-            {
-                // We have a link element try to save it
-                linkNode = currentElement;
-                break;
-            }
-            currentElement = currentElement.parentNode;
-        }
-
-        var link = linkNode.href;
-        tryToSaveUrl(link);
-
-        event.stopPropagation();
-    }
-
-    function pocketContextSavePageOnCommand(event) {
-        tryToSaveCurrentPage();
-    }
-
-
     // -- Communication to API -- //
 
     /**
      * Either save or attempt to log the user in
      */
 	function tryToSaveCurrentPage() {
 		tryToSaveUrl(getCurrentUrl(), getCurrentTitle());
 	}
-     
+
     function tryToSaveUrl(url, title) {
 
     	// If the user is logged in, go ahead and save the current page
     	if (pktApi.isUserLoggedIn()) {
     		saveAndShowConfirmation(url, title);
             return;
     	}
 
@@ -287,18 +128,18 @@ var pktUI = (function() {
      * Show the sign-up panel
      */
     function showSignUp() {
         getFirefoxAccountSignedInUser(function(userdata)
         {
             var fxasignedin = (typeof userdata == 'object' && userdata !== null) ? '1' : '0';
             var startheight = 490;
             var inOverflowMenu = isInOverflowMenu();
-            
-            if (inOverflowMenu) 
+
+            if (inOverflowMenu)
             {
             	startheight = overflowMenuHeight;
             }
             else if (pktApi.getSignupAB().indexOf('storyboard') > -1)
             {
                 startheight = 460;
                 if (fxasignedin == '1')
                 {
@@ -316,17 +157,17 @@ var pktUI = (function() {
             if (inOverflowMenu)
             {
                 variant = 'overflow';
             }
             else
             {
                 variant = pktApi.getSignupAB();
             }
-            var panelId = showPanel("about:pocket-signup?pockethost=" + Services.prefs.getCharPref("browser.pocket.site") + "&fxasignedin=" + fxasignedin + "&variant=" + variant + '&inoverflowmenu=' + inOverflowMenu + "&locale=" + getUILocale(), {
+            var panelId = showPanel("chrome://pocket/content/panels/signup.html?pockethost=" + Services.prefs.getCharPref("extensions.pocket.site") + "&fxasignedin=" + fxasignedin + "&variant=" + variant + '&inoverflowmenu=' + inOverflowMenu + "&locale=" + getUILocale(), {
             		onShow: function() {
                     },
         			onHide: panelDidHide,
             		width: inOverflowMenu ? overflowMenuWidth : 300,
             		height: startheight
             	});
             });
     }
@@ -344,17 +185,17 @@ var pktUI = (function() {
         var isValidURL = (typeof url !== 'undefined' && (url.startsWith("http") || url.startsWith('https')));
 
         var inOverflowMenu = isInOverflowMenu();
         var startheight = pktApi.isPremiumUser() && isValidURL ? savePanelHeights.expanded : savePanelHeights.collapsed;
         if (inOverflowMenu) {
         	startheight = overflowMenuHeight;
         }
 
-    	var panelId = showPanel("about:pocket-saved?pockethost=" + Services.prefs.getCharPref("browser.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? '1' : '0') + '&inoverflowmenu='+inOverflowMenu + "&locale=" + getUILocale(), {
+    	var panelId = showPanel("chrome://pocket/content/panels/saved.html?pockethost=" + Services.prefs.getCharPref("extensions.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? '1' : '0') + '&inoverflowmenu='+inOverflowMenu + "&locale=" + getUILocale(), {
     		onShow: function() {
                 var saveLinkMessageId = 'saveLink';
 
                 // Send error message for invalid url
                 if (!isValidURL) {
                     // TODO: Pass key for localized error in error object
                     var error = {
                         message: 'Only links can be saved',
@@ -474,17 +315,17 @@ var pktUI = (function() {
           iframe.style.height = options.height + "px";
         }
     }
 
     /**
      * Called when the signup and saved panel was hidden
      */
     function panelDidHide() {
-        
+
     }
 
     /**
      * Register all of the messages needed for the panels
      */
     function registerEventMessages() {
     	var iframe = getPanelFrame();
 
@@ -610,17 +451,17 @@ var pktUI = (function() {
 				    pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _deleteItemMessageId, error);
 				}
 			})
 		});
 
         var _initL10NMessageId = "initL10N";
         pktUIMessaging.addMessageListener(_initL10NMessageId, function(panelId, data) {
             var strings = {};
-            var bundle = Services.strings.createBundle("chrome://browser/locale/browser-pocket.properties");
+            var bundle = Services.strings.createBundle("chrome://pocket/locale/pocket.properties");
             var e = bundle.getSimpleEnumeration();
             while(e.hasMoreElements()) {
                 var str = e.getNext().QueryInterface(Components.interfaces.nsIPropertyElement);
                 strings[str.key] = str.value;
             }
             pktUIMessaging.sendResponseMessageToPanel(panelId, _initL10NMessageId, { strings: strings });
         });
 
@@ -720,130 +561,37 @@ var pktUI = (function() {
 
     function getFirefoxAccountSignedInUser(callback) {
 	    fxAccounts.getSignedInUser().then(userData => {
     		callback(userData);
     	}).then(null, error => {
       		callback();
 	    });
     }
-    
+
     function getUILocale() {
     	var locale = Cc["@mozilla.org/chrome/chrome-registry;1"].
              getService(Ci.nsIXULChromeRegistry).
              getSelectedLocale("browser");
         return locale;
     }
 
-    /**
-     * Toolbar animations
-     */
-    
-    function showPocketAnimation() {
-    	
-    	// Borrowed from bookmark star animation:
-    	// https://dxr.mozilla.org/mozilla-central/source/browser/base/content/browser-places.js#1568
-    	
-    	// TODO : Clean-up : Probably don't need all of this since the css animation does most of the heavy lifting
-    	// TODO : Do not show when saving from context menu -- or get really fancy and launch the icon from the link that was saved into the bookmark menu
-    
-    	function getCenteringTransformForRects(rectToPosition, referenceRect) {
-	      let topDiff = referenceRect.top - rectToPosition.top;
-	      let leftDiff = referenceRect.left - rectToPosition.left;
-	      let heightDiff = referenceRect.height - rectToPosition.height;
-	      let widthDiff = referenceRect.width - rectToPosition.width;
-	      return [(leftDiff + .5 * widthDiff) + "px", (topDiff + .5 * heightDiff) + "px"];
-	    }
-	
-	    if (_notificationTimeout) {
-	      clearTimeout(this._notificationTimeout);
-	   	}
-	
-		var button = document.getElementById('pocket-menu-button');
-		var bookmarksButton = document.getElementById('bookmarks-menu-button');
-		var notifier = document.getElementById("pocketed-notification-anchor");
-		var dropmarkerNotifier = document.getElementById("bookmarked-notification-dropmarker-anchor");
-	
-		
-    	// If the Pocket button is not immediately after the bookmark button, then do not do the animation 
-    	//	(because it's hard-coded for the positions right now)
-    	// TODO - double check this in small and large toolbar button sizes
-    	if (bookmarksButton.nextElementSibling != button)
-    		return;
-	
-	    if (notifier.style.transform == '') {
-	      // Get all the relevant nodes and computed style objects
-	      let dropmarker = document.getAnonymousElementByAttribute(bookmarksButton, "anonid", "dropmarker");
-	      let dropmarkerIcon = document.getAnonymousElementByAttribute(dropmarker, "class", "dropmarker-icon");
-	      let dropmarkerStyle = getComputedStyle(dropmarkerIcon);
-	      
-	      // Check for RTL and get bounds
-	      let isRTL = getComputedStyle(button).direction == "rtl"; // need this?
-	      let buttonRect = button.getBoundingClientRect();
-	      let notifierRect = notifier.getBoundingClientRect();
-	      let dropmarkerRect = dropmarkerIcon.getBoundingClientRect();
-	      let dropmarkerNotifierRect = dropmarkerNotifier.getBoundingClientRect();
-	
-	      // Compute, but do not set, transform for pocket icon
-	      let [translateX, translateY] = getCenteringTransformForRects(notifierRect, buttonRect);
-	      let starIconTransform = "translate(" +  (translateX) + ", " + translateY + ")";
-	      if (isRTL) {
-	        starIconTransform += " scaleX(-1)";
-	      }
-	
-	      // Compute, but do not set, transform for dropmarker
-	      [translateX, translateY] = getCenteringTransformForRects(dropmarkerNotifierRect, dropmarkerRect);
-	      let dropmarkerTransform = "translate(" + translateX + ", " + translateY + ")";
-	
-	      // Do all layout invalidation in one go:
-	      notifier.style.transform = starIconTransform;
-	      dropmarkerNotifier.style.transform = dropmarkerTransform;
-	
-	      let dropmarkerAnimationNode = dropmarkerNotifier.firstChild;
-	      dropmarkerAnimationNode.style.MozImageRegion = dropmarkerStyle.MozImageRegion;
-	      dropmarkerAnimationNode.style.listStyleImage = dropmarkerStyle.listStyleImage;
-	    }
-	
-	    let isInOverflowMenu = button.getAttribute("overflowedItem") == "true";
-	    if (!isInOverflowMenu) {
-	      notifier.setAttribute("notification", "finish");
-	      button.setAttribute("notification", "finish");
-	      dropmarkerNotifier.setAttribute("notification", "finish");
-	    }
-	
-	    _notificationTimeout = setTimeout( () => {
-	      notifier.removeAttribute("notification");
-	      dropmarkerNotifier.removeAttribute("notification");
-	      button.removeAttribute("notification");
-	
-	      dropmarkerNotifier.style.transform = '';
-	      notifier.style.transform = '';
-	    }, 1000);
-    }
-    
-    
 	/**
      * Public functions
      */
     return {
-    	onLoad: onLoad,
     	getPanelFrame: getPanelFrame,
 
         openTabWithUrl: openTabWithUrl,
 
-    	pocketButtonOnCommand: pocketButtonOnCommand,
     	pocketPanelDidShow: pocketPanelDidShow,
     	pocketPanelDidHide: pocketPanelDidHide,
 
-        pocketContextSaveLinkOnCommand,
-        pocketContextSavePageOnCommand,
-
-        pocketBookmarkBarOpenPocketCommand,
-
-    	tryToSaveUrl: tryToSaveUrl
+    	tryToSaveUrl: tryToSaveUrl,
+    	tryToSaveCurrentPage: tryToSaveCurrentPage
     };
 }());
 
 // -- Communication to Background -- //
 // https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
 var pktUIMessaging = (function() {
 
     /**
@@ -852,17 +600,17 @@ var pktUIMessaging = (function() {
     function prefixedMessageId(messageId) {
         return 'PKT_' + messageId;
     }
 
     /**
      * Register a listener and callback for a specific messageId
      */
     function addMessageListener(messageId, callback) {
-        document.addEventListener(prefixedMessageId(messageId), function(e) { 
+        document.addEventListener(prefixedMessageId(messageId), function(e) {
             // ignore to ensure we do not pick up other events in the browser
             if (e.target.tagName !== 'PKTMESSAGEFROMPANELELEMENT') {
                 return;
             }
 
             // Pass in information to callback
             var payload = JSON.parse(e.target.getAttribute("payload"))[0];
             var panelId = payload.panelId;
rename from browser/components/pocket/panels/css/firasans.css
rename to browser/extensions/pocket/content/panels/css/firasans.css
rename from browser/components/pocket/panels/css/normalize.css
rename to browser/extensions/pocket/content/panels/css/normalize.css
rename from browser/components/pocket/panels/css/saved.css
rename to browser/extensions/pocket/content/panels/css/saved.css
rename from browser/components/pocket/panels/css/signup.css
rename to browser/extensions/pocket/content/panels/css/signup.css
rename from browser/components/pocket/panels/fonts/FiraSans-Regular.woff
rename to browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woff
rename from toolkit/themes/shared/reader/pocket.svg
rename to browser/extensions/pocket/content/panels/img/pocket.svg
rename from browser/components/pocket/panels/img/pocketerror@1x.png
rename to browser/extensions/pocket/content/panels/img/pocketerror@1x.png
rename from browser/components/pocket/panels/img/pocketerror@2x.png
rename to browser/extensions/pocket/content/panels/img/pocketerror@2x.png
rename from browser/components/pocket/panels/img/pocketlogo@1x.png
rename to browser/extensions/pocket/content/panels/img/pocketlogo@1x.png
rename from browser/components/pocket/panels/img/pocketlogo@2x.png
rename to browser/extensions/pocket/content/panels/img/pocketlogo@2x.png
rename from browser/components/pocket/panels/img/pocketlogosolo@1x.png
rename to browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.png
rename from browser/components/pocket/panels/img/pocketlogosolo@2x.png
rename to browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.png
rename from browser/components/pocket/panels/img/pocketmenuitem16.png
rename to browser/extensions/pocket/content/panels/img/pocketmenuitem16.png
rename from browser/components/pocket/panels/img/pocketmenuitem16@2x.png
rename to browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.png
rename from browser/components/pocket/panels/img/pocketsignup_button@1x.png
rename to browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.png
rename from browser/components/pocket/panels/img/pocketsignup_button@2x.png
rename to browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.png
rename from browser/components/pocket/panels/img/pocketsignup_devices@1x.png
rename to browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.png
rename from browser/components/pocket/panels/img/pocketsignup_devices@2x.png
rename to browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.png
rename from browser/components/pocket/panels/img/pocketsignup_hero@1x.png
rename to browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.png
rename from browser/components/pocket/panels/img/pocketsignup_hero@2x.png
rename to browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.png
rename from browser/components/pocket/panels/img/signup_firefoxlogo@1x.png
rename to browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.png
rename from browser/components/pocket/panels/img/signup_firefoxlogo@2x.png
rename to browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.png
rename from browser/components/pocket/panels/img/signup_help@1x.png
rename to browser/extensions/pocket/content/panels/img/signup_help@1x.png
rename from browser/components/pocket/panels/img/signup_help@2x.png
rename to browser/extensions/pocket/content/panels/img/signup_help@2x.png
rename from browser/components/pocket/panels/img/signup_or@1x.png
rename to browser/extensions/pocket/content/panels/img/signup_or@1x.png
rename from browser/components/pocket/panels/img/signup_or@2x.png
rename to browser/extensions/pocket/content/panels/img/signup_or@2x.png
rename from browser/components/pocket/panels/img/tag_close@1x.png
rename to browser/extensions/pocket/content/panels/img/tag_close@1x.png
rename from browser/components/pocket/panels/img/tag_close@2x.png
rename to browser/extensions/pocket/content/panels/img/tag_close@2x.png
rename from browser/components/pocket/panels/img/tag_closeactive@1x.png
rename to browser/extensions/pocket/content/panels/img/tag_closeactive@1x.png
rename from browser/components/pocket/panels/img/tag_closeactive@2x.png
rename to browser/extensions/pocket/content/panels/img/tag_closeactive@2x.png
rename from browser/components/pocket/panels/js/messages.js
rename to browser/extensions/pocket/content/panels/js/messages.js
rename from browser/components/pocket/panels/js/saved.js
rename to browser/extensions/pocket/content/panels/js/saved.js
rename from browser/components/pocket/panels/js/signup.js
rename to browser/extensions/pocket/content/panels/js/signup.js
rename from browser/components/pocket/panels/js/tmpl.js
rename to browser/extensions/pocket/content/panels/js/tmpl.js
rename from browser/components/pocket/panels/js/vendor/handlebars.runtime.js
rename to browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js
rename from browser/components/pocket/panels/js/vendor/jquery-2.1.1.min.js
rename to browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js
rename from browser/components/pocket/panels/js/vendor/jquery.tokeninput.min.js
rename to browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js
rename from browser/components/pocket/panels/license.txt
rename to browser/extensions/pocket/content/panels/license.txt
rename from browser/components/pocket/panels/saved.html
rename to browser/extensions/pocket/content/panels/saved.html
--- a/browser/components/pocket/panels/saved.html
+++ b/browser/extensions/pocket/content/panels/saved.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="utf-8">
-        <base href="chrome://browser/content/pocket/panels/">
+        <base href="chrome://pocket/content/panels/">
         <title>Pocket: Page Saved</title>
         <link rel="stylesheet" href="css/normalize.css">
         <link rel="stylesheet" href="css/firasans.css">
         <link rel="stylesheet" href="css/saved.css">
     </head>
     <body class="pkt_ext_containersaved" aria-live="polite">
         <script type="text/javascript" src="js/vendor/jquery-2.1.1.min.js"></script>
         <script type="text/javascript" src="js/vendor/handlebars.runtime.js"></script>
rename from browser/components/pocket/panels/signup.html
rename to browser/extensions/pocket/content/panels/signup.html
--- a/browser/components/pocket/panels/signup.html
+++ b/browser/extensions/pocket/content/panels/signup.html
@@ -1,13 +1,13 @@
 <!DOCTYPE html>
 <html>
     <head>
         <meta charset="utf-8">
-        <base href="chrome://browser/content/pocket/panels/">
+        <base href="chrome://pocket/content/panels/">
         <title>Pocket: Sign Up</title>
         <link rel="stylesheet" href="css/normalize.css">
         <link rel="stylesheet" href="css/firasans.css">
         <link rel="stylesheet" href="css/signup.css">
     </head>
     <body class="pkt_ext_containersignup" aria-live="polite">
         <script type="text/javascript" src="js/vendor/jquery-2.1.1.min.js"></script>
         <script type="text/javascript" src="js/vendor/handlebars.runtime.js"></script>
rename from browser/components/pocket/panels/tmpl/saved_premiumextras.handlebars
rename to browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars
rename from browser/components/pocket/panels/tmpl/saved_premiumshell.handlebars
rename to browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars
rename from browser/components/pocket/panels/tmpl/saved_shell.handlebars
rename to browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars
rename from browser/components/pocket/panels/tmpl/signup_shell.handlebars
rename to browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars
rename from browser/components/pocket/panels/tmpl/signupstoryboard_shell.handlebars
rename to browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars
rename from browser/components/pocket/pktApi.js
rename to browser/extensions/pocket/content/pktApi.jsm
--- a/browser/components/pocket/pktApi.js
+++ b/browser/extensions/pocket/content/pktApi.jsm
@@ -37,37 +37,44 @@
  * Definition of keys stored in preferences to preserve user state:
  *      premium_status:   Current premium status for logged in user if available
  *                        Can be 0 for no premium and 1 for premium
  *      latestSince:      Last timestamp a save happened
  *      tags:             All tags for logged in user
  *      usedTags:         All used tags from within the extension sorted by recency
  */
 
+const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components;
+this.EXPORTED_SYMBOLS = ["pktApi"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+
 var pktApi = (function() {
 
     /**
      * Configuration
      */
 
     // Base url for all api calls
-    var pocketAPIhost = Services.prefs.getCharPref("browser.pocket.api"); 	// api.getpocket.com
-    var pocketSiteHost = Services.prefs.getCharPref("browser.pocket.site"); // getpocket.com
+    var pocketAPIhost = Services.prefs.getCharPref("extensions.pocket.api"); 	// api.getpocket.com
+    var pocketSiteHost = Services.prefs.getCharPref("extensions.pocket.site"); // getpocket.com
     var baseAPIUrl = "https://" + pocketAPIhost + "/v3";
 
 
     /**
      * Auth keys for the API requests
      */
-    var oAuthConsumerKey = Services.prefs.getCharPref("browser.pocket.oAuthConsumerKey");
+    var oAuthConsumerKey = Services.prefs.getCharPref("extensions.pocket.oAuthConsumerKey");
 
 	/**
 	 *
 	 */
-	var prefBranch = Services.prefs.getBranch("browser.pocket.settings.");
+	var prefBranch = Services.prefs.getBranch("extensions.pocket.settings.");
 
     /**
      * Helper
      */
 
     var extend = function(out) {
         out = out || {};
 
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/install.rdf.in
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+#filter substitution
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+     xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+  <Description about="urn:mozilla:install-manifest">
+    <em:id>firefox@getpocket.com</em:id>
+    <em:version>@FIREFOX_VERSION@</em:version>
+    <em:type>2</em:type>
+    <em:bootstrap>true</em:bootstrap>
+
+    <!-- Target Application this theme can install into,
+        with minimum and maximum supported versions. -->
+    <em:targetApplication>
+      <Description>
+        <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+        <em:minVersion>@FIREFOX_VERSION@</em:minVersion>
+        <em:maxVersion>@FIREFOX_VERSION@</em:maxVersion>
+      </Description>
+    </em:targetApplication>
+
+    <!-- Front End MetaData -->
+    <em:name>Pocket</em:name>
+    <em:description>When you find something you want to view later, put it in Pocket.</em:description>
+  </Description>
+</RDF>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/jar.mn
@@ -0,0 +1,12 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+[features/firefox@getpocket.com] chrome.jar:
+% content pocket %content/ contentaccessible=yes
+% skin pocket classic/1.0 %skin/linux/ os=Linux
+% skin pocket classic/1.0 %skin/osx/ os=Darwin
+% skin pocket classic/1.0 %skin/windows/ os=WINNT
+% skin pocket-shared classic/1.0 %skin/shared/
+  content/  (content/*)
+  skin/  (skin/*)
rename from browser/locales/en-US/chrome/browser/browser-pocket.properties
rename to browser/extensions/pocket/locales/en-US/pocket.properties
--- a/browser/locales/en-US/chrome/browser/browser-pocket.properties
+++ b/browser/extensions/pocket/locales/en-US/pocket.properties
@@ -24,8 +24,18 @@ signuptosave = Sign up for Pocket. It’s free.
 suggestedtags = Suggested Tags
 tagline = Save articles and videos from Firefox to view in Pocket on any device, any time.
 taglinestory_one = Click the Pocket Button to save any article, video or page from Firefox.
 taglinestory_two = View in Pocket on any device, any time.
 tagssaved = Tags Added
 signinfirefox = Sign in with Firefox
 signupfirefox = Sign up with Firefox
 viewlist = View List
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Save to Pocket
+saveToPocketCmd.label = Save Page to Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Save Link to Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = View Pocket List
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/locales/jar.mn
@@ -0,0 +1,8 @@
+#filter substitution
+# 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/.
+
+[features/firefox@getpocket.com] @AB_CD@.jar:
+%   locale pocket @AB_CD@ %locale/@AB_CD@/
+    locale/@AB_CD@/ (%*)
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/locales/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ['jar.mn']
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/moz.build
@@ -0,0 +1,17 @@
+# -*- 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/.
+
+DIRS += ['locales']
+
+FINAL_TARGET_FILES.features['firefox@getpocket.com'] += [
+  'bootstrap.js'
+]
+
+FINAL_TARGET_PP_FILES.features['firefox@getpocket.com'] += [
+  'install.rdf.in'
+]
+
+JAR_MANIFESTS += ['jar.mn']
new file mode 100644
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/pocket.css
@@ -0,0 +1,38 @@
+#pocket-button[cui-areatype="toolbar"][open] {
+  -moz-image-region: rect(36px, 774px, 54px, 756px);
+}
+
+@media (min-resolution: 1.1dppx) {
+
+  #pocket-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 1548px, 36px, 1512px);
+  }
+
+  #pocket-button[cui-areatype="toolbar"][open] {
+    -moz-image-region: rect(72px, 1548px, 108px, 1512px);
+  }
+}
+
+@media (min-resolution: 2dppx) {
+  #panelMenu_pocket,
+  #menu_pocket,
+  #BMB_pocket {
+    list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16@2x.png");
+  }
+
+  #panelMenu_pocket > .toolbarbutton-icon {
+    width: 16px;
+  }
+}
+
+@media not all and (min-resolution: 1.1dppx) {
+  #pocket-button:hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) {
+    -moz-image-region: rect(18px, 774px, 36px, 756px);
+  }
+}
+
+@media (min-resolution: 1.1dppx) {
+  #pocket-button:hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) {
+    -moz-image-region: rect(36px, 1548px, 72px, 1512px);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/skin/shared/pocket.css
@@ -0,0 +1,68 @@
+/* Bug 1164419 - increase Pocket panel size to accomidate wider Russian text. */
+panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-viewstack > .panel-mainview:not([panelid="PanelUI-popup"]) {
+  max-width: 33em; /* standaloneSubviewWidth + 3 */
+}
+
+.cui-widget-panel[viewId="PanelUI-pocketView"] > .panel-arrowcontainer > .panel-arrowcontent {
+  padding-top: 0;
+  padding-bottom: 0;
+}
+
+#PanelUI-pocketView > .panel-subview-body,
+#PanelUI-pocketView {
+  overflow: visible;
+}
+
+#pocket-button {
+  list-style-image: url("chrome://browser/skin/Toolbar.png");
+}
+
+toolbar[brighttext] #pocket-button {
+  list-style-image: url(chrome://browser/skin/Toolbar-inverted.png);
+}
+
+@media not all and (min-resolution: 1.1dppx) {
+  #pocket-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #pocket-button {
+    list-style-image: var(--menupanel-list-style-image);
+    -moz-image-region: rect(0px, 992px, 32px, 960px);
+  }
+
+  #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
+    -moz-image-region: rect(32px, 992px, 64px, 960px);
+  }
+}
+
+@media (min-resolution: 1.1dppx) {
+  #pocket-button {
+    list-style-image: url("chrome://browser/skin/Toolbar@2x.png");
+  }
+
+  toolbar[brighttext] #pocket-button {
+    list-style-image: url("chrome://browser/skin/Toolbar-inverted@2x.png");
+  }
+
+  #pocket-button[cui-areatype="menu-panel"],
+  toolbarpaletteitem[place="palette"] > #pocket-button {
+    list-style-image: var(--menupanel-list-style-image-2x);
+    -moz-image-region: rect(0px, 1984px, 64px, 1920px);
+  }
+
+  #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
+    -moz-image-region: rect(64px, 1984px, 128px, 1920px);
+  }
+}
+
+#pocket-button[cui-areatype="toolbar"] {
+  -moz-image-region: rect(0, 774px, 18px, 756px);
+}
+
+#pocket-button[cui-areatype="toolbar"][open] {
+  -moz-image-region: rect(18px, 774px, 36px, 756px);
+}
+
+#panelMenu_pocket,
+#menu_pocket,
+#BMB_pocket {
+  list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16.png");
+}
new file mode 100644
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/pocket.css
@@ -0,0 +1,9 @@
+@media (min-resolution: 1.1dppx) {
+  #pocket-button[cui-areatype="toolbar"] {
+    -moz-image-region: rect(0, 1548px, 36px, 1512px);
+  }
+
+  #pocket-button[cui-areatype="toolbar"][open] {
+    -moz-image-region: rect(36px, 1548px, 72px, 1512px);
+  }
+}
--- a/browser/locales/Makefile.in
+++ b/browser/locales/Makefile.in
@@ -128,16 +128,17 @@ libs:: $(call MERGE_FILES,$(addprefix pr
 libs-%:
 	$(NSINSTALL) -D $(DIST)/install
 	@$(MAKE) -C ../../toolkit/locales libs-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
 	@$(MAKE) -C ../../services/sync/locales AB_CD=$* XPI_NAME=locale-$*
 ifdef MOZ_WEBAPP_RUNTIME
 	@$(MAKE) -C ../../webapprt/locales AB_CD=$* XPI_NAME=locale-$*
 endif
 	@$(MAKE) -C ../../extensions/spellcheck/locales AB_CD=$* XPI_NAME=locale-$*
+	@$(MAKE) -C ../extensions/pocket/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../../intl/locales AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) -C ../../devtools/client/locales AB_CD=$* XPI_NAME=locale-$* XPI_ROOT_APPID='$(XPI_ROOT_APPID)'
 	@$(MAKE) -B searchplugins AB_CD=$* XPI_NAME=locale-$*
 	@$(MAKE) libs AB_CD=$* XPI_NAME=locale-$* PREF_DIR=$(PREF_DIR)
 	@$(MAKE) -C $(DEPTH)/$(MOZ_BRANDING_DIRECTORY)/locales AB_CD=$* XPI_NAME=locale-$*
 
 repackage-win32-installer: WIN32_INSTALLER_OUT=$(_ABS_DIST)/$(PKG_INST_PATH)$(PKG_INST_BASENAME).exe
 repackage-win32-installer: $(call ESCAPE_WILDCARD,$(WIN32_INSTALLER_IN)) $(SUBMAKEFILES) libs-$(AB_CD)
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -929,15 +929,8 @@ you can use these alternative items. Oth
 <!ENTITY panicButton.thankyou.buttonlabel         "Thanks!">
 
 <!ENTITY emeLearnMoreContextMenu.label            "Learn more about DRM…">
 <!ENTITY emeLearnMoreContextMenu.accesskey        "D">
 <!ENTITY emeNotificationsNotNow.label             "Not now">
 <!ENTITY emeNotificationsNotNow.accesskey         "N">
 <!ENTITY emeNotificationsDontAskAgain.label       "Don't ask me again">
 <!ENTITY emeNotificationsDontAskAgain.accesskey   "D">
-
-<!-- LOCALIZATION NOTE (saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label): Pocket is a brand name -->
-<!ENTITY saveToPocketCmd.label     "Save Page to Pocket">
-<!ENTITY saveToPocketCmd.accesskey "k">
-<!ENTITY saveLinkToPocketCmd.label     "Save Link to Pocket">
-<!ENTITY saveLinkToPocketCmd.accesskey "o">
-<!ENTITY pocketMenuitem.label      "View Pocket List">
--- a/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
+++ b/browser/locales/en-US/chrome/browser/customizableui/customizableWidgets.properties
@@ -119,15 +119,10 @@ web-apps-button.label = Apps
 web-apps-button.tooltiptext = Discover Apps
 
 # LOCALIZATION NOTE(devtools-webide-button.label, devtools-webide-button.tooltiptext):
 # widget is only visible after WebIDE has been started once (Tools > Web Developers > WebIDE)
 # %S is the keyboard shortcut
 devtools-webide-button2.label = WebIDE
 devtools-webide-button2.tooltiptext = Open WebIDE (%S)
 
-# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext): "Pocket"
-# is a brand name.
-pocket-button.label = Pocket
-pocket-button.tooltiptext = Save to Pocket
-
 e10s-button.label = New Non-e10s Window
 e10s-button.tooltiptext = Open a new Non-e10s Window
--- a/browser/locales/filter.py
+++ b/browser/locales/filter.py
@@ -6,17 +6,18 @@ def test(mod, path, entity = None):
   import re
   # ignore anything but Firefox
   if mod not in ("netwerk", "dom", "toolkit", "security/manager",
                  "devtools/client", "devtools/shared",
                  "browser", "webapprt",
                  "extensions/reporter", "extensions/spellcheck",
                  "other-licenses/branding/firefox",
                  "browser/branding/official",
-                 "services/sync"):
+                 "services/sync",
+                 "browser/extensions/pocket"):
     return "ignore"
   if mod not in ("browser", "extensions/spellcheck"):
     # we only have exceptions for browser and extensions/spellcheck
     return "error"
   if not entity:
     # the only files to ignore are spell checkers and search
     if mod == "extensions/spellcheck":
       return "ignore"
--- a/browser/locales/jar.mn
+++ b/browser/locales/jar.mn
@@ -19,17 +19,16 @@
 #endif
     locale/browser/aboutSessionRestore.dtd         (%chrome/browser/aboutSessionRestore.dtd)
     locale/browser/aboutTabCrashed.dtd             (%chrome/browser/aboutTabCrashed.dtd)
     locale/browser/syncCustomize.dtd               (%chrome/browser/syncCustomize.dtd)
     locale/browser/aboutSyncTabs.dtd               (%chrome/browser/aboutSyncTabs.dtd)
     locale/browser/browser.dtd                     (%chrome/browser/browser.dtd)
     locale/browser/baseMenuOverlay.dtd             (%chrome/browser/baseMenuOverlay.dtd)
     locale/browser/browser.properties              (%chrome/browser/browser.properties)
-    locale/browser/browser-pocket.properties       (%chrome/browser/browser-pocket.properties)
     locale/browser/customizableui/customizableWidgets.properties (%chrome/browser/customizableui/customizableWidgets.properties)
     locale/browser/lightweightThemes.properties    (%chrome/browser/lightweightThemes.properties)
     locale/browser/loop/loop.properties            (%chrome/browser/loop/loop.properties)
     locale/browser/newTab.dtd                      (%chrome/browser/newTab.dtd)
     locale/browser/newTab.properties               (%chrome/browser/newTab.properties)
     locale/browser/pageInfo.dtd                    (%chrome/browser/pageInfo.dtd)
     locale/browser/pageInfo.properties             (%chrome/browser/pageInfo.properties)
     locale/browser/quitDialog.properties           (%chrome/browser/quitDialog.properties)
--- a/browser/locales/l10n.ini
+++ b/browser/locales/l10n.ini
@@ -7,16 +7,17 @@ depth = ../..
 all = browser/locales/all-locales
 
 [compare]
 dirs = browser
      extensions/reporter
      other-licenses/branding/firefox
      browser/branding/official
      devtools/client
+     browser/extensions/pocket
 
 [includes]
 # non-central apps might want to use %(topsrcdir)s here, or other vars
 # RFE: that needs to be supported by compare-locales, too, though
 toolkit = toolkit/locales/l10n.ini
 services_sync = services/sync/locales/l10n.ini
 webapprt = webapprt/locales/l10n.ini
 
--- a/browser/modules/ReaderParent.jsm
+++ b/browser/modules/ReaderParent.jsm
@@ -8,33 +8,30 @@
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 this.EXPORTED_SYMBOLS = [ "ReaderParent" ];
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", "resource:///modules/CustomizableUI.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils","resource://gre/modules/PlacesUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode", "resource://gre/modules/ReaderMode.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "UITour", "resource:///modules/UITour.jsm");
 
 const gStringBundle = Services.strings.createBundle("chrome://global/locale/aboutReader.properties");
 
 var ReaderParent = {
   _readerModeInfoPanelOpen: false,
 
   MESSAGES: [
     "Reader:AddToList",
-    "Reader:AddToPocket",
     "Reader:ArticleGet",
     "Reader:FaviconRequest",
     "Reader:ListStatusRequest",
-    "Reader:PocketEnabledGet",
     "Reader:RemoveFromList",
     "Reader:Share",
     "Reader:SystemUIVisibility",
     "Reader:UpdateReaderButton",
     "Reader:SetIntPref",
     "Reader:SetCharPref",
   ],
 
@@ -42,54 +39,29 @@ var ReaderParent = {
     let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager);
     for (let msg of this.MESSAGES) {
       mm.addMessageListener(msg, this);
     }
   },
 
   receiveMessage: function(message) {
     switch (message.name) {
-      case "Reader:AddToPocket": {
-        let doc = message.target.ownerDocument;
-        let pocketWidget = doc.getElementById("pocket-button");
-        let placement = CustomizableUI.getPlacementOfWidget("pocket-button");
-        if (placement) {
-          if (placement.area == CustomizableUI.AREA_PANEL) {
-            doc.defaultView.PanelUI.show().then(function() {
-              // The DOM node might not exist yet if the panel wasn't opened before.
-              pocketWidget = doc.getElementById("pocket-button");
-              pocketWidget.doCommand();
-            });
-          } else {
-            pocketWidget.doCommand();
-          }
-        }
-        break;
-      }
-
       case "Reader:ArticleGet":
         this._getArticle(message.data.url, message.target).then((article) => {
           // Make sure the target browser is still alive before trying to send data back.
           if (message.target.messageManager) {
             message.target.messageManager.sendAsyncMessage("Reader:ArticleData", { article: article });
           }
         }, e => {
           if (e && e.newURL) {
             message.target.loadURI("about:reader?url=" + encodeURIComponent(e.newURL));
           }
         });
         break;
 
-      case "Reader:PocketEnabledGet": {
-        let pocketPlacement = CustomizableUI.getPlacementOfWidget("pocket-button");
-        let isPocketEnabled = pocketPlacement && pocketPlacement.area;
-        message.target.messageManager.sendAsyncMessage("Reader:PocketEnabledData", { enabled: !!isPocketEnabled});
-        break;
-      }
-
       case "Reader:FaviconRequest": {
         if (message.target.messageManager) {
           let faviconUrl = PlacesUtils.promiseFaviconLinkUrl(message.data.url);
           faviconUrl.then(function onResolution(favicon) {
             message.target.messageManager.sendAsyncMessage("Reader:FaviconReturn", {
               url: message.data.url,
               faviconUrl: favicon.path.replace(/^favicon:/, "")
             })
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -519,22 +519,16 @@ menuitem:not([type]):not(.menuitem-toolt
   list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png");
 }
 
 #BMB_unsortedBookmarks,
 #panelMenu_unsortedBookmarks {
   list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
 }
 
-#panelMenu_pocket,
-#menu_pocket,
-#BMB_pocket {
-  list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png");
-}
-
 #menu_openDownloads {
   list-style-image: url("chrome://browser/skin/Toolbar-small.png");
   -moz-image-region: rect(0px 16px 16px 0px);
 }
 
 #menu_openAddons {
   list-style-image: url("chrome://mozapps/skin/extensions/extensionGeneric-16.png");
 }
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -588,34 +588,16 @@ toolbarpaletteitem[place="palette"] > #p
     list-style-image: url("chrome://browser/skin/places/bookmarksToolbar@2x.png");
   }
 
   #BMB_unsortedBookmarks {
     list-style-image: url("chrome://browser/skin/places/unfiledBookmarks@2x.png");
   }
 }
 
-#panelMenu_pocket,
-#menu_pocket,
-#BMB_pocket {
-  list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png");
-}
-
-@media (min-resolution: 2dppx) {
-  #panelMenu_pocket,
-  #menu_pocket,
-  #BMB_pocket {
-    list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16@2x.png");
-  }
-
-  #panelMenu_pocket > .toolbarbutton-icon {
-    width: 16px;
-  }
-}
-
 /* ----- PRIMARY TOOLBAR BUTTONS ----- */
 
 :-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1 > .toolbarbutton-icon,
 :-moz-any(toolbar, .widget-overflow-list) .toolbarbutton-1 > :-moz-any(.toolbarbutton-menubutton-button, .toolbarbutton-badge-stack) > .toolbarbutton-icon {
   max-width: 16px;
   margin: 1px;
 }
 
@@ -834,20 +816,16 @@ toolbar .toolbarbutton-1 > .toolbarbutto
   #e10s-button@toolbarButtonPressed@ {
     -moz-image-region: rect(18px, 342px, 36px, 324px);
   }
 
   #webide-button@toolbarButtonPressed@ {
     -moz-image-region: rect(18px, 738px, 36px, 720px);
   }
 
-  #pocket-button@toolbarButtonPressed@ {
-    -moz-image-region: rect(18px, 774px, 36px, 756px);
-  }
-
   #new-tab-button@toolbarButtonPressed@ {
     -moz-image-region: rect(18px, 360px, 36px, 342px);
   }
 
   #privatebrowsing-button@toolbarButtonPressed@ {
     -moz-image-region: rect(18px, 378px, 36px, 360px);
   }
 
@@ -1001,20 +979,16 @@ toolbar .toolbarbutton-1 > .toolbarbutto
   #e10s-button > .toolbarbutton-icon {
     transform: scaleY(-1);
   }
 
   #webide-button@toolbarButtonPressed@ {
     -moz-image-region: rect(36px, 1476px, 72px, 1440px);
   }
 
-  #pocket-button@toolbarButtonPressed@ {
-    -moz-image-region: rect(36px, 1548px, 72px, 1512px);
-  }
-
   #new-tab-button@toolbarButtonPressed@ {
     -moz-image-region: rect(36px, 720px, 72px, 684px);
   }
 
   #privatebrowsing-button@toolbarButtonPressed@ {
     -moz-image-region: rect(36px, 756px, 72px, 720px);
   }
 
--- a/browser/themes/shared/browser.inc
+++ b/browser/themes/shared/browser.inc
@@ -1,13 +1,13 @@
 %filter substitution
 
 % Note that zoom-reset-button is a bit different since it doesn't use an image and thus has the image with display: none.
 %define nestedButtons #zoom-out-button, #zoom-reset-button, #zoom-in-button, #cut-button, #copy-button, #paste-button
-%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #web-apps-button, #webide-button, #pocket-button
+%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #web-apps-button, #webide-button
 
 %ifdef XP_MACOSX
 % Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button to exit fullscreen
 % and want it to behave like other toolbar buttons.
 %define primaryToolbarButtons @primaryToolbarButtons@, #restore-button
 %endif
 
 %define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]), [overflowedItem=true])
--- a/browser/themes/shared/customizableui/panelUIOverlay.inc.css
+++ b/browser/themes/shared/customizableui/panelUIOverlay.inc.css
@@ -245,36 +245,26 @@ panelmultiview[nosubviews=true] > .panel
   max-width: @menuPanelWidth@;
 }
 
 #BMB_bookmarksPopup,
 .panel-mainview:not([panelid="PanelUI-popup"]) {
   max-width: @standaloneSubviewWidth@;
 }
 
-/* Bug 1164419 - increase Pocket panel size to accomidate wider Russian text. */
-panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-viewstack > .panel-mainview:not([panelid="PanelUI-popup"]) {
-  max-width: 33em; /* standaloneSubviewWidth + 3 */
-}
-
 panelview:not([mainview]) .toolbarbutton-text,
 .cui-widget-panel toolbarbutton > .toolbarbutton-text {
   text-align: start;
   display: -moz-box;
 }
 
 .cui-widget-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 4px 0;
 }
 
-.cui-widget-panel[viewId="PanelUI-pocketView"] > .panel-arrowcontainer > .panel-arrowcontent {
-  padding-top: 0;
-  padding-bottom: 0;
-}
-
 .cui-widget-panel.cui-widget-panelWithFooter > .panel-arrowcontainer > .panel-arrowcontent {
   padding-bottom: 0;
 }
 
 #PanelUI-contents {
   display: block;
   flex: 1 0 auto;
   margin-left: auto;
@@ -1400,19 +1390,17 @@ toolbaritem[overflowedItem=true],
 menuitem[checked="true"].subviewbutton > .menu-iconic-left {
   visibility: hidden;
 }
 
 .panel-mainview[panelid=customizationui-widget-panel],
 #customizationui-widget-multiview > .panel-viewcontainer,
 #customizationui-widget-multiview > .panel-viewcontainer > .panel-viewstack,
 #PanelUI-panicView > .panel-subview-body,
-#PanelUI-panicView,
-#PanelUI-pocketView > .panel-subview-body,
-#PanelUI-pocketView {
+#PanelUI-panicView {
   overflow: visible;
 }
 
 #PanelUI-panicView.cui-widget-panelview {
   min-width: 280px;
 }
 
 #PanelUI-panic-timeframe {
--- a/browser/themes/shared/menupanel.inc.css
+++ b/browser/themes/shared/menupanel.inc.css
@@ -163,25 +163,16 @@
     -moz-image-region: rect(0, 928px, 32px, 896px);
   }
 
   #webide-button[cui-areatype="menu-panel"],
   toolbarpaletteitem[place="palette"] > #webide-button {
     -moz-image-region: rect(0px, 960px, 32px, 928px);
   }
 
-  #pocket-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #pocket-button {
-    -moz-image-region: rect(0px, 992px, 32px, 960px);
-  }
-
-  #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(32px, 992px, 64px, 960px);
-  }
-
   toolbaritem[sdkstylewidget="true"] > toolbarbutton {
     -moz-image-region: rect(0, 832px, 32px, 800px);
   }
 
   /* Wide panel control icons */
 
   #edit-controls@inAnyPanel@ > toolbarbutton,
   #zoom-controls@inAnyPanel@ > toolbarbutton,
@@ -310,25 +301,16 @@
     -moz-image-region: rect(0px, 1024px, 64px, 960px);
   }
 
   #webide-button[cui-areatype="menu-panel"],
   toolbarpaletteitem[place="palette"] > #webide-button {
     -moz-image-region: rect(0px, 1920px, 64px, 1856px);
   }
 
-  #pocket-button[cui-areatype="menu-panel"],
-  toolbarpaletteitem[place="palette"] > #pocket-button {
-    -moz-image-region: rect(0px, 1984px, 64px, 1920px);
-  }
-
-  #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
-    -moz-image-region: rect(64px, 1984px, 128px, 1920px);
-  }
-
   #new-tab-button[cui-areatype="menu-panel"],
   toolbarpaletteitem[place="palette"] > #new-tab-button {
     -moz-image-region: rect(0px, 1088px, 64px, 1024px);
   }
 
   #privatebrowsing-button[cui-areatype="menu-panel"],
   toolbarpaletteitem[place="palette"] > #privatebrowsing-button {
     -moz-image-region: rect(0px, 1152px, 64px, 1088px);
--- a/browser/themes/shared/toolbarbuttons.inc.css
+++ b/browser/themes/shared/toolbarbuttons.inc.css
@@ -170,28 +170,16 @@ toolbar[brighttext] #bookmarks-menu-butt
 #web-apps-button[cui-areatype="toolbar"] {
   -moz-image-region: rect(0, 720px, 18px, 702px);
 }
 
 #webide-button[cui-areatype="toolbar"] {
   -moz-image-region: rect(0, 738px, 18px, 720px);
 }
 
-#pocket-button[cui-areatype="toolbar"] {
-  -moz-image-region: rect(0, 774px, 18px, 756px);
-}
-
-#pocket-button[cui-areatype="toolbar"][open] {
-%ifdef XP_MACOSX
-  -moz-image-region: rect(36px, 774px, 54px, 756px);
-%else
-  -moz-image-region: rect(18px, 774px, 36px, 756px);
-%endif
-}
-
 %if defined(XP_WIN) || defined(XP_MACOSX)
 @media (min-resolution: 1.1dppx) {
   :-moz-any(@primaryToolbarButtons@),
   #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
     list-style-image: url("chrome://browser/skin/Toolbar@2x.png");
   }
 
   toolbar[brighttext] :-moz-any(@primaryToolbarButtons@),
@@ -352,22 +340,10 @@ toolbar[brighttext] #bookmarks-menu-butt
 
   #web-apps-button[cui-areatype="toolbar"] {
     -moz-image-region: rect(0, 1440px, 36px, 1404px);
   }
 
   #webide-button[cui-areatype="toolbar"] {
     -moz-image-region: rect(0, 1476px, 36px, 1440px);
   }
-
-  #pocket-button[cui-areatype="toolbar"] {
-    -moz-image-region: rect(0, 1548px, 36px, 1512px);
-  }
-
-  #pocket-button[cui-areatype="toolbar"][open] {
-%ifdef XP_MACOSX
-    -moz-image-region: rect(72px, 1548px, 108px, 1512px);
-%else
-    -moz-image-region: rect(36px, 1548px, 72px, 1512px);
-%endif
-  }
 }
 %endif
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -2299,22 +2299,16 @@ notification[value="translation"] {
 }
 
 #BMB_unsortedBookmarks,
 #panelMenu_unsortedBookmarks {
   list-style-image: url("chrome://browser/skin/places/unsortedBookmarks.png");
   -moz-image-region: auto;
 }
 
-#panelMenu_pocket,
-#menu_pocket,
-#BMB_pocket {
-  list-style-image: url("chrome://browser/content/pocket/panels/img/pocketmenuitem16.png");
-}
-
 /* ::::: Keyboard UI Panel ::::: */
 
 .KUI-panel {
   -moz-appearance: none;
   background: rgba(27%,27%,27%,.9) url(KUI-background.png) repeat-x;
   color: white;
   border-style: none;
   border-radius: 20px;
--- a/devtools/.eslintrc
+++ b/devtools/.eslintrc
@@ -89,17 +89,17 @@
     // Enforces spacing between keys and values in object literal properties.
     "key-spacing": [1, {"beforeColon": false, "afterColon": true}],
     // Allow mixed 'LF' and 'CRLF' as linebreaks.
     "linebreak-style": 0,
     // Don't enforce the maximum depth that blocks can be nested. The complexity
     // rule is a better rule to check this.
     "max-depth": 0,
     // Maximum length of a line.
-    "max-len": [1, 80],
+    "max-len": [1, 80, 2, {"ignoreUrls": true, "ignorePattern": "^\\s*loader\\.lazy"}],
     // Maximum depth callbacks can be nested.
     "max-nested-callbacks": [2, 3],
     // Don't limit the number of parameters that can be used in a function.
     "max-params": 0,
     // Don't limit the maximum number of statement allowed in a function. We
     // already have the complexity rule that's a better measurement.
     "max-statements": 0,
     // Require a capital letter for constructors, only check if all new
--- a/devtools/client/framework/toolbox.js
+++ b/devtools/client/framework/toolbox.js
@@ -14,17 +14,17 @@ const OS_HISTOGRAM = "DEVTOOLS_OS_ENUMER
 const OS_IS_64_BITS = "DEVTOOLS_OS_IS_64_BITS_PER_USER";
 const SCREENSIZE_HISTOGRAM = "DEVTOOLS_SCREEN_RESOLUTION_ENUMERATED_PER_USER";
 
 var {Cc, Ci, Cu} = require("chrome");
 var promise = require("promise");
 var EventEmitter = require("devtools/shared/event-emitter");
 var Telemetry = require("devtools/client/shared/telemetry");
 var HUDService = require("devtools/client/webconsole/hudservice");
-var sourceUtils = require("devtools/client/shared/source-utils");
+var viewSource = require("devtools/client/shared/view-source");
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://devtools/client/framework/gDevTools.jsm");
 Cu.import("resource://devtools/client/scratchpad/scratchpad-manager.jsm");
 Cu.import("resource://devtools/client/shared/DOMHelpers.jsm");
 Cu.import("resource://gre/modules/Task.jsm");
 
 loader.lazyImporter(this, "CommandUtils",
@@ -2131,40 +2131,40 @@ Toolbox.prototype = {
     return this.frame.contentWindow.gViewSourceUtils;
   },
 
   /**
    * Opens source in style editor. Falls back to plain "view-source:".
    * @see devtools/client/shared/source-utils.js
    */
   viewSourceInStyleEditor: function(sourceURL, sourceLine) {
-    return sourceUtils.viewSourceInStyleEditor(this, sourceURL, sourceLine);
+    return viewSource.viewSourceInStyleEditor(this, sourceURL, sourceLine);
   },
 
   /**
    * Opens source in debugger. Falls back to plain "view-source:".
    * @see devtools/client/shared/source-utils.js
    */
   viewSourceInDebugger: function(sourceURL, sourceLine) {
-    return sourceUtils.viewSourceInDebugger(this, sourceURL, sourceLine);
+    return viewSource.viewSourceInDebugger(this, sourceURL, sourceLine);
   },
 
   /**
    * Opens source in scratchpad. Falls back to plain "view-source:".
    * TODO The `sourceURL` for scratchpad instances are like `Scratchpad/1`.
    * If instances are scoped one-per-browser-window, then we should be able
    * to infer the URL from this toolbox, or use the built in scratchpad IN
    * the toolbox.
    *
    * @see devtools/client/shared/source-utils.js
    */
   viewSourceInScratchpad: function(sourceURL, sourceLine) {
-    return sourceUtils.viewSourceInScratchpad(sourceURL, sourceLine);
+    return viewSource.viewSourceInScratchpad(sourceURL, sourceLine);
   },
 
   /**
    * Opens source in plain "view-source:".
    * @see devtools/client/shared/source-utils.js
    */
   viewSource: function(sourceURL, sourceLine) {
-    return sourceUtils.viewSource(this, sourceURL, sourceLine);
+    return viewSource.viewSource(this, sourceURL, sourceLine);
   },
 };
--- a/devtools/client/memory/app.js
+++ b/devtools/client/memory/app.js
@@ -93,17 +93,17 @@ const App = createClass({
             onClick: onClickSnapshotListItem,
             diffing,
           }),
 
           HeapView({
             snapshot: selectedSnapshot,
             diffing,
             onSnapshotClick: () => dispatch(takeSnapshotAndCensus(front, heapWorker)),
-            toolbox
+            onViewSourceInDebugger: frame => toolbox.viewSourceInDebugger(frame.source, frame.line),
           })
         )
       )
     );
   },
 });
 
 /**
deleted file mode 100644
--- a/devtools/client/memory/components/frame.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
-const { L10N, parseSource } = require("../utils");
-
-const Frame = module.exports = createClass({
-  displayName: "frame-view",
-
-  propTypes: {
-    frame: PropTypes.object.isRequired,
-    toolbox: PropTypes.object.isRequired,
-  },
-
-  render() {
-    let { toolbox, frame } = this.props;
-    const { short, long, host } = parseSource(frame.source);
-
-    let func = frame.functionDisplayName || "";
-    let tooltip = `${func} (${long}:${frame.line}:${frame.column})`;
-    let viewTooltip = L10N.getFormatStr("viewsourceindebugger", `${long}:${frame.line}:${frame.column}`);
-    let onClick = () => toolbox.viewSourceInDebugger(long, frame.line);
-
-    let fields = [
-      dom.span({ className: "frame-link-function-display-name" }, func),
-      dom.a({ className: "frame-link-filename", onClick, title: viewTooltip }, short),
-      dom.span({ className: "frame-link-colon" }, ":"),
-      dom.span({ className: "frame-link-line" }, frame.line),
-      dom.span({ className: "frame-link-colon" }, ":"),
-      dom.span({ className: "frame-link-column" }, frame.column)
-    ];
-
-    if (host) {
-      fields.push(dom.span({ className: "frame-link-host" }, host));
-    }
-
-    return dom.span({ className: "frame-link", title: tooltip }, ...fields);
-  }
-});
--- a/devtools/client/memory/components/heap.js
+++ b/devtools/client/memory/components/heap.js
@@ -29,21 +29,21 @@ function createParentMap (node, aggregat
 
   return aggregator;
 }
 
 /**
  * Creates properties to be passed into the Tree component.
  *
  * @param {censusModel} census
- * @param {Object} toolbox
+ * @param {Function} onViewSourceInDebugger
  * @param {Object} diffing
  * @return {Object}
  */
-function createTreeProperties(census, toolbox, diffing) {
+function createTreeProperties(census, onViewSourceInDebugger, diffing) {
   const report = census.report;
   let map = createParentMap(report);
   const { totalBytes, totalCount } = report;
 
   const getPercentBytes = totalBytes === 0
     ? _ => 0
     : bytes => (bytes / totalBytes) * 100;
 
@@ -55,17 +55,17 @@ function createTreeProperties(census, to
     autoExpandDepth: 0,
     getParent: node => {
       const parent = map[node.id];
       return parent === report ? null : parent;
     },
     getChildren: node => node.children || [],
     renderItem: (item, depth, focused, arrow, expanded) =>
       new TreeItem({
-        toolbox,
+        onViewSourceInDebugger,
         item,
         depth,
         focused,
         arrow,
         expanded,
         getPercentBytes,
         getPercentCount,
         showSign: !!diffing,
@@ -86,22 +86,22 @@ function createTreeProperties(census, to
  */
 
 const Heap = module.exports = createClass({
   displayName: "heap-view",
 
   propTypes: {
     onSnapshotClick: PropTypes.func.isRequired,
     snapshot: snapshotModel,
-    toolbox: PropTypes.object.isRequired,
+    onViewSourceInDebugger: PropTypes.func.isRequired,
     diffing: diffingModel,
   },
 
   render() {
-    let { snapshot, diffing, onSnapshotClick, toolbox } = this.props;
+    let { snapshot, diffing, onSnapshotClick, onViewSourceInDebugger } = this.props;
 
     let census;
     let state;
     let statusText;
     let error;
     if (diffing) {
       census = diffing.census;
       state = diffing.state;
@@ -179,17 +179,17 @@ const Heap = module.exports = createClas
         content.push(
           dom.div({ className: "header" },
             dom.span({ className: "heap-tree-item-bytes" }, L10N.getStr("heapview.field.bytes")),
             dom.span({ className: "heap-tree-item-count" }, L10N.getStr("heapview.field.count")),
             dom.span({ className: "heap-tree-item-total-bytes" }, L10N.getStr("heapview.field.totalbytes")),
             dom.span({ className: "heap-tree-item-total-count" }, L10N.getStr("heapview.field.totalcount")),
             dom.span({ className: "heap-tree-item-name" }, L10N.getStr("heapview.field.name"))
           ),
-          Tree(createTreeProperties(census, toolbox, diffing))
+          Tree(createTreeProperties(census, onViewSourceInDebugger, diffing))
         );
         break;
 
       default:
         assert(false, "Unexpected state: ${state}");
     }
     assert(!!content, "Should have set content in the above switch block");
 
--- a/devtools/client/memory/components/moz.build
+++ b/devtools/client/memory/components/moz.build
@@ -1,13 +1,12 @@
 # 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/.
 
 DevToolsModules(
-    'frame.js',
     'heap.js',
     'list.js',
     'snapshot-list-item.js',
     'toolbar.js',
     'tree-item.js',
 )
--- a/devtools/client/memory/components/tree-item.js
+++ b/devtools/client/memory/components/tree-item.js
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 const { isSavedFrame } = require("devtools/shared/DevToolsUtils");
 const { DOM: dom, createClass, createFactory, PropTypes } = require("devtools/client/shared/vendor/react");
 const { L10N } = require("../utils");
-const FrameView = createFactory(require("./frame"));
+const FrameView = createFactory(require("devtools/client/shared/components/frame"));
+const unknownSourceString = L10N.getStr("unknownSource");
 
 const INDENT = 10;
 const MAX_SOURCE_LENGTH = 200;
 
 
 /**
  * An arrow that displays whether its node is expanded (▼) or collapsed
  * (▶). When its node has no children, it is hidden.
@@ -50,16 +51,17 @@ const TreeItem = module.exports = create
       item,
       depth,
       arrow,
       focused,
       toolbox,
       getPercentBytes,
       getPercentCount,
       showSign,
+      onViewSourceInDebugger,
     } = this.props;
 
     const bytes = this.formatNumber(showSign, item.bytes);
     const percentBytes = this.formatPercent(showSign, getPercentBytes(item.bytes));
 
     const count = this.formatNumber(showSign, item.count);
     const percentCount = this.formatPercent(showSign, getPercentCount(item.count));
 
@@ -79,24 +81,31 @@ const TreeItem = module.exports = create
       dom.span({ className: "heap-tree-item-field heap-tree-item-total-bytes" },
                dom.span({ className: "heap-tree-number" }, totalBytes),
                dom.span({ className: "heap-tree-percent" }, percentTotalBytes)),
       dom.span({ className: "heap-tree-item-field heap-tree-item-total-count" },
                dom.span({ className: "heap-tree-number" }, totalCount),
                dom.span({ className: "heap-tree-percent" }, percentTotalCount)),
       dom.span({ className: "heap-tree-item-field heap-tree-item-name", style: { marginLeft: depth * INDENT }},
         arrow,
-        this.toLabel(item.name, toolbox)
+        this.toLabel(item.name, onViewSourceInDebugger)
       )
     );
   },
 
-  toLabel(name, toolbox) {
+  toLabel(name, linkToDebugger) {
     if (isSavedFrame(name)) {
-      return FrameView({ frame: name, toolbox });
+      let onClickTooltipString =
+        L10N.getFormatStr("viewsourceindebugger",`${name.source}:${name.line}:${name.column}`);
+      return FrameView({
+        frame: name,
+        onClick: () => linkToDebugger(name),
+        onClickTooltipString,
+        unknownSourceString
+      });
     }
 
     if (name === null) {
       return L10N.getStr("tree-item.root");
     }
 
     if (name === "noStack") {
       return L10N.getStr("tree-item.nostack");
--- a/devtools/client/memory/test/unit/test_utils.js
+++ b/devtools/client/memory/test/unit/test_utils.js
@@ -44,27 +44,8 @@ add_task(function *() {
     "utils.breakdownNameToSpec() works for presets");
 
   let custom = { by: "internalType", then: { by: "count", bytes: true }};
   Preferences.set("devtools.memory.custom-breakdowns", JSON.stringify({ "My Breakdown": custom }));
 
   ok(utils.breakdownEquals(utils.getCustomBreakdowns()["My Breakdown"], custom),
     "utils.getCustomBreakdowns() returns custom breakdowns");
 });
-
-// Test `utils.parseSource`.
-add_task(function* () {
-  const url = "http://example.com/foo/bar/baz.js";
-  let results = utils.parseSource(url);
-  equal(results.short, "baz.js");
-  equal(results.long, url);
-  equal(results.host, "example.com");
-
-  results = utils.parseSource("self-hosted");
-  equal(results.short, "self-hosted");
-  equal(results.long, "self-hosted");
-  equal(results.host, undefined);
-
-  results = utils.parseSource("");
-  equal(typeof results.short, "string");
-  equal(typeof results.long, "string");
-  equal(results.host, undefined);
-});
--- a/devtools/client/memory/utils.js
+++ b/devtools/client/memory/utils.js
@@ -336,59 +336,16 @@ exports.getSnapshotTotals = function (ce
     bytes = report.totalBytes;
     count = report.totalCount;
   }
 
   return { bytes, count };
 };
 
 /**
- * Parse a source into a short and long name as well as a host name.
- *
- * @param {String} source
- *        The source to parse.
- *
- * @returns {Object}
- *          An object with the following properties:
- *            - {String} short: A short name for the source.
- *            - {String} long: The full, long name for the source.
- *            - {String?} host: If available, the host name for the source.
- */
-exports.parseSource = function (source) {
-  const sourceStr = source ? String(source) : "";
-
-  let short;
-  let long;
-  let host;
-
-  try {
-    const url = new URL(sourceStr);
-    short = url.fileName;
-    host = url.host;
-    long = url.toString();
-  } catch (e) {
-    // Malformed URI.
-    long = sourceStr;
-    short = sourceStr.slice(0, 100);
-  }
-
-  if (!short) {
-    // Last ditch effort.
-
-    if (!long) {
-      long = L10N.getStr("unknownSource");
-    }
-
-    short = long.slice(0, 100);
-  }
-
-  return { short, long, host };
-};
-
-/**
  * Takes some configurations and opens up a file picker and returns
  * a promise to the chosen file if successful.
  *
  * @param {String} .title
  *        The title displayed in the file picker window.
  * @param {Array<Array<String>>} .filters
  *        An array of filters to display in the file picker. Each filter in the array
  *        is a duple of two strings, one a name for the filter, and one the filter itself
--- a/devtools/client/performance/modules/logic/frame-utils.js
+++ b/devtools/client/performance/modules/logic/frame-utils.js
@@ -1,50 +1,32 @@
 /* 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");
-
 loader.lazyRequireGetter(this, "Services");
 loader.lazyRequireGetter(this, "global",
   "devtools/client/performance/modules/global");
 const demangle = require("devtools/client/shared/demangle");
+const { isChromeScheme, isContentScheme, parseURL } =
+  require("devtools/client/shared/source-utils");
 
 // Character codes used in various parsing helper functions.
-const CHAR_CODE_A = "a".charCodeAt(0);
-const CHAR_CODE_C = "c".charCodeAt(0);
-const CHAR_CODE_E = "e".charCodeAt(0);
-const CHAR_CODE_F = "f".charCodeAt(0);
-const CHAR_CODE_H = "h".charCodeAt(0);
-const CHAR_CODE_I = "i".charCodeAt(0);
-const CHAR_CODE_J = "j".charCodeAt(0);
-const CHAR_CODE_L = "l".charCodeAt(0);
-const CHAR_CODE_M = "m".charCodeAt(0);
-const CHAR_CODE_O = "o".charCodeAt(0);
-const CHAR_CODE_P = "p".charCodeAt(0);
 const CHAR_CODE_R = "r".charCodeAt(0);
-const CHAR_CODE_S = "s".charCodeAt(0);
-const CHAR_CODE_T = "t".charCodeAt(0);
-const CHAR_CODE_U = "u".charCodeAt(0);
 const CHAR_CODE_0 = "0".charCodeAt(0);
 const CHAR_CODE_9 = "9".charCodeAt(0);
 const CHAR_CODE_CAP_Z = "Z".charCodeAt(0);
 
 const CHAR_CODE_LPAREN = "(".charCodeAt(0);
 const CHAR_CODE_RPAREN = ")".charCodeAt(0);
 const CHAR_CODE_COLON = ":".charCodeAt(0);
-const CHAR_CODE_SLASH = "/".charCodeAt(0);
 const CHAR_CODE_SPACE = " ".charCodeAt(0);
 const CHAR_CODE_UNDERSCORE = "_".charCodeAt(0);
 
-// The cache used in the `nsIURL` function.
-const gNSURLStore = new Map();
-
 // The cache used to store inflated frames.
 const gInflatedFrameStore = new WeakMap();
 
 // The cache used to store frame data from `getInfo`.
 const gFrameData = new WeakMap();
 
 /**
  * Parses the raw location of this function call to retrieve the actual
@@ -145,51 +127,41 @@ function parseLocation(location, fallbac
           i > 0 &&
           location.charCodeAt(i - 1) === CHAR_CODE_SPACE) {
         parenIndex = i;
         break;
       }
     }
   }
 
-  let uri;
+  let parsedUrl;
   if (lineAndColumnIndex > 0) {
     let resource = location.substring(parenIndex + 1, lineAndColumnIndex);
     url = resource.split(" -> ").pop();
     if (url) {
-      uri = nsIURL(url);
+      parsedUrl = parseURL(url);
     }
   }
 
-  let functionName, fileName, hostName, port, host;
+  let functionName, fileName, port, host;
   line = line || fallbackLine;
   column = column || fallbackColumn;
 
-  // If the URI digged out from the `location` is valid, this is a JS frame.
-  if (uri) {
+  // If the URL digged out from the `location` is valid, this is a JS frame.
+  if (parsedUrl) {
     functionName = location.substring(0, parenIndex - 1);
-    fileName = uri.fileName || "/";
-    hostName = getHost(url, uri.host);
-    // nsIURL throws when accessing a piece of a URL that doesn't
-    // exist, because we can't have nice things. Only check this if hostName
-    // exists, to save an extra try/catch.
-    if (hostName) {
-      try {
-        port = uri.port === -1 ? null : uri.port;
-        host = port !== null ? `${hostName}:${port}` : hostName;
-      } catch (e) {
-        host = hostName;
-      }
-    }
+    fileName = parsedUrl.fileName;
+    port = parsedUrl.port;
+    host = parsedUrl.host;
   } else {
     functionName = location;
     url = null;
   }
 
-  return { functionName, fileName, hostName, host, port, url, line, column };
+  return { functionName, fileName, host, port, url, line, column };
 };
 
 /**
  * Sets the properties of `isContent` and `category` on a frame.
  *
  * @param {InflatedFrame} frame
  */
 function computeIsContentAndCategory(frame) {
@@ -351,139 +323,16 @@ InflatedFrame.prototype.getFrameKey = fu
     options.isMetaCategoryOut = true;
     return this.category;
   }
 
   // Return an empty string denoting that this frame should be skipped.
   return "";
 };
 
-/**
- * Helper for getting an nsIURL instance out of a string.
- */
-function nsIURL(url) {
-  let cached = gNSURLStore.get(url);
-  // If we cached a valid URI, or `null` in the case
-  // of a failure, return it.
-  if (cached !== void 0) {
-    return cached;
-  }
-  let uri = null;
-  try {
-    uri = Services.io.newURI(url, null, null).QueryInterface(Ci.nsIURL);
-    // Access the host, because the constructor doesn't necessarily throw
-    // if it's invalid, but accessing the host can throw as well
-    uri.host;
-  } catch(e) {
-    // The passed url string is invalid.
-    uri = null;
-  }
-
-  gNSURLStore.set(url, uri);
-  return uri;
-};
-
-/**
- * Takes a `host` string from an nsIURL instance and
- * returns the same string, or null, if it's an invalid host.
- */
-function getHost (url, hostName) {
-  return isChromeScheme(url, 0) ? null : hostName;
-}
-
-// For the functions below, we assume that we will never access the location
-// argument out of bounds, which is indeed the vast majority of cases.
-//
-// They are written this way because they are hot. Each frame is checked for
-// being content or chrome when processing the profile.
-
-function isColonSlashSlash(location, i) {
-  return location.charCodeAt(++i) === CHAR_CODE_COLON &&
-         location.charCodeAt(++i) === CHAR_CODE_SLASH &&
-         location.charCodeAt(++i) === CHAR_CODE_SLASH;
-}
-
-function isContentScheme(location, i) {
-  let firstChar = location.charCodeAt(i);
-
-  switch (firstChar) {
-  case CHAR_CODE_H: // "http://" or "https://"
-    if (location.charCodeAt(++i) === CHAR_CODE_T &&
-        location.charCodeAt(++i) === CHAR_CODE_T &&
-        location.charCodeAt(++i) === CHAR_CODE_P) {
-      if (location.charCodeAt(i + 1) === CHAR_CODE_S) {
-        ++i;
-      }
-      return isColonSlashSlash(location, i);
-    }
-    return false;
-
-  case CHAR_CODE_F: // "file://"
-    if (location.charCodeAt(++i) === CHAR_CODE_I &&
-        location.charCodeAt(++i) === CHAR_CODE_L &&
-        location.charCodeAt(++i) === CHAR_CODE_E) {
-      return isColonSlashSlash(location, i);
-    }
-    return false;
-
-  case CHAR_CODE_A: // "app://"
-    if (location.charCodeAt(++i) == CHAR_CODE_P &&
-        location.charCodeAt(++i) == CHAR_CODE_P) {
-      return isColonSlashSlash(location, i);
-    }
-    return false;
-
-  default:
-    return false;
-  }
-}
-
-function isChromeScheme(location, i) {
-  let firstChar = location.charCodeAt(i);
-
-  switch (firstChar) {
-  case CHAR_CODE_C: // "chrome://"
-    if (location.charCodeAt(++i) === CHAR_CODE_H &&
-        location.charCodeAt(++i) === CHAR_CODE_R &&
-        location.charCodeAt(++i) === CHAR_CODE_O &&
-        location.charCodeAt(++i) === CHAR_CODE_M &&
-        location.charCodeAt(++i) === CHAR_CODE_E) {
-      return isColonSlashSlash(location, i);
-    }
-    return false;
-
-  case CHAR_CODE_R: // "resource://"
-    if (location.charCodeAt(++i) === CHAR_CODE_E &&
-        location.charCodeAt(++i) === CHAR_CODE_S &&
-        location.charCodeAt(++i) === CHAR_CODE_O &&
-        location.charCodeAt(++i) === CHAR_CODE_U &&
-        location.charCodeAt(++i) === CHAR_CODE_R &&
-        location.charCodeAt(++i) === CHAR_CODE_C &&
-        location.charCodeAt(++i) === CHAR_CODE_E) {
-      return isColonSlashSlash(location, i);
-    }
-    return false;
-
-  case CHAR_CODE_J: // "jar:file://"
-    if (location.charCodeAt(++i) === CHAR_CODE_A &&
-        location.charCodeAt(++i) === CHAR_CODE_R &&
-        location.charCodeAt(++i) === CHAR_CODE_COLON &&
-        location.charCodeAt(++i) === CHAR_CODE_F &&
-        location.charCodeAt(++i) === CHAR_CODE_I &&
-        location.charCodeAt(++i) === CHAR_CODE_L &&
-        location.charCodeAt(++i) === CHAR_CODE_E) {
-      return isColonSlashSlash(location, i);
-    }
-    return false;
-
-  default:
-    return false;
-  }
-}
-
 function isNumeric(c) {
   return c >= CHAR_CODE_0 && c <= CHAR_CODE_9;
 }
 
 function shouldDemangle(name) {
   return name && name.charCodeAt &&
          name.charCodeAt(0) === CHAR_CODE_UNDERSCORE &&
          name.charCodeAt(1) === CHAR_CODE_UNDERSCORE &&
--- a/devtools/client/performance/test/unit/test_frame-utils-01.js
+++ b/devtools/client/performance/test/unit/test_frame-utils-01.js
@@ -54,33 +54,33 @@ add_task(function () {
   for (let frame of CONTENT_LOCATIONS) {
     ok(isContent.apply(null, frameify(frame)), `${frame[0]} should be considered a content frame.`);
   }
 
   for (let frame of CHROME_LOCATIONS) {
     ok(!isContent.apply(null, frameify(frame)), `${frame[0]} should not be considered a content frame.`);
   }
 
-  // functionName, fileName, hostName, url, line, column
-  const FIELDS = ["functionName", "fileName", "hostName", "url", "line", "column", "host", "port"];
+  // functionName, fileName, host, url, line, column
+  const FIELDS = ["functionName", "fileName", "host", "url", "line", "column", "host", "port"];
   const PARSED_CONTENT = [
     ["hello/<.world", "bar.js", "foo", "https://foo/bar.js", 123, 987, "foo", null],
     ["hello/<.world", "bar.js", "foo", "http://foo/bar.js", 123, 987, "foo", null],
     ["hello/<.world", "bar.js", "foo", "http://foo/bar.js", 123, null, "foo", null],
     ["hello/<.world", "bar.js", "foo", "http://foo/bar.js#baz", 123, 987, "foo", null],
     ["hello/<.world", "bar.js", "foo", "http://foo/bar.js?myquery=params&search=1", 123, 987, "foo", null],
     ["hello/<.world", "/", "foo", "http://foo/#bar", 123, 987, "foo", null],
     ["hello/<.world", "/", "foo", "http://foo/", 123, 987, "foo", null],
     ["hello/<.world", "file.js", "myfxosapp", "app://myfxosapp/file.js", 100, 1, "myfxosapp", null],
-    ["hello/<.world", "file.js", "localhost", "http://localhost:8888/file.js", 100, 1, "localhost:8888", 8888],
-    ["hello/<.world", "file.js", "localhost", "http://localhost:8888/file.js", 100, null, "localhost:8888", 8888],
-    ["hello/<.world", "/", "localhost", "http://localhost:8888/", 1, null, "localhost:8888", 8888],
-    ["hello/<.world", "/", "localhost", "http://localhost:8888/", 100, 50, "localhost:8888", 8888],
-    ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost", "http://localhost:8888/profiler.html", 4, null, "localhost:8888", 8888],
-    ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost", "http://localhost:8888/profiler.html", 4, 5, "localhost:8888", 8888],
+    ["hello/<.world", "file.js", "localhost:8888", "http://localhost:8888/file.js", 100, 1, "localhost:8888", 8888],
+    ["hello/<.world", "file.js", "localhost:8888", "http://localhost:8888/file.js", 100, null, "localhost:8888", 8888],
+    ["hello/<.world", "/", "localhost:8888", "http://localhost:8888/", 1, null, "localhost:8888", 8888],
+    ["hello/<.world", "/", "localhost:8888", "http://localhost:8888/", 100, 50, "localhost:8888", 8888],
+    ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost:8888", "http://localhost:8888/profiler.html", 4, null, "localhost:8888", 8888],
+    ["Native[\"arraycopy(blah)\"]", "profiler.html", "localhost:8888", "http://localhost:8888/profiler.html", 4, 5, "localhost:8888", 8888],
   ];
 
   for (let i = 0; i < PARSED_CONTENT.length; i++) {
     let parsed = parseLocation.apply(null, CONTENT_LOCATIONS[i]);
     for (let j = 0; j < FIELDS.length; j++) {
       equal(parsed[FIELDS[j]], PARSED_CONTENT[i][j], `${CONTENT_LOCATIONS[i]} was parsed to correct ${FIELDS[j]}`);
     }
   }
--- a/devtools/client/performance/test/unit/test_tree-model-08.js
+++ b/devtools/client/performance/test/unit/test_tree-model-08.js
@@ -60,29 +60,29 @@ add_task(function test() {
       location: "main (http://localhost:8888/file.js:123:987)",
       line: 123,
     }), false),
     new FrameNode("main (resource://devtools/timeline.js:123)", compute({
       location: "main (resource://devtools/timeline.js:123)",
     }), false),
   ];
 
-  let fields = ["nodeType", "functionName", "fileName", "hostName", "url", "line", "column", "categoryData.abbrev", "isContent", "port"]
+  let fields = ["nodeType", "functionName", "fileName", "host", "url", "line", "column", "categoryData.abbrev", "isContent", "port"]
   let expected = [
-    // nodeType, functionName, fileName, hostName, url, line, column, categoryData.abbrev, isContent, port
+    // nodeType, functionName, fileName, host, url, line, column, categoryData.abbrev, isContent, port
     ["Frame", "hello/<.world", "bar.js", "foo", "http://foo/bar.js", 123, 987, void 0, true],
     ["Frame", "hello/<.world", "bar.js", "foo", "http://foo/bar.js#baz", 123, 987, void 0, true],
     ["Frame", "hello/<.world", "/", "foo", "http://foo/#bar", 123, 987, void 0, true],
     ["Frame", "hello/<.world", "/", "foo", "http://foo/", 123, 987, void 0, true],
     ["Frame", "hello/<.world", "baz.js", "bar", "http://bar/baz.js", 123, 987, "other", false],
     ["Frame", "Foo::Bar::Baz", null, null, null, 456, void 0, "other", false],
     ["Frame", "EnterJIT", null, null, null, null, null, "js", false],
     ["Frame", "chrome://browser/content/content.js", null, null, null, 456, null, "other", false],
     ["Frame", "hello/<.world", "foo.js", null, "resource://gre/foo.js", 123, 434, "other", false],
-    ["Frame", "main", "file.js", "localhost", "http://localhost:8888/file.js", 123, 987, null, true, 8888],
+    ["Frame", "main", "file.js", "localhost:8888", "http://localhost:8888/file.js", 123, 987, null, true, 8888],
     ["Frame", "main", "timeline.js", null, "resource://devtools/timeline.js", 123, null, "tools", false]
   ];
 
   for (let i = 0; i < frames.length; i++) {
     let info = frames[i].getInfo();
     let expect = expected[i];
 
     for (let j = 0; j < fields.length; j++) {
--- a/devtools/client/responsivedesign/responsivedesign.jsm
+++ b/devtools/client/responsivedesign/responsivedesign.jsm
@@ -47,16 +47,28 @@ this.ResponsiveUIManager = {
    *
    * @param aWindow the main window.
    * @param aTab the tab targeted.
    */
   toggle: function(aWindow, aTab) {
     if (this.isActiveForTab(aTab)) {
       ActiveTabs.get(aTab).close();
     } else {
+      this.runIfNeeded(aWindow, aTab);
+    }
+  },
+
+  /**
+   * Launches the responsive mode.
+   *
+   * @param aWindow the main window.
+   * @param aTab the tab targeted.
+   */
+  runIfNeeded: function(aWindow, aTab) {
+    if (!this.isActiveForTab(aTab)) {
       new ResponsiveUI(aWindow, aTab);
     }
   },
 
   /**
    * Returns true if responsive view is active for the provided tab.
    *
    * @param aTab the tab targeted.
@@ -78,25 +90,21 @@ this.ResponsiveUIManager = {
    * @param aWindow the browser window.
    * @param aTab the tab targeted.
    * @param aCommand the command name.
    * @param aArgs command arguments.
    */
   handleGcliCommand: function(aWindow, aTab, aCommand, aArgs) {
     switch (aCommand) {
       case "resize to":
-        if (!this.isActiveForTab(aTab)) {
-          new ResponsiveUI(aWindow, aTab);
-        }
+        this.runIfNeeded(aWindow, aTab);
         ActiveTabs.get(aTab).setSize(aArgs.width, aArgs.height);
         break;
       case "resize on":
-        if (!this.isActiveForTab(aTab)) {
-          new ResponsiveUI(aWindow, aTab);
-        }
+        this.runIfNeeded(aWindow, aTab);
         break;
       case "resize off":
         if (this.isActiveForTab(aTab)) {
           ActiveTabs.get(aTab).close();
         }
         break;
       case "resize toggle":
           this.toggle(aWindow, aTab);
@@ -846,46 +854,48 @@ ResponsiveUI.prototype = {
 
   /**
    * Change the size of the browser.
    *
    * @param aWidth width of the browser.
    * @param aHeight height of the browser.
    */
   setSize: function RUI_setSize(aWidth, aHeight) {
-    aWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH);
-    aHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_HEIGHT);
+    this.setWidth(aWidth);
+    this.setHeight(aHeight);
+  },
 
-    // We resize the containing stack.
-    let style = "max-width: %width;" +
-                "min-width: %width;" +
-                "max-height: %height;" +
-                "min-height: %height;";
+  setWidth: function RUI_setWidth(aWidth) {
+    aWidth = Math.min(Math.max(aWidth, MIN_WIDTH), MAX_WIDTH);
+    this.stack.style.maxWidth = this.stack.style.minWidth = aWidth + "px";
 
-    style = style.replace(/%width/g, aWidth + "px");
-    style = style.replace(/%height/g, aHeight + "px");
-
-    this.stack.setAttribute("style", style);
-
-    if (!this.ignoreY)
-      this.resizeBarV.setAttribute("top", Math.round(aHeight / 2));
     if (!this.ignoreX)
       this.resizeBarH.setAttribute("left", Math.round(aWidth / 2));
 
     let selectedPreset = this.menuitems.get(this.selectedItem);
 
-    // We update the custom menuitem if we are using it
     if (selectedPreset.custom) {
       selectedPreset.width = aWidth;
-      selectedPreset.height = aHeight;
-
       this.setMenuLabel(this.selectedItem, selectedPreset);
     }
   },
 
+  setHeight: function RUI_setHeight(aHeight) {
+    aHeight = Math.min(Math.max(aHeight, MIN_HEIGHT), MAX_HEIGHT);
+    this.stack.style.maxHeight = this.stack.style.minHeight = aHeight + "px";
+
+    if (!this.ignoreY)
+      this.resizeBarV.setAttribute("top", Math.round(aHeight / 2));
+
+    let selectedPreset = this.menuitems.get(this.selectedItem);
+    if (selectedPreset.custom) {
+      selectedPreset.height = aHeight;
+      this.setMenuLabel(this.selectedItem, selectedPreset);
+    }
+  },
   /**
    * Start the process of resizing the browser.
    *
    * @param aEvent
    */
   startResizing: function RUI_startResizing(aEvent) {
     let selectedPreset = this.menuitems.get(this.selectedItem);
 
new file mode 100644
--- /dev/null
+++ b/devtools/client/shared/components/frame.js
@@ -0,0 +1,50 @@
+/* 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 { DOM: dom, createClass, PropTypes } = require("devtools/client/shared/vendor/react");
+const { getSourceNames } = require("devtools/client/shared/source-utils");
+
+const Frame = module.exports = createClass({
+  displayName: "frame-view",
+
+  propTypes: {
+    // SavedFrame
+    frame: PropTypes.object.isRequired,
+    // Clicking on the frame link -- probably should link to the debugger.
+    onClick: PropTypes.func.isRequired,
+    // Tooltip to display when hovering over the link to the frame;
+    // Something like "View source in debugger -> http://foo.com/file.js:100:2".
+    onClickTooltipString: PropTypes.string.isRequired,
+    // Source to display when cannot determine a good display name.
+    // Something like "(unknown)".
+    unknownSourceString: PropTypes.string.isRequired,
+  },
+
+  render() {
+    let { onClick, frame, onClickTooltipString, unknownSourceString } = this.props;
+    const { short, long, host } = getSourceNames(frame.source, unknownSourceString);
+
+    let func = frame.functionDisplayName || "";
+    let tooltip = `${func} (${long}:${frame.line}:${frame.column})`;
+
+    let fields = [
+      dom.span({ className: "frame-link-function-display-name" }, func),
+      dom.a({
+        className: "frame-link-filename",
+        onClick,
+        title: onClickTooltipString
+      }, short),
+      dom.span({ className: "frame-link-colon" }, ":"),
+      dom.span({ className: "frame-link-line" }, frame.line),
+      dom.span({ className: "frame-link-colon" }, ":"),
+      dom.span({ className: "frame-link-column" }, frame.column)
+    ];
+
+    if (host) {
+      fields.push(dom.span({ className: "frame-link-host" }, host));
+    }
+
+    return dom.span({ className: "frame-link", title: tooltip }, ...fields);
+  }
+});
--- a/devtools/client/shared/components/moz.build
+++ b/devtools/client/shared/components/moz.build
@@ -1,11 +1,12 @@
 # -*- 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/.
 
 DevToolsModules(
+    'frame.js',
     'tree.js',
 )
 
 MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
--- a/devtools/client/shared/moz.build
+++ b/devtools/client/shared/moz.build
@@ -34,10 +34,11 @@ DevToolsModules(
     'options-view.js',
     'output-parser.js',
     'poller.js',
     'source-utils.js',
     'SplitView.jsm',
     'telemetry.js',
     'theme-switching.js',
     'theme.js',
-    'undo.js'
+    'undo.js',
+    'view-source.js',
 )
--- a/devtools/client/shared/source-utils.js
+++ b/devtools/client/shared/source-utils.js
@@ -1,141 +1,210 @@
 /* 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";
 
-loader.lazyRequireGetter(this, "Services");
-loader.lazyImporter(this, "gDevTools", "resource://devtools/client/framework/gDevTools.jsm");
-loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm");
+const { URL } = require("sdk/url");
 
-var DevToolsUtils = require("devtools/shared/DevToolsUtils");
+// Character codes used in various parsing helper functions.
+const CHAR_CODE_A = "a".charCodeAt(0);
+const CHAR_CODE_C = "c".charCodeAt(0);
+const CHAR_CODE_E = "e".charCodeAt(0);
+const CHAR_CODE_F = "f".charCodeAt(0);
+const CHAR_CODE_H = "h".charCodeAt(0);
+const CHAR_CODE_I = "i".charCodeAt(0);
+const CHAR_CODE_J = "j".charCodeAt(0);
+const CHAR_CODE_L = "l".charCodeAt(0);
+const CHAR_CODE_M = "m".charCodeAt(0);
+const CHAR_CODE_O = "o".charCodeAt(0);
+const CHAR_CODE_P = "p".charCodeAt(0);
+const CHAR_CODE_R = "r".charCodeAt(0);
+const CHAR_CODE_S = "s".charCodeAt(0);
+const CHAR_CODE_T = "t".charCodeAt(0);
+const CHAR_CODE_U = "u".charCodeAt(0);
+const CHAR_CODE_COLON = ":".charCodeAt(0);
+const CHAR_CODE_SLASH = "/".charCodeAt(0);
+
+// The cache used in the `nsIURL` function.
+const gURLStore = new Map();
 
 /**
- * Tries to open a Stylesheet file in the Style Editor. If the file is not found,
- * it is opened in source view instead.
- * Returns a promise resolving to a boolean indicating whether or not
- * the source was able to be displayed in the StyleEditor, as the built-in Firefox
- * View Source is the fallback.
+ * Takes a string and returns an object containing all the properties
+ * available on an URL instance, with additional properties (fileName),
+ * Leverages caching.
+ *
+ * @TODO If loaded through Browser Loader, we can use the web API URL
+ * directly, giving us the same interface without needing the SDK --
+ * we still need to add `fileName` though.
  *
- * @param {Toolbox} toolbox
- * @param {string} sourceURL
- * @param {number} sourceLine
- *
- * @return {Promise<boolean>}
+ * @param {String} location
+ * @return {Object?} An object containing most properties available
+ *                   in https://developer.mozilla.org/en-US/docs/Web/API/URL
  */
-exports.viewSourceInStyleEditor = Task.async(function *(toolbox, sourceURL, sourceLine) {
-  let panel = yield toolbox.loadTool("styleeditor");
+
+function parseURL(location) {
+  let url = gURLStore.get(location);
+
+  if (url !== void 0) {
+    return url;
+  }
 
   try {
-    yield panel.selectStyleSheet(sourceURL, sourceLine);
-    yield toolbox.selectTool("styleeditor");
-    return true;
-  } catch (e) {
-    exports.viewSource(toolbox, sourceURL, sourceLine);
-    return false;
+    url = new URL(location);
+    // Definitions:
+    // Example: https://foo.com:8888/file.js
+    // `hostname`: "foo.com"
+    // `host`: "foo.com:8888"
+    //
+    // sdk/url does not match several definitions.: both `host` and `hostname`
+    // are actually the `hostname` (even though this is the `host` property on the
+    // original nsIURL, with `hostPort` representing the actual `host` name, AH!!!)
+    // So normalize all that garbage here.
+    let isChrome = isChromeScheme(location);
+    let fileName = url.fileName || "/";
+    let hostname = isChrome ? null : url.hostname;
+    let host = isChrome ? null :
+               url.port ? `${url.host}:${url.port}` :
+               url.host;
+
+    let parsed = Object.assign({}, url, { host, fileName, hostname });
+    gURLStore.set(location, parsed);
+    return parsed;
   }
-});
+  catch (e) {
+    gURLStore.set(location, null);
+    return null;
+  }
+}
 
 /**
- * Tries to open a JavaScript file in the Debugger. If the file is not found,
- * it is opened in source view instead.
- * Returns a promise resolving to a boolean indicating whether or not
- * the source was able to be displayed in the Debugger, as the built-in Firefox
- * View Source is the fallback.
- *
- * @param {Toolbox} toolbox
- * @param {string} sourceURL
- * @param {number} sourceLine
+ * Parse a source into a short and long name as well as a host name.
  *
- * @return {Promise<boolean>}
+ * @param {String} source
+ *        The source to parse. Can be a URI or names like "(eval)" or "self-hosted".
+ * @param {String} unknownSourceString
+ *        The string to use if no valid source name can be generated.
+ * @return {Object}
+ *         An object with the following properties:
+ *           - {String} short: A short name for the source.
+ *           - {String} long: The full, long name for the source.
+ *           - {String?} host: If available, the host name for the source.
  */
-exports.viewSourceInDebugger = Task.async(function *(toolbox, sourceURL, sourceLine) {
-  // If the Debugger was already open, switch to it and try to show the
-  // source immediately. Otherwise, initialize it and wait for the sources
-  // to be added first.
-  let debuggerAlreadyOpen = toolbox.getPanel("jsdebugger");
-  let { panelWin: dbg } = yield toolbox.loadTool("jsdebugger");
+function getSourceNames (source, unknownSourceString) {
+  let short, long, host;
+  const sourceStr = source ? String(source) : "";
+  const parsedUrl = parseURL(sourceStr);
 
-  if (!debuggerAlreadyOpen) {
-    yield dbg.DebuggerController.waitForSourcesLoaded();
+  if (!parsedUrl) {
+    // Malformed URI.
+    long = sourceStr;
+    short = sourceStr.slice(0, 100);
+  } else {
+    short = parsedUrl.fileName;
+    long = parsedUrl.href;
+    host = parsedUrl.host;
   }
 
-  let { DebuggerView } = dbg;
-  let { Sources } = DebuggerView;
-
-  let item = Sources.getItemForAttachment(a => a.source.url === sourceURL);
-  if (item) {
-    yield toolbox.selectTool("jsdebugger");
-    const isLoading = dbg.DebuggerController.getState().sources.selectedSource !== item.attachment.source.actor;
-    DebuggerView.setEditorLocation(item.attachment.source.actor, sourceLine, { noDebug: true });
-    if (isLoading) {
-      yield dbg.DebuggerController.waitForSourceShown(sourceURL);
+  if (!short) {
+    if (!long) {
+      long = unknownSourceString;
     }
-    return true;
+    short = long.slice(0, 100);
   }
 
-  // If not found, still attempt to open in View Source
-  exports.viewSource(toolbox, sourceURL, sourceLine);
-  return false;
-});
+  return { short, long, host };
+}
+
+// For the functions below, we assume that we will never access the location
+// argument out of bounds, which is indeed the vast majority of cases.
+//
+// They are written this way because they are hot. Each frame is checked for
+// being content or chrome when processing the profile.
+
+function isColonSlashSlash(location, i=0) {
+  return location.charCodeAt(++i) === CHAR_CODE_COLON &&
+         location.charCodeAt(++i) === CHAR_CODE_SLASH &&
+         location.charCodeAt(++i) === CHAR_CODE_SLASH;
+}
+
+function isContentScheme(location, i=0) {
+  let firstChar = location.charCodeAt(i);
 
-/**
- * Tries to open a JavaScript file in the corresponding Scratchpad.
- *
- * @param {string} sourceURL
- * @param {number} sourceLine
- *
- * @return {Promise}
- */
-exports.viewSourceInScratchpad = Task.async(function *(sourceURL, sourceLine) {
-  // Check for matching top level scratchpad window.
-  let wins = Services.wm.getEnumerator("devtools:scratchpad");
+  switch (firstChar) {
+  case CHAR_CODE_H: // "http://" or "https://"
+    if (location.charCodeAt(++i) === CHAR_CODE_T &&
+        location.charCodeAt(++i) === CHAR_CODE_T &&