Merge m-c to b2g-inbound
authorCarsten "Tomcat" Book <cbook@mozilla.com>
Tue, 14 Oct 2014 15:54:06 +0200
changeset 210293 91b8132b33d4eea867ba7e504168c55779d45563
parent 210292 7d9a9169d23ef69b27e1d5eea3cccf8f6364867c (current diff)
parent 210279 eb1b8ecbefdeacc53e8fbdc9a194476a233228d8 (diff)
child 210294 86b50e6b9816ec1ced06efc7768ee77cef119abd
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone36.0a1
Merge m-c to b2g-inbound
content/media/test/test_bug879717.html
memory/replace/defs.mk
tools/jprof/split-profile.pl
widget/xremoteclient/Makefile.in
widget/xremoteclient/XRemoteClientFactory.cpp
widget/xremoteclient/mozilla-xremote-client.cpp
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Merge day clobber
\ No newline at end of file
+Bug 1061335 - CLOBBER for Win32 compiler update.
--- a/b2g/config/mozconfigs/win32_gecko/debug
+++ b/b2g/config/mozconfigs/win32_gecko/debug
@@ -10,17 +10,17 @@ ac_add_options --enable-debug
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
-  . $topsrcdir/build/win32/mozconfig.vs2010-win64
+  . $topsrcdir/build/win32/mozconfig.vs2013-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # B2G Options
 ac_add_options --enable-application=b2g
 ENABLE_MARIONETTE=1
 
--- a/b2g/config/mozconfigs/win32_gecko/nightly
+++ b/b2g/config/mozconfigs/win32_gecko/nightly
@@ -9,17 +9,17 @@ ac_add_options --enable-signmar
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
-  . $topsrcdir/build/win32/mozconfig.vs2010-win64
+  . $topsrcdir/build/win32/mozconfig.vs2013-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # B2G Options
 ac_add_options --enable-application=b2g
 export CXXFLAGS=-DMOZ_ENABLE_JS_DUMP
 
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -110,17 +110,16 @@
 #ifndef MOZ_FOLD_LIBS
 @BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
 #endif
 @BINPATH@/blocklist.xml
 @BINPATH@/ua-update.json
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
 @BINPATH@/run-mozilla.sh
-@BINPATH@/mozilla-xremote-client
 #endif
 #endif
 
 ; [Components]
 @BINPATH@/components/components.manifest
 @BINPATH@/components/alerts.xpt
 #ifdef ACCESSIBILITY
 #ifdef XP_WIN32
--- a/browser/base/content/aboutaccounts/aboutaccounts.js
+++ b/browser/base/content/aboutaccounts/aboutaccounts.js
@@ -285,32 +285,32 @@ function getStarted() {
 }
 
 function openPrefs() {
   window.openPreferences("paneSync");
 }
 
 function init() {
   fxAccounts.getSignedInUser().then(user => {
+    // tests in particular might cause the window to start closing before
+    // getSignedInUser has returned.
+    if (window.closed) {
+      return;
+    }
     // If the url contains an entrypoint query parameter, extract it into a variable
     // to append it to the accounts URI resource.
     // Works for the following cases:
     // - about:accounts?entrypoint="abouthome"
     // - about:accounts?entrypoint=abouthome&action=signup
     let entryPointQParam = "entrypoint=";
     let entryPointPos = window.location.href.indexOf(entryPointQParam);
     let entryPoint = "";
     if (entryPointPos >= 0) {
       entryPoint = window.location.href.substring(entryPointPos).split("&")[0];
     }
-    // tests in particular might cause the window to start closing before
-    // getSignedInUser has returned.
-    if (window.closed) {
-      return;
-    }
     if (window.location.href.contains("action=signin")) {
       if (user) {
         // asking to sign-in when already signed in just shows manage.
         show("stage", "manage");
       } else {
         show("remote");
         wrapper.init(fxAccounts.getAccountsSignInURI(), entryPoint);
       }
--- a/browser/base/content/sanitize.js
+++ b/browser/base/content/sanitize.js
@@ -389,35 +389,50 @@ Sanitizer.prototype = {
         return true;
       }
     },
 
     siteSettings: {
       clear: function ()
       {
         // Clear site-specific permissions like "Allow this site to open popups"
+        // we ignore the "end" range and hope it is now() - none of the
+        // interfaces used here support a true range anyway.
+        let startDateMS = this.range == null ? null : this.range[0] / 1000;
         var pm = Components.classes["@mozilla.org/permissionmanager;1"]
                            .getService(Components.interfaces.nsIPermissionManager);
-        pm.removeAll();
+        if (startDateMS == null) {
+          pm.removeAll();
+        } else {
+          pm.removeAllSince(startDateMS);
+        }
 
         // Clear site-specific settings like page-zoom level
         var cps = Components.classes["@mozilla.org/content-pref/service;1"]
                             .getService(Components.interfaces.nsIContentPrefService2);
-        cps.removeAllDomains(null);
+        if (startDateMS == null) {
+          cps.removeAllDomains(null);
+        } else {
+          cps.removeAllDomainsSince(startDateMS, null);
+        }
 
         // Clear "Never remember passwords for this site", which is not handled by
         // the permission manager
+        // (Note the login manager doesn't support date ranges yet, and bug
+        //  1058438 is calling for loginSaving stuff to end up in the
+        // permission manager)
         var pwmgr = Components.classes["@mozilla.org/login-manager;1"]
                               .getService(Components.interfaces.nsILoginManager);
         var hosts = pwmgr.getAllDisabledHosts();
         for each (var host in hosts) {
           pwmgr.setLoginSavingEnabled(host, true);
         }
 
-        // Clear site security settings
+        // Clear site security settings - no support for ranges in this
+        // interface either, so we clearAll().
         var sss = Cc["@mozilla.org/ssservice;1"]
                     .getService(Ci.nsISiteSecurityService);
         sss.clearAll();
       },
 
       get canClear()
       {
         return true;
--- a/browser/components/loop/MozLoopService.jsm
+++ b/browser/components/loop/MozLoopService.jsm
@@ -1600,21 +1600,31 @@ this.MozLoopService = {
 
     // clearError calls notifyStatusChanged so should be done last when the
     // state is clean.
     MozLoopServiceInternal.clearError("registration");
     MozLoopServiceInternal.clearError("login");
     MozLoopServiceInternal.clearError("profile");
   }),
 
-  openFxASettings: function() {
-    let url = new URL("/settings", gFxAOAuthClient.parameters.content_uri);
-    let win = Services.wm.getMostRecentWindow("navigator:browser");
-    win.switchToTabHavingURI(url.toString(), true);
-  },
+  openFxASettings: Task.async(function() {
+    try {
+      let fxAOAuthClient = yield MozLoopServiceInternal.promiseFxAOAuthClient();
+      if (!fxAOAuthClient) {
+        log.error("Could not get the OAuth client");
+        return;
+      }
+
+      let url = new URL("/settings", fxAOAuthClient.parameters.content_uri);
+      let win = Services.wm.getMostRecentWindow("navigator:browser");
+      win.switchToTabHavingURI(url.toString(), true);
+    } catch (ex) {
+      log.error("Error opening FxA settings", ex);
+    }
+  }),
 
   /**
    * Performs a hawk based request to the loop server.
    *
    * @param {LOOP_SESSION_TYPE} sessionType The type of session to use for the request.
    *                                        One of the LOOP_SESSION_TYPE members.
    * @param {String} path The path to make the request to.
    * @param {String} method The request method, e.g. 'POST', 'GET'.
--- a/browser/components/loop/test/mochitest/browser_fxa_login.js
+++ b/browser/components/loop/test/mochitest/browser_fxa_login.js
@@ -386,8 +386,46 @@ add_task(function* loginWithRegistration
   },
   error => {
     ise(error.code, 401, "Check error code");
     checkFxAOAuthTokenData(null);
   });
 
   yield checkFxA401();
 });
+
+add_task(function* openFxASettings() {
+  yield resetFxA();
+
+  // Since the default b-c window has a blank tab, open a new non-blank tab to
+  // force switchToTabHavingURI to open a new tab instead of reusing the current
+  // blank tab.
+  gBrowser.selectedTab = gBrowser.addTab(BASE_URL);
+
+  let params = {
+    client_id: "client_id",
+    content_uri: BASE_URL + "/content",
+    oauth_uri: BASE_URL + "/oauth",
+    profile_uri: BASE_URL + "/profile",
+    state: "state",
+    test_error: "token_401",
+  };
+  yield promiseOAuthParamsSetup(BASE_URL, params);
+
+  let deferredTab = Promise.defer();
+  let progressListener = {
+    onLocationChange: function onLocationChange(aBrowser) {
+      gBrowser.removeTabsProgressListener(progressListener);
+      let contentURI = Services.io.newURI(params.content_uri, null, null);
+      is(aBrowser.currentURI.spec, Services.io.newURI("/settings", null, contentURI).spec,
+         "Check settings tab URL");
+      deferredTab.resolve();
+    },
+  };
+  gBrowser.addTabsProgressListener(progressListener);
+
+  MozLoopService.openFxASettings();
+
+  yield deferredTab.promise;
+  while (gBrowser.tabs.length > 1) {
+    gBrowser.removeTab(gBrowser.tabs[1]);
+  }
+});
--- a/browser/components/nsBrowserContentHandler.js
+++ b/browser/components/nsBrowserContentHandler.js
@@ -337,96 +337,16 @@ nsBrowserContentHandler.prototype = {
     if (cmdLine.handleFlag("browser", false)) {
       // Passing defaultArgs, so use NO_EXTERNAL_URIS
       openWindow(null, this.chromeURL, "_blank",
                  "chrome,dialog=no,all" + this.getFeatures(cmdLine),
                  this.defaultArgs, NO_EXTERNAL_URIS);
       cmdLine.preventDefault = true;
     }
 
-    try {
-      var remoteCommand = cmdLine.handleFlagWithParam("remote", true);
-    }
-    catch (e) {
-      throw NS_ERROR_ABORT;
-    }
-
-    if (remoteCommand != null) {
-      try {
-        var a = /^\s*(\w+)\(([^\)]*)\)\s*$/.exec(remoteCommand);
-        var remoteVerb;
-        if (a) {
-          remoteVerb = a[1].toLowerCase();
-          var remoteParams = [];
-          var sepIndex = a[2].lastIndexOf(",");
-          if (sepIndex == -1)
-            remoteParams[0] = a[2];
-          else {
-            remoteParams[0] = a[2].substring(0, sepIndex);
-            remoteParams[1] = a[2].substring(sepIndex + 1);
-          }
-        }
-
-        switch (remoteVerb) {
-        case "openurl":
-        case "openfile":
-          // openURL(<url>)
-          // openURL(<url>,new-window)
-          // openURL(<url>,new-tab)
-
-          // First param is the URL, second param (if present) is the "target"
-          // (tab, window)
-          var url = remoteParams[0];
-          var target = nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW;
-          if (remoteParams[1]) {
-            var targetParam = remoteParams[1].toLowerCase()
-                                             .replace(/^\s*|\s*$/g, "");
-            if (targetParam == "new-tab")
-              target = nsIBrowserDOMWindow.OPEN_NEWTAB;
-            else if (targetParam == "new-window")
-              target = nsIBrowserDOMWindow.OPEN_NEWWINDOW;
-            else {
-              // The "target" param isn't one of our supported values, so
-              // assume it's part of a URL that contains commas.
-              url += "," + remoteParams[1];
-            }
-          }
-
-          var uri = resolveURIInternal(cmdLine, url);
-          handURIToExistingBrowser(uri, target, cmdLine);
-          break;
-
-        case "xfedocommand":
-          // xfeDoCommand(openBrowser)
-          if (remoteParams[0].toLowerCase() != "openbrowser")
-            throw NS_ERROR_ABORT;
-
-          // Passing defaultArgs, so use NO_EXTERNAL_URIS
-          openWindow(null, this.chromeURL, "_blank",
-                     "chrome,dialog=no,all" + this.getFeatures(cmdLine),
-                     this.defaultArgs, NO_EXTERNAL_URIS);
-          break;
-
-        default:
-          // Somebody sent us a remote command we don't know how to process:
-          // just abort.
-          throw "Unknown remote command.";
-        }
-
-        cmdLine.preventDefault = true;
-      }
-      catch (e) {
-        Components.utils.reportError(e);
-        // If we had a -remote flag but failed to process it, throw
-        // NS_ERROR_ABORT so that the xremote code knows to return a failure
-        // back to the handling code.
-        throw NS_ERROR_ABORT;
-      }
-    }
-
     var uriparam;
     try {
       while ((uriparam = cmdLine.handleFlagWithParam("new-window", false))) {
         var uri = resolveURIInternal(cmdLine, uriparam);
         if (!shouldLoadURI(uri))
           continue;
         openWindow(null, this.chromeURL, "_blank",
                    "chrome,dialog=no,all" + this.getFeatures(cmdLine),
--- a/browser/config/mozconfigs/win32/common-opt
+++ b/browser/config/mozconfigs/win32/common-opt
@@ -22,17 +22,17 @@ fi
 ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
-  . $topsrcdir/build/win32/mozconfig.vs2010-win64
+  . $topsrcdir/build/win32/mozconfig.vs2013-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Package js shell.
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -15,17 +15,17 @@ else
   _google_oauth_api_keyfile=/e/builds/google-oauth-api.key
 fi
 ac_add_options --with-google-oauth-api-keyfile=${_google_oauth_api_keyfile}
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
-  . $topsrcdir/build/win32/mozconfig.vs2010-win64
+  . $topsrcdir/build/win32/mozconfig.vs2013-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Treat warnings as errors in directories with FAIL_ON_WARNINGS.
 ac_add_options --enable-warnings-as-errors
 
 # Package js shell.
--- a/browser/config/mozconfigs/win32/l10n-mozconfig
+++ b/browser/config/mozconfigs/win32/l10n-mozconfig
@@ -3,14 +3,14 @@
 ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
 ac_add_options --enable-update-packaging
 ac_add_options --with-l10n-base=../../l10n
 ac_add_options --with-windows-version=601
 
 export MOZILLA_OFFICIAL=1
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
-  . $topsrcdir/build/win32/mozconfig.vs2010-win64
+  . $topsrcdir/build/win32/mozconfig.vs2013-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 . "$topsrcdir/build/mozconfig.common.override"
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -156,17 +156,16 @@
 #ifndef MOZ_FOLD_LIBS
 @BINPATH@/@DLL_PREFIX@mozsqlite3@DLL_SUFFIX@
 #endif
 #endif
 @BINPATH@/browser/blocklist.xml
 #ifdef XP_UNIX
 #ifndef XP_MACOSX
 @BINPATH@/run-mozilla.sh
-@BINPATH@/mozilla-xremote-client
 #endif
 #endif
 
 ; [Components]
 @BINPATH@/browser/components/components.manifest
 @BINPATH@/components/alerts.xpt
 #ifdef ACCESSIBILITY
 #ifdef XP_WIN32
--- a/config/config.mk
+++ b/config/config.mk
@@ -670,20 +670,29 @@ ifneq ($(OS_ARCH),Darwin)
 CHECK_STDCXX = @$(TOOLCHAIN_PREFIX)objdump -p $(1) | grep -v -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null || ( echo 'TEST-UNEXPECTED-FAIL | check_stdcxx | We do not want these libstdc++ symbols to be used:' && $(TOOLCHAIN_PREFIX)objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && false)
 endif
 endif
 
 ifeq (,$(filter $(OS_TARGET),WINNT Darwin))
 CHECK_TEXTREL = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep TEXTREL > /dev/null && echo 'TEST-UNEXPECTED-FAIL | check_textrel | We do not want text relocations in libraries and programs' || true
 endif
 
+ifeq ($(MOZ_WIDGET_TOOLKIT),android)
+# While this is very unlikely (libc being added by the compiler at the end
+# of the linker command line), if libmozglue.so ends up after libc.so, all
+# hell breaks loose, so better safe than sorry, and check it's actually the
+# case.
+CHECK_MOZGLUE_ORDER = @$(TOOLCHAIN_PREFIX)readelf -d $(1) | grep NEEDED | awk '{ libs[$$NF] = ++n } END { if (libs["[libmozglue.so]"] && libs["[libc.so]"] < libs["[libmozglue.so]"]) { print "libmozglue.so must be linked before libc.so"; exit 1 } }'
+endif
+
 define CHECK_BINARY
 $(call CHECK_STDCXX,$(1))
 $(call CHECK_TEXTREL,$(1))
 $(call LOCAL_CHECKS,$(1))
+$(call CHECK_MOZGLUE_ORDER,$(1))
 endef
 
 # autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
 # this file
 OBJ_SUFFIX := $(_OBJ_SUFFIX)
 
 # PGO builds with GCC build objects with instrumentation in a first pass,
 # then objects optimized, without instrumentation, in a second pass. If
--- a/config/external/nss/Makefile.in
+++ b/config/external/nss/Makefile.in
@@ -325,30 +325,29 @@ ifdef MOZ_FOLD_LIBS
 # Add all static libraries for nss, smime, ssl and nssutil
 STATIC_LIBS += $(addprefix $(DEPTH)/security/,$(NSS_STATIC_LIBS))
 
 nss_def_file := $(srcdir)/nss.def
 
 ifeq (WINNT,$(OS_TARGET))
 # Create a .def file based on the various .def files for nss, smime, ssl and
 # nssutil.
-nss3.def: $(nss_def_file) $(DEPTH)/db/sqlite3/src/sqlite-processed.def
+nss3.def: $(nss_def_file) $(DEPTH)/db/sqlite3/src/sqlite-processed.def $(NSS_EXTRA_SYMBOLS_FILE)
 	echo LIBRARY nss3$(DLL_SUFFIX) > $@.tmp
 	echo EXPORTS >> $@.tmp
 	grep -v -h -e ^LIBRARY -e ^EXPORTS -e ^\; $^ >> $@.tmp
 	mv $@.tmp $@
 else
 ifdef GCC_USE_GNU_LD
 sqlite_def_file := $(topsrcdir)/db/sqlite3/src/sqlite.def
 nspr_def_file := $(srcdir)/nspr-dummy.def
 
-nss3.def: $(nss_def_file) $(sqlite_def_file) $(nspr_def_file)
+nss3.def: $(nss_def_file) $(sqlite_def_file) $(nspr_def_file) $(NSS_EXTRA_SYMBOLS_FILE)
 	@$(call py_action,convert_def_file, \
-	  $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ \
-	  $(nss_def_file) $(sqlite_def_file) $(nspr_def_file))
+	  $(DEFINES) $(ACDEFINES) $(XULPPFLAGS) -o $@ $^)
 
 GARBAGE += \
   nss3.def \
   $(NULL)
 endif # GCC_USE_GNU_LD
 endif # WINNT
 
 endif # MOZ_FOLD_LIBS
--- a/configure.in
+++ b/configure.in
@@ -7187,19 +7187,17 @@ else
     AC_DEFINE(MOZ_MEMORY_DARWIN)
     ;;
   *-*freebsd*)
     AC_DEFINE(MOZ_MEMORY_BSD)
     ;;
   *-android*|*-linuxandroid*)
     AC_DEFINE(MOZ_MEMORY_LINUX)
     AC_DEFINE(MOZ_MEMORY_ANDROID)
-    if test -z "$gonkdir"; then
-      _WRAP_MALLOC=1
-    else
+    if test -n "$gonkdir"; then
       AC_DEFINE(MOZ_MEMORY_GONK)
     fi
     MOZ_GLUE_LDFLAGS=
     ;;
   *-*linux*)
     AC_DEFINE(MOZ_MEMORY_LINUX)
     ;;
   *-netbsd*)
@@ -7238,62 +7236,25 @@ AC_SUBST_LIST(WIN32_CRT_LIBS)
 dnl Need to set this for make because NSS doesn't have configure
 AC_SUBST(DLLFLAGS)
 
 dnl We need to wrap dlopen and related functions on Android because we use
 dnl our own linker.
 if test "$OS_TARGET" = Android; then
     WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue"
     WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
-    if test "$MOZ_WIDGET_TOOLKIT" = android; then
-        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=gai_strerror"
-    fi
     if test -z "$gonkdir"; then
-        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork,--wrap=raise"
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=memccpy,--wrap=memchr,--wrap=memrchr,--wrap=memcmp,--wrap=memcpy,--wrap=memmove,--wrap=memset,--wrap=memmem,--wrap=index,--wrap=strchr,--wrap=strrchr,--wrap=strlen,--wrap=strcmp,--wrap=strcpy,--wrap=strcat,--wrap=strcasecmp,--wrap=strncasecmp,--wrap=strstr,--wrap=strcasestr,--wrap=strtok,--wrap=strtok_r,--wrap=strerror,--wrap=strerror_r,--wrap=strnlen,--wrap=strncat,--wrap=strncmp,--wrap=strncpy,--wrap=strlcat,--wrap=strlcpy,--wrap=strcspn,--wrap=strpbrk,--wrap=strsep,--wrap=strspn,--wrap=strcoll,--wrap=strxfrm"
     fi
     if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=__pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2,--wrap=tgkill"
     fi
 fi
 
 dnl ========================================================
-dnl = Use malloc wrapper lib
-dnl ========================================================
-MOZ_ARG_ENABLE_BOOL(wrap-malloc,
-[  --enable-wrap-malloc    Wrap malloc calls (gnu linker only)],
-    _WRAP_MALLOC=1,
-    _WRAP_MALLOC= )
-
-if test -n "$_WRAP_MALLOC"; then
-    if test -n "$GNU_CC"; then
-        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=malloc,--wrap=calloc,--wrap=valloc,--wrap=free,--wrap=realloc,--wrap=memalign"
-        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=__builtin_new,--wrap=__builtin_vec_new,--wrap=__builtin_delete,--wrap=__builtin_vec_delete"
-        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=strdup,--wrap=strndup"
-        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=vasprintf,--wrap=asprintf"
-        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=posix_memalign,--wrap=malloc_usable_size"
-        dnl Wrap operator new and operator delete on Android.
-        if test "$OS_TARGET" = "Android"; then
-            WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=_Znwj,--wrap=_Znaj,--wrap=_ZdlPv,--wrap=_ZdaPv"
-            dnl Wrap the nothrow variants too.
-            WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=_ZnwjRKSt9nothrow_t,--wrap=_ZnajRKSt9nothrow_t,--wrap=_ZdlPvRKSt9nothrow_t,--wrap=_ZdaPvRKSt9nothrow_t"
-        fi
-    else
-        AC_MSG_ERROR([--enable-wrap-malloc is not supported for non-GNU toolchains])
-    fi
-fi
-
-dnl ========================================================
-dnl = Location of malloc wrapper lib
-dnl ========================================================
-MOZ_ARG_WITH_STRING(wrap-malloc,
-[  --with-wrap-malloc=DIR  Location of malloc wrapper library],
-    WRAP_LDFLAGS="${WRAP_LDFLAGS} $withval")
-
-dnl ========================================================
 dnl = Use JS Call tracing
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(trace-jscalls,
 [  --enable-trace-jscalls  Enable JS call enter/exit callback (default=no)],
     MOZ_TRACE_JSCALLS=1,
     MOZ_TRACE_JSCALLS= )
 if test -n "$MOZ_TRACE_JSCALLS"; then
     AC_DEFINE(MOZ_TRACE_JSCALLS)
@@ -8933,16 +8894,18 @@ AC_SUBST(MOZ_FOLD_LIBS)
 AC_SUBST(MOZ_ENABLE_SZIP)
 AC_SUBST(MOZ_SZIP_FLAGS)
 
 if test "$MOZ_DEBUG"; then
     MOZ_EM_DEBUG=1
 fi
 AC_SUBST(MOZ_EM_DEBUG)
 
+AC_SUBST(NSS_EXTRA_SYMBOLS_FILE)
+
 if test -n "$COMPILE_ENVIRONMENT"; then
 AC_CHECK_FUNCS(posix_fadvise posix_fallocate)
 
 dnl Check for missing components
 if test "$MOZ_X11"; then
     if test "$WITHOUT_X11"; then
         AC_MSG_ERROR([--without-x specified and MOZ_X11 still defined])
     fi
@@ -9131,19 +9094,16 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$M
         ;;
     esac
   elif test -z "$MOZ_JEMALLOC3"; then
     MANGLE=$_MANGLE
     JEMALLOC_WRAPPER=replace_
   fi
   if test -n "$MANGLE"; then
     MANGLED=
-    if test -n "$_WRAP_MALLOC" -a -z "$JEMALLOC_WRAPPER"; then
-      JEMALLOC_WRAPPER=__wrap_
-    fi
     for mangle in ${MANGLE}; do
       if test -n "$MANGLED"; then
         MANGLED="$mangle:$JEMALLOC_WRAPPER$mangle,$MANGLED"
       else
         MANGLED="$mangle:$JEMALLOC_WRAPPER$mangle"
       fi
     done
     ac_configure_args="$ac_configure_args --with-mangling=$MANGLED"
@@ -9227,21 +9187,16 @@ if test -n "$_subconfigure_subdir"; then
   srcdir="$_save_srcdir"
 fi
 
 # No need to run subconfigures when building with LIBXUL_SDK_DIR
 if test "$COMPILE_ENVIRONMENT" -a -z "$LIBXUL_SDK_DIR"; then
 
 export WRAP_LDFLAGS
 
-if test -n "$_WRAP_MALLOC"; then
-    # Avoid doubling wrap malloc arguments
-    _SUBDIR_CONFIG_ARGS="`echo $_SUBDIR_CONFIG_ARGS | sed -e 's/--enable-wrap-malloc *//'`"
-fi
-
 if test -n "$MOZ_USING_CCACHE"; then
     # Avoid double prepending ccache by omitting --with-ccache in building NSPR.
     _SUBDIR_CONFIG_ARGS="`echo $_SUBDIR_CONFIG_ARGS | sed -e 's/--with-ccache[[^ ]]*//'`"
 fi
 
 MOZ_SUBCONFIGURE_NSPR()
 
 dnl ========================================================
--- a/content/html/content/public/HTMLMediaElement.h
+++ b/content/html/content/public/HTMLMediaElement.h
@@ -280,23 +280,16 @@ public:
   /**
    * Called when there's been an error fetching the resource. This decides
    * whether it's appropriate to fire an error event.
    */
   void NotifyLoadError();
 
   void NotifyMediaTrackEnabled(MediaTrack* aTrack);
 
-  /**
-   * Called by a DOMMediaStream when it has tracks available.
-   * This allows us to setup audio and video outputs after the stream
-   * has already reported that playback started, in case they are added late.
-   */
-  void NotifyMediaStreamTracksAvailable(DOMMediaStream* aStream);
-
   virtual bool IsNodeOfType(uint32_t aFlags) const MOZ_OVERRIDE;
 
   /**
    * Returns the current load ID. Asynchronous events store the ID that was
    * current when they were enqueued, and if it has changed when they come to
    * fire, they consider themselves cancelled, and don't fire.
    */
   uint32_t GetCurrentLoadID() { return mCurrentLoadID; }
@@ -618,17 +611,16 @@ public:
     return FinishDecoderSetup(aDecoder, aStream, nullptr, nullptr);
   }
 
 protected:
   virtual ~HTMLMediaElement();
 
   class MediaLoadListener;
   class StreamListener;
-  class MediaStreamTracksAvailableCallback;
 
   virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
   virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
 
   class WakeLockBoolWrapper {
   public:
     explicit WakeLockBoolWrapper(bool val = false)
       : mValue(val), mCanPlay(true), mOuter(nullptr) {}
@@ -1021,19 +1013,16 @@ protected:
   // These events get re-dispatched when the bfcache is exited.
   nsTArray<nsString> mPendingEvents;
 
   // Media loading flags. See:
   //   http://www.whatwg.org/specs/web-apps/current-work/#video)
   nsMediaNetworkState mNetworkState;
   nsMediaReadyState mReadyState;
 
-  // Last value passed from codec or stream source to UpdateReadyStateForData.
-  NextFrameStatus mLastNextFrameStatus;
-
   enum LoadAlgorithmState {
     // No load algorithm instance is waiting for a source to be added to the
     // media in order to continue loading.
     NOT_WAITING,
     // We've run the load algorithm, and we tried all source children of the
     // media element, and failed to load any successfully. We're waiting for
     // another source element to be added to the media element, and will try
     // to load any such element when its added.
--- a/content/html/content/src/HTMLMediaElement.cpp
+++ b/content/html/content/src/HTMLMediaElement.cpp
@@ -66,18 +66,16 @@
 #include "nsURIHashKey.h"
 #include "nsJSUtils.h"
 #include "MediaStreamGraph.h"
 #include "nsIScriptError.h"
 #include "nsHostObjectProtocolHandler.h"
 #include "mozilla/dom/MediaSource.h"
 #include "MediaMetadataManager.h"
 #include "MediaSourceDecoder.h"
-#include "AudioStreamTrack.h"
-#include "VideoStreamTrack.h"
 
 #include "AudioChannelService.h"
 
 #include "mozilla/dom/power/PowerManagerService.h"
 #include "mozilla/dom/WakeLock.h"
 
 #include "mozilla/dom/AudioTrack.h"
 #include "mozilla/dom/AudioTrackList.h"
@@ -661,20 +659,17 @@ void HTMLMediaElement::AbortExistingLoad
   mLoadedDataFired = false;
   mAutoplaying = true;
   mIsLoadingFromSourceChildren = false;
   mSuspendedAfterFirstFrame = false;
   mAllowSuspendAfterFirstFrame = true;
   mHaveQueuedSelectResource = false;
   mSuspendedForPreloadNone = false;
   mDownloadSuspendedByCache = false;
-  mHasAudio = false;
-  mHasVideo = false;
   mSourcePointer = nullptr;
-  mLastNextFrameStatus = NEXT_FRAME_UNINITIALIZED;
 
   mTags = nullptr;
 
   if (mNetworkState != nsIDOMHTMLMediaElement::NETWORK_EMPTY) {
     NS_ASSERTION(!mDecoder && !mSrcStream, "How did someone setup a new stream/decoder already?");
     ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY);
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING);
     mPaused = true;
@@ -898,49 +893,16 @@ void HTMLMediaElement::NotifyMediaTrackE
     } else {
       SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_TRACK);
     }
   } else if (VideoTrack* track = aTrack->AsVideoTrack()) {
     mDisableVideo = !track->Selected();
   }
 }
 
-void HTMLMediaElement::NotifyMediaStreamTracksAvailable(DOMMediaStream* aStream)
-{
-  if (!mSrcStream || mSrcStream != aStream) {
-    return;
-  }
-
-  bool oldHasAudio = mHasAudio;
-  bool oldHasVideo = mHasVideo;
-
-  nsAutoTArray<nsRefPtr<AudioStreamTrack>,1> audioTracks;
-  aStream->GetAudioTracks(audioTracks);
-  nsAutoTArray<nsRefPtr<VideoStreamTrack>,1> videoTracks;
-  aStream->GetVideoTracks(videoTracks);
-
-  mHasAudio = !audioTracks.IsEmpty();
-  mHasVideo = !videoTracks.IsEmpty();
-
-  if (!oldHasAudio && mHasAudio) {
-    GetSrcMediaStream()->AddAudioOutput(this);
-    GetSrcMediaStream()->SetAudioOutputVolume(this, float(mMuted ? 0.0 : mVolume));
-  }
-  if (!oldHasVideo && mHasVideo ) {
-    VideoFrameContainer* container = GetVideoFrameContainer();
-    if (container) {
-      GetSrcMediaStream()->AddVideoOutput(container);
-    }
-    // mHasVideo changed so make sure the screen wakelock is updated
-    NotifyOwnerDocumentActivityChanged();
-  }
-
-  CheckAutoplayDataReady();
-}
-
 void HTMLMediaElement::LoadFromSourceChildren()
 {
   NS_ASSERTION(mDelayingLoadEvent,
                "Should delay load event (if in document) during load");
   NS_ASSERTION(mIsLoadingFromSourceChildren,
                "Must remember we're loading from source children");
 
   nsIDocument* parentDoc = OwnerDoc()->GetParentDocument();
@@ -2020,17 +1982,16 @@ HTMLMediaElement::LookupMediaElementURIT
 }
 
 HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
   : nsGenericHTMLElement(aNodeInfo),
     mSrcStreamListener(nullptr),
     mCurrentLoadID(0),
     mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
     mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING),
-    mLastNextFrameStatus(NEXT_FRAME_UNINITIALIZED),
     mLoadWaitStatus(NOT_WAITING),
     mVolume(1.0),
     mPreloadAction(PRELOAD_UNDEFINED),
     mMediaSize(-1,-1),
     mLastCurrentTime(0.0),
     mFragmentStart(-1.0),
     mFragmentEnd(-1.0),
     mDefaultPlaybackRate(1.0),
@@ -2849,38 +2810,16 @@ private:
   bool mHaveCurrentData;
   bool mBlocked;
 
   // mMutex protects the fields below; they can be accessed on any thread
   Mutex mMutex;
   bool mPendingNotifyOutput;
 };
 
-class HTMLMediaElement::MediaStreamTracksAvailableCallback:
-    public DOMMediaStream::OnTracksAvailableCallback
-{
-public:
-  explicit MediaStreamTracksAvailableCallback(HTMLMediaElement* aElement,
-                                              DOMMediaStream::TrackTypeHints aExpectedTracks = 0):
-      DOMMediaStream::OnTracksAvailableCallback(aExpectedTracks),
-      mElement(aElement)
-    {}
-  virtual void NotifyTracksAvailable(DOMMediaStream* aStream)
-  {
-    NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
-
-    if (!mElement) {
-      return;
-    }
-    mElement->NotifyMediaStreamTracksAvailable(aStream);
-  }
-private:
-  HTMLMediaElement* mElement;
-};
-
 void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream)
 {
   NS_ASSERTION(!mSrcStream && !mSrcStreamListener, "Should have been ended already");
 
   mSrcStream = aStream;
 
   nsRefPtr<MediaStream> stream = mSrcStream->GetStream();
   if (stream) {
@@ -2892,55 +2831,53 @@ void HTMLMediaElement::SetupSrcMediaStre
   mSrcStreamListener = new StreamListener(this);
   GetSrcMediaStream()->AddListener(mSrcStreamListener);
   if (mPaused) {
     GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
   }
   if (mPausedForInactiveDocumentOrChannel) {
     GetSrcMediaStream()->ChangeExplicitBlockerCount(1);
   }
-
-  mSrcStream->OnTracksAvailable(new MediaStreamTracksAvailableCallback(this, DOMMediaStream::HINT_CONTENTS_AUDIO));
-  mSrcStream->OnTracksAvailable(new MediaStreamTracksAvailableCallback(this, DOMMediaStream::HINT_CONTENTS_VIDEO));
-
-  MediaInfo mediaInfo;
-  mediaInfo.mAudio.mHasAudio = mHasAudio;
-  mediaInfo.mVideo.mHasVideo = mHasVideo;
-  MetadataLoaded(&mediaInfo, nullptr);
-
-  DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
-  mNetworkState = nsIDOMHTMLMediaElement::NETWORK_IDLE;
-
   ChangeDelayLoadStatus(false);
+  GetSrcMediaStream()->AddAudioOutput(this);
+  GetSrcMediaStream()->SetAudioOutputVolume(this, float(mMuted ? 0.0 : mVolume));
+  VideoFrameContainer* container = GetVideoFrameContainer();
+  if (container) {
+    GetSrcMediaStream()->AddVideoOutput(container);
+  }
 
   // Note: we must call DisconnectTrackListListeners(...)  before dropping
   // mSrcStream
   mSrcStream->ConstructMediaTracks(AudioTracks(), VideoTracks());
 
+  ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
+  DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
+  DispatchAsyncEvent(NS_LITERAL_STRING("loadedmetadata"));
+  ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_IDLE);
   AddRemoveSelfReference();
   // FirstFrameLoaded() will be called when the stream has current data.
 }
 
 void HTMLMediaElement::EndSrcMediaStreamPlayback()
 {
   MediaStream* stream = GetSrcMediaStream();
   if (stream) {
     stream->RemoveListener(mSrcStreamListener);
   }
   mSrcStream->DisconnectTrackListListeners(AudioTracks(), VideoTracks());
 
   // Kill its reference to this element
   mSrcStreamListener->Forget();
   mSrcStreamListener = nullptr;
-  if (stream && mHasAudio) {
+  if (stream) {
     stream->RemoveAudioOutput(this);
   }
   VideoFrameContainer* container = GetVideoFrameContainer();
   if (container) {
-    if (stream && mHasVideo) {
+    if (stream) {
       stream->RemoveVideoOutput(container);
     }
     container->ClearCurrentFrame();
   }
   if (mPaused && stream) {
     stream->ChangeExplicitBlockerCount(-1);
   }
   if (mPausedForInactiveDocumentOrChannel && stream) {
@@ -2982,29 +2919,23 @@ void HTMLMediaElement::MetadataLoaded(co
   // delete the VideoFrameContainer. This happens when the src is changed to an
   // audio only file.
   if (!aInfo->HasVideo() && mVideoFrameContainer) {
     // call ForgetElement() such that callbacks from |mVideoFrameContainer|
     // won't reach us anymore.
     mVideoFrameContainer->ForgetElement();
     mVideoFrameContainer = nullptr;
   }
-
-  if (IsVideo()) {
-    // Update the screen wakelock in case mHasVideo changed
-    NotifyOwnerDocumentActivityChanged();
-  }
 }
 
 void HTMLMediaElement::FirstFrameLoaded()
 {
   NS_ASSERTION(!mSuspendedAfterFirstFrame, "Should not have already suspended");
 
   ChangeDelayLoadStatus(false);
-  UpdateReadyStateForData(NEXT_FRAME_UNAVAILABLE);
 
   if (mDecoder && mAllowSuspendAfterFirstFrame && mPaused &&
       !HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
       mPreloadAction == HTMLMediaElement::PRELOAD_METADATA) {
     mSuspendedAfterFirstFrame = true;
     mDecoder->Suspend();
   }
 }
@@ -3157,28 +3088,20 @@ void HTMLMediaElement::DownloadStalled()
 
 bool HTMLMediaElement::ShouldCheckAllowOrigin()
 {
   return mCORSMode != CORS_NONE;
 }
 
 void HTMLMediaElement::UpdateReadyStateForData(MediaDecoderOwner::NextFrameStatus aNextFrame)
 {
-  mLastNextFrameStatus = aNextFrame;
-
   if (mReadyState < nsIDOMHTMLMediaElement::HAVE_METADATA) {
     // aNextFrame might have a next frame because the decoder can advance
     // on its own thread before MetadataLoaded gets a chance to run.
     // The arrival of more data can't change us out of this readyState.
-
-    return;
-  }
-
-  if (!mHasAudio && !mHasVideo) {
-    // No tracks available yet, don't advance from HAVE_METADATA
     return;
   }
 
   if (aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_SEEKING) {
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_METADATA);
     return;
   }
 
@@ -3191,24 +3114,16 @@ void HTMLMediaElement::UpdateReadyStateF
     // this transition if the decoder is in ended state; the readyState
     // should remain at HAVE_CURRENT_DATA in this case.
     // Note that this state transition includes the case where we finished
     // downloaded the whole data stream.
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA);
     return;
   }
 
-  if (mReadyState < nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA && mHasVideo) {
-    VideoFrameContainer* container = GetVideoFrameContainer();
-    if (container && mMediaSize == nsIntSize(-1,-1)) {
-      // No frame has been set yet. Don't advance.
-      return;
-    }
-  }
-
   if (aNextFrame != MediaDecoderOwner::NEXT_FRAME_AVAILABLE) {
     ChangeReadyState(nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA);
     if (!mWaitingFired && aNextFrame == MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING) {
       FireTimeUpdate(false);
       DispatchAsyncEvent(NS_LITERAL_STRING("waiting"));
       mWaitingFired = true;
     }
     return;
@@ -3339,25 +3254,24 @@ void HTMLMediaElement::ChangeNetworkStat
   } else if (mNetworkState == nsIDOMHTMLMediaElement::NETWORK_IDLE && !mError) {
     // Fire 'suspend' event when entering NETWORK_IDLE and no error presented.
     DispatchAsyncEvent(NS_LITERAL_STRING("suspend"));
   }
 }
 
 bool HTMLMediaElement::CanActivateAutoplay()
 {
-  // For stream inputs, we activate autoplay on HAVE_METADATA because
+  // For stream inputs, we activate autoplay on HAVE_CURRENT_DATA because
   // this element itself might be blocking the stream from making progress by
   // being paused.
   return !mPausedForInactiveDocumentOrChannel &&
          mAutoplaying &&
          mPaused &&
          ((mDecoder && mReadyState >= nsIDOMHTMLMediaElement::HAVE_ENOUGH_DATA) ||
-          (mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA)) &&
-         (mHasAudio || mHasVideo) &&
+          (mSrcStream && mReadyState >= nsIDOMHTMLMediaElement::HAVE_CURRENT_DATA)) &&
          HasAttr(kNameSpaceID_None, nsGkAtoms::autoplay) &&
          mAutoplayEnabled &&
          !IsEditable();
 }
 
 void HTMLMediaElement::CheckAutoplayDataReady()
 {
   if (CanActivateAutoplay()) {
@@ -3376,24 +3290,34 @@ void HTMLMediaElement::CheckAutoplayData
       GetSrcMediaStream()->ChangeExplicitBlockerCount(-1);
     }
     DispatchAsyncEvent(NS_LITERAL_STRING("play"));
   }
 }
 
 VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer()
 {
-  if (mVideoFrameContainer)
-    return mVideoFrameContainer;
+  // If we have loaded the metadata, and the size of the video is still
+  // (-1, -1), the media has no video. Don't go a create a video frame
+  // container.
+  if (mReadyState >= nsIDOMHTMLMediaElement::HAVE_METADATA &&
+      mMediaSize == nsIntSize(-1, -1)) {
+    return nullptr;
+  }
 
   // Only video frames need an image container.
   if (!IsVideo()) {
     return nullptr;
   }
 
+  mHasVideo = true;
+
+  if (mVideoFrameContainer)
+    return mVideoFrameContainer;
+
   mVideoFrameContainer =
     new VideoFrameContainer(this, LayerManager::CreateAsynchronousImageContainer());
 
   return mVideoFrameContainer;
 }
 
 nsresult HTMLMediaElement::DispatchEvent(const nsAString& aName)
 {
@@ -3496,17 +3420,16 @@ void HTMLMediaElement::NotifyDecoderPrin
     mMediaKeys->Shutdown();
   }
 #endif
 }
 
 void HTMLMediaElement::UpdateMediaSize(nsIntSize size)
 {
   mMediaSize = size;
-  UpdateReadyStateForData(mLastNextFrameStatus);
 }
 
 void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendEvents)
 {
   if (aPauseElement != mPausedForInactiveDocumentOrChannel) {
     mPausedForInactiveDocumentOrChannel = aPauseElement;
     if (aPauseElement) {
 #ifdef MOZ_EME
--- a/content/media/MediaDecoderReader.h
+++ b/content/media/MediaDecoderReader.h
@@ -34,16 +34,19 @@ public:
   explicit MediaDecoderReader(AbstractMediaDecoder* aDecoder);
 
   // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
   // on failure.
   virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0;
 
   // True if this reader is waiting media resource allocation
   virtual bool IsWaitingMediaResources() { return false; }
+  // True if this reader is waiting for a Content Decryption Module to become
+  // available.
+  virtual bool IsWaitingOnCDMResource() { return false; }
   // True when this reader need to become dormant state
   virtual bool IsDormantNeeded() { return false; }
   // Release media resources they should be released in dormant state
   // The reader can be made usable again by calling ReadMetadata().
   virtual void ReleaseMediaResources() {};
   // Breaks reference-counted cycles. Called during shutdown.
   // WARNING: If you override this, you must call the base implementation
   // in your override.
--- a/content/media/eme/MediaKeys.cpp
+++ b/content/media/eme/MediaKeys.cpp
@@ -11,19 +11,26 @@
 #include "mozilla/dom/MediaKeyError.h"
 #include "mozilla/dom/MediaKeySession.h"
 #include "mozilla/dom/DOMException.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/EMELog.h"
 #include "nsContentUtils.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "mozilla/Preferences.h"
+#include "nsContentTypeParser.h"
+#ifdef MOZ_FMP4
+#include "MP4Decoder.h"
+#endif
 #ifdef XP_WIN
 #include "mozilla/WindowsVersion.h"
 #endif
+#include "nsContentCID.h"
+#include "nsServiceManagerUtils.h"
+#include "mozIGeckoMediaPluginService.h"
 
 namespace mozilla {
 
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeys,
                                       mElement,
                                       mParent,
@@ -102,39 +109,118 @@ MediaKeys::SetServerCertificate(const Ar
     return promise.forget();
   }
 
   mProxy->SetServerCertificate(StorePromise(promise), data);
   return promise.forget();
 }
 
 static bool
-IsSupportedKeySystem(const nsAString& aKeySystem)
+HaveGMPFor(const nsCString& aKeySystem,
+           const nsCString& aAPI,
+           const nsCString& aTag = EmptyCString())
+{
+  nsCOMPtr<mozIGeckoMediaPluginService> mps =
+    do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+  if (NS_WARN_IF(!mps)) {
+    return false;
+  }
+
+  nsTArray<nsCString> tags;
+  tags.AppendElement(aKeySystem);
+  if (!aTag.IsEmpty()) {
+    tags.AppendElement(aTag);
+  }
+  // Note: EME plugins need a non-null nodeId here, as they must
+  // not be shared across origins.
+  bool hasPlugin = false;
+  if (NS_FAILED(mps->HasPluginForAPI(aAPI,
+                                     &tags,
+                                     &hasPlugin))) {
+    return false;
+  }
+  return hasPlugin;
+}
+
+static bool
+IsPlayableMP4Type(const nsAString& aContentType)
 {
-  return aKeySystem.EqualsASCII("org.w3.clearkey") ||
+#ifdef MOZ_FMP4
+  nsContentTypeParser parser(aContentType);
+  nsAutoString mimeType;
+  nsresult rv = parser.GetType(mimeType);
+  if (NS_FAILED(rv)) {
+    return false;
+  }
+  nsAutoString codecs;
+  parser.GetParameter("codecs", codecs);
+
+  NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
+  return MP4Decoder::CanHandleMediaType(mimeTypeUTF8, codecs);
+#else
+  return false;
+#endif
+}
+
+bool
+MediaKeys::IsTypeSupported(const nsAString& aKeySystem,
+                           const Optional<nsAString>& aInitDataType,
+                           const Optional<nsAString>& aContentType)
+{
+  if (aKeySystem.EqualsLiteral("org.w3.clearkey") &&
+      (!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) &&
+      (!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) &&
+      HaveGMPFor(NS_LITERAL_CSTRING("org.w3.clearkey"),
+                 NS_LITERAL_CSTRING("eme-decrypt"))) {
+    return true;
+  }
+
 #ifdef XP_WIN
-         (aKeySystem.EqualsASCII("com.adobe.access") &&
-          IsVistaOrLater() &&
-          Preferences::GetBool("media.eme.adobe-access.enabled", false)) ||
+  // Note: Adobe Access's GMP uses WMF to decode, so anything our MP4Reader
+  // thinks it can play on Windows, the Access GMP should be able to play.
+  if (aKeySystem.EqualsLiteral("com.adobe.access") &&
+      Preferences::GetBool("media.eme.adobe-access.enabled", false) &&
+      IsVistaOrLater() && // Win Vista and later only.
+      (!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) &&
+      (!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) &&
+      HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
+                 NS_LITERAL_CSTRING("eme-decrypt")) &&
+      HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
+                 NS_LITERAL_CSTRING("decode-video"),
+                 NS_LITERAL_CSTRING("h264")) &&
+      HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"),
+                 NS_LITERAL_CSTRING("decode-audio"),
+                 NS_LITERAL_CSTRING("aac"))) {
+      return true;
+  }
 #endif
-         false;
+
+  return false;
 }
 
 /* static */
 IsTypeSupportedResult
 MediaKeys::IsTypeSupported(const GlobalObject& aGlobal,
                            const nsAString& aKeySystem,
                            const Optional<nsAString>& aInitDataType,
                            const Optional<nsAString>& aContentType,
                            const Optional<nsAString>& aCapability)
 {
   // TODO: Should really get spec changed to this is async, so we can wait
   //       for user to consent to running plugin.
-  return IsSupportedKeySystem(aKeySystem) ? IsTypeSupportedResult::Maybe
-                                          : IsTypeSupportedResult::_empty;
+  bool supported = IsTypeSupported(aKeySystem, aInitDataType, aContentType);
+
+  EME_LOG("MediaKeys::IsTypeSupported keySystem='%s' initDataType='%s' contentType='%s' supported=%d",
+          NS_ConvertUTF16toUTF8(aKeySystem).get(),
+          (aInitDataType.WasPassed() ? NS_ConvertUTF16toUTF8(aInitDataType.Value()).get() : ""),
+          (aContentType.WasPassed() ? NS_ConvertUTF16toUTF8(aContentType.Value()).get() : ""),
+          supported);
+
+  return supported ? IsTypeSupportedResult::Probably
+                   : IsTypeSupportedResult::_empty;
 }
 
 already_AddRefed<Promise>
 MediaKeys::MakePromise(ErrorResult& aRv)
 {
   nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
   if (!global) {
     NS_WARNING("Passed non-global to MediaKeys ctor!");
@@ -237,17 +323,17 @@ MediaKeys::Create(const GlobalObject& aG
 already_AddRefed<Promise>
 MediaKeys::Init(ErrorResult& aRv)
 {
   nsRefPtr<Promise> promise(MakePromise(aRv));
   if (aRv.Failed()) {
     return nullptr;
   }
 
-  if (!IsSupportedKeySystem(mKeySystem)) {
+  if (!IsTypeSupported(mKeySystem)) {
     promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
     return promise.forget();
   }
 
   mProxy = new CDMProxy(this, mKeySystem);
 
   // Determine principal (at creation time) of the MediaKeys object.
   nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetParentObject());
@@ -266,17 +352,17 @@ MediaKeys::Init(ErrorResult& aRv)
   }
   nsCOMPtr<nsIDOMWindow> topWindow;
   window->GetTop(getter_AddRefs(topWindow));
   nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
   if (!top || !top->GetExtantDoc()) {
     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     return promise.forget();
   }
-  
+
   mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal();
 
   if (!mPrincipal || !mTopLevelPrincipal) {
     NS_WARNING("Failed to get principals when creating MediaKeys");
     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     return promise.forget();
   }
 
--- a/content/media/eme/MediaKeys.h
+++ b/content/media/eme/MediaKeys.h
@@ -119,16 +119,20 @@ public:
   bool IsBoundToMediaElement() const;
 
   // Return NS_OK if the principals are the same as when the MediaKeys
   // was created, failure otherwise.
   nsresult CheckPrincipals();
 
 private:
 
+  static bool IsTypeSupported(const nsAString& aKeySystem,
+                              const Optional<nsAString>& aInitDataType = Optional<nsAString>(),
+                              const Optional<nsAString>& aContentType = Optional<nsAString>());
+
   bool IsInPrivateBrowsing();
   already_AddRefed<Promise> Init(ErrorResult& aRv);
 
   // Removes promise from mPromises, and returns it.
   already_AddRefed<Promise> RetrievePromise(PromiseId aId);
 
   // Owning ref to proxy. The proxy has a weak reference back to the MediaKeys,
   // and the MediaKeys destructor clears the proxy's reference to the MediaKeys.
--- a/content/media/fmp4/BlankDecoderModule.cpp
+++ b/content/media/fmp4/BlankDecoderModule.cpp
@@ -104,17 +104,17 @@ public:
   MediaData* Create(Microseconds aDTS,
                     Microseconds aDuration,
                     int64_t aOffsetInStream)
   {
     // Create a fake YUV buffer in a 420 format. That is, an 8bpp Y plane,
     // with a U and V plane that are half the size of the Y plane, i.e 8 bit,
     // 2x2 subsampled. Have the data pointers of each frame point to the
     // first plane, they'll always be zero'd memory anyway.
-    uint8_t* frame = new uint8_t[mFrameWidth * mFrameHeight];
+    nsAutoArrayPtr<uint8_t> frame(new uint8_t[mFrameWidth * mFrameHeight]);
     memset(frame, 0, mFrameWidth * mFrameHeight);
     VideoData::YCbCrBuffer buffer;
 
     // Y plane.
     buffer.mPlanes[0].mData = frame;
     buffer.mPlanes[0].mStride = mFrameWidth;
     buffer.mPlanes[0].mHeight = mFrameHeight;
     buffer.mPlanes[0].mWidth = mFrameWidth;
--- a/content/media/fmp4/MP4Reader.h
+++ b/content/media/fmp4/MP4Reader.h
@@ -87,17 +87,17 @@ private:
   void Error(mp4_demuxer::TrackType aTrack);
   bool Decode(mp4_demuxer::TrackType aTrack);
   void Flush(mp4_demuxer::TrackType aTrack);
   void DrainComplete(mp4_demuxer::TrackType aTrack);
   void UpdateIndex();
   bool IsSupportedAudioMimeType(const char* aMimeType);
   void NotifyResourcesStatusChanged();
   bool IsWaitingOnCodecResource();
-  bool IsWaitingOnCDMResource();
+  virtual bool IsWaitingOnCDMResource() MOZ_OVERRIDE;
 
   nsAutoPtr<mp4_demuxer::MP4Demuxer> mDemuxer;
   nsAutoPtr<PlatformDecoderModule> mPlatform;
 
   class DecoderCallback : public MediaDataDecoderCallback {
   public:
     DecoderCallback(MP4Reader* aReader,
                     mp4_demuxer::TrackType aType)
--- a/content/media/fmp4/PlatformDecoderModule.cpp
+++ b/content/media/fmp4/PlatformDecoderModule.cpp
@@ -56,16 +56,17 @@ PlatformDecoderModule::Init()
 #ifdef XP_WIN
   WMFDecoderModule::Init();
 #endif
 #ifdef MOZ_APPLEMEDIA
   AppleDecoderModule::Init();
 #endif
 }
 
+#ifdef MOZ_EME
 class CreateTaskQueueTask : public nsRunnable {
 public:
   NS_IMETHOD Run() {
     MOZ_ASSERT(NS_IsMainThread());
     mTaskQueue = new MediaTaskQueue(GetMediaDecodeThreadPool());
     return NS_OK;
   }
   nsRefPtr<MediaTaskQueue> mTaskQueue;
@@ -76,17 +77,16 @@ CreateTaskQueue()
 {
   // We must create the MediaTaskQueue/SharedThreadPool on the main thread.
   nsRefPtr<CreateTaskQueueTask> t(new CreateTaskQueueTask());
   nsresult rv = NS_DispatchToMainThread(t, NS_DISPATCH_SYNC);
   NS_ENSURE_SUCCESS(rv, nullptr);
   return t->mTaskQueue.forget();
 }
 
-#ifdef MOZ_EME
 /* static */
 PlatformDecoderModule*
 PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
                                         bool aHasAudio,
                                         bool aHasVideo,
                                         MediaTaskQueue* aTaskQueue)
 {
   bool cdmDecodesAudio;
--- a/content/media/gmp/GMPAudioDecoderParent.cpp
+++ b/content/media/gmp/GMPAudioDecoderParent.cpp
@@ -26,16 +26,17 @@ extern PRLogModuleInfo* GetGMPLog();
 #define LOGD(msg)
 #define LOG(level, msg)
 #endif
 
 namespace gmp {
 
 GMPAudioDecoderParent::GMPAudioDecoderParent(GMPParent* aPlugin)
   : mIsOpen(false)
+  , mShuttingDown(false)
   , mPlugin(aPlugin)
   , mCallback(nullptr)
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPAudioDecoderParent::~GMPAudioDecoderParent()
 {
@@ -156,27 +157,29 @@ GMPAudioDecoderParent::Close()
 
 // Note: Consider keeping ActorDestroy sync'd up when making changes here.
 nsresult
 GMPAudioDecoderParent::Shutdown()
 {
   LOGD(("%s: %p", __FUNCTION__, this));
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
+  if (mShuttingDown) {
+    return NS_OK;
+  }
+  mShuttingDown = true;
+
   // Notify client we're gone!  Won't occur after Close()
   if (mCallback) {
     mCallback->Terminated();
     mCallback = nullptr;
   }
 
-  if (mIsOpen) {
-    // Don't send DecodingComplete if we died
-    mIsOpen = false;
-    unused << SendDecodingComplete();
-  }
+  mIsOpen = false;
+  unused << SendDecodingComplete();
 
   return NS_OK;
 }
 
 // Note: Keep this sync'd up with DecodingComplete
 void
 GMPAudioDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
 {
--- a/content/media/gmp/GMPAudioDecoderParent.h
+++ b/content/media/gmp/GMPAudioDecoderParent.h
@@ -48,16 +48,17 @@ private:
   virtual bool RecvDecoded(const GMPAudioDecodedSampleData& aDecoded) MOZ_OVERRIDE;
   virtual bool RecvInputDataExhausted() MOZ_OVERRIDE;
   virtual bool RecvDrainComplete() MOZ_OVERRIDE;
   virtual bool RecvResetComplete() MOZ_OVERRIDE;
   virtual bool RecvError(const GMPErr& aError) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mIsOpen;
+  bool mShuttingDown;
   nsRefPtr<GMPParent> mPlugin;
   GMPAudioDecoderProxyCallback* mCallback;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPAudioDecoderParent_h_
--- a/content/media/gmp/GMPDecryptorParent.cpp
+++ b/content/media/gmp/GMPDecryptorParent.cpp
@@ -8,16 +8,17 @@
 #include "mp4_demuxer/DecoderData.h"
 #include "mozilla/unused.h"
 
 namespace mozilla {
 namespace gmp {
 
 GMPDecryptorParent::GMPDecryptorParent(GMPParent* aPlugin)
   : mIsOpen(false)
+  , mShuttingDown(false)
   , mPlugin(aPlugin)
   , mCallback(nullptr)
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPDecryptorParent::~GMPDecryptorParent()
 {
@@ -323,26 +324,29 @@ GMPDecryptorParent::Close()
   Shutdown();
 }
 
 void
 GMPDecryptorParent::Shutdown()
 {
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
+  if (mShuttingDown) {
+    return;
+  }
+  mShuttingDown = true;
+
   // Notify client we're gone!  Won't occur after Close()
   if (mCallback) {
     mCallback->Terminated();
     mCallback = nullptr;
   }
 
-  if (mIsOpen) {
-    mIsOpen = false;
-    unused << SendDecryptingComplete();
-  }
+  mIsOpen = false;
+  unused << SendDecryptingComplete();
 }
 
 // Note: Keep this sync'd up with Shutdown
 void
 GMPDecryptorParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   mIsOpen = false;
   if (mCallback) {
--- a/content/media/gmp/GMPDecryptorParent.h
+++ b/content/media/gmp/GMPDecryptorParent.h
@@ -101,16 +101,17 @@ private:
                              const nsTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
 
   virtual bool RecvSetCaps(const uint64_t& aCaps) MOZ_OVERRIDE;
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mIsOpen;
+  bool mShuttingDown;
   nsRefPtr<GMPParent> mPlugin;
   GMPDecryptorProxyCallback* mCallback;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // GMPDecryptorChild_h_
--- a/content/media/gmp/GMPService.cpp
+++ b/content/media/gmp/GMPService.cpp
@@ -138,16 +138,17 @@ NS_IMPL_ISUPPORTS(GeckoMediaPluginServic
 
 #define GMP_DEFAULT_ASYNC_SHUTDONW_TIMEOUT 3000
 static int32_t sMaxAsyncShutdownWaitMs = 0;
 
 GeckoMediaPluginService::GeckoMediaPluginService()
   : mMutex("GeckoMediaPluginService::mMutex")
   , mShuttingDown(false)
   , mShuttingDownOnGMPThread(false)
+  , mScannedPluginOnDisk(false)
   , mWaitingForPluginsAsyncShutdown(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   static bool setTimeoutPrefCache = false;
   if (!setTimeoutPrefCache) {
     setTimeoutPrefCache = true;
     Preferences::AddIntVarCache(&sMaxAsyncShutdownWaitMs,
                                 "media.gmp.async-shutdown-timeout",
@@ -585,17 +586,17 @@ GeckoMediaPluginService::UnloadPlugins()
 
   MOZ_ASSERT(!mShuttingDownOnGMPThread);
   mShuttingDownOnGMPThread = true;
 
   {
     MutexAutoLock lock(mMutex);
     // Note: CloseActive is async; it will actually finish
     // shutting down when all the plugins have unloaded.
-    for (uint32_t i = 0; i < mPlugins.Length(); i++) {
+    for (size_t i = 0; i < mPlugins.Length(); i++) {
       mPlugins[i]->CloseActive(true);
     }
     mPlugins.Clear();
   }
 
   if (!mAsyncShutdownPlugins.IsEmpty()) {
     // We have plugins that require async shutdown. Set a timer to abort
     // waiting if they take too long to shutdown.
@@ -614,17 +615,17 @@ GeckoMediaPluginService::UnloadPlugins()
 
 void
 GeckoMediaPluginService::CrashPlugins()
 {
   LOGD(("%s::%s", __CLASS__, __FUNCTION__));
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
 
   MutexAutoLock lock(mMutex);
-  for (uint32_t i = 0; i < mPlugins.Length(); i++) {
+  for (size_t i = 0; i < mPlugins.Length(); i++) {
     mPlugins[i]->Crash();
   }
 }
 
 void
 GeckoMediaPluginService::LoadFromEnvironment()
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
@@ -647,16 +648,18 @@ GeckoMediaPluginService::LoadFromEnviron
     if (next == -1) {
       AddOnGMPThread(nsDependentSubstring(allpaths, pos));
       break;
     } else {
       AddOnGMPThread(nsDependentSubstring(allpaths, pos, next - pos));
       pos = next + 1;
     }
   }
+
+  mScannedPluginOnDisk = true;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginService::PathRunnable::Run()
 {
   if (mAdd) {
     mService->AddOnGMPThread(mPath);
   } else {
@@ -688,76 +691,119 @@ GeckoMediaPluginService::RemovePluginDir
   if (NS_FAILED(rv)) {
     return rv;
   }
   nsCOMPtr<nsIRunnable> r = new PathRunnable(this, aDirectory, false);
   thread->Dispatch(r, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
+class DummyRunnable : public nsRunnable {
+public:
+  NS_IMETHOD Run() { return NS_OK; }
+};
+
 NS_IMETHODIMP
-GeckoMediaPluginService::HasPluginForAPI(const nsACString& aNodeId,
-                                         const nsACString& aAPI,
+GeckoMediaPluginService::HasPluginForAPI(const nsACString& aAPI,
                                          nsTArray<nsCString>* aTags,
                                          bool* aResult)
 {
   NS_ENSURE_ARG(aTags && aTags->Length() > 0);
   NS_ENSURE_ARG(aResult);
 
-  nsCString temp(aAPI);
-  GMPParent *parent = SelectPluginForAPI(aNodeId, temp, *aTags, false);
-  *aResult = !!parent;
+  const char* env = nullptr;
+  if (!mScannedPluginOnDisk && (env = PR_GetEnv("MOZ_GMP_PATH")) && *env) {
+    // We have a MOZ_GMP_PATH environment variable which may specify the
+    // location of plugins to load, and we haven't yet scanned the disk to
+    // see if there are plugins there. Get the GMP thread, which will
+    // cause an event to be dispatched to which scans for plugins. We
+    // dispatch a sync event to the GMP thread here in order to wait until
+    // after the GMP thread has scanned any paths in MOZ_GMP_PATH.
+    nsCOMPtr<nsIThread> thread;
+    nsresult rv = GetThread(getter_AddRefs(thread));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    thread->Dispatch(new DummyRunnable(), NS_DISPATCH_SYNC);
+    MOZ_ASSERT(mScannedPluginOnDisk, "Should have scanned MOZ_GMP_PATH by now");
+  }
+
+  {
+    MutexAutoLock lock(mMutex);
+    nsCString api(aAPI);
+    GMPParent* gmp = FindPluginForAPIFrom(0, api, *aTags, nullptr);
+    *aResult = (gmp != nullptr);
+  }
 
   return NS_OK;
 }
 
 GMPParent*
+GeckoMediaPluginService::FindPluginForAPIFrom(size_t aSearchStartIndex,
+                                              const nsCString& aAPI,
+                                              const nsTArray<nsCString>& aTags,
+                                              size_t* aOutPluginIndex)
+{
+  mMutex.AssertCurrentThreadOwns();
+  for (size_t i = aSearchStartIndex; i < mPlugins.Length(); i++) {
+    GMPParent* gmp = mPlugins[i];
+    bool supportsAllTags = true;
+    for (size_t t = 0; t < aTags.Length(); t++) {
+      const nsCString& tag = aTags.ElementAt(t);
+      if (!gmp->SupportsAPI(aAPI, tag)) {
+        supportsAllTags = false;
+        break;
+      }
+    }
+    if (!supportsAllTags) {
+      continue;
+    }
+    if (aOutPluginIndex) {
+      *aOutPluginIndex = i;
+    }
+    return gmp;
+  }
+  return nullptr;
+}
+
+GMPParent*
 GeckoMediaPluginService::SelectPluginForAPI(const nsACString& aNodeId,
                                             const nsCString& aAPI,
-                                            const nsTArray<nsCString>& aTags,
-                                            bool aCloneCrossNodeIds)
+                                            const nsTArray<nsCString>& aTags)
 {
-  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread || !aCloneCrossNodeIds,
+  MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread,
              "Can't clone GMP plugins on non-GMP threads.");
 
   GMPParent* gmpToClone = nullptr;
   {
     MutexAutoLock lock(mMutex);
-    for (uint32_t i = 0; i < mPlugins.Length(); i++) {
-      GMPParent* gmp = mPlugins[i];
-      bool supportsAllTags = true;
-      for (uint32_t t = 0; t < aTags.Length(); t++) {
-        const nsCString& tag = aTags[t];
-        if (!gmp->SupportsAPI(aAPI, tag)) {
-          supportsAllTags = false;
-          break;
-        }
-      }
-      if (!supportsAllTags) {
-        continue;
-      }
+    size_t index = 0;
+    GMPParent* gmp = nullptr;
+    while ((gmp = FindPluginForAPIFrom(index, aAPI, aTags, &index))) {
       if (aNodeId.IsEmpty()) {
         if (gmp->CanBeSharedCrossNodeIds()) {
           return gmp;
         }
       } else if (gmp->CanBeUsedFrom(aNodeId)) {
         MOZ_ASSERT(!aNodeId.IsEmpty());
         gmp->SetNodeId(aNodeId);
         return gmp;
       }
 
-      // This GMP has the correct type but has the wrong origin; hold on to it
+      // This GMP has the correct type but has the wrong nodeId; hold on to it
       // in case we need to clone it.
       gmpToClone = gmp;
+      // Loop around and try the next plugin; it may be usable from aNodeId.
+      index++;
     }
   }
 
   // Plugin exists, but we can't use it due to cross-origin separation. Create a
   // new one.
-  if (aCloneCrossNodeIds && gmpToClone) {
+  if (gmpToClone) {
     GMPParent* clone = ClonePlugin(gmpToClone);
     if (!aNodeId.IsEmpty()) {
       clone->SetNodeId(aNodeId);
     }
     return clone;
   }
 
   return nullptr;
@@ -842,17 +888,17 @@ GeckoMediaPluginService::RemoveOnGMPThre
 
   nsCOMPtr<nsIFile> directory;
   nsresult rv = NS_NewLocalFile(aDirectory, false, getter_AddRefs(directory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   MutexAutoLock lock(mMutex);
-  for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
+  for (size_t i = 0; i < mPlugins.Length(); ++i) {
     nsCOMPtr<nsIFile> pluginpath = mPlugins[i]->GetDirectory();
     bool equals;
     if (NS_SUCCEEDED(directory->Equals(pluginpath, &equals)) && equals) {
       mPlugins[i]->CloseActive(true);
       mPlugins.RemoveElementAt(i);
       return;
     }
   }
--- a/content/media/gmp/GMPService.h
+++ b/content/media/gmp/GMPService.h
@@ -14,16 +14,17 @@
 #include "mozilla/Monitor.h"
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "nsIThread.h"
 #include "nsThreadUtils.h"
 #include "nsITimer.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
+#include "mozilla/Atomics.h"
 
 template <class> struct already_AddRefed;
 
 namespace mozilla {
 namespace gmp {
 
 class GMPParent;
 
@@ -44,18 +45,21 @@ public:
   void AsyncShutdownComplete(GMPParent* aParent);
   void AbortAsyncShutdown();
 
 private:
   ~GeckoMediaPluginService();
 
   GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
                                 const nsCString& aAPI,
-                                const nsTArray<nsCString>& aTags,
-                                bool aCloneCrossNodeIds = true);
+                                const nsTArray<nsCString>& aTags);
+  GMPParent* FindPluginForAPIFrom(size_t aSearchStartIndex,
+                                  const nsCString& aAPI,
+                                  const nsTArray<nsCString>& aTags,
+                                  size_t* aOutPluginIndex);
 
   void UnloadPlugins();
   void CrashPlugins();
   void SetAsyncShutdownComplete();
 
   void LoadFromEnvironment();
   void ProcessPossiblePlugin(nsIFile* aDir);
 
@@ -89,16 +93,20 @@ private:
   };
 
   Mutex mMutex; // Protects mGMPThread and mShuttingDown and mPlugins
   nsTArray<nsRefPtr<GMPParent>> mPlugins;
   nsCOMPtr<nsIThread> mGMPThread;
   bool mShuttingDown;
   bool mShuttingDownOnGMPThread;
 
+  // True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
+  // plugins found there into mPlugins.
+  Atomic<bool> mScannedPluginOnDisk;
+
   template<typename T>
   class MainThreadOnly {
   public:
     MOZ_IMPLICIT MainThreadOnly(T aValue)
       : mValue(aValue)
     {}
     operator T&() {
       MOZ_ASSERT(NS_IsMainThread());
--- a/content/media/gmp/GMPVideoDecoderParent.cpp
+++ b/content/media/gmp/GMPVideoDecoderParent.cpp
@@ -40,16 +40,17 @@ namespace gmp {
 //    on Close -> Dead
 //    on ActorDestroy -> Dead
 //    on Shutdown -> Dead
 // Dead: mIsOpen == false
 
 GMPVideoDecoderParent::GMPVideoDecoderParent(GMPParent* aPlugin)
   : GMPSharedMemManager(aPlugin)
   , mIsOpen(false)
+  , mShuttingDown(false)
   , mPlugin(aPlugin)
   , mCallback(nullptr)
   , mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
 {
   MOZ_ASSERT(mPlugin);
 }
 
 GMPVideoDecoderParent::~GMPVideoDecoderParent()
@@ -182,28 +183,30 @@ GMPVideoDecoderParent::Drain()
 
 // Note: Consider keeping ActorDestroy sync'd up when making changes here.
 nsresult
 GMPVideoDecoderParent::Shutdown()
 {
   LOGD(("%s: %p", __FUNCTION__, this));
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
+  if (mShuttingDown) {
+    return NS_OK;
+  }
+  mShuttingDown = true;
+
   // Notify client we're gone!  Won't occur after Close()
   if (mCallback) {
     mCallback->Terminated();
     mCallback = nullptr;
   }
   mVideoHost.DoneWithAPI();
 
-  if (mIsOpen) {
-    // Don't send DecodingComplete if we died
-    mIsOpen = false;
-    unused << SendDecodingComplete();
-  }
+  mIsOpen = false;
+  unused << SendDecodingComplete();
 
   return NS_OK;
 }
 
 // Note: Keep this sync'd up with Shutdown
 void
 GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
 {
--- a/content/media/gmp/GMPVideoDecoderParent.h
+++ b/content/media/gmp/GMPVideoDecoderParent.h
@@ -72,16 +72,17 @@ private:
   virtual bool RecvResetComplete() MOZ_OVERRIDE;
   virtual bool RecvError(const GMPErr& aError) MOZ_OVERRIDE;
   virtual bool RecvParentShmemForPool(Shmem& aEncodedBuffer) MOZ_OVERRIDE;
   virtual bool AnswerNeedShmem(const uint32_t& aFrameBufferSize,
                                Shmem* aMem) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mIsOpen;
+  bool mShuttingDown;
   nsRefPtr<GMPParent> mPlugin;
   GMPVideoDecoderCallbackProxy* mCallback;
   GMPVideoHostImpl mVideoHost;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
--- a/content/media/gmp/GMPVideoEncoderParent.cpp
+++ b/content/media/gmp/GMPVideoEncoderParent.cpp
@@ -47,16 +47,17 @@ namespace gmp {
 //    on Close -> Dead
 //    on ActorDestroy -> Dead
 //    on Shutdown -> Dead
 // Dead: mIsOpen == false
 
 GMPVideoEncoderParent::GMPVideoEncoderParent(GMPParent *aPlugin)
 : GMPSharedMemManager(aPlugin),
   mIsOpen(false),
+  mShuttingDown(false),
   mPlugin(aPlugin),
   mCallback(nullptr),
   mVideoHost(MOZ_THIS_IN_INITIALIZER_LIST())
 {
   MOZ_ASSERT(mPlugin);
 
   nsresult rv = NS_NewNamedThread("GMPEncoded", getter_AddRefs(mEncodedThread));
   if (NS_FAILED(rv)) {
@@ -215,27 +216,30 @@ GMPVideoEncoderParent::SetPeriodicKeyFra
 
 // Note: Consider keeping ActorDestroy sync'd up when making changes here.
 void
 GMPVideoEncoderParent::Shutdown()
 {
   LOGD(("%s::%s: %p", __CLASS__, __FUNCTION__, this));
   MOZ_ASSERT(mPlugin->GMPThread() == NS_GetCurrentThread());
 
+  if (mShuttingDown) {
+    return;
+  }
+  mShuttingDown = true;
+
   // Notify client we're gone!  Won't occur after Close()
   if (mCallback) {
     mCallback->Terminated();
     mCallback = nullptr;
   }
   mVideoHost.DoneWithAPI();
-  if (mIsOpen) {
-    // Don't send EncodingComplete if we died
-    mIsOpen = false;
-    unused << SendEncodingComplete();
-  }
+
+  mIsOpen = false;
+  unused << SendEncodingComplete();
 }
 
 static void
 ShutdownEncodedThread(nsCOMPtr<nsIThread>& aThread)
 {
   aThread->Shutdown();
 }
 
--- a/content/media/gmp/GMPVideoEncoderParent.h
+++ b/content/media/gmp/GMPVideoEncoderParent.h
@@ -69,16 +69,17 @@ private:
                            const nsTArray<uint8_t>& aCodecSpecificInfo) MOZ_OVERRIDE;
   virtual bool RecvError(const GMPErr& aError) MOZ_OVERRIDE;
   virtual bool RecvParentShmemForPool(Shmem& aFrameBuffer) MOZ_OVERRIDE;
   virtual bool AnswerNeedShmem(const uint32_t& aEncodedBufferSize,
                                Shmem* aMem) MOZ_OVERRIDE;
   virtual bool Recv__delete__() MOZ_OVERRIDE;
 
   bool mIsOpen;
+  bool mShuttingDown;
   nsRefPtr<GMPParent> mPlugin;
   GMPVideoEncoderCallbackProxy* mCallback;
   GMPVideoHostImpl mVideoHost;
   nsCOMPtr<nsIThread> mEncodedThread;
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/content/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/content/media/gmp/mozIGeckoMediaPluginService.idl
@@ -21,33 +21,31 @@ class GMPVideoHost;
 [ptr] native GMPVideoDecoderProxy(GMPVideoDecoderProxy);
 [ptr] native GMPVideoEncoderProxy(GMPVideoEncoderProxy);
 [ptr] native GMPVideoHost(GMPVideoHost);
 [ptr] native MessageLoop(MessageLoop);
 [ptr] native TagArray(nsTArray<nsCString>);
 [ptr] native GMPDecryptorProxy(GMPDecryptorProxy);
 [ptr] native GMPAudioDecoderProxy(GMPAudioDecoderProxy);
 
-[scriptable, uuid(b350d3b6-00c9-4602-bdfe-84c2be8d1e7a)]
+[scriptable, uuid(657443a4-6b5d-4181-98b0-56997b35bd57)]
 interface mozIGeckoMediaPluginService : nsISupports
 {
 
   /**
    * The GMP thread. Callable from any thread.
    */
   readonly attribute nsIThread thread;
 
   /**
    * Get a plugin that supports the specified tags.
    * Callable on any thread
    */
   [noscript]
-  boolean hasPluginForAPI([optional] in ACString nodeId,
-                          in ACString api,
-                          in TagArray tags);
+  boolean hasPluginForAPI(in ACString api, in TagArray tags);
 
   /**
    * Get a video decoder that supports the specified tags.
    * The array of tags should at least contain a codec tag, and optionally
    * other tags such as for EME keysystem.
    * Callable only on GMP thread.
    */
   [noscript]
new file mode 100644
--- /dev/null
+++ b/content/media/gtest/TestGMPCrossOrigin.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "gtest/gtest.h"
+
+#include "mozilla/StaticPtr.h"
+#include "GMPVideoDecoderProxy.h"
+#include "GMPVideoEncoderProxy.h"
+#include "GMPService.h"
+
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsIFile.h"
+#include "nsISimpleEnumerator.h"
+
+using namespace mozilla;
+using namespace mozilla::gmp;
+
+struct GMPTestRunner
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPTestRunner)
+
+  void DoTest(void (GMPTestRunner::*aTestMethod)());
+  void RunTestGMPTestCodec();
+  void RunTestGMPCrossOrigin();
+
+private:
+  ~GMPTestRunner() { }
+};
+
+void
+GMPTestRunner::RunTestGMPTestCodec()
+{
+  nsRefPtr<GeckoMediaPluginService> service =
+    GeckoMediaPluginService::GetGeckoMediaPluginService();
+
+  GMPVideoHost* host = nullptr;
+  GMPVideoDecoderProxy* decoder = nullptr;
+  GMPVideoDecoderProxy* decoder2 = nullptr;
+  GMPVideoEncoderProxy* encoder = nullptr;
+
+  nsTArray<nsCString> tags;
+  tags.AppendElement(NS_LITERAL_CSTRING("h264"));
+
+  service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("o"), &host, &decoder2);
+  service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING(""), &host, &decoder);
+
+  service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING(""), &host, &encoder);
+
+  EXPECT_TRUE(host);
+  EXPECT_TRUE(decoder);
+  EXPECT_TRUE(decoder2);
+  EXPECT_TRUE(encoder);
+
+  if (decoder) decoder->Close();
+  if (decoder2) decoder2->Close();
+  if (encoder) encoder->Close();
+}
+
+void
+GMPTestRunner::RunTestGMPCrossOrigin()
+{
+  nsRefPtr<GeckoMediaPluginService> service =
+    GeckoMediaPluginService::GetGeckoMediaPluginService();
+
+  GMPVideoHost* host = nullptr;
+  nsTArray<nsCString> tags;
+  tags.AppendElement(NS_LITERAL_CSTRING("h264"));
+
+  GMPVideoDecoderProxy* decoder1 = nullptr;
+  GMPVideoDecoderProxy* decoder2 = nullptr;
+  GMPVideoEncoderProxy* encoder1 = nullptr;
+  GMPVideoEncoderProxy* encoder2 = nullptr;
+
+  service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &decoder1);
+  service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin2"), &host, &decoder2);
+  EXPECT_TRUE(!!decoder1 && !!decoder2 &&
+              decoder1->ParentID() != decoder2->ParentID());
+
+  service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &encoder1);
+  service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin2"), &host, &encoder2);
+  EXPECT_TRUE(!!encoder1 && !!encoder2 &&
+              encoder1->ParentID() != encoder2->ParentID());
+
+  if (decoder2) decoder2->Close();
+  if (encoder2) encoder2->Close();
+
+  service->GetGMPVideoDecoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &decoder2);
+  EXPECT_TRUE(!!decoder1 && !!decoder2 &&
+              decoder1->ParentID() == decoder2->ParentID());
+
+  service->GetGMPVideoEncoder(&tags, NS_LITERAL_CSTRING("origin1"), &host, &encoder2);
+  EXPECT_TRUE(!!encoder1 && !!encoder2 &&
+              encoder1->ParentID() == encoder2->ParentID());
+
+  if (decoder1) decoder1->Close();
+  if (decoder2) decoder2->Close();
+  if (encoder1) encoder1->Close();
+  if (encoder2) encoder2->Close();
+}
+
+void
+GMPTestRunner::DoTest(void (GMPTestRunner::*aTestMethod)())
+{
+  nsRefPtr<GeckoMediaPluginService> service =
+    GeckoMediaPluginService::GetGeckoMediaPluginService();
+  nsCOMPtr<nsIThread> thread;
+
+  service->GetThread(getter_AddRefs(thread));
+  thread->Dispatch(NS_NewRunnableMethod(this, aTestMethod), NS_DISPATCH_SYNC);
+}
+
+TEST(GeckoMediaPlugins, GMPTestCodec) {
+  nsRefPtr<GMPTestRunner> runner = new GMPTestRunner();
+  runner->DoTest(&GMPTestRunner::RunTestGMPTestCodec);
+}
+
+TEST(GeckoMediaPlugins, GMPCrossOrigin) {
+  nsRefPtr<GMPTestRunner> runner = new GMPTestRunner();
+  runner->DoTest(&GMPTestRunner::RunTestGMPCrossOrigin);
+}
--- a/content/media/gtest/moz.build
+++ b/content/media/gtest/moz.build
@@ -1,16 +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/.
 
 UNIFIED_SOURCES += [
     'TestAudioCompactor.cpp',
+    'TestGMPCrossOrigin.cpp',
     'TestTrackEncoder.cpp',
     'TestVideoSegment.cpp',
     'TestWebMBuffered.cpp'
 ]
 
 TEST_HARNESS_FILES.gtest += [
     'test.webm'
 ]
@@ -20,13 +21,14 @@ if CONFIG['MOZ_WEBM_ENCODER']:
                         'TestVorbisTrackEncoder.cpp',
                         'TestWebMWriter.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 LOCAL_INCLUDES += [
     '/content/media/encoder',
+    '/content/media/gmp',
 ]
 
 FINAL_LIBRARY = 'xul-gtest'
 
 FAIL_ON_WARNINGS = True
--- a/content/media/mediasource/MediaSourceDecoder.cpp
+++ b/content/media/mediasource/MediaSourceDecoder.cpp
@@ -182,9 +182,22 @@ MediaSourceDecoder::NotifyTimeRangesChan
 
 void
 MediaSourceDecoder::PrepareReaderInitialization()
 {
   MOZ_ASSERT(mReader);
   mReader->PrepareInitialization();
 }
 
+#ifdef MOZ_EME
+nsresult
+MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
+{
+  nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = mReader->SetCDMProxy(aProxy);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+#endif
+
 } // namespace mozilla
--- a/content/media/mediasource/MediaSourceDecoder.h
+++ b/content/media/mediasource/MediaSourceDecoder.h
@@ -58,16 +58,20 @@ public:
   // Called whenever a TrackBuffer has new data appended or a new decoder
   // initializes.  Safe to call from any thread.
   void NotifyTimeRangesChanged();
 
   // Indicates the point in time at which the reader should consider
   // registered TrackBuffers essential for initialization.
   void PrepareReaderInitialization();
 
+#ifdef MOZ_EME
+  virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
+#endif
+
 private:
   // The owning MediaSource holds a strong reference to this decoder, and
   // calls Attach/DetachMediaSource on this decoder to set and clear
   // mMediaSource.
   dom::MediaSource* mMediaSource;
   nsRefPtr<MediaSourceReader> mReader;
 };
 
--- a/content/media/mediasource/MediaSourceReader.cpp
+++ b/content/media/mediasource/MediaSourceReader.cpp
@@ -324,16 +324,19 @@ MediaSourceReader::CreateSubDecoder(cons
     new MediaDataDecodedListener<MediaSourceReader>(this, GetTaskQueue());
   reader->SetCallback(callback);
   reader->SetTaskQueue(GetTaskQueue());
   reader->Init(nullptr);
 
   MSE_DEBUG("MediaSourceReader(%p)::CreateSubDecoder subdecoder %p subreader %p",
             this, decoder.get(), reader.get());
   decoder->SetReader(reader);
+#ifdef MOZ_EME
+  decoder->SetCDMProxy(mCDMProxy);
+#endif
   return decoder.forget();
 }
 
 void
 MediaSourceReader::AddTrackBuffer(TrackBuffer* aTrackBuffer)
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   MSE_DEBUG("MediaSourceReader(%p)::AddTrackBuffer %p", this, aTrackBuffer);
@@ -510,9 +513,25 @@ MediaSourceReader::Ended()
 
 bool
 MediaSourceReader::IsEnded()
 {
   ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
   return mEnded;
 }
 
+#ifdef MOZ_EME
+nsresult
+MediaSourceReader::SetCDMProxy(CDMProxy* aProxy)
+{
+  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
+
+  mCDMProxy = aProxy;
+  for (size_t i = 0; i < mTrackBuffers.Length(); i++) {
+    nsresult rv = mTrackBuffers[i]->SetCDMProxy(aProxy);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return NS_OK;
+}
+#endif
+
 } // namespace mozilla
--- a/content/media/mediasource/MediaSourceReader.h
+++ b/content/media/mediasource/MediaSourceReader.h
@@ -96,16 +96,20 @@ public:
   bool TrackBuffersContainTime(int64_t aTime);
 
   // Mark the reader to indicate that EndOfStream has been called on our MediaSource
   void Ended();
 
   // Return true if the Ended method has been called
   bool IsEnded();
 
+#ifdef MOZ_EME
+  nsresult SetCDMProxy(CDMProxy* aProxy);
+#endif
+
 private:
   bool SwitchAudioReader(int64_t aTarget);
   bool SwitchVideoReader(int64_t aTarget);
 
   // Return a reader from the set available in aTrackDecoders that has data
   // available in the range requested by aTarget.
   already_AddRefed<MediaDecoderReader> SelectReader(int64_t aTarget,
                                                     const nsTArray<nsRefPtr<SourceBufferDecoder>>& aTrackDecoders);
@@ -118,16 +122,20 @@ private:
   nsRefPtr<MediaDecoderReader> mAudioReader;
   nsRefPtr<MediaDecoderReader> mVideoReader;
 
   nsTArray<nsRefPtr<TrackBuffer>> mTrackBuffers;
   nsTArray<nsRefPtr<TrackBuffer>> mEssentialTrackBuffers;
   nsRefPtr<TrackBuffer> mAudioTrack;
   nsRefPtr<TrackBuffer> mVideoTrack;
 
+#ifdef MOZ_EME
+  nsRefPtr<CDMProxy> mCDMProxy;
+#endif
+
   // These are read and written on the decode task queue threads.
   int64_t mLastAudioTime;
   int64_t mLastVideoTime;
 
   int64_t mTimeThreshold;
   bool mDropAudioBeforeThreshold;
   bool mDropVideoBeforeThreshold;
 
--- a/content/media/mediasource/SourceBufferDecoder.h
+++ b/content/media/mediasource/SourceBufferDecoder.h
@@ -6,16 +6,19 @@
 
 #ifndef MOZILLA_SOURCEBUFFERDECODER_H_
 #define MOZILLA_SOURCEBUFFERDECODER_H_
 
 #include "AbstractMediaDecoder.h"
 #include "MediaDecoderReader.h"
 #include "SourceBufferResource.h"
 #include "mozilla/Attributes.h"
+#ifdef MOZ_EME
+#include "mozilla/CDMProxy.h"
+#endif
 #include "mozilla/ReentrantMonitor.h"
 
 namespace mozilla {
 
 class MediaResource;
 class MediaDecoderReader;
 
 namespace dom {
@@ -76,28 +79,49 @@ public:
   }
 
   void SetTaskQueue(MediaTaskQueue* aTaskQueue)
   {
     MOZ_ASSERT((!mTaskQueue && aTaskQueue) || (mTaskQueue && !aTaskQueue));
     mTaskQueue = aTaskQueue;
   }
 
+#ifdef MOZ_EME
+  virtual nsresult SetCDMProxy(CDMProxy* aProxy)
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+    mCDMProxy = aProxy;
+    return NS_OK;
+  }
+
+  virtual CDMProxy* GetCDMProxy() MOZ_OVERRIDE
+  {
+    MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
+    ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
+    return mCDMProxy;
+  }
+#endif
+
   // Given a time convert it into an approximate byte offset from the
   // cached data. Returns -1 if no such value is computable.
   int64_t ConvertToByteOffset(double aTime);
 
 private:
   virtual ~SourceBufferDecoder();
 
   // Our TrackBuffer's task queue, this is only non-null during initialization.
   RefPtr<MediaTaskQueue> mTaskQueue;
 
   nsRefPtr<MediaResource> mResource;
 
   AbstractMediaDecoder* mParentDecoder;
   nsRefPtr<MediaDecoderReader> mReader;
   int64_t mMediaDuration;
+
+#ifdef MOZ_EME
+  nsRefPtr<CDMProxy> mCDMProxy;
+#endif
 };
 
 } // namespace mozilla
 
 #endif /* MOZILLA_SOURCEBUFFERDECODER_H_ */
--- a/content/media/mediasource/TrackBuffer.cpp
+++ b/content/media/mediasource/TrackBuffer.cpp
@@ -232,27 +232,27 @@ TrackBuffer::NewDecoder()
   }
   ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
   mCurrentDecoder = decoder;
   mDecoders.AppendElement(decoder);
 
   mLastStartTimestamp = 0;
   mLastEndTimestamp = 0;
 
+  decoder->SetTaskQueue(mTaskQueue);
   return QueueInitializeDecoder(decoder);
 }
 
 bool
 TrackBuffer::QueueInitializeDecoder(SourceBufferDecoder* aDecoder)
 {
   RefPtr<nsIRunnable> task =
     NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
                                                       &TrackBuffer::InitializeDecoder,
                                                       aDecoder);
-  aDecoder->SetTaskQueue(mTaskQueue);
   if (NS_FAILED(mTaskQueue->Dispatch(task))) {
     MSE_DEBUG("MediaSourceReader(%p): Failed to enqueue decoder initialization task", this);
     RemoveDecoder(aDecoder);
     return false;
   }
   return true;
 }
 
@@ -267,18 +267,26 @@ TrackBuffer::InitializeDecoder(SourceBuf
 
   MediaDecoderReader* reader = aDecoder->GetReader();
   MSE_DEBUG("TrackBuffer(%p): Initializing subdecoder %p reader %p",
             this, aDecoder, reader);
 
   MediaInfo mi;
   nsAutoPtr<MetadataTags> tags; // TODO: Handle metadata.
   nsresult rv = reader->ReadMetadata(&mi, getter_Transfers(tags));
+  reader->SetIdle();
+
+  if (NS_SUCCEEDED(rv) && reader->IsWaitingOnCDMResource()) {
+    ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
+    mWaitingDecoders.AppendElement(aDecoder);
+    return;
+  }
+
   aDecoder->SetTaskQueue(nullptr);
-  reader->SetIdle();
+
   if (NS_FAILED(rv) || (!mi.HasVideo() && !mi.HasAudio())) {
     // XXX: Need to signal error back to owning SourceBuffer.
     MSE_DEBUG("TrackBuffer(%p): Reader %p failed to initialize rv=%x audio=%d video=%d",
               this, reader, rv, mi.HasAudio(), mi.HasVideo());
     RemoveDecoder(aDecoder);
     return;
   }
 
@@ -410,16 +418,41 @@ TrackBuffer::ResetDecode()
 
 const nsTArray<nsRefPtr<SourceBufferDecoder>>&
 TrackBuffer::Decoders()
 {
   // XXX assert OnDecodeThread
   return mInitializedDecoders;
 }
 
+#ifdef MOZ_EME
+nsresult
+TrackBuffer::SetCDMProxy(CDMProxy* aProxy)
+{
+  ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
+
+  for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
+    nsresult rv = mDecoders[i]->SetCDMProxy(aProxy);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  for (uint32_t i = 0; i < mWaitingDecoders.Length(); ++i) {
+    CDMCaps::AutoLock caps(aProxy->Capabilites());
+    caps.CallOnMainThreadWhenCapsAvailable(
+      NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
+                                                        &TrackBuffer::QueueInitializeDecoder,
+                                                        mWaitingDecoders[i]));
+  }
+
+  mWaitingDecoders.Clear();
+
+  return NS_OK;
+}
+#endif
+
 #if defined(DEBUG)
 void
 TrackBuffer::Dump(const char* aPath)
 {
   char path[255];
   PR_snprintf(path, sizeof(path), "%s/trackbuffer-%p", aPath, this);
   PR_MkDir(path, 0700);
 
--- a/content/media/mediasource/TrackBuffer.h
+++ b/content/media/mediasource/TrackBuffer.h
@@ -68,16 +68,20 @@ public:
   // Call ResetDecode() on each decoder in mDecoders.
   void ResetDecode();
 
   // Returns a reference to mInitializedDecoders, used by MediaSourceReader
   // to select decoders.
   // TODO: Refactor to a cleaner interface between TrackBuffer and MediaSourceReader.
   const nsTArray<nsRefPtr<SourceBufferDecoder>>& Decoders();
 
+#ifdef MOZ_EME
+  nsresult SetCDMProxy(CDMProxy* aProxy);
+#endif
+
 #if defined(DEBUG)
   void Dump(const char* aPath);
 #endif
 
 private:
   ~TrackBuffer();
 
   // Create a new decoder, set mCurrentDecoder to the new decoder, and queue
@@ -122,16 +126,20 @@ private:
   // All of the decoders managed by this TrackBuffer.  Access protected by
   // mParentDecoder's monitor.
   nsTArray<nsRefPtr<SourceBufferDecoder>> mDecoders;
 
   // Contains only the initialized decoders managed by this TrackBuffer.
   // Access protected by mParentDecoder's monitor.
   nsTArray<nsRefPtr<SourceBufferDecoder>> mInitializedDecoders;
 
+  // Decoders which are waiting on a Content Decryption Module to be able to
+  // finish ReadMetadata.
+  nsTArray<nsRefPtr<SourceBufferDecoder>> mWaitingDecoders;
+
   // The decoder that the owning SourceBuffer is currently appending data to.
   nsRefPtr<SourceBufferDecoder> mCurrentDecoder;
 
   nsRefPtr<MediaSourceDecoder> mParentDecoder;
   const nsCString mType;
 
   // The last start and end timestamps added to the TrackBuffer via
   // AppendData.  Accessed on the main thread only.
new file mode 100644
--- /dev/null
+++ b/content/media/test/gizmo-frag-cenc.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  This XML file describes the encryption applied to |gizmo-frag-cenc*|. To
+  generate the gizmo-frag-cenc files, run the following commands:
+
+  Encrypt gizmo.mp4 with the keys specified in this file, and output to |gizmo-cenc.mp4|
+    MP4Box -crypt gizmo-frag-cenc.xml -out gizmo-cenc.mp4 gizmo.mp4
+
+  Fragment |gizmo-cenc.mp4| into 1000ms segments:
+    MP4Box -dash 1000 -rap -segment-name gizmo-frag-cenc -subsegs-per-sidx 5 -rem 2 gizmo-cenc.mp4
+
+  The above command will generate a set of fragments in |gizmo-frag-cenc*.m4s|
+  and a single |gizmo-frag-cencinit.mp4| containing just the init segment.
+  
+  To cut down the duration, we throw out all but the first two segments:
+    rm gizmo-frag-cenc[^12].m4s
+-->
+
+<GPACDRM type="CENC AES-CTR">
+
+  <DRMInfo type="pssh" version="1">
+    <!--
+    SystemID specified in
+    https://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/cenc-format.html
+    -->
+    <BS ID128="1077efecc0b24d02ace33c1e52e2fb4b" />
+    <!-- Number of KeyIDs = 2 -->
+    <BS bits="32" value="2" />
+    <!-- KeyID -->
+    <BS ID128="0x7e571d037e571d037e571d037e571d03" />
+    <BS ID128="0x7e571d047e571d047e571d047e571d04" />
+  </DRMInfo>
+
+  <CrypTrack trackID="1" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+    first_IV="0x00000000000000000000000000000000">
+    <key KID="0x7e571d037e571d037e571d037e571d03"
+      value="0x7e5733337e5733337e5733337e573333" />
+  </CrypTrack>
+
+  <CrypTrack trackID="2" isEncrypted="1" IV_size="16" saiSavedBox="senc"
+    first_IV="0x00000000000000000000000000000000">
+    <key KID="0x7e571d047e571d047e571d047e571d04"
+      value="0x7e5744447e5744447e5744447e574444" />
+  </CrypTrack>
+
+</GPACDRM>
+
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..6e2529377cabb4cdb439061a412e9c594b9d9b39
GIT binary patch
literal 57143
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
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..12b4481cd675abe3dda6acae3f4b80210a9ba85a
GIT binary patch
literal 93065
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%0A&yYi5
zuTnH?SWH6>e^1VeU2om3yp154c1>P5jI#B*l6oRW^<!j(NCo^13%JXt5U8PcSVp^!
zlo;}LS8w2~208HyXMgm({2U9cqn*`u2^HJhPSsn~o0&-NY@#TVXa^RT*9tKFtp-;3
zrp^<qhi2w6H<@L-#Mb)?%jotfRyJJXq#NG>49y``Xo5E@2jGZ&*8`9w&%Q74vF+Kh
zZSBnL*tTukwr$(CZQHi(nH{}7_w0*z&p+;c74hxL`eb%yWyP<fyX9239-t89x~;m#
z0l6UdOl(r<2XBz7c=P8SP}_>G=W>u`7khN7VM9w;`ff@qprG-~Fi*FSdAOkGJwl6Z
z`Jd+GnLX2LZ@w(yGY-cqRIvQh`*D+iXt&P8mFh5>VO@N*@eTCoua@ZT-6F<T0w?*Z
z>I6x9<<R;X^hu<8BaNxic%tOL)g<p|b9K3y6cEL11M(IaqmMF7z-tphq}#r>s_(7e
zoaYMoNDHKKF`7Ld(LOfVegHn=Pg53~4NR!=DX6c94%BkMQVi&V<V=86&M>tTjmdV4
z!K{|A`pXkF7BA`!diLy&pq>hEpSf))>S^rk&Oa{~HOv?d&S@D>dxwCh*$6eBw>wo+
z?vr6~EXqayI;M5ccycVYb@j!U$=Skenswo=F@!WX4seF8XhAoXvboj437V}=z3paz
zii;LT6E?BSlK-U!?YB(Z1T7P|%S$Z22&Vz=UJRkIP9y+^N5^gaQBxLgj*}DI^Q>pb
zR0!kV@d&{f0OFINcZDebGqTD<ypEs?FP1}SZ|S`C+L)s$My9t6r*W{mQ9hr#v+=$(
zjjq#)GL~isF1!NrBH7TIk?4+tCsSb~j<u{gPPAWKQI!xYl$mhH*p<JtQ<>4Sy{&Sg
z5KWeb*)s3$xDY58@UhX8zZd!N)qk?pN&A_KHMp@1YyKCiYl=Nrjex!AtFr@s_C3hi
zc#1)vB%-}qgYjDQ?@HWYEu=WYF4dGl9ag=`qt#W!?_^P*q=$oao2cnex~H=%HK$86
zVzSh%74blOgkPZwpqsw{eN++wuB^526JzpMLErNDz)3OjaDudZMEUgXA#&z3HsMVQ
zv|60MlZ$}ocElqlRd_VrX<P3<dTIepyMpx;EadzmB_5~==kWv>Hc;9F-UpT{w#GPw
z#yrF@O6DLA$(w|KcBltd>lw9si1dRhafPRiyr0uO>sjde>eb&VDhl7R3!62ae&H{m
z>3mnv^!^y;)IK-bIpJU13~kafO|R`>%+~L_QG)MvMl;8x)b|Qidr@#gfp%V)1FmUN
za?&`(gb5^{l#ZqCk*<(?lL>|Ai%oZ?St&l(et{p2C@tTC&BjY<dRL`7PF))(;Ij!F
zuVILTRnXsLe*(}12cdJgWV^*Tid^&u$ABvIu&t8!(Q%}ZP|WzbDWlU}!i>~~jx9E&
zi53?ep$(>O0l0zq<Y1#_t1!4J`8@ZaVA}uyX2^M=w7iu&?P+Q)Sfa$ah&)+B0L2s^
zu3g5XNHrr6ukrc9r@P473RXA)+gh-7c9p05^bq$*PN0bqcoUli_@arJ)H>E3CW~fl
zgWFx-Fn<2*uU0UT-cxCmOBpT%VL%HjEB68}1lkRCXUKw)ch980W}WBkuif?DH0Q^#
zho+28h?kzs)pmn*xGwe07$=gb?ey?I8~`iY)-ksYRW2M+stY-SfPKdPgY&n6-*#3@
zw3$@aXjh^M;TqH()_}4cxX|Pl=ur=^+Qn}Q>4(1RlveXy^mJyK(utp$jjH#n@J@yZ
ztS_I-U6<{2$a@W+YZY4el3@~!OWk|k`j`pJY`($Lmg=a**9>={Kv5>pKvd{C<2=KK
z_5O&ES>Dke$?Xl!y(+<iydk&O4TOg2v)on~QDEz9w2vdQ4|~?((CLLoCDIj^Txx2D
z$SI3TwzEB+kXGD3$aDidAi9v3?D{l}(wZwtM?=Gw`;TZ2lId~RA+mnyI@M8N`xVqC
z575b`FfCU`=YxDfY;_*j&e@`0km780SOWiaL%%>VH3C(|Mv^lX`dud#-YU{A+RC+Y
za=FRhb^?uZVi0R(G0M&YSGvL_82tSk^zkcA4U&k8G#R9~%YcK`com1m8z-2tKedYq
zX<pE|bKxso!cm;ij7qo@AX&5Jip839h^Jh5yj^^l8AIpire7iX{G*F+96=Q09ahB{
zl$NJ8B?tqUzfS49UdyvxT&>&+kB|<K90yh9@q89HKQ9Wa`KmVA)_l_>7rZK6v98@Z
z?m)o<73cH0&Vu-C;axL<x*!jDo9rDt`n4Es-neO`oSvU_0}b<Md1Z=dTkzurJ@Z*L
zq5%sb5{DeiB%(33LH|;Oa@K2ra~WGHV6q@^Qm*(5nOh6@QXL+}WeV?Pbkbw2GXEn&
z1>H?}l!50|{Zv$LX=&H?)~<sq`hASf^5aACSqi8b0@e!$gu+9Noy)I+u=Z8PFbA|o
z5VHBveF{xYKVBJ7E((+q6z&Y=c+=#@InKV-YhzmM`*sqbd;E1BOltSONZ{4E=?`ap
zuCPZ_>e__HsvUhdf@o*l?YJO<7U>N^dXwe{Xvftt55p;nCA0d|Gh>Fl>qouv-Z(qO
z88H2UC=ryoQgwa4!dkxA`(u;tcw`q@bMqyj3E&{z%VFi5#1acua*XC=1eo9^@hV{{
zoT+}=)gP3VW!jF^RQ_Q4M$MGn3`I5}XhazMu<!b6U~H(M8T-s}4qFPZ58~9M!A<^<
z(tc2j!Gq5>li$we?&vw`pm)L9Ec5P6h2A|<{4U+t3X2}+egoP}%Ui<VpjerHw{*hz
zFX&2jbiO0tMPja-GdrWp)|_Ys6v4FFSazJ3XI?;5<{uw#>U4CKLL;-nEGett!Nb15
zbpEjv@B9aBMLT2Q7K`z-H*MP^Ky-N=<|LHn-1}Y(vACSpL`D%=Or_-H*l;_}dkl6U
z>{tEa+I!L!u=b>Q5;_lCr*A<Xa6~#786%XWG(9ab2nyG+nC;$x-(|{}XMc)+#TpP_
z>P0A#NO0#_lzAEX+sQMG9k7DgU+I^qdY|#QdElY^1|AWxGAHK2&ASUv#bjg@ib`IS
zek`0Q){2k{!ZG1s_%r7_rhq`3vI(<nZWQXmHtb@Zuq_XaSIlaswuPiUkt-o(UJnnx
z<+glHC%&KT;OobuBzwG@nkpH1Pv|Cxv2NsBR;Wrbl((77VOq!i-T8@Ux=zN9-2T9z
zAUGLJPWyV4JrlCHma6yEZi5IbFt9)PJ=?hyEvl2lIWj$i?y<zigkh{>OvCKCuBIR5
z9+ER?Pdxf&$n1<ciJwj!$7OXk*6R}{y)B8<z^?5UW-R?-JQrPdkPpKh#g5%=%2=cF
z)8?sr9{>^H6K7jO_{9ty_vtb}4;3!os>4Q5q&{)SUcBaS(d6|-<()Bkch^W%YSer<
z6f4w*Jng%ckF<Q22p?lty9~9&#8e@oin(7ht$XkWU*846&ggnWVu$cXkRoIWg@P%1
z`~Dr*bGegl7QRv9ZO_BUy|K;xK<X_=M?2*}Y|_?X{jdI;Rp_h>%gytJJwiXCPY&O6
zy2Xq7s3RN64ndi<o7$M8%l-OPhXGlH+zr6hH=t=)ua^Bh=LUy0tQB%T;ZfHVn1TQN
zP)r<Fq#QJsGjUs^Gr0LA6)fw%PR!A!dkR7%?>>|bn=fi^jz3`wtSUPH?pnoK+8;xs
zGS4x$^}2kybxe;Ygd-FVsuVGo`-od48sOq_qgif7!4P5Z_kqmFK|JEZe%6)I#9nnz
zJ*eHxXmM%4!e`IV3`05P<TD14v2COpT-_Kw89AMD3}FMADF^vsLdEh7AWpvBw;5bH
z7<|JA9D`;4LLzS6_Cd;6DVdpfY$|tCDIhj}Uq(cgY`Xk_B%EC7;k9l)=ET{`DS_#B
z^b6Hf<CG{t0D?5AD3GPaD9j8!>jlzBGMW68f<E#%7ba%hh5lU;>c^^6F_HZOwexGe
z)}q#Q8^5__NCbGWQceUZ5Vag~%o1Kp$0K`NED%0niy_;+Hl0F=qV^~@O6guhtU1&B
z*`Bi8Dr4G}QI+8}1|_DVTR>AltOyLv$LWtBpeLBrPiE=()+;*03Hg0pF#C2B?}!Tb
zAvmgoAr*$YXT)TZ18zLD-@>1qMLGe$WGuS@aYm+VFNj#YV9#ffzTTz;d~tQypCA&6
zG@{RLo`)BHdbScJr3X^MXI{_)`Y-vXM5o*DC-5mWfTi(tIuC-2kzWG6X0@$r=AP=6
z4pdC{+)g`H-BW(d<pK8qS0*S}zl=uDoAJRxF`5(jBi`b~il612h`H2^boRTw_%|!T
zp|K)SyX2^NHVH-zyxMrdVsByh?dbdWI&LL_Mkkzq<t>-x%iEV$)Ydj&zVt{lC`fsO
z`2>YM_JvQqb3-NpAB|v@u>C@{@Cw0N_x*TTAgW09@$mYDIe0wWeqeblRHET*!8(*s
zg+T8`0qP5uuC?=xg4c&Re2x=_0(0<TYYgPg`{?yR40au=_=vOeiyYcje5dBdOCdm$
zsprhhK37^qVuhr^=lUiq@dON_ba8RdsOmf(ShQHi`b6T}>3J4?DwcJ)et$|H0U2(5
zCNzwO96kr^fFGK(@byIgVl%$kOJ+iHC2nLBO_^@L?z+GnnpIR<=-%e-as%+`#Ua)P
z7^_$_$W~F$g{8Df+Tv;*H<3Rr<J>kWPWrv%R%kb;!*0$}0gXJ}v>;1S?MI~9osd7{
z^@HR>t4y~ME8*x-=zv#?#`iML)TSEeI@4wgw1zE`vbWNzPKv~I;<k3*J$tfmh0gQC
zFYm<&g8{O)FJHsew{TL#Oaki9e>F&Uc;7wr3;hG3S-Hw<=5CBQ7!*TtSGF6_wTnfM
zZr4coxsZs1c%dEhR9k~+o_e<shD$4skKfi}SRi4!bC*9(Oq+&LzRn{&ED1A#yAFOB
zz$#eBBJ9?d7kL5cZ-TPh_GBnYT~8k^bKy)k@F1WX!v|)fpIrDqg;oW}S)%6c&QQch
z=c?Pf`c+M&9WJIF52zjaH!`4Lqv}h%qux<e@#KxM&!n@F4FGqf9$|xF$NG`um($&9
z*uYjI<^wY73eaEVkWh+dR{4heBlINaYhUAt>NeBzUg2SoW(SmGy6M6GoHfU&sz!uK
zsVmE_ta~G&yV-+6paz5pH=16D3?*19e#hjoogU%^#BB;y=2;O0>MR2MdIC-n>sP>S
zUx((k2TDb+HmATi7agTf9no)hgmvSATsO`QZ9&g5`GnAJZ&)~{ZX{IX5O{X1!knP3
zXU$&@_(;3n1cMXPGT<v9A>x&5^`sPU&6*%y&<#~u!MNg=K?8-YTSp;D;ESiUJuAfA
z@IeL*j*(()>66?>*&$*_H1rJ__OAEkG-J11+D+t-KWtfe!_0<(X*h#>f&&<>Gw>`H
z_J~ZJl;_yP+fnr;J~t6sOK<032%jGHyZ4RnzXh>97JGrl_iqsLYed`ES7Z=N$^ip_
znijZK$Y%@Y68frTjz3Wq>mn{lZf$1J`*!ncx@$NT*9E*dmxO!x&ijbe10{ZG`Y1X3
z1iwq9DB@`^kAr}S{?c?Qs>VChLI!Uxo$?5ozu$6C9#;R<X&;wyA=KM%Lb-YIj!}fN
zz0F+4@Gx&D?KR^XI?F*Z2jRL_cGrS5KxI{1lRq=g1!<TxmJ&O_GF4F!H8o4`vA!S;
z$wOHz<4Wf+^hS=zV<38keTXKq8EezAQtyBetrl41u)1EqsdDw~>~?RV+SD2?+?ye<
z?XU{@0BLEy$#G>bU28@+5zg<vUx>4E=x3kYd}cY`Dr{9TLXJCJIXViI?Au_JcmK^E
z?q}ST)53I}I`0slEER)_mI70!G0pacWCl*B{-s)jgRHFPj!hR5D`o_$_*!+#8B^rD
z-lk1@%IqZhOXT9LDK)BI%0{P<K1&rogtYZj(IC&oM2E?gAXdeB-K!U<ENfzyit?Ao
z8s&NAySH~;jqvEyse6S(UD^mOY30dQttP;`upggq?77x@SQ(g%xMvQba103*Fv6M3
zX*kriz0BNFjb@AFV^Oy9*FrY(7D8^w<dTck?euD^y-rp_@+YpqqS{VoIG}Ez2XW25
zdVn{Ff<a6~s`te!CIXq2>R0gdYsIE)z4n`p%Z1I>OLOH#%w<W_f-sY@Eo`7CcWycF
zZ(GVxcPC7HVjh_5jHvig5`n4+*2at9!o3^aBW))P^$;zhQEpr_dLmt)M~jx9GRYQD
zS$^bF&vD3O33{&?L;;2Hr^LZR13gAX8b@$G&#FQ=r&k3XspFGs$(B=;h|PToM-N=q
zi5oQ<MB~f^U(1;XkV%h^Rb)=C>pyN`Q_Vedonk0kboH7xNp`F1A9%z3t$Z7PU7}Nm
z)znq&x~hKq2D*s3DaIMGBuE0Hktb+fSFo?(#@DXZI)pl`#Okr-&RCiKphEyL?!5(R
zHK|>7t6@)z9s<O%3pKbZZYeNOf$Zibws<Z?qTg1S5=b*2b|&+uO2fSC4fYKNXA7fS
zL0V)kA2lA41gNN_eDtP0hZVI6JOVZmLnI4-^S6z>Y`<#OU|GALwjEuikEWXdnl^;k
zY^(AuOtuHp$|O$5^U0reqWs~VDp1&kEzjl#ASI=4xD8dHd?C1nyo?908=;Y(bS+{k
z*mXcfkztLvZ1)&bdV`VoW|`g;DqsmktcD7cf*M<y6$qz*5o`|rBd=NMJ?K7=^7#&q
zw>n%BlNo&@_EC!XtcjyQZkV8xQs$)ZJ6TDnwZ?>bwusIQSHrgc2Y}{=H`S=;@!jH3
z!%UG>b@d4T<7n0h9lS#H&m^@LBMC~<z~aToSuk+dUYJcA72ZnDU1Pq8PuL{ro<#kD
z55?Hq2V4x}EJa@GgXK9@R<&nv`$e|)$sbLYXnDlKa@d9S#eQ~Mx-nZu)J-fB2K&a*
zw-x*jcTdXBAx0PB@M)S*1*|Hv3+JkUb#4i5?E5?pSy^#O#Ma_;I@R2I188f3cnm_U
zPGkhKX!+|+0XKuT-w|l!qFNF=xfHtD1bVwRIoL8wqDIxLB?y!wKXVz{^*S5SaWKOl
zRF0txVFv+xs7ro>iV6KPAV^pBV&D{oubqo|kf}aNx^UXPNB=3|E2L_spDj4v_ER+%
zf|$lsRHx3Vhh6=wORa9`JOtLe35Lee9FMfZF9|KfLQMPDT3Kug)W!3sTjn+BDifng
zs-k=kg^x41;}Xavdx0tK)oKLtV_(4MQB=Fw{m(1;>k8)IhQQpN_vH;qM+-dE14E}|
zYRx8`&KoUMQk(l-BpdHD?nK83QanoG^tZO8k6}~PSdc1fhR^B^<rnl*mYM_9m;DO{
z+;n%Qg;Nso<y0Ti4`Ilvo(#OWIIP6fC}06i^x#sWVgqfPvU)Db8d4X7WE)vOA`_17
zc}Cb1cmvx|b}(>cMzgvy1=&N*YRnyLSJy71lGZl{l*>jZILQWz(Yv@+XOO_{4^1OX
zfg!oVykrM-?0EQ>+W0*-hR9(J;jU;lS{2^_{nIfc$<f1>TFKd4KBos(j7eP-$uu}_
zXO}>*+PQzi)^6a$n+=tO4)brkza(6G6^YuxMhbLj<ku{&1AHa|eXY!@8s`tX#~o&>
ztB!zH*fv}@<veEnMwTd0ADR#JXZ-a;wmeX|_my&ZqC5KJ939j6HZCm(^y9QY=0tC0
z78GJ)OHZWr4${!(IMdP%xuKaJZ}!l>WUT~tQu2`9T;7&lj(KFZ*TuOWgHOIs$c9Z@
zWzloeb{C9waT!m>dg%ZstivfVEZMwseE;&J{fZNE9lH$<Hw;X_$nNzWg1xCP_S{ms
z?i+!MO^NpUK&PoMZNPBEg8)VM?S`s?s{zKJhIMP-7Dv(w4YoHqe7@DrX=au*y#yJ$
zsP*h%Wtc=$Yu}mYETrJny9ZOSZ#6AJADf(pHiN_;Dm3`iw5~!MHzfW?7LH+e&m{{D
z{ITN~Tk$|~*AtZA{jw}nHX6J!zy*GWPGC4ii)|6LRLORG^vKcggZb!gGu$-{uAUC?
z9X72tXkoI;cW|d*sHSvL4Bxl|P%%T}Ogg^It_)%MEub$Ht!+(fs6I@BLNZI`j<NuV
z`N2Tid(WRa^vK9Y#wih&p=SOll{T)*dq+t7skjePujT7F8FI`m$x}RbQAxb+YHo!F
zr%A1y^hACR&^O@{J;naub0VcYc}i0Ty!s=Z*+hG50etL?7BHgkwg{!<hR>)sr1W`*
z(2r3?LHj!a9*Tm}W_3*FC7=$f`tIVFGoENSR;b37j{U2zwuf5}yHrJy?}h!nLMn!r
z+SO%l+b?{_jU9P07#PU@jf%<zwxNz1&1DWebPn?OKyMy`Kair{_>1}D?R39)K}j6o
z@wsd4*8SS;7B)sSG{rqoL>7~)F=Qn+N=uz_1_xk8b^>7UAHaHh4r9&*Pp>i{YPt>k
zII)}Ac(J;~Evek7U6&OE_<Ze3SJ$|YOVgSO`8Gkm1X1pi8EQqV#7_J$eA(*XP<Plx
zt8{ZDG08R)Zkok<nb&_EeH~~k!;Nw_<5WBgnQPD<Dwlr?x9T!;8HoTkB0O42*>&M>
z0`Gh%R;%|qy-kcPo7;4qVbNIJV_*V4MLjQex0^_N>=yYvRU-rJHg83P)oFOcM8OGH
zy+B!Iw9gMq2B4*VT`yH=I*v8s5Tj*XnoV@c_!*`jNC}jF)YkC$WP^bRWs9rDrXb^J
zQEiHr7Cm^sonzqE%^ygh4?VCsV5X;q++&#DAJoWXh~hb`q>4TqbT*E8@xgj%u1wNH
z1SWw%D3#i+LMXGgGwGc36JASWkygW@-XJ(T8u(no^KhPkwcTEhQInEY9mgn|QPaR0
zQdX^{Y=%)qvCQI_eHx+HsqK@K^qy=D)Y~M9*=J{SB}tz4DpHuacvWPcivcSiR1gGk
zLnHe*nLdeA6N<5QzdYGM7xw7){Z2HB<Q)55`{^ZDO62!ZU`6)9$slGTHHD!UAdCXX
zv0o2epC-a)vr=xasLiESv~fzSsqwS0CFSF{Z9zREu%p{;Eo~Z^CPZfXB&H%hLub8n
z+QKa88T6PiN^(${ioOQdvL<+KPC_7Rs>D%GPI?R>Ri?d^cp6y2K0@MCeR)V}spBI@
z&@<ayLl~4Wul1y{4ry7u>ng5f`gZLREU_XU;mk!%Kpp@*i;nDT11>gF2Oa4i*pVsb
zTFe`zoi)lD|Fkg|ql0g=P3U}|^5QY2c8ZY8lX+kK;VWdJ2qj7abY0{twd2C5jQ6c0
zGuSo@wPt0NPp(rZkUnpRed?~W{1B{d1GkTt%aaCYFZFV-Iq#>D@A4{Tj?OTMgct?^
zTQ*MeHr(7m^A5AA^O3xi7@Y2r8GK<$NC&mf-mwg&U*&O=Krr5phe;?wqDeR5_hNwW
zYd>RxOtLJvX*j_RrZet_D2`R0^R=XUIv1DFqPc)&MW=fZdHr~@o_*!Tx(bX)#W~U~
z;u}-1{`X=<t>4Fq1hjM=v#R}Wds5dyC*N<p(&X54I`<~jOJysiN(FyVV>ZnYhj^~t
z;7+q8==W@eMX(*90NUn^t5l3xaRyAGp05Ml4Hgy1yGa>OOOh+Zd8SG2^BKmYGLl0Q
zLqpsko`r?9d>d<q=p~L!u7RVY@OU>`X6dE+?LC{1_k+uM)kZ4*&7|>4VDQWrpS%w;
z9)8C@a>v{)GjnJvCk}{)Pzj%KzI+qm)Y49}h^<FYI}n%hLH9eLn*v>wDcAQ~7-NSG
z)uxB|Z_}rqTU;OR9m*bk9m$1`Z-rNWlC9y*Q1!Z?46jl`Q(EuFX&5=fw6fblp3w0g
zx-o1!I@<3T^=BR#`GgqI)Oi>cA2*u1A+se19Wf;fTWVd>KpGFh3UwW!s%D0xLn4ou
z0y@X4@iIkyM?cOH+?UsVeF!1cZsp!J;rCuZUHn;0*F1FzKT8bhPEg>}w~eo9iO4RT
zZi`R)4tmEf#3Ex^tD+1+TANNMuoxeUHQ?+}CG3EoKf4f1@SAh|e+j~js+7@3aFJ_T
zc0_0)&9-GCezTlZD40L06tv;gy23D$Rt?!4IdMaaM5uY0vqEpix*oZdo@iq=zvR0p
zYsFdY<c)(7;SvZS&IMr-WcK~;6RQNa;>ZN322Q)6H`HLNV2OL*>yUg8s)yTMBSnX8
z^o}@&obctLo$H|vL-F9cC+ObSv8$C%h{cj`(1|u7Z$G2tf3o4#tF;}C=bK*9mewLX
zFlGsgJlAVc&3wz;_Gl3-*julpr7rDWj5~IeEhwG+;M*|+?5@<$;89qki`Q$N{VqtZ
z?+DFUrIH@O1}L+W?M(XZsGOK;k}EX<KzFsHv_fQVn1EK=+FX>Hw~$;5L+<n5ZIQ3u
z$rKqaAr6u}wIuSSIQ1JuRi1<qHi&1Sm)hUOcUa)Lz-sRBhhBtlb7c^63jz$InA$O|
z`NelItJRp-{tKrbB=sQI%xw(exwesoEjn1U{4$cl6SU}$jC%rS(j1h+5r~L8=`+S^
zIE{+Rb-GpPJt)FERPYyKT-fEB?QvponYk<%z-GtNqsm{UTB}o0l@j_ECE=gauhOLh
zuS-17GGJ$Rc$U=;{3IT~&d$w;=s-7hq)+A?C?7iShZF@G%F#}^$?`YD!iV!SDPe3$
zi|sCN3>STu5h`mLF$3vCEXt5JRoe;)e9H+dvw7V@!y?L~#k!3k{LK}^ZbeskNQKR}
zA|5BM_$^T`ZDFHQryu%dBPs{GN~~m55h=tq(i6xosJhxzz8Nq2D%V`75Sr`tpl*<-
z^X+v@ZJ5UG>C#>1{2TRLy!u`py?oCWVp?2(@CL~$&2_9+j*zgr9v-T;KYVE?hWc7L
zZa6Ul?2k}a@}(@}RF|YrQf_PEdp~B;2vHcAt*PUl{v!B($Kz5>&6i6J9Dp1l6$}^`
zX;lsfeF^*dh%x(n!0$C;r-x?xApVosc}0rUJH3kYzP9&Tmr0GT38MR}S^E}uvbW27
zUXp(GsMKc+(<G4rQVE^v9@Ol!?Bb<QPLRe9F|I9OJtqK2lScMwVk3*;7n^VjGq?v`
zYz}yN;a+mYS8dW5m8u9;dD;#Xut(40?pL>2Y1TaEZO(}ys|#Kja;?pARsKk(%H|Sn
z!E)C(c6seiP;GWTCL>g;eypECB8kTN7B6d$V!RKKEP0ci5D|){5`pB_TdqMdi5RN!
z*GnQU+3n!WiCT$b-l|n-(z8Y6x+T`uTs8mDm%pi^AB}Qvi>BVNO;pEr@>5pAN1~=D
z2;YdXPue;BN9Z{I1EC&hP${-b=3zlgg=X)H%y<DfSYX^by<F|e0xFc%p_tZ4B;0Id
zRA#edFqoX>&dq65%t~MnHj3aTA{?(Ym3819=SnK|@0*=~SU~03aAaOg{2ltZ9VR=M
z(8CZ()hjgN%0*0NpxF^-b-psO?pJ}cRBsd=!Ox_PfE}x^<++Wz>3w@5QrAqHIy~n2
znN}6m?;pn$KT_UBV)-u&<h3HK0&DTBF}7W_aFN;y?RhxSy7zEbDd*<I_YEa}PgmfX
zw!?<eMpo_N&1crjD_@#xv1X+k`+$t-N5|eh(0642th4g7a9N72^dyn99Obx1{Hfba
zi%#|l-`b6(J4A#sMU{oJDnj__VVVQR_{Ljcpg?uw!LcnQmK7*BiaEt1{PT3o{k;Tn
zAY#|ZS7+H>j=xVF+@9N1#93kI!nd>XEEJNST@7l_Q<2D*uxC2LF02b2)z)Z0-afZ-
zMRv0mAiJjL<5y9nddwmVx@+n^G>uF@2FHMA7g1b*qOE>gsE-rdf$JJj6G|9J_wvC2
z;(3j#-c5dc)=KX}Mq6%AitS8gH-OfsJNRnN^^zxBxE*9izq(jCO_)eIc=$#H3EEp$
zZnmqv3!9iaTY``@PKdB)S!S@nXuP3mET8Wvir0g_7q2uM(LIHdld($Tzy>T#P`P=1
zse8~-li70zZLGuUu>rj|$dF7bbXgO_&0&Tpur`|axxAn%M<5#s6M?l$c;i@1lt#Y)
zCl@docEiAO)@^*|APG8Imisv7lBlm)Jp-ypFWN;(9ZG}vmAp9q%>2HCV|nC(T-|O8
zc+t@96il{-8+(j~tSOE&Q%HKQNO-=7-LB0<^E=Ik1pP%-6H92bc29T9dL=?_9XdeU
zx?v0v^(J{Fls%yCE47pS^sWLw773;>se+MK+9W(5wI$xD;UsHVyzURpeHUwfne-q$
z;j!P0Ay?~l{dU}sp`~D1zA{7Z8;MRY5liOZf~k@}zZnv{Jd8y+yTIMuvJ_80>F)Y@
zmQ=Cm^zo-+BXyQTMSUp-^d9B?zPWRCfXf$}5kti&7Jm}Z#^rmw4fNgakOr%>k__n<
zE6o3@(ZCY`8r_GCKeB$lIRmBwbSw(RlLBILWqKDDN6M$Q-ufm~e<z+b9UNzsB-t{}
z&joRW>LVq0x=CYll-g)|2N=j;0)%v{%T7st=Q>D)QV9u5*mzLKdKn2dG8;l27ctw<
zMK7s>CFv&CaB4(T-~}sR^oh6=d3Kq`X^Si07@Zpd{w#c|-j#-m{^;Ym3-?4pZof>l
z34AvVeDb>p5h*Itv>^i^>Q9`hq+0}XTUuXkXK)8tMdShbUHjV~)<EL!l8G@_RQ6Ke
zIr0}oE>Y6E-9V_Z4`u66I&x*I>1FmRWDcQDX~ZyUb}x1{VvJ<$=*%tA<w;=ob<(yu
zMk!Mfy=*fA{UwOb>7kPbFjqe*Am4KLSKyE(Mz-*j1yzHV@i#~o<m13AoND$Q$Z!AT
zOY%oZU4pJ0aRjvX%YFoegAX!g{^W;(>N9LVRUvr(T^FVzccx!@(yj~ufm7Q6nB1q{
z(7zE~I}PZ3Z<H-^95ityVfOm`GcM3F{YNS!h&L_BcY3}(+v!ywT%@O;sp5&v^bp*a
zO`ehrN4BLEj}7Jv%WJUts%4G+94&azI%u;~4l7o3Exfza&5BnmC&xT#9QyZw!-u=0
z&5cT<l8aPvO%$3H(z^DR=$?tgyI9$BU{ax~b{dlO%qnq}%Mv`?5t(vrm5R@r#xRDh
zLU0Axe39#>$FeON{H!c|h$&alL{V?NWJ8J5X1qKTgfy&a%2Vbh1N7ETz_jjIoIliI
z#tMW@;_pxCwP`F{pVg7rUv>C|=!BgcHM=2gY&V!dJO=yGq_J25`6K828X`dWuTQ~8
ztFtr@^QX5ns#s)bKU}=BejL6Jchtyf&5Ma?Y40PUO6me%OC?yJA9nMc`k;G`>$8Nw
zNC)SkFOJfILl<(d;8COyEoUIrtV}y+f1HRD863HrQ#U1@#Vx2|bS*hZQ0hRBrOd?s
zP8<kvgCsu3u0b(Hh2$!qV{CR*p7oIicRjOkNGz|_z*_R%2JBmXxd&ihdl87>Dr{pA
z_1LiVbH^+(Bi1eW35uW-&q!n9P1+&uXJoaL829SBL_c?Rn~0n)Mb?fW%a(ODb^Fmt
z<tEKZAp*MAZ`ndL)^M60y<BbE{QPEa&Lw$%Wi`2mjS&&yp8u`!9LvPym=5lbx9dfj
zze#Cx>&%#8GRy9EiEv0pd;F1;KQ!k$smeV4^l@Dt|3(FZkXjnL25sDF@%&&UY$D$X
z)=NJc;J==?@`n4$4Z}3v>)B2Tmzl~_%&5+Yrk`kTox(TlJ<XR?XY}Bj^%7i{*3@ZP
zt8U<&657N|D4b2$AsNfh_Zp(H(DanY&i$fBtB?!qwsiHgmrsCI_~zn!eX0q$9#=kx
z!Ti}R%)&i}Gwiip*_(r5l8joW_Mrj3#d8w=9C)(+skrS>Ud^{}eOl?cYCpPzxltE4
zu4gEhmN#nY-jT&=xq@!|wwPy*=_PUIM$bwyNfxH~_Vsu2DKcCrNateAjf~PDpx5nC
zAnz4S0!{Tk-N47;#e0o$R4)JksK1qsjWGZK0D_gVsUg6>4-fzVAR$M4y?;51<G&mT
z0RK-L5P<K$`VkzB4ITfh1q849=M~#Q-^BJ`mkvf|CjT`K0092)8Ph?}%>7?&10!pL
ze~rQT+ll?B!{)zt{C&gIpU67eJ6Zpk{qIDe;Q#>OBme*q>Hq+c9RL7evwyA`{<H-F
z0H6>60HB8e0AM=*B>PX8{<!6z82uUV@aL@cXIfW>f3E@bckTanAZq+s74*-1`2X;!
ze>;TIe>#%Fza6sqAAa+12b=g$N7np1KlML+=I=Z_|LG_O|8^+o|8!K4e>-&VKfL$f
z4%70Vju!dX)Be-ZmH#^Je>w){-}^E7hu8jf-T!n<;lIzv`XB!Hxk3IZ3}BM~p@@Kh
z{yp&j6%iozzh3{RB0>lF{}d5A!2eoAz<&w_!1lit(Vwx&Fn_v6|77uRX8vU1PbUAQ
z`%nH95n%7%_Me9d*!U-He=_&i|COabsri$pKUx1frtVMn{;c!!zZDt!e?Am2`~TX;
zf35!?9`n~1|KU~ti%<OZnSc1{Utjo72M7D>lmBp{zux^1=lSbH|8UK}-un-C{a@xu
z{OkWHO7Pmh-uMrn{OfK1@c+B7x&L$su>bjfAPD~#=l<(U|M362ubO|j%U^H$hbR2?
z^?!KX|GY1VslQ(L4?p|sf9j@<&B{>k&j$gVfDh-9c?h(gr%vAAXinr8j49S<qDs*{
zj+ok0Baer6kD<b3G*RrJ)y&?7Z69y4|5!UCujI~S?sv3&L4Hj$1|gi%!V6dl|IJE5
z1u)H=;Dh<R#W5pWh;dlJ@>YhHq9B$Kkw``?FLXFx79)XxNbs5lLi9=`EjLc#x~}8>
zM6xf)c(OdS7ni|;2X@q4GwU~*BkuKLQ3G1*fS@5Uvbnx3ho;pG2!3`OYU2|BgOOl4
zrbcWujy?#h1m^MPVrC8S;I=N;*o!ncpSGx=;B5>Lrnoceyn+Ng>zAIcH3=E+Qee!L
zRI)J#ONAeNIzc$+k1sCH-qn}~(ve-heje+Hg85tl;m^kB`}LKVYZ;g0;3mA>#Q}&~
zUFNYoJB#&DxTO7T8Z<X?{-BW~NGc=g@X_8KvnD3FBh8r7gkR<Ux8k2L;_Vu8E+lv6
zB%awOo8gBENx;s)=tn9J@~{rW<JXsuq2ND>-`+q#6nBM$!W?-tqM+Mj2n+T=#s)7h
z2&y}lXL936Bb}>GvKpRL4W5JhvRB(0ySn|nlwFz=KJ!Elk5k&mtAn8WE7<ja9wFcw
zS_Rmum`DDyEC|@XxmU0bo45_)N-C;dfQ7eypK|(zEOzA+y_WPY<dqS|Ri`(Bctf2g
z4RaTcunqum&8RAtLS@oGuEq8y(WJ&FYJ0V(s-*dhh9B)&nrXAW2yrF=cOnyirSc6d
zBwV)Us&e7ea#ZU+6xJ;Q{zKx~t^@@XYx!jIr}7lHI+;t(C@y=BXM{ElX?*s52_4j|
z@bd)ZV+2c`=zEg$#u-jcRf!4(8PeEoaHY142b|NFO@2NjCb4g`h}E`9s?g7#htett
z0YY?%AFBmYW>@Z9=@UJXYw=}g1s)VR)9z}tuf`^B)KE&8`W{D^Lubx@cSrFLoU{#k
zI-E6<zBBw!%|S7ZPMKC}csG2idnpr>K&t13^XYo5wx>SfF&;d~n){eccml4?-E3NK
zB+LSjwMrN{zI2KQ=h^OpwI~?2?^B}|kKDkIO9ZcL@<=XE;46_r)$>$3`2|)G#^^1-
zCN&l*p3okHYKm2`_EMkQFfsCJh60Ra(}%v3_lP*~`P$8bawV3benx!4t*%JHj>w+N
zId7#9FL)x-;p5T{TrRC$5Ass>`@K{Gv_P7unV7z&*lQZB?rrqfLj3e3;cNJKwRAVE
z-zqeTi5inN(u9zJp+328lG62Pxpc}YTZM(P-x5~pq12)hfa7Cu`zj?m-gQA^6BrQ}
z0^-oTKJICs|Aa}BMiqpeD`E$_)WL|H=8QF)^UcSx7~*TjZ41v~S)A40^CAeMq~0Um
z=BUW}zE{VfOo9dZh_gg@7F2E7Z76^NECU2@wpj!0)=)S2fm%tf6F4j7u+-6ii;QTZ
zRk2hCVNNa%EGq+X_Hj6UWHDbFcP1PETc8ahvQ5L40s`l)h;MZ4M8O=i&*-;1Z1I@7
z6Rj{uYCnV-vqr+`PnMWegW1q#D$dxPsRqMSXi%U{csqP`lRXy&2c+lI=mJ=)6l{^-
zJ=hsI71my($+bo3kj`geDSFP3cxs4ohWabko=f{>)FZVP*q5VCHbq~GR;C6zI}hy#
zrJ_)QfeWFb80ih%p<D!42--k(?6zr{y$4Muve}>}$L!P)*$rxOM~>xClRx<)faUb{
z?7tIc_VX9?$;969I;@ff=*e5OtCyy@+}Zk)a(5~e;Hr+Z1rHC-vBL7DO)W$H+^z9)
zgw30LybbpkBRDI5ipYex!-sy6%s&N>;$`N^fhLvG@EXrD#OoC=|8n?Y+D8_|-90*J
zqpm?4nOpAu=FFOW=q?T@XsvL;mQ;UQOCCgiSUW&V;tWD8^T@8EpZ}7o2SjHew4GFQ
zdg7{lXrta2$<je328*qFG`@)fNZYUqATvVu0!1h#L|-7_hn8uO+GN4QHv#X{jb+i5
zrK5U}2n`laioN|>1D>!4nGI({L<hVhU8U3>$qgaGf|rGi4UyA5YPbT8&Sy#qAYir}
zk#epV6QBF6Hu#uKsjJboy3n$|NfGG0v}G;wg8lvzRyl}^u~y>ptj8((UHk*ZJ+0w@
zM^IGLewB7a9LqSGtwgD!^>k+TwK&5}ILy%Y38d0&8mu6A`Yz%57g4wtcB5{I#-~jz
z?XC^w*h1sWH=oqO!B^WtPrMg~<_0qi!5cyNrd#qp@?ooiFu5_la9WUUEb1n|7)xqh
z1XN2P*uYLJlSZvt*?4MqAEr&0VkjY~V|9hXw@T40m2x?<XZ|CZC{d21A$xZLvsG+h
zhsIzi;{&&~R}=bHP~iqE@~3i=e0uI6<C;5YI>E1NBoA}?(;iKEO87!V1T<&u^)#cV
zT{*g}<SdJH0vUF*I(Ebk+Vieo-|Pkx&aDau0SwPxp^=3XcYnS(mHAAf36(9F`&<mo
zu2wIY9I^{-VmqZ9$T<4q)77z&e-m`ZOCkv{pMH2B@9~vDV$$|%2g0U@$_JZ~Exu8K
z_2nU!-_niJxumqaX9X#giU(lsfbg?9Ssj46xWWc%o3gc-Qw5AfT!FUtWtPe}s<z+J
zxa2R)+H0HK;z)7aqe*6mykwMPXunNP4?jANn$*e%=}g?24b90^kiBx2(u&oTM((kY
zaPK7-H%HY0Mt}DI&hKl~mKBGBweS6MurF+rG?_g+&Qqh$rTnZ&Q|l8%8Nl@hkiRi1
zq%KP%VL1*L$ZvNKk&P_WFK2?@>zI#yLT8?Sj##G!4|uZ#5bQYd!?N<YXk>Mh`4L8D
z#L<5)316)-Jh(kKb2{U+skKQ7u{Ir(j=!Fqsn%^TXQ34r<N|mmrn#Cy)Hc4a4Fyy6
zD^!V%io;-JZfrw(he(fwwV)u_Y#%&Hb$Go4=_4a3Rs4xT{(&Pf3Qc3ze;1v4KLUj9
z*n~x9XIc3!n6Cf9f-ATWa^@=GQ&olfD{ht(ez5OZm{BOR-J&+>@XhI2bSo-bK$k%=
z@|-5GCiDCvPknNHTE_n4xhO-nY=rpC<=h&%W$5ynT(rkaN5V?PdUVIrVV(Y2D@_I<
zv$G8GrvoNylF9K0GLQ%D%J#8z1<l!9BaE|`?ZQR`!+azmfLrs(RS)Ia)28;vN=s=C
zk9Jz~C%}fqhzq?dOKp5#+k1(2g?YvYX=-b$wCQ~d4gY+wOhtpS0&CjX?7M16pH4>A
z2ZVDp5lup=4D5}D4+77^E0=2esU)|hs*<BY>^-1Pr%P9TKUCIQI@RGh*9!`=p<0}K
zs&dWExyKQ#I#*`b^obY^td6#7%`Z~}X9<_+l-K$&j`%BSBVvOA!v6Sveg8f^6veTg
z^V$t4s_TT0*UVXwmY06XJE7(jI@{KyPNQ-Z5_;s>*7r<W0I}=!kwx`L@y&3mD9izu
z&S}zW|9R$>_{`#$h;Pk3uY|${UzjD^!*HIOcBVXT)lI9KiJqd=D_8<VZL3ck!l9E3
zZa;B8{L<m`Z>1ioklqgiN|TBbh>G8roCISv`KwlmPTaldmOOSS8bO?&(PZO3cnAXB
zTIp!YLI44TnmKFOgp)&xt99ABp?MRLRmE*E7L|7|FjBB7+sp8Ddl&~xx)_Zz=@OK-
zK0jG+Kz@}(pHwWP>7XrSsVE%|A6*}K%lb7(1bmDqO}e{5aHe*iE~mQv>T>ne&i@TE
zd3bwM^SND$KYOAYMqU8DpSf$Os*gSN@y6OCdxV)133&yx)oLeK7#tebZi2AP57cE+
zEam`m72q+K>{nE)Q0KllAe#sq?+0OVk0O!2q8B5N*P(JD-5-oi-Fb+lxqH;Jgr}xW
zWrZZAwp1opK%vaCos`W<Z2#uCtXs@v$b~R0AdtS<W3bpNwN^AB;NEx8dT{K!_3Ny=
zzC(bQ(>NFJAl*)XbYo4`Wc&yhSYwZt`wes?eS24Y)aOLw>;;=iGZCLfV*bs1a~?xZ
z%IyebfJNgPV+BH!z_(aQ*POs%LYxj$<qL}X`w_;&5o_+W$Vkmaq;1yW^wgV7ir+BF
z8&pF93cF|Kl6!*g#&7c5KU@|(iLfo~^yRGH1XZhh#*6flu2DtFsaroB^gC!uU;#tA
z=N9GZ#A~L;535y{)AS8904t!O&V=efeckQ;^}{Qt#DQ{U*lEl$gp7N$uH%O|^h`yv
zx})96468)UB>!hob<#!|0uj@2K(bmrbI-o36cIF(SMFmm(eaS!bexrKxYmqWP(xn{
z0Iv#xErt*G2sQ@Hb}46uQup(Cf)7E&8fjzDeCC~LO}?a;<R0eW1%xdj-xRT9;}45~
zc|b;G@~xjb(96WBcwP~&=(W4tNvu}_*x_nn55{@u1+#BwjS}{R`(W%gfPGrL&LS4e
z&|Pl=!F+KClPwMbh%V^Zm6ii=sk-JuMER9Y{#tjP1-uL`&8>3*+}hX3{x=0eH!?Ca
zqHvuwXHPVVev?-WCC9t7{vc>1{UF9Q;ED>PmOHmr1=VXb7bD21Q1+%9m?42ZAL^`<
zPZOtT0{K3?p1sBZt-6FH>UcNWcJtHY&uGInaj}<6pn4}Kp;}CB^bT%Q;1CKzXQ~VH
z*clZ-hmDV<x7~{eJ`WkaIyy`@`3#2sJb+-Z(kH2(5OY+8u<6SHN{#dQgFDAyZ##vH
zmW;P$yl>|siLqK9wO9A8qy|_<iW68R=h;>*aDd`|nOF1)Vea@M)NT?<vLGDaJBm*Z
zG(tPeI`}mEBO<Q!lX>22fY#8$!Gj5PnX=sXBosQ(%`(4UEoF<OY;svT+ddf?B8zuX
zN0`5IemuFTGkk*!I)nWtApBsx+$+Q4;(fh3IHv#d2Yk_DgrN;v*o?J>t2a<Pm%kee
zk{0pI9lW%lt`Y16;Agj0IJsXlSpbTDN~;zUV9O!HQ=xQw*F>-n8npmo2>^S{qgfbJ
z{z#{sc4;pp0-Rdmu<l9X<GkBzApVRp7j$P!Tfl+u!VXET(TsfLs?9ZK?I5~iNijQ(
zKM%8^W^({9%;29*!Z7ZW+|YJP2}xWK6g_h%UaN$hszVo4VV*h`#?ELdvIE{4hIl$$
zfSB5%c%*uJVL^(g`K>@|YtRnzquwM*l^qx{9YW25+S6^#6C!zF;!PkvHbRDSn=pC%
zQx+-I*ws@hWJ3@4F5bQR7VyHrPzoHIPmPhZi$tGV{Ek{_Q5u*r^;@fAxXJTmS<Faj
z%j%Ni<K{p;jlw!N0!d^1V%5tfRJ;2kd>nvBZU6Uglgcnmq!?8QK@`_UXLbMp$QC~I
zcGk~|-hTWovf8f;mb==(iS*Fr)lY2lDAg|-EsuZ>M>e2RzG$@<wDh^n{pc@-3e|%K
z&C+@Dtn88nLrc~sFq)!^zCD3<d?1C5(wD^a)5oMNrQG239>${WnazHN#>2;iV1jPz
zIrNTkTvh25-yg-AZHm@RxT@NgZ7b#UyvWoCQDO4Lbmr-gtpws6V~L9!wAu1sx0>)Q
zO0a$6lZNfEI5+}Ad<aUsKz8d-=_{}D{*Fk_18QhS6xjhRqcS<L@h!n|6WrE!p{*^Y
zz!{BUM5H)%8Um0(y5vew#LuNfr?9|{whTCL>a#ZXgYflgaK|Ze?>{nrc+6xN>{8fA
zzU*YsdYFBxRWmlX%T3g~)-r=thVFX7_C(mWf~FMnbnlHE)f^ZXX&URFRNKS#hiD2h
z;LEW*Ojb^~8p*O5!iI|y&<88(vfti{5+Ab^u0_*=(9;&?Huzze4#9(Rg`1J52itHm
zWP{_?wg)$2SqIYetx_;va`%-q3gXlZX$<{*)Z(oa@Y-^*er<kwpUkLu=SnF3;eGhs
z-$ESr{cGH22#NLF1mKY($%QwE2PhQ*pBM_7O={+=A-PGa_DS3|I4fnDirt;zX37}h
z{uk@@4lp-3rCoOCYQ!E^hcJmr9t|;g?GY@1|9db<z<SSlNCpaaoLm)MRpX&@wuc7k
zdi{F8_k+&2BQgo9UWp@w=F20J%+%C2AN@NVSPClv_YA-Hgv&<u({l>WeO;U_S(D-`
zc3P;k`yH-sc<_tV$#y<;u!&5Z<Q~E%<?R8PLo=9mYeXyi1lR|uhSfyLPKXv^t-4~@
zV`0R;Ye=<<!Rz5-%Wq|h(h|SaiQGn7=l6yYf7mU~VI+_0;qaqO=B_Cum%viQGNIWj
z{4+jyS7$MgP>rTmmVRZ&O7kDcfe&RQE^s^vwo#vIG8AgzUrqfK2n4WN3fY}6BEMv+
z4UcG$v9wEgX^R){%8$!3EV)zh70_!w*%RT03aEKm@47PxN~ZhE9x<f}i6Mr7dU@#D
zJn_WPX3sR;QR@-v^kx~#*}}zTtWCb|cqM>!!!B@GLloOX;)~l&_(mk(!<q&?IzlhD
zg0%UXX!9~a!%%#-=6|Jz=%CJ|Cs{<G)wHi$B&SdX1~G~zPfYVLa=~9wvj=*l<`g-;
z9HC7@sHBj*NK7$`s#VAxUvAg5!GlLF2er^r7V1^&;`-K+qJ>mcJ)a^B6<Ek@x_A{+
zLoNixJuyD2Ag)^Pn-y(1(PmyWH}h0gDb=SH*2hr3ROJX3Ka;nsZI!=^Q<;2t???>D
zGfLK3fkud!RrsraeZak95Dau-3q6!{dZjC3O&<srNFS6VeOL!@l1&_DRNF*rQO2YM
zHru%)qS#M3zY)SBQz^3m=YcG)U0@CLd0-1p2IC4ovj5O5ReXgQilx;3S>w#@7@(E$
z^8tYQ1v!)S5L5)W6Z50_%H?RBPGJ`WH6H6na@Ma_r|1HTjj^q1xk;TWToK6MROYPn
z@+vj4-(c~EL7U>LM|@6RwTvI%SmwBds^0dF%2;nJMnwf-(4P_XCYk=E@47m-!#7!Q
zC{X*tuw;Q}@9SqZ<nUg3i&C5)976oOoCa!XZB;KE+aYLSftP0=0mOsMg6lW<cC;}s
zhGbMI0dLerR*W!Tu*t%_Q#Qx4Js#mi+^jZ*P8lYFboa596|U~Qy%2ozVfcF)>OfnW
zk&?%W&FFGz-QPlKlGNI!iv-4fTnZa`US)lHCxank4=U(yxL#eRVP|zj3Atih7dph=
zSwFFkMUVVPz@e>FuduYzKN-cmOo7L-T;?Xg>Av!3*HD?bLK_5?gNw`A;l&K${Y$gT
ze$&3ndnd7n$@{!<^-GG3#ql_!n1xUXBA>~K18{z8KCd+uW9d4%qo-+Q3J)%erJp2|
zItDXQC<NRGtxUeng$qF(q-L=NiXOAw5Uuvg?>tQS2~Z68W|fYIeFUG^84BQt8}Iap
z5HySdnZS$s+sq^Ztg8yXj&QoDgW=OL)?cf8>Z9y%@0s!_`uJ*xw)vxpNiRQ;TkBJ=
zVZIg)0T*N~?v2E*-hTI|8xWgdV2x;st<G1Zoe&nzqoSTdBu;R!u}<1tb_5{A*t0#g
z*xO=gFviUl%;YP0h34&NYw)!%PT0!X-_!IuqqFfx3<QSgqrIin@z|sx%ZEFSrfG2p
zMCL~I81&GBM+Njj5b;2aVQ&}Deucq1^`4mt*{b<Tfylr>qf;+<Mxt}JD-Q(C=~=P%
zpX+>*PE<ou{SM|K=t_jJ!oP4e|33f+K={Ah$L|QMdUMuX%Pvfa)gz`BX><ICg#^$U
zFpukdq{XH|Hz!Gb;Fn)z51O<bNk}E*IniJEX=;lt<i7r4QRfxV!_MwS^SGV_Em&F9
zaS+0E9-Z@Cl`k;LmsEp0Q9x6y;(Vxat6IKg1Ze;|0tkQlb#bo_^<ZfVTgkEve~1>a
zAcxEr_2FNvh2OhnRv}IU$0-7pJ7@Dd8hxhDF!v`wU87m0JB<(56S-BOt7NyhX!=?A
zmo9bOJQFR^U#;z%d3t_D!Ydu=e<FdX@;Gaep*Bb+4~zg+YIe{i6xIcD!CB%LtGIpF
zDb>kmgbtprm8f5&#D;~z7Jqmfu-iq0JQ~QZ14IYVOXb!m6L`bMmK(-qvbU;&o5GfB
zb2RX{hV)a2QTxpR!G2FTD#_Kf8%!cvM|$CS3j2RrUPA1Ke!%7I?$&@aM5zss4LA8|
zrVrp+V%wdv%Lt-iz35X{SB+=oGE2aQWGi6lgx|x7no!5<krKI$Rx0jQtixJZ(?Z9k
zuL_>^R0da=oiFU8#09fad@I;hA$!c_6YOrwVqKwtTNnLw8)x@MzzG%%B0jk7d^3Yl
zFe8SxqHYXMltp8Wf9s7&b>8-Zn1+2};tX9p$dor9&u4GdHDJvO_Ow3^{azCOJ%CzN
zbH!dhartN9ecY}%W0QhiL2+t0sb0jk)IKjIa(@a;NVPp~BJ5}FN3V)MI1jUm=U8MA
z@SaT7+16KuJ-vKS3#S*HEfoc~q^DW%s%?Q#uozjnq>5b)WRV-ojSr^Ca9S5B=KoHh
z64xs!d?;s#`|o25BFW(WFghTF%U7=*CD<{uPdtK#7fK%v?5kcOT<&b+Xn?)@d5cg6
z4E<)B;Z_$dMXo?4O|-&>33kwM)6JI+jLe-BTYEoSc3npa#rzuj%sWlMyxW1Fn@e1u
z#7|?MX8fI145^(Ir2gH>$HD)335xV8pf@Ch=!^~m-8VM*?gqTlXT6pjD!gfoxIO>?
z2FyVn41{XY!46M{P^d(zZo|5VY8*DcpKnIr2K@k#SU_Vn<9AF@fhZ0rPE(4Kyl3~a
zd|fvJnO{coebZAZc!eu%O%HV3x`T=YiPJ%ocBvnK1NiF(bp;q?9Q5B0#|Y$$A=XIH
ziMGQHfrb1wMImN6pMs~ROkC82Pso2;zeT9Ud+HNF(4(<5l<;87Xq1j;oemY%t=`C{
z1Iz-K=K#HH1d!Q(z2I{AJP*j@ul%5#;7~dA?%H{T(Yk`#yHZE1bQJru2$Q-<7Ew;_
ziFTQ(fLayKVp=V3`|0=iio5APQ_^$_L*jm@1Ict0N2MR-?z`f!w}rTu3rzFI37t|b
zcR23Am0)FBEKc#^FcFpuD-d2`6U&`S>_U0r())uR1_}dc^yS(1_VEK4VCD;WB)0cN
zT@h#=!exx<@02;_6q%6@=xt3AUWaHKSx)IX_BPCp<<N}T0`$pLlqeuAwQ|1O9v*=A
z_W3MB)UsJRSsnQidVT{)?Q8X;Udz49gy421Zfq8ZGZVl>hcKivaiFw4<e<p%2lbc;
z3cH3NdYf%T1~p0*Y1Dw2iH`F@reTvub&xsUx7U``o(<)F&Mq#t-WLdyUYTMk7Ua!?
z=epG$UlPg{S@5e@l;3Ds)jvH#)J{f73acy#lB#<es^YuXM~HJ_y4ji<L*ZE^tO^<l
zHzDWv#-WKGw6QA|C_y<(1wiDYZs5LNOyc$+dXkBA0@EBn4*yVT`HY7p(E3ms$4|P^
zrYOQfeMm&87+85kLB6So*2*D)eYx44U+Uua2#hhGbl%XG*;3a0FWlZ1nvWVC2a2Gc
zE+<zC|0kl4h+8+%Q+QiT27Ib04&_MnoKZI-u@<q*rJ(vkykA>f%5Ud3&o=Nj8T;@6
z7;k3If^kqIhjnm&PCQ;vM%|9-_x|9W6wQ{Yr+q~Pr933KoUDeMf6AVPaeazge~gvj
ze_fV6D=A>SQ%CZH>plJI)B>8Q>3RS|K-}wl!Wf}lJOAwD^Mg4P^JN%lB<pb7K6p>-
z3({Uwh)ZmsUU(g^r@CJM`t<k+KxmqvC-a(P;2O>G==Svl%aK7*m}xY7CU<+yNhGtu
zfIUnGp6w2=BtuH(5L7czy8?5G+_`$R^$e*neI5pjL$f~FxDDanHs>Djxh@k{-O{ds
z((_*X(~%4Z^&#1PQWAVME4sRB)pOZui)#Rm^Qfk0{UCbwhfdqYZB_8QuxRs%km*Rq
zh@cu21VIpFua^89J@K_SD_iu67tqYS<$VH=pFa+fJX2#oZYAC8n19~eqy*thd8_uo
z+si$9K4HoW74KOX>ys5Uc$pZ}1Z0MB;mAQ?)v5rj?8-xjJwO-@+6l_<B(~t?7Y^e3
zLUSgPye&Bj-D;du@|+ZZJ@D8%)l5XsOxJNlGm^|r$BwTxx|-m~-~Np1M6u&b9)g}m
z%@-b-cb$N3b-F=5y(T6`m%l}2%{JQge?x8yPN*__W3&4ix$a_^4s#i+IjieSgzO@8
z`Nt1#XB;_Ue0#)fb)&yX*~$3cnc8zu(xJ9a@%9E|3jGwd@cv9bESTkNR6VGD{S=KA
zF9*hT56h$dr$YfOg3&D?RL|w#K5L8a^_ql0%q$sNbg-b+M0z+AMzOOssQ8Nq7+rLz
zKo#hS9~k1F$tbToovxCl`AMV1kBR95?p@f&a^LSzqTMJmqB|O0@9C2fDi-oVZY9M(
z>yX=Z(E&HTxO-=uu74kXUBrjfCCGig^Gt?m05LEdXv6F^qUeJ*m2C`Zdt2cVqTDXu
zTfYKAUF(L9o;rN2$)$ESB`E3o1qGq6yG_x8XKPpGhheQ-qytIb5$1d1N}$PvaR++1
z@*)bN*Bb-EVqca~15D=-6vfU#e=Y5jCh}zFjVB~4lF-Tu&uA1M#h&E4mn<~Sb(DSG
zg!P-W%r^Ay)Vuc1LAuVXm{Q7P`%Pxp^RBa2CXms-!ow-ySQ+3>CoeivAmbNY>3rrz
zDN)vH8O!12Z7<2s77T@0?7Z;nT+nY_e^meC88FM>R0`9*7_WJK1=zc|Mu<7~Wh@jk
zef{8f^A+EuI&sm?rPnz1{Fjqa<2PE11P0uccV*BMH!)w^lC>8~LW7FVbUd^$X1(ou
za`7KqTx#WsJUX)H=U$`(qb~?BFI3p@%?kbs)e&zP8aIqG?6#^0p3H<F{#*kFYR%`&
z7@oU3zpK9sj@?&>`?bFYRB+;Yd5Hp|M92ZN+|gc8qs{Nt>s1cR1``%{>W}ga0nqF|
zynj(YUT<doQmwFrU~eDm&Ihziwaux8f@1&x2Q5MU$RrnOnNVZ^H$E!T*S0g9hdgXF
z<sEAD3QG`*fFC_k*X_}BzHYei4unHc>;U%N@mmaDL{Xz-mhftHFjW9CgEdB#N&gd=
zc7EJZKS>NnVHcOkOKo3;Eh?qaUu{o`Y<u$vM=WHNah$5^2+kLm{6*K!R9^l0!2`f;
z!Bx$8Dr6IRfB#V}A<Y{bvVaNf)o^;)+<?tQ=!X~F`B`{HxV}PT2?hq;jiBFsTrgWi
z60y6K;2g*x1-e*~rQCH)wAbh<QyYmlr31%P=k5Rh5g8-byz~==Ut2}TXj$Aksg2Z)
zz0kNU>nV*I1}E0b(8*H94AYfO`zQU9n>K?}hpH@+_)+qoiqn08n4Ptvw@n7W0=NTY
zdcxLi+Z$ISMv4Bo0gl3a$-5u$=>A$!YxbSNeW|(Vf1XJ^Kj~73{QpAQ#-Zl~WaLRD
z8G1P;Z5pd<lotOZfu<X_Qm<R)VR5v$PzIDrJ@>klK??lxBIE|}$CAud61^NIO6CaR
z5*@i5NX<v`FJEeL*u`6{k(-)rx#9EVnh5p3zyQ;s>8YNrVo6iR>I#^^lAE&b7P%Hc
zA#%&?gZ9_e{9Yhn`6ub{Nf_~Pnk!T>Ew{zEZ=R1g*M(Xfb!hFSK6G2<j!Xb)qav5L
zm!lkV;MUZ^S<X<O;g^VtPv`J+oJRYnA)4^czBtaUnC6+Rp_o~~$`h3x_II)<yqO|X
z{hc};sq)VHPn$TRU5~jW&sol*&+1qp9K8WDX?qNGu<&qX^`0RDE*y)iDk~EdYCIn~
zYVbC4c$2dTOt~=f|05pN;$Clwnv`bJ!E7^l;4w|RwiqlXQNb@8;eE_T9kvkuRI35H
zK<vWUYxmzEcg?II&G*%Q<P0OW8qR8|LD3t_#PGgaPC?q@Nxk3k9^ad+b7Z|seB{%-
zVqcfn*C{|0(f~JF4I5tfet!;F`y<>!@_!a*(6hT&KVFMS2y^z!4{{}O3=mP-Vgut4
z#pqhqJe=^Bc3-(kN_F}ox;gee4MG^p7LChGH*rd`G@>v%lJ@WE&bjDp|8|$}tiz-)
z>hb$KoK>TRH>R0UQ%tV7Og&xa<vZDL6Ny(5f@-LPE=s83+1Bs`7~tQ_a8lS!bM#`|
zek@dVw4u^97V4*{|3`;yx%5|GVNdgr-$*^3iH1jN1uZ6N3_)!xJJx9NL8xa-3i_W*
za5oV2Bjj1;b1;kh+s)2ht>KwPAv_#)Tvn2Q<$z*AbaCDGOVIo=;t9Hu>}W}Mz7mbZ
zeX1HfW?XX&=-{7~=-Ngmd!-IbcPuMK6YrRkihO%Vhw(B{2I=v7<h7SB9rCQziA3i7
z*Ix}sH~^132-H;Kol}z&=DlO#j_g4zQ6rj*a*Vq-ydF=PK<yaEHUtL)cm?b-jCF)7
zxjPYyWu4!cByFk#&kkKVjVIcp&z=yb<(LDSo&2!5TF+VpSqVTQNlywCtcWhhFNi|V
zS8&jH6#oG9s9Byk`--m)TBj!A2!eVdffNv{ec5Am@C|ciXjIT%hOf-JYs1z3#6wB=
zP(T+RpI1`}_q4SPV44xCn|%ABN#>?V)cy8{z&irQGJd`S(3x+~njviTOt}h#^6$d)
z4d{}Z(&Tl7Ho=NzP+QvOVQlJ-Vw}fhsXpY5xq=bFs8qzP$ln?n4NCmdvPT!bf#$O?
zprpkDwlUngm0ehwOic{EcV+Xi+6GV7WKfsSP3lBX|3L{U{D2k-zk@;0I(Q!ym`f~K
zLBH!Zieu8o27iV6;!Y=YVYBic!v!ma!JKuhiA$AQ57>Ac9J%(xrOE*oROS3E608u4
zrfcqZILCLlXu9Z+B4&tg6wCbb$wd<jJe+hp7$FpUE^}sUc`=WQ;&9|&wQ&7aFZ-=p
z{1P()9Y3tbdSN5aRu^M>fWnl}W57^yNo4c~k0V=cRm{7t!{(&J45%k!1W&p;lG*e$
zh!tey13qK>n9cev$S0|lOua0zFv-|oB`VP@jWd2V3pe1idf_+Ab->t|AZ?G8@1r@?
zy=%f}*stg;Iz%<c!zlT)&cA#F;{YI&>X%1)V+1<5{42q74RPWTEmfc%-M=qUI1H>h
zHde%EX-SVr>r<y2HKj6Ey{WPWl=JMk(kkPu(wcHsKjd%JrM42UoAN8-bC$C}7%eEw
zJcxx|9INMhN9cK;CbLkd0WVAl#2S7>NY|Umet49|mbTS-_;n!rnNA4Z^~6D&BL5Pf
zZ;+W~$}e?&P&L^Gg1`M{P0cFhDEJLJBYS<N7q;tIrg+i!1Vs(K|08;l1h*9jNw+$2
z7PF)Z+>Cq)R?o5T4Lx^p(m;)8oo<TFw+Z|qm2w&7;Jt|Ch!&HRo{8?PizJ8>8D;gG
zX2%#f<h~&fs@a)`lBNvTt@BYI?_`a$!;#Ha4>ExoQx!j8dJe79T=6-XA(++x00}@r
zOtJS1b$XdYA~tkKti&h%%)RqAT>y9n5SCF}QKNdulISQvHq%8rH|T-^cgak`PHqG<
z0y{5Sq5B4`wVA$#w|-fNeqhS{AK7omk+U+EdFFCO2rymAz-cTp6xgD;K3hQ?++Fy3
zRUK}Aqhrq>k(ZoH@CELw^kV&clRCrGO?&eTL*+J<qkc93azKIflle?2i=^U7DH+a#
zfdRW&cVeAwc7~#ID31dSLxr@rCQ9rZweh@lH?E+rdD<{xdq;nHz5^ngg1UlkxrA$w
z;V2ai*a{up&;Vn#{z4&A^kDNB-;Y_y0+{D&=FQj+iH?*s{s8(Kiv*!G|DarSV{jHw
zBiT2GdeWFusKGxK#Z?M>RHR2iyq5qC{vYk6Ohs4dU5bkDd!26pRC#Zl%#5b2tyWO#
z1{5|8kqSYxUEszju&7Ie;9?#GUJ*mEsU+(-Pf`j0r+_iPWvepB%AM<*IcN*OC;xtA
z1G*F6vx#2>RG+p@d&N4$E1FZER5cj2dI8|Hsy1UO%mT()h~gT%R?r*%yR{+OP5w`v
z1r^f!UnTH7z(gnWGt99~gTrk-C+sFo?Kfcx_fksxVq43Mn>^V9*G<eyOYBtL05^)(
zuxho$>TM!!Vre#NhKe#@<cXp^uOX5B-S&I>Hn1sKqGs3qS)ua>{84neSL7Z(a`l@x
z^}IOv(qvBSD-c!c#F5^uDM#{P<HAU2`p%Z+SlaMCxc}h67<X&Dt&NQCEo0+})UfC$
zI}}B&cvb3VIi^sY{w|Bs00QeJ?~CIljofn5J7L6BWk8rNJz(k5dCYiM{nx@*<Ns1A
z1Cqycz)Xy(R)rQIigxTf>ZA`n6S|n5?v%m2^uYlYV5Y0qBNKLA$Pi=N4br)srT<&k
zlscCM^VkkL_*X9=K+uV`ZbgX1xlLuR8mmIhM=yg~5r)YXFe1M1#aHV+D8>Dkvk|`6
zpeP{B7lx;mK_tFU!2ic<-wf08L!l$nV>qG9n|4F6Fp;Xw^9z*-y^W3FsaY6Sh)bs<
z<~5$-x-r%Az@`fchNLk5Dv!P9lRG-~A>WrJ-FX**wWA?9F_vHeu@kbI2{Oc)0-LOo
zr3$XXDS!{~ERi5(j_#h1asco1aRrfEB^8NEBJTuX4Z>~ENcBR)A+tCRY@H&6(0Z^H
zNW=C6n7&i1e__w8h_5&H5_KUyY|{vIx1p&?rQin5d<h@5<>fUsFsy51{MbJEjN}I=
zM+jJ3R9=5mj)drpHIh>$)+Ojg12sF2Os*On2i9*p^11_RqoFz4cYigg%!d0xPk(P8
zq&Pr$G)oE(`%2XS;|0@+S2z+jiUVZ&l=+9K&B&~J@p>A?<Ig`0C-WT#v>yJ;Sh~{N
zt1{_l(f*Cr4C7)A*zAAZaGs@kgsCmU2qp2lTdTIlWI~Ya0Aq5TJEC?ED$8EQ(Sxr3
zSwtwpn$j5h{~2nU9SpNjc>^LtE}U++$T}TJ-|f@<6@hD8<Z^fh=*1Q!w9{;NU?Q+q
zU7^x{mq0&L=^Scdq@nm!t!*=Ec6WLEC9H1$@=iEqyO}b4qk>fyLnXWF4f1|O-|st}
zRD6?i@n!O>Ung;dlVq6Db0l<Wev3rT?#c||g!UzHH;o^n><;gcwSsHUo4qUfW+2`1
z7!R{(UhI4=K(1ehKIW<SC^$8lWHHDMwrfkRcpiMK6>_icJglPzAmky9{~v`4^1hdD
z^Q9LiL%6L@_W*0Jg9UbPYGnHv{ia%bd5268WB=zhn?y~RBV<r)7V)R8>YS=@_eX)<
z8)XVJJz+E*mqQcbdLKQG#v{GGpX0fvI8$*nws$T)A3DcxRMNg)J0Ua6rvP;HW=UR}
zT+b5c8YtL2)OHsfcJvpVMXeWl6Sr7&2+$d2(~#M;4OR(`+EzHbTlTLOyDpd{f8Lu=
z!!Z+~ub8ec0WxmQ?Eds6rUz*_b4aEl=6ad7;AC)?@7wuKEzHT((0mo$sIhMx;X(#r
zx|hxDZ3qD^NLgx|JGk+eNRosX!VyeEWngkM^gS!P#fQpqS<ZKWq4LJ%*B8HMhFa~I
z_5m0i$kiPdWPcfiV(SvJTN|{t*4b+342LrZ=JrXZ$1=6JB*?Q@l6kw&FPA2)LiyU5
z&&>-<h#10Uq+m&CgF(^?Pp_gNX~s2=?&`T4xaI3-@j%2rt8;WruX;nI3T(ICK7K80
z2s0)nvcshPG9}uNM`-(#>UV)xRfU%&TaCZ(^3zbq+HO7zC1hJY&f`if%$SDsAhy|<
zrJ}F<!9G#=84`myn=aS9b>@CjF(yxVlRY~-Q<8X_LBdqM@HGeORYB0c2^9+L5#cKE
z#WQ;ktWmGl|711c%+1QR)4(#^Noe{!ky_3%KvxUBJ{q$`^1CNpEhvKCi!FNYL+FYy
z_=nErr43)#q3kdz2$2RZ%uS{*h~P7%BwQ&<5hFm~-X2{IDx2yrtMciS_}#X90`ktD
z)$N_ERETQG14zC9pTiV}d~h`QNe4*{J1e&5s^I8SwT#b}j?CA+dzWgwkcF8)^4@c^
zMAcS5b91ok*j^9A1;P)*6Y0^M5t#@i6`>2w<60k}Rp>If`|_Nbzn;uCpz&SU7E@hJ
z-&93;t)$A!wL<P@6nT(uTv<MGwNpC0pOKV9*RB?=u@!vS@m>`4MB_p7pyUF<M0}ca
zJ$GDb%%`JKn;`Py{Dk%wU!TNUL`xX*xVgj*c;Ol2sT$?SAY;L&)A^pktI61vJkPD6
z9+dS)Dj8;72JG6^V_>r8uwv%RrIdlOayj#3E_FHF%F)CM9W#>0<i;%8d_SD|1rD9l
zm@%%vJT_f5N}DesOYYUegY)xVAd~N$|7<Lp7hT!%U%BVcOb|GHHHmIyFsiDqa>5X!
z3Sc|@S9Dd0M`(`2>H$&^*7`K-y+O?#!-z$`YVmnvlZ+L3=41K2s`hxgf6oZ1t?~+B
zs1J5Qz_w4#+al8;fkDU|1-`Bdq8H>xq*zN!WsW+~Rr`4${&y1F%XMD<h4ZDI(eI3U
z+lSlyJ$xN>`H1|sG*XNPli4KGQGwc%ojBIV&j>AbK&CF7f+|FOw8w9WH1C!zoleWL
zMHi7Mu+Y;2nPwfuckW?mwoWUhnu~(`u|fa<016C2AY5YBJz^t1bvW(EU7Pw%Rhg{<
zg!LYTr2ke)6rWV&EN{GTj@qX;cEzS7E>wv~7aJ5a^^sPT<su2JKSHF#g|4I@{9*vI
zPoGIN(>%b!$rdPqC$+U{LXQHUXtIw$)=C(0O=ZRG0iBljMa4kEg}G$Fndq(7;Ou;u
z&n9{3A$%0TH;V?1z64!;nN_!H%?<S@6=CU9#^FU_kQbUbk^dbI43YL_4draF$IO9#
zavqd^ikFMVK=GA$P%uFFxRCxz=5x(2Qz^)q_!c62MUN5~W!G_=7D~+0Khi=zBm#}!
zw#`E_!xwMoRM*9sQFhTSWx`j?WIXGD+2;HpkiW5)^!ktt)$C7!=u&`0MN`7ml^mc9
zLfgk1afG389OvG2&oybs(|6-eX2zI(73*B2z4EI<!+3iQ$Ty%~-n4~dm7aCg3Ynlw
z*|h(|nU0~*Ibi6s_+T?0PY2`uC#?OB5@{c==_ulG&(DWyBJu|##8Sz6&zYvzivB)6
zmrQ8s+fs=J<;zv9DCOq8Yz@|gXg-X)6XQaB_`HLb^xHQSHk6aBI6HhQFzbw@Uzy2<
z+CHnrZD~))0n@Mq%A~TuW@@9m_C$|W+;@ti&I8eLrhw9G*1GCX`4C?+y!Hx$m%CnG
zR12tk4tmAQl86M}sY6&+FLlnxo7BY8?(r9IxE!>IZE}GAMPZYNjq^<VmYeBg>vXcW
z?Q0n9WD^(LYmKs&Mlg&gRmX%{PI(`K0=R(OI26Sa_`2)URri}zd!%LT-KrKiyn+m6
z%1KY7qc2%f=@x&A?e%>_OVQxM#eVo~5DwT^xPz4j&eF<;Cd`Ivar)ET)<|7q;1&zc
zky5|x;|x2S0*iNf`Z09cix+1>K0#`pGfc<5VWouf@J|#v9SNw7$&%fRV#_==ty8=r
zf9uf~=1?W|S?LsS7dZH4OgA&rW10eGmv4#7->eqnpM7G9YJS>&&Hkep!MIH_<TR>-
z1)iz?OgwLa&!meNe1^y!K<L9tmrncm^!+W_0XA6)Rs^}^BZb~?vl7hHmhDQ?wfFl$
z&a}6ua{Cu&_2)b8Ab<_l))rAhK-X~fKbe8HQp;QISc{%0cT_7p&b<J0um}6EOR2XH
zED5jA1c1t>4*P^Mq#gshf=k|2Y(9`=;<n5yy_x8CM77uu1>iiiso%ZISUe4h1QO8r
z&6`6!DJ00|th8b+MS*ow13fjHFl+lIi&tl5QjR+Ua?N53B$^&wN0hQDIBWn_z3y=H
zEn4$;_+qlOkVEBs6%5WIierv3b*zu%B4E73!(m|K>j06IH%nBxi!WTIw}QWq3t2=k
zZ0zI`GLcrn&tpyjlrKFx^65U1Pz>+5*%Z4Yl{?N!ZXbT<wIdf*?EXz=apgJ?Ao?_n
zyMR<`v!wO4_j+-}bDFAGcmYArVoO!OzK}xoPTzq%gZGqhys%?Oi^!VE1X<&vG3<~v
zlJe_TSB{_wNHghW{kUmAg4H(3TBGsb3D7a!<)e6aOZ+%=8$hfBN4IMk$M0~wS*EYF
zE<bMQhRi{{!F;p8`g(UuJJswkyW&Kk^^Ao4+BrX6rF$~hJ;yUUOz;KRA;NqgBdY0P
ziDY8J>4rco_7yXpvoSCIOZN7>+K==1K_ZYdxzqtDol*>R+VLJBW3X7RR0dL_$;8N~
zbso#6caVjU=f<^1JMu%Dih8?%JBa+FL$q*u`oJOqsonczLvh8ho{21!_A7(Y@hZVf
zsMXGqaP{-qo$$LgR!wocXU}EQh6-Cmem{_H-3v7k%&Bh@2-V`@)@t>MbQ{ZOCw)6C
zZwrm?RG^}^fRxF9O+%tVmYwBL_u+H!3RJ-3o}0A#1Ymnhk!tH=S6i_$9`~;e>gQ`A
z9*F>oxlnRmILjN8pv;EF0Q@b*b5=w~h+S%m-o{sZQqs<rG~y9i`nS{uxb}k&2%XyV
z+xv_J(aZafCe^#R=TYeYqCm{sD^Ehe3g0+P4EH7Vq2TwGIm;c;(mR|A9^|Se+=(0I
z_z}Llf6|oEv^S6&H01wa3V0ZFE$Cf^q-8QFRzBNTj-VFQZeQRKG2whyuEpQd9q3nQ
z;2i%P1D)F51Ee*MI0E(4D3xyw%Br*Hf{eYq2eOn1p%L=hYNiWzSTEu#NUyRDYuzQ&
ze;jVbqNwpRi03OoIOXd3FfffxsI5w2)9*Fvgih?kNyp$Rz()}-MU<x~Z)8obwVPzT
zPrb}RZ<hCp$eEQ!3hu#}y!|~T?-GhSvxPsJi=Rl3Va;PQPkXknLP%@Ub6@FLIp&k+
zN3qm~2uD7^hiecBZm)K^<IB3M5}nI${KOqn!kK=cOqJbw)(p{8ZnsfD0>oKRvFN%X
zHR6*w8Yiv^h^yupH955z=|nCzs|?~A;nYy^bUOjKaU<vvE~j));(Xqli5aF;Jnt||
zrA#f3k>N#IyMEXe$o|4Bdu!d>bFC<=a8E+#ca)pmu-XDdo!Se*4vW*ojfcpVc`^%(
z09lB^iZHeMIRpTtDZi|E@WKh@$t?cC0;t4QGE>1&v=<Zq{~K<NG7EU~K@91dw|K4i
zuo*ep3rPj(ShUpzWg6QR$4Z^h;wE-pm)J&IZtG44dH95Il5$D}OjWWsD$eN*Ljh<P
zT<GKUR91%4xmxKFVN4XKT1&ieb*8(+zR8qPQi`h*!pK6nY*`|r3Q|#0@*<>HXgUT&
z`$Fjt!7|o<z12FM|I)foP>4ZiiGh(1B@|^O<S-6e@)nC({nsFQm1@v?EDTMgiv8|N
zeb{s}SOT44tF`KqipnGa%b^)zB^1dXFnzdfVC&3Bdn|6dqnM{6fe~`DuX##cRgf{D
zlLQ<*M?l*7ySqX9fhv|2`(FCG!*i!kKcJ~Re=7#u=@BWB-?kj@`x@&%nJ~_<H%dV$
zg$$zHbRB;V<!2awjrbQgM*URz#|QwR!>V_kcen*3K!;qbWf_Hg2K{_{GW)otON=%s
z^Er1Hwc}vmGwx@vMUj)va_tYv>{G92Bt)qvDq}6RX>B#YnHy`dg}Ib)%&?RenwIbU
z){L@{3>aB7fLqkzRP7!$CH>d?7ccNweYu%u3>K%lctb~pD*4JC)+Ak8qo)GD%J|3c
zRuq|v7cL#~KxzGChi^0BG&1?gDuYxSJ!LH<(5@qqs*_?|<4G(q0%nQ74J4a3AD`x|
z7A4CL2}F;FOd2Ol5}-2VZy8{WYZB7N3vSF=hLN7{99Dxk2NCRg+#J*Q(W|4=3ELs6
zfOVU>MM$pZ)r7s}^eTxK6<I5B)$jPUj9Xaxr!n(_^CluE59s!IH-8e&*)v!#i!$1O
ztNK^;`ZGr&s>QsU3H`fml*%&eF0ZRtZWdTwkn#!Ev=eR5?tEywRD@jxJ*)|?#~#b7
z{Gv1f01LrEBQ~NiGVnpnpQrS|b_an73PQDKm!Y!$ZBf|>1(xuibh91|S<bsdwy+7M
zPNSH;%9~%+6Rw4x{U6TQ`PrkubynUUal!!M1qdXFHlAPc@em4Uf_-0cwS9XN6BgM0
z0kt9)?hF|pq*|)Qmqdt2mrJCkp<S@b^mOS=ZxGpj%)AefQ)1B?S%opPTe`*e_wD=!
zx%&-03qBA^`Z7pVKj=EXAqi$t$?2aN9YUp_l1nkc3T#X>sUfOHFHJ6fQtY7~lb>RW
z5`j;rDwaZi8=c+ixk>0LEYf*|BtawEf>WLRT*A;#;mw2h!jOZ==mrCpMFJSpoSK@a
zLecV4#dEN|ou0Wa6k4}Y(Oy-8edI@a<e;WO{K;pfe~f@=Z=@~%<fl|{Yz!W7pOlhF
zPbd$inS`J`nc~A)ocU#hQVTWsU~)T7`P6Sf-y7kbL!dMw%`)r@3gi28nA#WEmhKdX
zwk;X{GIr{-F4Y^}S(!7j-c7Lg$Ux)dsJjW?e17}VmaXY3pZ8mx9!>Gn?bhvrH^IzO
z6Jec3m>sa{p$>AIh?_YRA71$WpBCw}88B=ji;0isZwfEhF;RWGBkoeWY4|Nj$P=g^
z98dryyFN&vhbz*C0q?oSNeL}-zXv}poGV44v_!6ok>(NDYJ@5}F<695iX;fea(eGw
zYBv8NNU?G4UE`2MWR?DjEvLtxuz-LoQO&NjmvC1}Rr&240|;u?PvU&L&UN!UWFtxX
z4}br~+Z+Vl%9{EXN=+Zi)5kgQNUd}%ViC!mBMLMS&pDt@NMj+zlk!oNE+d7$3v^2C
z>Xmg~>3WMuSWq=MR{}i>o7CL@*Z`M$o(vJ|3F)9Iq>rHJE(SPXD3ycVOTNb;Fv2;a
z6~FqMV>LKFF!WVi1P{mhpw#lXI{m%VyhZF;T~njvC{oA<Kfx7e)e7q|rMZPg!oVav
zm+swJp5REhc0UG3Kl)MA6LfaEx=WdEe^)VFUKd!p*?Tx9T%&2gJWr4eRX5(Jcdgml
zn~R!tg_(CHAkxHm6r^Mk|E*l;h4vNJKevaT4c70+ko7j&yE5Gh{xXYh<=6!Yb9xD^
z+L{F0pFLP};P>+7p_uN+o65T-fosbinHZWM16c<TJR!$de!vm0L7rTvo|fpzm<Ir<
zQTKOIt9rJ)QGt!0Twy2A_5_%jxt3-t<?hjzy81T>e1{5XJGhuSpFfrTzZm;69ZZ%k
zS1)ETag8!DY0vQKdog3JLd{AS#<hi(7Za$g6a8^k0T%ROh?QQjE5NZXbyM-O)(cJ|
z*g>$uqwse8_Zy^kHlEJou6=WB9Tjv9&&;rqSGaFCue_)%MCNx^oaeZ3U!a!W_3eeT
z1VE*&IgSv#?X6$8!DFeYK4%0Qj|*0+YCf;$%*b@B(l2DG3R7dgxbY|UMM#-`7Dv^2
ztCy4H$^6%&Plp1AGZ_+qn~3Fzr{_7rgL^+;XqR~m?aW?T7$t;=bC>q`9d+oqh%TlA
z+-nVaL{HBBQ0I;E<#P;veesxHAqR0@DrE52tmEJSfiftdC+M>tX+4(|d^b4}lN&v1
z%}o-kD`MqOX;+~w#E+hL5iX>mA&=PnP*Md<9=4`nF$!6^E_O}4)B8)#`Xv}RTxb!&
zX&nA_(Pjlh`{1L?)TaO#>Net7xnrtOQ}V$LBL6~TQd{Tx`mR!9>;{odaPTwqW$ZJ+
zt0>8BO{1rRvPbo#a{Op}?(z#Khs?m;)X7X#&zBzjV1frjmCtF{bl+NDvK*0xA+=?-
zXm9UbCwJHg2V@~?GZ5fyk_Tg6G{yb$qc@?v!H;cHRiQ%n+zM-pN~Hg0#${w7r<ho0
zwT;#Xen#;>o>{Cnyr9{MXKoncbo#^m4Goa-b1Z_F_n3cDZ`VHL;Hi9Hp{G1m^2`_m
z1+`k;{=d2Q0ft-`rW@4nsuO9>EGS>+T@w`&gHaM+0Z*p#!{@Pm6Z?2`Z=F)GhZ9n<
z;^Pe7zv3jiHK@GXQGZUs?L*586;Y8R@Lay<QN>@b<DuDWFr$pXZToAu>|_#dMc;}`
zmc$=4Lb56f2*&pQSFY8!a~vJ<qz#_xEDC>z+d7uFjq?uX!|>s*&TGr`ero|nxQbM6
zvbfE}T(94Hl(6#}ELe>WwU~bcf$exS!P#%*NwuYyRc?=M-%dxNBlVtZ;d`XB_k4rO
z#f1%~O>MCuX^n55=`A?AGE>pM<EboR;<8?0HoHipyC~I*<3Ip<G8yU$alv~Zn9UFa
z_Uemf#wKdHB6GruxAmFG!8QrSr&0?*LD0mnm6eIVV}O89dZy<Aao_e{FZR@AyiHz}
zvca%IRF@2V&)Dmvk?xf7!JCMQGKys`51TA+S#D>_v4C>d(((X?q*oDrObf976p+Ks
zwTd*J&IQRQih%#Dr&3S`P-4;i$byy=twir~CyshvSsYkl@a-ef2XGyrH*@I~&D;Li
zVsbfTk@rQ$BW<wumD(!6A)?xZRQFIDLjG;zrzOZdK0`QSU~^JDwOr)ASo_~Zw^Y?3
zQ`?vbwAsw5&<D?%%+Cr)ktxwYf`e!eIrp7{8=4hkwu;v(yJzk(<D37#$Gw-?%CepV
z?9YC{)kX`>(<G;1t0y)FHC8-hZaB~gN*5#AN+y{*Le223`3#U;lc8@sJ-724qa?Nv
zua=Z&Sl3&OT1&VU$Pm_TRhSQj3lJys^|}7G_Ya6`6)C-tARqBAzUv;uX`gZrc_@d0
z25h;sk$m(W)IdAwZTd7A1)|D!#5M}7nI)~Xr(!&xYt|}GgaOP~VL9pC23;TAW|6Gh
zQ4;L5Uc{pqPaz^5N1p02EBbh~hl!^6GO^F*zsYM2tc|=|`$s{Nt^5u&M+(X3H5^mX
zP7trKeqg>Gl+t)k*)QT6=s#|`w_U!R*tJrUEN3Vjq_9t9Al4s|H{LcF!OU+TQ00}o
zs6ycrU7d00-dN^kY=UlvU&JySvl>>F8T=1<%!HPmW$q#!<I${m3Tg5!##Kp;l#@Pw
z9n}YVB`vdA5g5ZdV3Tu0U~q!GcPt@sd>Rm(`h~HBuDDC!eCb@Ed$->xRpEmU{WMj6
z6?2&te=XTJkeAcla?1Ec&`vvpFqn$8H#QU8`(eK<YBJz!hp>W3s&uKRX{0@eG!LUD
zhLUBzxQ8KubWuH9uLL{|^7Eu6pLgs&?{N))eMkUsrEDn8m{v?9sfuwM`Tt{eyuBw6
z;Hy&s|0R-&7E=LCl0~8GY|%Ai7z9cnz^duECd+_kqRSS?NpZm1B!CTjELE(4Bqit5
z(f)TcYQEQ-V|5Cl?-J{0LCCE?T8HiLTsGZOytJ2P1vT8cHMdl}R@ZNC)<7-;ion^{
zq{GS|2v+d0e($E#-<(bcykqPwUmLJnn&CTsGYa>|Duey6js+zmLI?WEW4+d|VIuRN
znoZTd0N{4d7*JFq_NYQk*~gKcR(^Q^{(ahuNS)iMz{SNEdjjm+^Fb~RvF{<M_m2%W
z0pu7@51O6_)&Zj&#DdV(+Tsa&hnQ|ag+wJ~SO|6j{J#0&%1|O^$(UR}g~N{3w-g)$
z`f6E)5yP57rKC>>Oj?&fJdZSw)@~+Z)H!%2PulWIGNzwq+^?x5P2)L{n*C_Lk1Kbi
z6E}Hb9bO)@8odHeqwIaA%(RuN-GxEY$dKtMqc)%(xnA}e!)K2V8<{x-;t7~X%H^ms
z1aN?<<|?c-ZELv4^}h~Tiy+ANz(N}-e!XHLl;L==18Fz@=Df^&1#hIiz<QIW`^nHi
zbTIi4o(!v{AkTU{UW<Zm!o<w<)nG8ixd~_R1H+)DVE<WsrEfJHbdoUns!`+n1QOQ=
zU+=`DRkqm^oPz)Nm?L-QERy0D`O=$VT@EhtEC}t6-kzI>mH@xf__cMM{r^I%b;PB#
zp@Av-dp{OsC=As_Oh~%S;`<)3>D0Q+t%%^b`Z|&4iUKu=OOHW?mcjjfO*cjg9|7$?
z000cQL5ACD?*4=ndqZ;~nS8nLQKf!LM?nECBMJn<^<1(EG>DPXQ5c2wh2w-PScW!~
zDX)~;lQgwr?<Pyxc?$?+jas<0jBE7<FIkZo`B53|ufWRSM1<sns#Y_kh2TNQjzote
zaTg_LY)hlX{@uDD?!85*vB0J`o-Qj>_r;rRIwadzIU@nH-Ca$umpqpWLY2nXGYSp$
z&mSZ(y9_#ub&R$>w2S$Guq&#q|5)o?TNjM9R~-+QC!ElX)B(~8R@kYYdz~aZ4w*`g
z7n9ou8AGiqnO8=e3Zg=L{rgQUkj*{7vML$@$KvD#lV}(&AxGjDPMR!GNr`A}&fL=O
zseeD$RvePav9)NZ=!H2mJn2CG!R$^cT1|nIE5<$nqv>if;M9rMd<$Ejxrx{A@{T+t
zVXwKvKI(p_9GXsszht<CO1t+9z2dhCycG}$EQ(Anf!Gma7cROU=Rs5YF(g5B_(lOm
zDu0pQ&oG}|CJy7ZnGPypmg?UEif8Ym5;j9u8R_tr;#be1fQZsvR;<w5C6Vs{l;cPS
z!T?scc?za2ba9_B(|pkC@K06&&(k73v7G$Z&|GyYL3=>27Wsom&a4`(Qm+oI+$Y?9
zhwX__?Jw7~okIi#!2kco1SQd{q$*LP;<%z^?S56_S0G+8S<IT)2hI;90i8aY^($9X
zUH*4%;J3{r>w332ZdildE^U(43@FC@*|&*}h4TqF*rzsn&uNnR1^FIUR=Jkh3t>@c
zPskdAP#L=e0|wJ+5M=zYw%|Ut#^C4DjnTMC4j*`O!-y-z!{et*r+jo|CY+bj)K_+H
z`m~OBCFg~FPRJ@tx(cbmsdmJZtq3VtF~T3`x1G3Ckk^s6V5sh@jpvm9n62MBbc!cK
zYnYN^@SEmEnBq4u1sur+n8b(6eH!6yvY;SlWtW7C|Eo}bqiCF&2^La^u9P8vK7<&)
zdd{uI+&Ht!pgd#9uY)H_<V$cmWYGC;k{?r&!dpzgrYLfY6JxJU+7!Tvv8Bwbz>a)k
zulF>?j1+75;pff4%y6ftgLJG>p*#L(+g?6T%}Myg!<!0ff5wC!+GB_PWW)=Jj_yme
zoS7+SEP>-uEuuZ6+;U5_;+XDAdTPT203ldiDv-qnA^(^pWtZJxJ;F`BRMw&JoKfXp
zF=+yZ<^&4eomk4{j2k!jro+zR`0XwvH!jh)_}%jG08PrBIo<9Y^6g2Ut)7Ic%kFz0
z2fB%|?TYS=q57rQv1Wg-(@zNP(ZWRMb#1`fV29J6r764hPPVDh^NEX`>*TmV%jy|>
zZ`PT$3By5-Syi4aEg*mMRr8{ADMmC5%Q4ZGyxfQohzB!e;HR`1wli7|84adq3pMaR
z2$tIW@vnf(esl<{cb-L%BRvQuwug9J<zd7HMZt1|;5C%Z=aZG2W2(0<OwK(fAegmh
zW>8%PdrlV2)QLo}vr_XV$|(KktL8h?bnSG&ec_&FY~ty^41T%SLJV2#;P36~HD?=M
zCJ;r*!6~Dk>)WD*mU#RKe)m<Q5odZ=Rj!Ko#o(8PY{<v5Uv@75lN}SvD}mCKM|yMh
z4u4&9<hPdfrDk`fnslx?FMH9(!xaL4yt|j+S#W+eRSje~<KU+HWf%Lc+@LT?Eh!XY
z<8`+SEE*Ffk`)>kygW|qG25PD<}xGeU25*BaRvE(R=d;viO~xQKbVW6@p>u|QkbE@
z%-2ZqEz?q7+(NZ$zF?S4Gu)zo@8R%UF)5Ki0$jsGR%tqqwM|<`-iX?0R1n49(<G5v
zj@lwA=h5ckZk3_K-{)l7ZA6XFxQP8q0s2ma=8(*m(bJb#70MZBS<zLLQ8Gt~N#_;B
zNUBRgw2P-H=}M$_COBQ9EAQUvi}DI#MH-c$LG(;7{AcbGiYHPr%TFGKA0O`Bc!NDt
zU#+oiQpb9``YV7B8AoGPjCsMw$<^}sG#-NL_Pf?|p4alBxroZnN|sx%R?q_(EKo5`
zt8d-3ia*U1d^)V8cwhAYx_~=rU;CW+gPd^MeqMK0P8$y${>1MFJl}c67=DW7r#is~
zyID~C!5+_PNd#`tyn<;Hw>%*1+<iaYiHpValz{teWkxTQ2W1`vRsfS*=t7tpVKqWM
zhUU06U9Ctk!L#%VT`~QVSHkIm%G5u3$4aU9s0aj)iO*5$2qD4WpmBfww2t36uFSvD
z8Xx3Z*Hw+fOef)Aa^SzU+fT8Xw2E+Bgu^KB_!Rs<090Rc!k?ZMvUTpx409M~DZJoT
z)w`H%QFV~#FO%$<D7u&XAZfe056}P^n7}cAYEK(pFeq)_qZI`{`6{d;2i7}0--nWV
zZL$ELaDg^4O|{=$oztM$pbd0x6vwhmodJ%CA;-4L?5c#~a}Nfzb54>14Y)R35>Jrn
z)zFTB?&c~&6&Rv1nXxYVp0<CdLoOrfn)zmi5|aSTbL3kuV&|KYpuoY{g>6cEpY>e-
z4nbss9Z%vve{|)hnHqhW&{eU1+H3VMhMLVu2XcbT12iM<P$v5PIi+YB!^-z`$;P7i
zGjqQFR+qElD_ze(`Ss#o8vRAOrdfVYNOSQ$I>nL6LW$^!3{0fF_)mkmR3<3DaF;~H
zdOgPs6se#6TJ-YfB-pQlIB+zeic`yXv{>8n0o6DbtNrZWhP#?OM^2@`7<kxRvSF1?
zT9Z?J$;QiCMuDz;hT-fO%F6dU8p$_^Zv(nk0KcstJa%^TS<x(7gew_J^iUnZW4?j?
zH`3G20{`(0@$}S@M#w-_$-}G!dr>lh4UQAwr0oDaaWo?b>0PcRfu-al#FR)$fWu20
zeuT79ZO5hm)`1r*yBT@QtO_4H(oOcFiVjaeB_Osp&#l+!^Y1ACscaDgjjr}Q8Wj)j
zRRBdp<+%_J=l5y98?df1FIBB4ogF4M_{BwES!xypTiQ4(ptsk5A1b_dn*Mw8YtTU?
zySAT@p`U9G2whoj)~yOck*7xZj1Yvy_lu(kQTLn8OqC*Fe9W7CrG1Vy&DGh9I9c^+
zn8Z&)DpLiqq~-#{eYCY~zH(Vgrd_v)A8iz2n>~;O`O%KVwxAjW8AKTY{I8S(+4EPH
zcQ<-M9K1}3ss-O`r3~n>yM6&E>Z1#Q-dMGxbpo+OOZ|$?Y-3GzTc}y0U`KdJDa-%Z
zNwVjyK=M@(Oexwd8qlL81H7~d1DdFj{5KG(CEs$CME~3tO;(y{gYS}05)x+|Pmb&o
z_@k3Xk`IdSj3@c<h~__R^#9{L!N0X0<@z6f1Y1`k`0HKYp!JU(@yb8op)h=9>Q8Ca
zQGjeOY6QN%fC~_|i8?F#o1ko4UNZo*K+~T-bgnwGJm5SiM>nyLFNo$!Fxxksa}#Sa
z2MPeWn{Pcc?$6$CoD?)Nz#5~dGFAHDVUH+X8YQy^l_OmbzD0Rsf#mLK;?81d8|TK&
zT&SuEjr}NNds?E+LX1C;DCwVm*0LqJ4bA?s6P!HPNILuEJ*@X}S+Ev>?t&6a5O68s
zW!Op!rB>lA)dxT)VDzt3p>_*r7k!HwtlBHQzk#Mgq-jhU{X77m+ERD93bgBU;wG{U
zoSCZJ5e&N`&?n53j6XhRHHekw!gAD404teiwEX|F2uvjABM~%eDcv9&OoH9_gNs;v
zj)VCJ(j@E7x-9lY*1E@o=VB+t8kP-ShR~dxCy{w`BkJ1il1`%E-4eD2&9bZl%|^K4
zrzG~(_w1zbgvXuHbKd^?^JJR195txV9d6WU=l(NeFC&j1Jd5aXGi&n4ye)MduHfTR
zD(Iym)qpd(9osehB--hj8y=4j^|9$hq8`Is$1o+sCcRQj!Sg_PoaD(u-|ITWzKkL@
zt@%RMcp12X(GvX;0P`?{oMzdCvpeWNnKSbU-8+I%lAk}$bb#uL7SF`WPBgFx64<Mi
z`h1UQe9Cp2XvK^es~H5(r?trcZ|Q3mI2<Uwyn-tA=3_>J*Dkf*1etrteo{vckuv`*
zVh>Rc2AJm3+d2y|rf9byUroj!h~s|kqU(L(x_u-s2YYHnHbva4G6|O0e6U#?t92?R
z7g4afeJ2TQH%52m0NI@vqIa;D?^m&sDs4-`($?@r%Oyp{)YRI9m8c!~U{^hEIom7|
z20<*-n^)*YBO_=%eXK<mG|KwYr`^G%p@Uk#q&#x!&&$JL7{LKk;`U(kwP3(+SQd~l
zK>F&))gf%Xd2HSu^r#X<g1tLyePmy32|adJAGrq^>H1I>kBAL+P6U#^bg-z737mWN
zH(cp-j&dcw;~~eU_-eiRLdh0b4KH7j=xRBMIWb9%CjM@_000b{LEnlTJ5Lg9U>%%X
z!Sqq8H?Nu?p>8M|Ah`hzgIuKtB%bz=hhLeMBm`>xj9CVR!MTM(ryOqsKpXkLUc&G=
zno6UT0dmgtedxe!c~7gPmo#O5yy+LW-|`Gs{HNWzDTk8ph0^+(jdB1&?pazwkYOPr
zy<QA0B5!FlR3SNEHOMlXW#;&Mv9O$qKy#UMnj+S7_o@E?)mOY8XBYED<RiOa=;rOI
zdd~05HqJS;Lev_vHH@+0@+dId=Inf7eVqfc0oiRPhm)e`do+0TcW7zd%P8p=$0sCQ
z0W#!c77pr^`ReMDEj+YBHQTK{#$|Ad?9^V}zWhvzgg00uc6y*+n$E;6vLhDh@Gy$I
z6u-FuB!0{96EsO^8uChhVnTO$l@-8+OG6Qim8^an=%4KW2r}a0@`rj~&j8*sYmrZ2
zGj<IX+il+j?-C*OXxhSiHH}u>oYqyPkx|XxJ(W-Yx_xk(Yc#os!d;g!-8DEZ7+upi
zVKWmG=b!A8|EsNU4FXTdGtd8=9)<eLRRSCyg7_q)ELd!Le&oxkfSKy~eRhHMDmR{I
z;xqza*}$}?wlgni(c3|G*W0xJFTj*&&$~vw$gj7ly8@zxE?kOOB{$M!de$p!E5XEa
zHU$olz^vw%NavA$A;BH`)PHzwoNE8m>iuIxdWnDA>b-!JoaDBK_F{UhiKS8F6$)oJ
z3RUIEtU9-m*8fjwqYPvXJf3`*bcUdxL$OqupgZBNL$KZP(oFyIdw8s51+J(g4;$4M
zs1dtew7xoteL?tu#7lQ1<(NO;azbA9S~WHfT9R8I`h*C*N|$;S>{}RA1Ma>qFR^}2
zJ`;r73mM{>5!C}+Lz<GdJ4sYmGZtMQ5iBbxPn-NN<2LV@XPcZGHQ7v0wUBWBHfubL
zee)>6oJ*+Pu4#J#&~Sa<W1LV`d|=dXkvu?VtS>;Y^B{#s%_(6d2c+}ERP)DZHNBaD
z+-HiULb?1M59lFg3HD5#Li_H;ZH#-MB%mCkXND$qC)7n?Z0gRiLW?Is@VWdQcLYJh
zxL4H9JW<m)F`pIz>QZ#AWtBH}FDxpJ1U@NTz9d(QfG5gks%8KUK=Qx)%(g7LQaG32
z{12qzEARoTi$sl>aL35fj9?k>*M2CfELfnh>UR<>G#$lz^?1ae)s=j#f^jT}ye_&h
z%nInv*J(92XAm65=%_?*d^elKnMf;h&<?bfE|0}RG}O2%!TFDSbxY>QZ6kXIZ^JNP
z48=WITAT(!VLuL{f=U}=s7?v3k~!*w;(N6W#UCwJk`GQByj`4}H`Xq+%k|Wkyj{-n
z9V@7w+sknGKh$VG@9iAZ&Q85S%};`%UJfvL_rqS@Te5;El+T&&`D;&UFVgHvC3g~a
zV|*<v4zosvobiL_B`DMMVpS*SFRhqO`1qAwpl708MMG}ImcTEocqJP1;}9h|5-Yk(
zDVAl9B}Cg-T-uUS*WSXu9!-o47tE9lC~>kt{`%BS$`x)@wE-~#QDe-2H#lQKT}W()
zNr?H#=Ob2^_@fH@(nlhW0~q(?aq{2(RR!3m=N5JuR<>IcD^O%SO2r!01g{vH=WhP(
zmV-GUKMB^T_T6*_+4@O4$NMAshjogqv54<JD*2G(b&#2uf;#hfKWnW6T0=(_&1k8_
z@xosuGKXH5TJLC)NyG5VGq+%9^Wh>J9Ai(`wRoJ6h(x7cC^}!p#{xPMOMJ$Z_V_8B
zPcn;l2P-weGflhWGBZ4JEY?ZoAO&VfynaKqPAqc^s0}it7N(Q(_yRIFtu=K?jT#Uv
znv@AMNu<%ib>cmI8{mLhruLb+nHB?TU0#_x7SPl-jKxGtDfI~4H&>G|fN0SaBaNDg
zIcCY=_TT?!8PjU6=2<k1%}~aQ6gde$si4wie5;^(#AcisZ;5ZSN@X;1G!Uv(S}^jo
zH}#eo@zR8wPz%W6b9;VCgI}*^qEmBKv(XB>{ka2g+4#(OP(cdW;BImeTLw(5$<e{p
ze0Crk%N+l3B*Ph7Lk5#2%<*i{at3>%zE|&3uw*}7q?jZmfbkU6wrO--VH*<7!UrD%
z$lBIVk*HBc=Xk5}(>s;Tv-T>xP))yO9zt_uYA>Aq7b)yPBXN>Iwf)W+KHRIU&3!H}
zaI%N##BUA6)WIiy0B8dd<^UXg<O(2=k@ohr#0@-wO`$CP_u-j1b_L4I?F_2n`Foui
z3flO5oVmKlSwXkF%qa;IeU^(I=l14Hux&m*_vxRTXav)N?HNtK52IGcc%UiMau~22
zENpPun@!EvxtMV>q7Ylf{1SRzvzloW2;0uu<>$V9sK5=<ON4a@0gQO~hlng0K-iGx
zgMzv*WW>W|z=O>K%=3Xcw3C!~%+zYOQmY-2Yv%c=`00N@D6F(!Q2hw;e-5_aCi;LJ
z`?_!A7Sc3uwy=QB{Eu|-e7Zuev!ncu9vz5(b}1^Z85!O|awPDnxy#6Rw_ODOCNNyw
z38O_BUW)6?(8I@r7Pu`#Ox``U4H->(kkpG`YX|UiSZx!WX>@U45@=q*p_s+&{muiN
z{V0%=fsIGV;cR|=AHvn&cfJ>y)?)8NYD#>o-3nw_l15z*Ju)Y{FBi~s;$A}Iw7V)k
z)7-p>BK`l`>Z(2hSApogmhn8RR5`^?1tHLDI=aVQ^p_PFnVC{%^iELrP&Q>%gTz}<
z=^V2ER6b5d$ufa1uj4wvi72`Zry!CMc+svvEV8*b1Qk0#{3&`#oUkm1O3sZHk7B|b
zlq+(AL$tA=lSd5DymbvgII0>L5&;`Om<(hzYKFt(ee*DnT7L&VLWV+R*emEva|X(v
z!iIxp2jaOS^4(}|Dg4U{R*21v;>~hy@wN#gRqJ1`l{MCzL=tJgk8GG8U7!Ohl|`_L
zH9+6}R5Z*hEG0hxT*y$|>g?t*=)SPY;isH$D;xAd(ef{3bUhXb8rMU3Kp!3zMZ#I?
zu1_ufMdR@gxN@St63H8&JI9|;YYVeS>LIz2;s`^8Tdd-gy(ORPc`ER1j>p}huftJO
za=Q4^AIKK-b>bB>l~vWhi;GiPapEQA`;J8Aw-%@p4~p=Nz9YDsNMh2b4gsolv(<la
z9nrsnqdfV%ip7xMOG-Sj>E7M!X87$J&p)C!RLzHx20W_p*|C~20szQt$9Lz+QOoNq
zzM!E`Pq9eqqn6mf7`W@5n{1t8K3&#mmlZbDm|lzTG3K6;yf-|FflaF4{Sg?jAJ>xE
zBsjN6ZyN@en4)V(LFWGUl|YvjX484{WQB6vsYy5>pZsxj%eKd9)nwCWWTsi^d6F%6
zMDBL>WHHAS{V^<GD@e#rzZ7Jfo-my^L`aOSw~XOICrkas5$m_ku(Ua}_OMU1Ne2|%
zwYpmS|0S&3ZA(Nd=MnkyFwq1GL+%IKAEygGb6K;z3~p%uaU|yfs>QVX&I*!+Juq?Z
zLw`hG*<r0Ou^IjwY&3zgEdp=|QS@WVH}h_4n24XI^;u&x$8lvgSl7?3`epp3Z&wgo
z^mZKSLKAy(@w~TVYBU>OQMEgnaq@EYFF_!NlGp<q*9TN$tr;g*0q~^wVw<v^#mfr)
za{##fv7$EUQ<Pn5PPKt=nd8^-%#Z67mQe0bs#Zt7Czl=-Ap-6&ac)^$pZ-d$57`^L
zpB91hJ&0GT^Z@>N%uer461VcxcQL$oM5P&~pbu8pq<!}!5RL>bdF5{rreN*PnKGcc
zo&ZND*8JG##tb&X4o$&{HAJyuIL4CK62g+JPIeQaak;(+N8boY;$e{npp2nd#sncN
zBU8`gZo9>t$(lE3F^K4?n!ST42EEBqz#_t@rd3V)ZD(9KN{jQ`z%!qbH{#FfniD5j
z^ss2g7!+ig)9ObQV$4eVQPIc*HxSewFJa<Xh@ztOqkzmlRZ2~8aa@B!O6h}PFrjYi
zN(J%Jq~kggWaCJwMDhZ_sIlK$vA5EL74MlX=i<~S<a<AYMCe+}yh3!aLYA0pF%h3`
zzEb-ejF1W1AIm#ZK(^63n*x7>CA8`rY=tqJ9R%3{V4;8p2!rUiwtZ|Ls`(t%y80MP
zV*bG#Q_oZ4_wT|^37EGfqtri|g8Ckqymxbh#sX5{vP@o{?Vqfg9bj_WYr1cs7PXC}
zj<yANj7mtRKhBnZQPEQuA}83?Z3P#blh#bz#w=}a1skP{k5D(4@%I+*X?+4cy7fqf
zx#%lQX_!B}t%}7Ya=zvfNnqU6z?pTo#vpXiE(Y29Gr@t6-rBLB*EAW&msgem01Pid
zVTfk3B|lM!N-bDe!h}By1r;WBlHN;XXuxnJ?Rnk181FrFNQFX`U2zsWgbF@Qr7JU+
z(KZMNFe+v)#jAZTGp^D+w!5F^wWIKXLFZVvDg>9e*|C7(<)d@?(%W0Y3SY$jH{in-
zMT*009JX=(-D6=ZFP=%`<hPBkP!GwGoG5^WmhW@Ec?I<a0$Ii>8=-rTXs;prutjMt
zlQtHD^cJJUOGv?8!Zj}E*Qr?uy`qNNwg5SoZUb!R$RIMF#iykuo4DI95(hpNVNc%L
z0u~<oNHG$krQ-ktxM0`v8+t|q?||-lXkzhg%MgY~hOUAonuprHs0X#M^g3MMTT~$}
zzwN@C65O9pS`xAwyX%7FAJ%9a-VDm&$rG=3J!s0BzFtS)V}j^>-CNix!%<A5QgA|Y
zWMC84y;HN*+SdW6H1yIBfTbB}A&%=!Ot!}-$u)N$Tt6<D{^7#&!*si<-<r>v;IIFq
z>G$NFrc2Yo=8!G<tlVmK+UWqVbEF5p=X)OaUu!_<9KWPIY?U41s6<|#O5%ZD$zc+u
z@Y*(^Dvl;qL>*kCfp)%lKCKLY?cPyv#u=hPZpWOmFl|Y`&J$6;DO6=^Y)Izqi5-Qm
zjnl9t-3Z^(r`q45RflrFg3CzC<11UL*g+J=8;(GB*<Xh+0@L1v&z?h8*|^_?5^OAR
z-e77IO~kV_o^cE7N#rC3?9CjJS|RdWCmpQq=$f@Yss$B5o%3Wlk7_h-vu~@~JNYM#
zuXXEIgBxgGQH(*N+qM>#O`M7XXGaY)*k@JF>PLnmQ<VkXGZG}!oXvivv5Zr8N*Nn-
zM7UwM)RwF|_DzsqCuh<(8Owz^zy_A>h46_k!pJwrQ+~G80p(371l)PzbB|y6lC@v|
zgk`a*$Sp=MrOr)=0}`T@5*<K~IJlV`ERUDhFr`YGj=!YN$PNah3QojXpDrD$u1fY5
z&9qJwgxW*NORZBgj;^U(pRRUoUbdW)nJj&@hE!|-a;v=O0%%A*f9p>>eK}8wXQkg&
z3!*pxBk<%cP?PRAT$dVmk<CVFlq{gc3W^Hp1+bzMHi&kg@>$4_?eO(pNp^@+swCj&
zv_BcS%)HEgn+5};`Q6+#&i(3$(Y*mk+bqRmq}*QGt3nP;V8Y+h-3OO|35p6pL+6}R
zZ5o)sv2!GNMvuLZ>qb^LLgxFX$y6o^Xp_^3CAydFl%Gr*SM#BeE#(qSfm+FgIqQfU
z16ieQpW>2S3q1$gJjrNoWnjl5Hg7}p`K_m)9IRb&G!kj?{etJ(ov>6@;>6O#__%Iv
zx;&Ra9>ceKG)0Zsjqgq8<rkPHHa!ze25p?`!eU!Xb9BH;G(nf)w}9r4GS|H#z#X_v
zVSa9#xGuA~qX6WpQ8Op-c=at`N*?AtAMbgk6j|C=br(saW;{A>kHNpz)*&Cc9qnSI
z5LYCaU7K*8>f&4KC}VV*C|q={AXoQTG+L965~ZhXB9WFenSwzEB{7CXMSh8LzcnVd
z5h*E@wZk=i2C!035T=Q?e42mf^657MSc>5Nx>EP;(nqZV>)F;QzPKd*R9rl=g@g#O
zYC;=nUkKd;DkM#g5y0qk0Dl=8G~l@$Huf+^J+sXW5jNM{Iue^!<==m-%^VuHCeX3E
zJcXcgN0p@~g7v2hR+qTUrOPtcGi2caA&@{*6S-z*%%0a%KO@zPPhu^k59q9ARHQsm
zI8NphJV2!%8~B|^^Ns@htZ4u7$%elOYPHnB-<$CsxJABjtR^%;c!h~^lp{@$9=b~g
zw-~UBqw>tqYz`Pz`DJ_(z0M?F8JzF!WCZ*wyWv}mnU`=&Ig9y<$J-N^Byq0-ZVI7e
z+?oc$q{dre1*Ltiw4=ruOLl$G%MxQuo$ltVe4T=2=7Sr=HbD1qKqn&X#w`y_dLYfb
z^tCIIWSI4h&Zp?LP7y+>vlvQ1xi5{*HrTJ(E%G%>up|O{6@JZ35kf`nA892E!=}m+
zcsvLrq?#4IfDEIq$_0IjuvAUww#adQ{YDmivI}a;1e37%)TNLK<3C%3ezOOHD_fpF
zt(*7iMTtexGpFTub1C2-emkOM^iGiBSRZE)3-0-zTF&lTP%^-X=fxpI6Ry`=rrNAm
z1JzCybGb!*)Ck&phn-FmP$_LXLLT@a|8`JYP(pZnN&6)d3v%dFTX=`uRQe+dw4wWz
zK{KpmVc4pP>l@FSaov>^ay#R!ID3W7TL}<W`=m(`2rBG|UcESI<b%vsnnS_>E4sl`
z_2S_KO<rinUhQBb^~5)mnl(K4pnht@?m0lK5R5r_wEtgAdS0P0*ed$c4+GtL3UcB9
zao0q-q_NWYqK#V5NEe1&6Ob&W(c>f&bzJXBAhK2Ly`y6eYH_$egd?|%vh0>ikD*yA
zUui@&80@09onRvE<A~0NULlJ8fgGOwOcRq0+q0fvyNM2k{BawI(v{C30l?^2h5qzA
zwepaz=`;|8`5OL<+?%ecEIb$ex>7cQi?e|9=?EKaIMkTC%6Xyq7E-vFEV7ZuksDwW
zh2g805gTyn<bG;03k@gfne{8@jNUkO50l9gR;@U3ta4i9@`(KlxagjbnF_ti$O5uE
zGz6R>lU2a_AKfVkgf6p{%bz|ZV>-j7fpWx{erSUBK=E9KZ*YaiYoeJg8O+mp33~mK
z8Qb~K<5@fsy#=?Bf+F+!1{r@ada_X1(#URUGItj=LBSzdwVhlF6cD-Xu_4ksphfVj
zPdtz@IQ~=cb^#2A`IukM+|l#zH~m0HgC$@mq*)WbBbpJ)QBQp!TyzSK7>gQ8Qd$X9
zR`z^)gYbd^(%*K-ggo7O7+sMMCZ!%ofq}AQueL%qEnMKt3Gs?i*&b>cZKq3Hj06H(
zK*dWM$$zhv%^~S2f|z8L@bH>Yc0Iu|-ebG0I+yY)N;)wB9_M(EJw|A;ft0nN{g)A@
zRh3;|+zlfq$VD~V-U~z70aJuPBTTR14fMtado)HZo%`ZkG~o;G2@OWh%&Lot9eR4p
z&2xJ1b0cvH7hui=DK?#3p@6*|3yF5^jPzB1hdlVC)N-p5!%3x7Af>`NR5?hgaqwos
z>bKi79yOkrHPe3N_h6(Nidu{}!#t*z3c=2FtM#0~)dvbs%G;SA$gF~P38m$VT{XPh
z@IlD?z>l+fp`w}D(ui%}0_QZJnjxK({+1GxN*q9==0hLy_wni8ZOX^8uJ5Lqm;8vm
zIr4feof4o}>r4b{u9g6hzxof|Lk~=b_4g5_%4rj~E{h|SL?OmsL4XIo2UCJD5ieeD
zx@%2J%jxMcezCfY<MO2+SQb36?<4ToJq@b0z9G7-pB_HO@8!}Goxh+6$q~4mF3{yA
zr!aJI6p7L3D>;WG&nrhQ-x8WZd}?Y%3TP}w#OK46s7sWIfp3;<e#pgR7ibB9Gx0+b
zQW_<gm|6-i&$DqO{B|>DZu_(;M`W!LtMmPc9nuz!c`$UQPDVkG&r9i3XnjW11c`ef
z(?MRom;bl%oRqK}ra;wK3{!=ztD66r@QSPqJ+@l9EP%spa!jkyj!vAiWKZ?xx$CKC
zN@|JQE*Prxc-%~NB*_s4vdNJm25ns_!8k04Y5{!x!E6*Q(23Je_2-`jb)Sw>=_9Gu
zXm?$$Pq!jVfUjY>x&HkN`kXA>J~{^fn2_EsR-Sv?BL$*=X`^Zp^1K9%SNAf+Ed7d4
zfS;(|F*9Z6x2Mpqo2GK%?A2YivYzvJIwgwVrJOpF73VX1b;#=HXXbKa&4=D8cZgFV
zfEL^A+_y@4Y)Q7ypBdZj8~|fREq1kv*^1?n>aw3aDIi3=)k2BvgHms5R8xoO6b&cd
zGCEQ3{imA2U5TbH|Jy8tNCY`%#J-?lrv6bb%x6%Yj<?94a{#MIb6*fiBX@6-v2YZV
z=t=7n+Z;}!yxM)HW`nx8_}WG!=b&MmHq0zDZ58LL-G{jOYQqm&q{1RgCb2EMhqsA-
ztxpD*)|$xP2v9>)zB1lsvH#sf5JE4H>r1eBQ>YI`1HWK2)B~piOpcX<Ma?&)taRy+
zma%iwnW#pUksz;^b-?V$XZ^Qv_*0h(UaKTVZ|G?wvXg$L#Fr<#PQO6{vcE-Y<&gjY
z31~qTiu!J&zpDtzZ`n8H{1rvqTTb3dR@a{jh<GqNLOdTN>0Wxl8^Q}Zc$~Ph-Q1nU
z7-#rq>Ehhj4qmW<m{oo!!s@ilSUBXCg0Rws0agV{;9Ai^tAh`vVJfF*qOIWE8a%7(
zmR`S$B=_iW>=2#4SmoMh$xs~LmB|Ys{j#n4s(3OnryR(TO?bPAx}bM0r*7x{&nLEP
zZWZI!I#{;{8jvQ{^MDH1Ni=2nL4|<X_sOapmgTfnUp3)M%*J~T1OZM0xi?!nKn%xd
zEYGJ5rw7b=apisuAa&lV{m?uY5_cFs7Awi&n&7@2HI;Y#wusu!$~@AVDF3`mol=zY
zSlj2SmG@=iUv|4p>-tc~HsPQ2^cgoT+|WB&oNG%ioF{5IVXVmR89zNS00?de)(b%4
zKj&`U>*Lo+LIA$%HeCcpxeBMm52iKfbN%C~y1yx`<#%Iq<$Qy*!_cGDMBY$O@Q92o
zIZShy`^7(~b~}^;jF@<FFA=Pbe>SdpeVI&1%sxubCX<xYT_?^kx6se;SpUFPn~|)|
z$u*b5Be{$Y?K@gBoE3$AIY^T(@Y+?P%p~Jm2*8(mfc!xc9N8#)iUUZ3)f%lJ64^J=
z@6KANUldG(zRIeWOFM#k)M!_G`tZUiV4R%Xig!RV{INuQYM54U+Qkl10$(#yvx#tw
zk~ZAYdxB%(-d%MF2c-O!S>}$qP5Tl{10`y--pzw5=JOwy#yPN`aeVQ)&N@c}ba#&E
zc-HY?gaSvrkwW|jMoVLO*3dBzf;IRH5_q~X@*6)n;q_((wg3aYbOl6tzS#QfAkz7(
z&;iB)$eDQ8ih^gi7902Bz-)*v)a5tb{N<%#^zkDKErb-_($?+zyE-)J2Qto6ei@qf
zJgW?DSNQ_8{fbcJ;La!7ILley7nYN1O3%=d{nr?gIQH30y1Z~zSUg?VK}thz{G4~@
z6*THcU~MA$2?dLWPzTD)Tbx1xG29g5pu-d=*)~A5MaV8ej!*03l;XYi`u$o@<J{5m
zYfrzJtAB;cQop~fNa0ZoGufo4-wqx?{B-PaU;vGf9Dwd}Vi`aZIGaZrF)oDMKWXSj
z!CmN(CKqNy_7r|f2a)PB$wuG%eK!+2lb{Bv32DdN!@HQAcT_iS&Kk2#)*N_4FT9g&
z?k2@nk_@KH8jhN(CtH1lwqO{IeH|SoEzr~h%Ou~is#H<Zn);tAsc@n|9#=AiV=v(!
zBrzDZ5p!NU8qRv;C-geJ{V-PKHvivs(up0oNyVGErxIJ}XNxBIE^KsrYr1-owU%%;
z0PT6`tiZ?w81df&k(Z+f4Ocz;{_FtmuQfqsY{(6iLQ^dld%Z){NlV>EF@vp#PB6*5
zS7bT_v(+=pMwo7bApNCmI|t}rGqfUOVs(#=ij<>)sE{{c+`o6B<PqH)2`lmuC62lJ
z(Hxh*75s?-$4C+h<_Ww6FmFY0DUDP&_P&mLmDVh>-w!t}nPD<e-M0ra<!q>`ibSyf
zEKC}?6sc-2i{-Z4YvohsHSl5iJ?lC_z%Ie=lcpU5kq_Be2a>7|k;k9Xr<S@|B|o-*
z$~GAGq+UbRO7*@_5h6WGY?TS6=0`VuY|h|c6^G>P5aNc4%dwA#|Nd7+C5kZH%Z&)0
z$5#%s9j^!yS6D~H*_)hZzo8|{F{?+VlSn-Io6)j7x3cd6V#+&gI-lYYh~KXaB5Y}4
z!Fy7*97Oa#3ST=KEocnQLhUXQglUe&Hn_^qXs7;+3OL3`9r>h=5@Oceny<PW8J~yY
z{-900-?7tU)N6o@0C`nleEK!ULTAcdRYTi7xNXXGhpFH*pbg`5wn3f-pQfO!`4M7&
zX6P_F`kCfP-McXPVB?i3Oqa0zgt1IVuN&+)^$eFZ_-qRr`&=1Xy;cNcoJ2X7f_X~J
zR!ccsz7p&5uyTCSuxJLR?!CDy4`LVkL?^3-`xus}pbc3Hh0)lW$*ZilFWZ&Ia}G`h
z9V(zi4Dss5kie)n^pS53G~ore<OmU|%Va#gXx;=$?t{%a`KW^pEG0cfhrrz%+cncq
zu|0FO*XV6OjS|BeugagM9mIbPQJXIS?knAmf>Q1Ab+Z&&U}&l>G`VvbqkC(5X#-1j
zY67C-7aIgzo6x?RE|~K=f=PdcWRz2BIC8a>>JzrsiWH(NK?_4gAS_fUzS{D4xn42_
zOFXL}=4>tLc+M9DGFC5r5{G-ii6bE(ccWi<+=SVJHDKD3LIkZ9u#e#sa?7FLbalRx
zZ^tn?jFs5fw-Rv+%Oq2(prj&ZQw~5GO^?*5NUk18!WSF`{~XONx9oqY!tg1w|1X{d
ztFoWpl(b$W+1Ea<x;}c?!&}i;<1(4?wrmHWbrysGX*i4|GBt>6C*r?O<vn36`vxYI
ze+Lot2hAm;-fPU0gO=N@p1+FVwGI|70GfWPjOHb!U+mO!Hgv)J)`k^GQ2xZ0<QNPt
zT44Vc%YAyf4siTIn$a||a#;1eXGO1Mb>qME;SdsgtmPm*7nN^;U^Zp15?Z6Ipo|wp
z%Lh;|oFHVPPefWyu+I!&vx_sO0)D<JvF<!lK$R;fgL&hmXZvt`e|v_t9g6Cjx96wR
zfhizbwU_)v#BmUc5R@lC!mypMzz4M8f@RKrzb&!JpMHq9#taiKS)vlqT<^z_Y_YyZ
zDN0pSa+ZVY3tidQ1v}AebY|)(l)Uk;OAWhSQ#U=;M|TYSDBRRhF|3#_@|#NgySb=S
zXP&pyu=IWSu|VN6xODof+|c5lqGgiRAQkI4r$&Q9)Fg$;Mi}?%)qa>ZYGwo4Fb#x5
z$uvU3uFDFw5<|Z@p%J`6l~c-@G#Ia>fDUn>-8m>(bcP2hq<T6fLBQO6XG!xAo?IeY
zs0Cn$2kQlS8|958_`$Jj%=Ve`=5tO*cnF-Lc#2K-Nli+cH)Dmex}liVfA{X&*k!A+
zuOP$XhH9Hd?4y{;B$LXu%zv&J9j9OXapkn}ee=MQJ8T}fm6o3^1d-VvfLA_q8<MrD
z1X(GL<5iM;SvVe-`As0Un6&m&Y2igot=Q6k9G4t-JcMV<KLF)p@VoS>PKz#2HPdhh
z-LXp+8A6q#445)Bg?&coBfIg9aceq_;$~Qwcq0!s^~7vt<f%G3b@#ystH;M;v)ccY
zIaq-^J@bwpV8MJ!w|Yk4J%RuL31LBwphT%oO_hH3B8DwWv5vt4)-cx?V>wg5Zw3m0
zZerVYjbi>p$!3uvU%3^W|GQ-3?vo5IRIOrjm)64n<;#QPtTKPMI$;yMri922tkej{
zlC=#!_x}K!A}}P#EAVRQ=X~>Nb9wYRUqlcc?VeOF?}Ta}8dDc9yV7k?u6UswEt*{&
z{E4TPl+%CfTN-wBA=l0$%iv(`o`<%wbY-?`s%%M`Epi9RQ6}w^5#tl6z`R4hc21)n
zP=rPV($Z4iEX?|pON@kKT*43md3Y~OfY+d<-ZBf>yT-L<hS}f|g6qPq>#UED^+!^*
zsR{sMh7}N(oI%$}1Wo&lZiA5Pl|L5O$3vsP8EJ`BNtSb6L%a4O@Pr1<m|-<;B{&o^
znPwT%(x@DFQP{vTLgP=>-}7kmd|@DbWa)@2AT!7NzB7d1-yrq^V4q26p<YqK$|Bv$
zK2D>c9`UoM?AD96>R}P(I4!!cBN5axEr+j8>hok1+3T`Y4W-vGnY#3*!K!zQK4XWQ
zQJ7U@e`@f(G68x&p)wywH<I@()I>xeHP(RWBpk&>zvL_k-ST%E0IH3<(muE8HtP#5
zb1en4kuh6-K9xj+_;^^5yAd#REP{6cA_Ek?_vKifUL3MV2i{2QU5UdTz*Zl$>&h-A
z2Bj*!Q6(Naq?t2|HHJ!LuQ-$!<AAN*AKXt@TcL&0Jz0gE#~}X(k60~_0=j{47+Vgq
z1QLbT<U$9Fg+%mYOj)L4x0QPbSgm~%9a~Mi=7rwv=~RVw+b71f!o-P_jDusj{7~Ku
z=E+<o1BqAqXp+fZOG}r4glQiVJqS_cfU?3toozppA&M(HKE?`<n31|AZd-xvPi|ak
zYUY_YtkJs&&-ot3P1?`6M{(@ZilXhmWq-gre}`oX2p&t_h`qRNpdRl(^^2W|;^eOv
zCeX7g?5E<DXz6A1X8?(p)=k#h?%nm~NgW!maod|X<5QRF+O6c}PzgF*=rUFP2zG06
z&U5c5G(Q>wbH21_4}avJiQ>V~6fUgR<=q1*V0|9Ld|9XtB8E#TXcI6CF%PcqDJr#(
zAKGQ&Z(~xLerT9lKWAZp0CPWy5@Mj6-kg-wi`n_-U^&zi>}^o{$#i2We#@#}Cv^WR
z;N<dv`8yf8Mon#_wMNZua%yP!?E#D+4i&;VI%+m!Py{IYFHr71e#AV?oLx7!0Cu+z
zpu07UXfl$eTC{liDImzn6iskaOTod)QHcJ|agNi_fKg_tYtAq}?=@<`=+f#F%pR|v
zZ>GArubw~-iW3;Y@6$Ox;`$PROEz-LVi-7pN-v0I6hT4S?e4c>Z}tMz3W@jh2+Ubb
zt}TH;?=K>k-a5Rf>Xd8hyA>d!xnvG6EN*YC4r&03b1DzYgJsrW{xhs@w|g(`0E?w!
zr$hN2U=~mS8T3X$u?abF>!ym!EE$QBF~FYXxiu3xFz_U=<N4>9%Ox~v$S(e)wYJ_y
z6GDDRGx1WT9;fP!eVP$qXoL&A=8Zk!vaeNDUK$u}89$YS<D3j?z}yIpjl#c2u&44X
z(&k3(Irb(rmt50x3}>2LvIr%ME5XPI%{$wS?}92u7KsWi>Tx0`v&Dtsw+pSFZ<xvU
zl=*@&D2mWJ5l0K)miY0q-d`zBcPm_o$)JWtj@3EoZ6?+^6+JER$_OC8>Fcskg5gsB
zxD|6FJNA*0e#w(C8?Qu^*CP2%gKa^`dkgWBLWR>|<osBJXHcFW&N;%&9Ke*v+!5+C
z3mNao=n@mX9`yY|cGn=(dRnbB@s0nP=Q>1qpbKDdIxTmZl%GX{B4LO@Bwn#`H<je`
zVXMAH8C?md$q5<VZXXJCwUBLy@+FR}hC$w*bV;^B%|{kJJT-S-CanQv%{9O6lfA*V
ztU<Lgg9MjOXIB<&+{-AuVSnFtyKW`HqwcE2q!MGs<|m3@xVK|9FYddzim1S|0GTsF
zw`wv(@I@z}T_bRYhr>qnalO-}ZI}=I>Ufj6A^D^9Dt7)&>V*tZ-C$%pQw$bGPL+vN
z*T8b;Fd>)%8pgk=#cr`%v99Ektjz-NCkvlTjM0BBPT@N|QS<39U0arxc?|t`wo9;O
zlE4bu>9iRi_qdXaK>K*bZ9lkxMoV^^1{d#rF%SXv<XxCHXP(-bVj<I=tTnhhLBDSI
zliz<A<)xriyq$$qD3*QL%i>V6Vcp!jjI7#rlu4u|Azz<S(7X#RFXl=kEaJD1Kzdzs
zcG4^;ruTS_#!)l;S$wy>hd;5^2i=5_Ie^7V%N76cgfj3Oez+-7Xv6073T$~8YE^LU
z$9`SxE|tDJ^a&qH#R;TOi&eigP5cE;^%YebqEn_8?8>&jF1V(R|5^Bc7M!Kj>t{a+
z3Wu(f!cWm~_|@n-V@d3uLjX?dg7+)6c*A5~3%9i<$;wPc+$>+lUnAl=xTI{<(&k`%
zCYcFO;_BOMa3<;9{R)RF|9VCb(1F!1BCTs8MsT*O+abv$@}HrN<W%*&uIMH1O4d8+
zn=lP-U*99mo{&o345|o0f}*;|8{?OSaDI)gc-)kb?aBlt&TjOXeXC4l-l$k+(l8>j
zWr4F-&#kF41B%hg31w$OZw<79*y!Jyg*f@r`&V2+R>v?k__)2B^kyW_0l$`%Q(4vz
z-fGTi-;hfksA-0pwZHTgB)7>OQr9zx`1{9~Pi_28Y$5o=@W#8|uX3OIHc~w(Cz^8>
zi^~yTZ{wgFQzJNnYqXs@(9TgOPY%XgWCw2MxnTx$`+Wu``s{I<qOQn!Zh#FXlQxDH
z&>69Rp!VLrmc#+*zC@js)04!?qB}Tm0=Gg|LcSnYfsu8f73E=lsi25XW)MJl2DyRA
z+NVCkJej;`t`vupGme<4n((#f2H3bPV7mKpT;H~tny$?o#_|Smjd%bi-~?r(;_nWC
zjybXlCj}Bk@5f}$v-D?Q;9kkZmZXq?>e?8j3vv4ZEEQ!=<%3vN(Ed;hql7A;1CvW=
zkwcD!PId0@Uf@&5xu5%8j2`=5)>ZZWm$ZR9+G>d4+eh;m`X2|-`Or58n{~~p@q1~y
z(=t8H+gy}~=(7)-#l=7dJ;2B9o$&!5@P*z#1v4$N(ln_-reSGd`(Z<7(1L>b&Q1`M
zx=#qY6f0**2mK0dbv%G4+?s{CmM8sU5_;4YXTrw-00?hES#&-7@yu7~5=0xJd!2v~
zWxdpX8{oGA1J;J96cJ>|>h7;v70>oTj=$1wY33-jxiiStZ<KU1zW>?-oO5YiQe)LE
z3u+*GcWGje<fvLH(HS0egwtwYA>duap$>cfU%)@fsnT>hO_eZl{|r0KyY95={-3(t
z2YheA{!lXet)qG<>M;*JIFco*<4`}}8Y=gG48U^dWv!cDQtbc82CeZBl`y0PKE2W_
z8k6@k>jk4oqm-r20V#>)xuE+@#Nnmmk^4DNiS#hBC(N4MO16{7P6#i!ja)qJEfkW%
zbEiYpd8aW%<*3nS-$L1h3Lq~j`3yy2|Ebd0H$w>55TZTW1Yuz!0V2qtLHg5lLa5BD
z%rkoTMBi@#=xT>u2|PjZF&upHrjP0kUqSz`XRK}|*(<ivYJthhJ8`RIipv2id?yGl
z9tjY?>@E4%W+a0b#d1+c$`-;s)*S0X^8*h~5S%hk$qNFNi_0Y@4BC%K&nPA;34;5U
zTSoJNHNP5j4UwhPp^*mfv!O7AOu29z)A}Qfj7@xyOettf@38v>jbLxhY8v|bn-3*P
zoPv}z#C>E4zg93NVBwv!Gd}WDMz92u=dxN0RHyGOe2)9VTi>|XM6W$wOC(R-k2P2$
zGd4rk3!|Z8gp;$j%!F?#p2*=cZa=}a1+wd&Br<)hl|w_6DmDLgb*mOym8|=v6=S4T
z{h)NM&ChuRb1jK4>>%9N#|nOzau1&IC?VFb)<4t>Z4<l9&|L)ebm061;L(&g6Ul*h
z&0#CLCt-E_<XN7LdGzOlq5R;-tl~TmYlruVhuYAmAc+C(1olF=Y#rW*GgAlBHN0RY
zJR~q-IOeb7<GMYnv%OLK11f@S@GepJk(ia{Zddfi8-53rg#NU9Nnem*Goq5qzofoy
zTv>L5`pX-Mao9KuW&~6uSfkO8vQ_OFs>V;GCaG@D;49{F<}ZYwr#~R@R+FN;+9dy=
zk`9}Ux!#=2vis+Y#ms5ix}aaKCQrxH!qKA2?|lvch{tehJER}GhJVREmW#eP7x`KN
zQ9>@sSG4?fccO*WzLtu%xd8J+16+5&hfD~1;c#zgueqJJorZfId(oKU=%I;?C%-B+
zVF-W1x8AT;_miF1ml#B!Q-O*k^-<L6vOdbvFUWspCfwCWc-AM64Oux$;#w;<aztKs
z@W`eH4}52FM}Z3Mr`bG*9^J=b`8Ln;AR)vEZLBZ4z}JX??I#$t_CGltOJiW6!k$LA
zaJP_-|9-0XSLbjsQDLKT0ZaaH1TuUe(?uO}7S3&BwK@Z8Z+=wkyFtpdXk@N-dZ=U<
zv%H;CcgyXSuh}(u=3#cg2Ed@gWH32tI1q1sUC$+1q-BN~iDC`?Sa2O3HvPmXQ^vV~
zW1pEowS6jJyt6aTnnF^;s?FY>yAG;4`40}=e21GtbqB<$kVF|kLkFmx)>%~b+3jA;
zmL^!FBc<$<wHVQqj#uI9KB8O8E5I<2*mww2Z5e>i&7%OMBPUGTUk_d16OHFoILZBK
z>3nj~Di8L@s^TF^p^n;*jdmi>Lq^S?>)oUU`vmkK0JjlJK^~8KIrVC{)=@<5ZIE|`
zMH6CvHq}5Qafzkr5tzop`kUs|Bb7csZvMm7!S2r%XA{W}xpx1?wIIgJ>>wEXhX2a3
zABz{%fsJ<-$bj#EuHB|rVL3Axigb-a$!RXxPuF#0g5zhIE<0)hpY!xw-QPDJuT~PU
zSIa{>%Bk5&g+6RoOW8s8lIAIM+n?)Q{42%!SvWjc?E+`M`%j)<+ZYvfO_z_EX1AW5
z-uv#4IGq7<anre63*_}@LK}-&(~Nf0wg-Z511{@sU3<j-Dcs4cCw&iyRHWMpwGLGk
z{!8zO=kEJtIx>muz|I9nRUbav>n$DI@5Cus;23?zczD<G5cset-_82L%jO&QnNbk1
z1)&Ia7@?|j2M{2lT6bg8gi|k1xtbsiaxJJv6xxuR{UaSURzhDd?COy@b<j9nUn>S*
zx17qSvzN_c!#DtT@?RsBC5w|p@Apnf0)uS3(U&1%q!7+E{a8_KFM!-ISQU5Dh1_Hr
zwC9Q+i07^|rJgcyI^Qe>LlnPPohuL-5;@Ej1&E5Dz4^yS8G+F$0hTfLWFc~RsUsnA
z<e2o!8zv6Zj*6*tJ=??~1d1zh4a;BThN>o0i@w9^#pn|ul;i4kQ0%>gfxp4qJ^~9-
z^pIIlDJ3L;QV}eh1aVU|YabXL)jHF0YH<gbF3jDykL)Y-2DjqBOmk1BH^sJ&p16HT
z)+9@j=6vVkNpee(2X^QrC54OCzcHwO<nu;kE__wl3t4pb@^LKxr>0reY8yM+q4YH3
zh=r$Nnqzw`@63|Lo;y|)mR*)!<-5~K3|@d@R2mj-kjt>1_y#!I&;TLi8kn5;KRK|A
zd#LqkV&ux;h~j?LgZx?%#Q3Y!_`%tc6i?V7&SMVfwV0(6Y$bFBN8=&jM6)~&7F&eo
z6LOyje9J<$xWuyQV_=`~t9M>r)I`DuelVoKh$1X98p1mvNYtq4sI=W3d){e=gpvlN
z&1Rv=OboysVL3M3HyNYBBY~=5tlt}h{+EM@{tA>es|N^l;VDF(#J5C=3wvx5?bYML
z2tU!g1D*WCB9(m%I%i*J3t;bpzbCB<ejrHE(`+IiZqY-A{=n7S6+Z*|K?W0iL}-}d
zd=8&iS!|v)>Tevi7#}ntjUJ5-t@m3Js4aX=-DGV)F=yj1g(D7@`eGg~c}&=9-kMnN
zT7#y(^W?Jk=cQO{jYwk$V&E9*VcVl4m#Ly*^+O(OgVmdYqvMCHPra8GhWhJL$NVF%
zrbI`5II*ewrnLY730Xn*pJ^auDiuU91kN=Gj)F@I5)#JPD2A)9$Ao?oNFf(U=TbmC
zVPSk{iOjq}-5fwl$(DQ!&zq*VCXhDin(haGJ8H|uc8J(O|KmWf@Ca4W>wtWky~cQ%
z*jiCUZ~$$kn~=TNA&U}gLGd1E+0+DozgObl0DM&ZNzbL?`#sJZm6L@jWwc(~sAfJ|
z(g$(-^!{sou`D8whXE;^ffhoEIWq~y&c!X$`tjvvYF`8dDv`KT56j<ubo&g%)4Wyh
zZW%H4IFX)MS``UGQR^U0Cp+sH4G&#%0nF!+v?Bo}Nr9YeTZ_s;vKZa+fgk8?XKyaR
zDi4J0Ji^SVFRbVBMEJ^nUvGK8GZ&pvw*=ZByDLAV$tmyz1{OsiUeEN}ef$A#wSV-j
zo&D;Tiv(oMkt7;F3hkkxR%4t2gUt}nJIXfNBsR(LyDvTOh$y1dvA`-&ru}_volD1N
z1Mhl_6-Jet@5|@j;anvcvH_mcXD-A7*}7sF5$lZSAajuDKvpKjq}3UQF+mVv4<(K1
zjn3~A`P?QRS|~`=Vh}=i*B*pD5>nWQTJ^xf_*NDHQ11W>5<>6=GyOwaa{R4h_~qx)
zoxhr<ORJ1W_9dO!%61gP!DBaNeHaAM?Z`G^ZHO&ssZ8=_qFOlSQDmyEm<I~d28bYG
zMVZXzQ$&q0l)<Xo<u`5KDtG_H=Ip`T6vf{1zb95qy>R7Cj3;8YLNM%!vetTs!PXWW
zgaA4$*84P6sly4xIPy-w*Og?IE#~<$CR*5waMujuMLRCIt;LB?{?$HjM4D*EdhGzK
zu5h2F!tBp>qdKC2_*OHYFbmiIxRUif<EK^rp7Om10;*lc!|wT+IDSn$>}Cu&n2&UK
z>#KxNb<?%%a<a$Ez#s18&a@1LQ!b82^2?#cojVUubT~;M;xO#|H{YGKQu3~$cYhS%
z{Y;_=QRKaDl4hZ96UObb6GHrW;S4^Ii!o?y61o#N!sn5*(#JW*;I~Ym-QR+7;@vUw
z*LJIImJls)lK<Vo$B1K547yu=O}G`X)v(d}!{MGmU7!RuL2R(={7%Y??G94A34x2P
z1d<sKA*eDWW@#O#%nJd}cOAh4V{MbJf)T3CwSHCSclgr7sK!+1V(X(<iL*+bsFnwi
z4DM7wTFuhO=#$~QCKsn907vmcRxftRzb;)Kqa2*=me`g_Ylql*`0ok@#!HtJ@z@El
zv*&88$5ZEw=Y6j}%W2=hFFe|CLgo1(a<PFzm=yGN!xd_iUz0C3NX?U8Pt?N;>H5dX
z;n{##mAr6&nU6`IZR&W<b=<Rs%b<@QPbWAmJ6T8~75Z#IXe%JCdH6mL=2Fn}8%Qcr
zkg(z$MeGL&r|aV*VXZ|JPT3K^!2+*B=7qF-2eWjduIl|y66k5Jd*6amU1%pFUD?cM
z&$HEMKm2RU#%LW~4^_}VSszV#jOBB942@yOTy=_Bu0tQRYzr8AFMp;~$0NGWpo_HR
z>Ahbw-KI5>AtIdQ<dl!{nPb`8OX*u;Ji@P+N-(N4qzl`#wK{KroNLrhC~pYjT7n|?
z_tW;DeDk5!Nli!l>hFjB)G!(P4Lk?3RXNr8udaUa(DCptTdkqXKK`eyw+@?FZU{7=
z^6New?pd5dt;cUcULM6Lf07JLIPMO%%%Iade-Z&kC?2YNdwg3Ozsu9RNB`*L=eHtB
zeO~BFg#s30hfFhJOy6Y0$sbYfKyJ<QG>|_Qzk1#8HlJF(yzcAuAg-jUAM3-=0EW?C
z#l}yBbZw;~_F0EsO)_MyF+(v~sGh{Gz_eRFSN}O`IFI4t>>Pgvs`6FZa^fK}?J}(`
zdOIEQL&sXLNP!Z&571T$^5<Fwwex~eB>21Z{<G!1k|0(Qfwm|mxp0(a6^Tjv&fUY_
zI4=P07Dr`sY>`HYr$fx9kkbTyfZdv&NR{G=6wIm5FjiIBL8c!if*><KB@`&{13)L*
z&nmv%@k2pN{%E(LQRzA$njYg3+4@hFnfrM*;QZR$$<b5G*&qLNGEUe@or?J8{fYOk
zfJL;prn)CEl`f_gB1el1z|CctSJF9qVsEwb)NaWB`p*olwY03OS8ZkZy?|lcIvE8X
zoF63Kz+|@G`4Qf0^gDd=D9>|nF<}*NX{G8v#U{7eA4P~;m32FVdje}zk1Wa2Q__ND
z9Xw?>RR7PGzzA*#@u!542t%I?aI{WFt{$8vjEPljP~_5UC12sO1_%Faa{v>}X%$`(
zJ{CzIK>Km~i5uug>bo<&qqQ#6R)D@l_<W)~$LmKIT^0*!UO9#{+^i0g!YWjvytchG
zsCZyX9drixJ15_pu`6Uqo+nG(oXurm>{MwWZvLjWRgQh)+O2cAznuv8tSm8g1n=4H
zrOUDciw`LpHDY8Y*3NSCo`NZ*E`lgsZHn0bhZ~UmQ@YU)ch+@gYN0aS_@g_<KpwZ(
zu-MR%BBYp+2el9@&*vx4T}!;;qX2<Ras1-FkOk;Y%3ScXd-8{EsWLX2raF+<*ZQOD
ztvp;{k_vo)AUr$(7E}+rL2U+pX@i!P423%<4{kb#S9ET4Nr~dW_bI%0WAIkp`1cS4
zlRnu*chwTO&eW*4k)-%AxXZ@D#OtLkjy)hLL)5l$C=(uCqJ!y#FOCiTq>1W#zft>M
z6v9V?2M2UF-RXXQ%KM6HdhXCWGi!#8jsFO$PYp{z&pcZL6R@}?OT~N3_R6blAmG_V
z54}nMGHNbZHR02yyNb-xSv)@R^_&RcWmuxJJn{~RLlsECNMM=$Pf<U%i>Zo63cxWy
z1}BqY=#^8B!~3>4X-BJc;B~$mapFsWU~MS(z^jI71%o<B6_N=qx*oPIs)gX|r|oUa
zqEwo(VWvUlsu!U8@Wwt;N>um|q)%tBSnF4(hnW5-^Ub04QEEGWKurNVyc41k9ZGs^
zI|TO1tlINYI}1$v<YAdolrN3BsuMH;JJlJtnIw*szcK$K*J}h6eBx(9^Q^WVz%}zH
zXm&M3Fg<l-YBaY$wEUm^a5G0vW8pW>m>;r5jVezJJqi@~AXu*}+kp%P&h-q#SpNTl
zl)vl($H`D=d0P7U+ad+Ow0?dw5to{F4Wc;^G1CxP>~%KhIO%pCJq-#C4@36|x^0CE
zrR8S^AbFKPYPosV&U37Cu!@W3Zdgcl*AzzqC83{iCr}v_0bAwYGpu;=FR2FmFpz!L
z6h8fkl5EjWQ@dU-&{e&qQL6#9<OgPVhY~tM^xG#|`7;7}zWN71wgPqW&UHT&QK*w(
z6tXZ_Qk{FA2Z{N1c}#ZCYs(*-)<<q-SyMpblCIni{@kDG?SP%_A46LQt+XJFm3E}(
zN?VyN)YldxCq?s2%*px%J=sL!Z7K#HDe$=Q04ky<;J_~YuVBV|AfI6?gBC&?wayDT
zEBDDafW<#-o2QXQ<!5trBhK0CjJN)G#K~k$G)>l2=_qAj2LYTeb<E6i7o;&%tE<k(
zh-7431uDn86Avp1s7s?*xS^U?_fMPOIwVMFD|E89CvJ3#`_$6@%%<7tx&6XZh4AP7
z?uqhr4CTH18zN344~}cX3x76lE<vO&K4FT-81*%kG1&9fWM9x06EIbb<;$mme#OiY
z<Yn89bUqaq9gDI}!q<|b@EsZeX<NEP`mU~G=s-2^RE`u6R~y%$V!6IiT&)r`4uo``
z5i9Q4HcXBoL(R+S_x8C<L>vh8zWPXB3*c)Y1d$hhFwYw>HyepK$vTo*bg@U{C8cY1
zc6)pSUfv@QxOKdh#R8*reqaeRc;|bzJHek&$*o0JW`uH0z&5|Kf@Qe29RbcucR&_}
zidNecd2&Sd;XX}$dC!ln!wZoxwo#^6ir9o|d#0K-Z+O3@ChC$We}>@h-WF0L`348W
zwh*iyrHoA9^i4+vNW^0r%m<<8<*~K9`Atf@&9w7&1ScsLP&@FAR#I;M0Ml_r0C_su
zCHs_{$#g)O8`gW;ne7wb^2t@ObxWbF#o>Y^8Tj#Ss}Tl108cu*gu2`JP?WJ%yhPdJ
zztzv@W5BBaxc(+5g$r1-1Y`*bR^ilZQmgd&Vm7q)8f-Sdv52<otX%D3;{NP=<8htR
zXfS0MluG<z0L@{<c!<xrX(P8CZeO8WU1;uDF+`&xgb<*VfP3ktDNO@cm)k{$-437P
zW(_3oh!hISul6{dxTJRy(V{82;Q~6Uoa3NyO7HfmZH(ZtDO+n6dA(a-4g!w>BY9C3
zE?Wt`kkoGtToYj<n3EQXxo4i-bsTwh(8q4oZj%Coqo#XgE*&TLe2bGQ49-$)ga=O@
zhp!1<R%Dg36_V9R0VkNQ45Jo=h$*-cu}NyP;~UFfwK5Zdz$-)3m0rNN9OX|n#wxKh
zlEU+mH-dw6nTT}OZJp6N)aNgh)D?{&-k>CNYN1ya3r?#?IdJdpk<XELGn;;INY+iF
z(s0;m043t2IATFr2Pu`v4!L8Kg;Ztluc&U+C-__kLa5M<y<PAPABey;#65<h;9RCQ
zR$-($PY=E7^TU{2ufF9JMU@7O4r@HZ7R+0l%$-;X!#VHNn5NHh-OB8Ma9yrHvz6iT
zKo(@2K+sSKjaoIK4|>vee{ceg1WAz3gU>#rnZLN8f=5KpF|m<|>(9m;06!MSEn*(#
z2`e}5S~PX{&uKw~J8Gv*Ic7YbUSH36-HjUb1_5(X)^LNXBZ7>eYxMj{<23SsLf>R1
zH#gj5OxCrRE+&xY1ammF{WRb!;O~wtKT3qth0cKsnuiI+r#HKAbhTx#LWyO96w!$&
zKTH^*3yu9bwt8u7nmZ4GapUqv!@NQf{5Y`@7d9z%R_84EaBVY)zmUC@MuG8kLwqi-
z&RW;Uta>o}SU}m)FYAwNLjf9nS=OmgUvMvD#ShWnlggY#S92woFN1|avJmI`o&QJ~
zCCUtC7OTRo<VslXb3ODV<M|d=AK_74*|EqNoAYlV?<By81~c2>KgN^q117D9F!DX<
z97HG}h&FMN8+{ltq@<SVARIyOL&hFIf$toRTUd$L-jD+4eBkNhYAiB(emlX%g5<0;
zdg#a0nPFbQj;gogG@Js>C1b17-_a9gVjx&f5jo>8z-hzbEhcSz_hV@-OcRI2k&4pU
z>O1V2p`s3&0nj2Z-6KfxE`w$XE_)T0SSG}UUy^2Z*J)cxoC^<+Hue0)qG2}w^Hf*i
z3+Gl!)!?`3Sq?w=-}Zdo-SXsvCq1YADpES5W!SWL8IM`S;+1h;HbyPX35%xOPNc`;
zG+%SD^h@}m2MByLj|K>WZwuA6P+a2<kAeg8*GfSJ%t&|jG`=odLQf$|=4Q;yg2QGi
z3gfxL6{+2~@;WRNk{0g!CH%s~=U10GzLj$FSPKnv=JmmFtqi1rw?XUB{}0rTYL`5Z
z;=4B@I4vK99Sfi<Nt7gG2%*gCyw;cJ_kw8v89Qa3&38O?dM?G@gTN!7uq@RkO+FRE
z9+OKC#!VgYD?Q+1DE?J>X2YP=RN`F>I_sTVCb19qS@a#|DhoHsJ|55IIO?Liy-yz9
zP%DPF<hX(LJn4O}yg;3925F#Pr)D7$As`&>N6syjARq1@O29sfR1plpb8B;wzjpCt
z2)^AjRr{{2zBOgBJHFrW6!`|NV=MfymzC3(CSvQ!f6^8};`LVlutByitH0yQ2g=U2
zDMOGwMP^UV*-8>Q7c3V7KJc(R1lvOq7p?cM9Y>sc%d>KH_kPH^u)p{W(YL`5xrmGz
zogCY<@ta>uiGG_UJZ4f|M_QV5(&GmUVMutFZt)(b#EE@BjjD(gdJOO8nQ=^(KVB6b
z3n?jiI>hXs*rHV3suXrM!PQc5`>iAk;r)BwA9fjp8+NE=WQ{e@zb`EW=sk)=TK89j
zsbs7f2Z`NkPG&RrKPE(a7G{R7dMex%%^qbz4VeXh>^rmqH@Gl-%HyfwA~ADEev2DT
z_ug+jI&=BXxOo6~!b{J6L_-2SF<h2?#o_07r*9cg5A>mf%_lq`Z*usYI)6u{745wV
zvjw4hIvo1jOr`IzVu094Nj0r$)Yp$q%}*Vb!I(oc-nH;37_BKq6km@P_G5U)VK?wH
z9=1ndB;p(af=)`0+yHszEo-dOWYNPEN3Q1a_9i^28wqY^I4w}6uUp{sFDx1liYthi
zc9j(qmGs<#&6wpxv=+Sgp*AQ%;tT9#Krzm)pN&|I8L+`A?-pMLqKxcj7+N#TSCE#^
z`V&_}M_9)!(U0!Zwvw20@CoZ#zbg+BIyC(@eFB6SEIMyV#2}G>1Mi;Q!Q*c$O!#U8
zo3dOll76J7>J9|#@#8txI<;*-WppkNYR;RNQ$JpnZnATbGr=pv33c!KmfDrxJ*5d5
zWCw#O4j(Y=+7_~nZ5gU1t(n5jnj75mlhFG>uk|ZGbv8BwMLH7gDp`1~aGSWzi3<#%
zeV#Fb&~9(us9ae2sb<(NL|ispr}xVljX19$DtnxAqra``YH-mM;7VJA_Oo|tbL;C{
zaMniECRq$7cz3pf?hbNzTf6&*egg<r5Zyx$$y0l#`$IyOgL<ouf0=k!N9kg+vA05C
zZ=AWAP@!YUOuEdQP!kOT8X+0pY1I$}We5gn%1Q#thr=CY<4I@VvB%nQTH>yBEBl@$
z3Y{H*Pp{7K7ootp2RMKhtm~A;TbLb-U?`>P_WP!AOBr%_(WF5$QST?{ZVWyF?vv(P
zUnxrshwctgIkSCF*4_Ram?f3P%;OJs+h-diCrwsmVN>u~nGm*h3mPLLTY&-rS+@ZS
z&SGYTGGHp(*H4?(IGVxTAK_rS9d&Q(cs6uRj&e=b+JCewh(o_u=ycA-+M~v-CH=<6
zOop=kV_rE<xfO^dn{QVmi6!QFq0vWp6x4iY!mo@~v&g11+mKgGGY8=KLmE$Qb>+pC
zyp0eb7^$j>%vUybylfKO(bf0HOYwq5a{Qy_+8{fQ9M=1SAgu+;XVln0b+$-Oeob?$
z(j;z3xCn!CXK+f}5wrd9iGp+^DSY^eLNg#81zX=Qr-dYBE|8O}&!WaktzqHmBuINp
zHU1{hi&R<8S9YO*K0f}(edwxq2=XK;<cW~@-hPsn0Hy3RgEL5DqWA~jmD!BEyDrBc
zc1lC$A$<On8r0@A_mYAdyM(!;kM*)qzL7T=1^vK+yD7?wuSe;O`L^DeVh<>UXZ4_g
z?;EiFONV#ZzEI`Mtk!*QH23V+5i7n2RN*<E<gB7ZOqz0R*H&vEZbpim!mzQ;Vy@sf
zGi+C3&dp7bRR&nm`ZQ(r%6-H=9(U!g+1hV6TnW?uXmHLWm5sivC-Ow$d#jjiKatS(
zIsfcB7WYQ4z?)T<!<kG3V7sLaZh7}=(Ag&JHS!BqfWvL<I47LkV)%MEvF)rJ+&|9v
ztjs+)hSuv{5@)=QSw_IxR|Zl;E&i!Xm`ce!#0x_K(P4WC^wr^OEeXo2Dq!vVu7RO8
z=8jme`*l`)!)_U}0*$t3Mor}(WVyaVe&?0|5VZ3lX}#oDs6)$fq=s14f0f%UP}r6G
zM9h_M1*)jf?tOp(ELN+TrbQoVkyDlf;9JR3G_VI=?ep_dB>ri}cz_Wph6O+KKaR68
zVs69XHQt^OKz+`=z2mn}LvXLgW~5IsLk=w($o^V%!vA;(N*1my!BVp=uG{j1o{E@W
zZ)*d-FxB?gnG1j?Cx={uSbql2vHfp=XEq$CREJOnNFV3Ur4Z9_@V69q0FKe)779`E
zdQeMAms@d&d0d(Ghk|Ynr(CJavJxTEEBf>@yL7VhWJAxBiWa(AI4O!0tQ>3p{|S|o
zb;)W++I1>>OWSD{@<b|%`hsp)#@r#1(2g@~JWHub86V@W8g>SrYwaz|>5@4Vy!)}e
z=#(6b^{wm(DeyMF!^_4k>qn?cQX^$D4t8EgEXM<Mdm$6|y8ihMlqrHL6Wbr+qbEqx
zt(h~OK(VnO0WT#bXJ*XA62D2hJpxe?UL*^fN#~Ynj+-+XQCI~R#`3@*cV3{|P|mao
zeYW9t%@NxA21alf#}Sk?C->A&65HSIE3QyNsNIClBw1MjY89s_tm{8dH=yoo@$b4r
zkiynSO<{ralqG{>-P*<Nor`S!=|Ux~9~|Qy$l8HmrXrfJNVS@J%Av?OL9PdV05%0p
zTBNZRf`~w<Y5Rz4Q;EuODURR*{dj_CuJxY(Oj)&za$>X^t)-^^V84j4d(3|$j{_&1
zthXxL<yMW8aOPpZp^%WNR0bP2xB;HAfl6(zNTRGq-%|PNnBT&=N+E1I@WTuKoY4-D
zgu9u^xTQxk1n6lQR}KNzZI-nk8k5+tESE3-sM$xwbslTBQRac-WJ{hOmje4`FHZkR
zS<>1k+|(lU5xKxwWLB&6zqI`2<0lRzG88uGd(CEWHzyEIX$NNpO~{fil6Y1nbAfnw
z1@Ena;Dc^v2~1_0v*UsA`;d>sPPDrNr3=dPuBQ4aV2f)ZGpj#Z4@0Y{V<;`>R9{L&
zG4kBo%%)4JJ`m{GIX!UBcdXn@6S?f&rehh-Q!V?hs`2{P>3~N9_8(^RhiE3SmV0;h
z^ypiD5RSmRWgt49E0r^Q&0%>zDdp}_G;F&2##e*4gyC3|d{$A{G=R=3+Ij9%qI|V7
z&))~S`;U=tzMV5Whe#f|2}?)vGNE2n${-+c28RMANZ8QOhb7}x4=m4J2Z<ALDFv7@
zCTssjyss+InUh_GK9AgE&2;kUxj@JRFJ0%#FSUb!VPx_xbL#hk6kVOV)6RX5m^^R&
zPl5FII4!HEV7_5r6d2y@Q#Ki`6Lcl)_KW=K5}3}eM?|6rhTT%(7~KecvQpH0qOr`1
z=jj#fIzE7N0IW+dydGMOSg;D<*3#_fQHlU>jTZXM(Q?`+ZoXW~#PY)`^4*vOFVt0?
zYpCNE2MBIQho>fmPowkVsH;O>_u$B(Y=3T=G}uhYN*Ygy<Q-qFo`;m|F*4gJAgpL?
z@B@~&{#z*+!%OsB1DMBUkQJK)a8D9UKH`J+R7T$cn!+_U3$!}dT#Mzoz?nopq{>IO
zbpa&~E9c5LC>)l{4My%JtaFpOt1N)5n9&B~R3{>7PYlGkGq*T;5@n1DTo8)$VYv*i
z*f+le%>%B=kik32uF4UheYx`1_BX`^!z+TH0MYndhfwax$3n?x2Gq=|0*a?$tG!wE
zd^zH(4%A5K^RSa67-D6nzJoZ)uRHi(18=f!{~@AoyJM=1RUY=lTzSf62X^rK!ZMXn
zFAhq3qU7;g8lHWn$*v(GfgLLvFg%R~vJ%&a*iGgbnZ+5kLJDoX1TLCWwP#txR>Gmt
z`d3(lEX_WUiCzQU3hGDYkDhCTWidPMu?2-YM!sh95+gML@>k5wdkdIK3u36gp>jo^
zyhyVzR`NY-yl(ymomw6|8O)DRs-OEe9Fq9ec0aRHGK(#Y#34JH-t#aqGKzl<TMn=!
z&Q0W^*xA;+kOtn@&Ta5Lx)H~bo}V3!XNv>9;@@3tl{FcWke8ORr=cum%X}FHFtZaS
zPk0GmykhWAKR19b713ujc(>($-|1-;c+^d)`{tw${_6IMw>k0QZrFz+buh|dL8eUU
z?U(%w6I=WeKMG9g`l>;R2b$$HEj*PVwaBDol>`^MDL_mPTp+x|2E$E10X)v+u=H?R
zQ@-Kxge|m~xT(RgeV?mj1eR-o1>vrl8vRyX8O*|FkrC4{2#>u5?(6x9`vlNss2xR8
zHgL>kX1tNmx&dkv4f!~2n$(h2TU31K6I*?wr4<~K#Wh<oXL(%2rl8M7VFnn}SUBew
zHqj8K;;u1YB6m1nSTI#GcX?!NQo>e#e&{2K$Jh|T^NMkcTd@{&?ewgalk3aK^r0EC
zwi>xnE(xpOtKTjIhej+x#cji)8rOjnu|c@WL#EF2SxL<WZK6GZIw-cULF61QdNh1)
z0V%)7`(o`(;CA2i_AhSNg9#6qWFnMR3^ilO3Ae6?XaLrZs+7vvBWK8RL*K4@x#a?M
zsz&ukz&uo&9peSJYcV#67RlvDym1?LFCXaQL6_8f7c=W)c|I|wTn<2b_@TBZx#b18
zoug&51VzoA^-IO^TcW0802@R%9t<gdtSa;d<MPWgH)#R4Ka>KOVNtB%IR?q&Gp|{L
zjz2L!>ADWLLZ4-&krjbpj-rj;n^~0T-A1vX%`hfA3BcMgZ3F3R6~$)_cu~9~f{@vk
zt>_P?Cla=SlsyF>P{3ojK^D5%)9b6&a9r|}3-<jnQX3rsR$=FBT#rU7(Ymp4k>}*A
z`X30aD5>G%&I)7=YpwA58Ib@!NoVW1qrKCkCLnyPGqzjmdk`}E@;b9xkc6!M!&{aG
zl5Puh2eB9i7B80965Ux%0f6k<p9cdHx2}=z6<|UdZ}W;~klQl(AjY!xr>mborh~!K
z3l|JX*l57AKgkhL)Ol^#ADkj`Rabr*x^6fOeSCF&yJ<8FG+&$W-vvp`cb}r2Q`|}f
z7^g8T4G{u;lu2pVPzE>#_Gm;mY`HGg^`UzxB5)r?Fxx``E6Hrd7;OU-Fh@0C&Bm9z
zpY-pCyF8P7SBQs^P>mZgK8Kv#t?8D0K~Ha(9oI$xr<FGomGNJyfD)11-WUF0`!J8O
zQ!ze0lhA9c4e<15ldnXT0<EKlpzGp%U<?+*17JMi%nZ`jITn4<{g{pLHwYKAalRp}
zUmc%wUwRjvBa}FQ8NBH>lyGUniGu5D&ZG3_q9y7SC1WqerGaa{`iGz+Yo%V>{%CTA
zl=#&Qkaa9r<@}e-Ap9lfjQU+Azswj&Nq;3LBFa1RRB`A!kDjC!<!Avo|Gq;zA1ku#
zZxRh0P?|@e`{KL9BM!JLb^(8<RVSM9a09nTc>ACRDP01UW>LHj<WeAiOyc%XzP{(!
zGZ01dLtNhRaotI09#>y_=oyc8MmV&jtR)R<{gYVhm~W|XqdTS*u21&IAqdl*R*C#K
z-5d@`m^{<v$X?V>l%j*r?--e6l&yK_K&r1L7?p3!B4k0LIuyHHPEHNSI*zF0fA%mM
zjId6|kvBp|pD^O?V%9f$x%WDKScKX+;iU+Jn~U}b$Y)!a#!j^e$(>atbNmyfa`nIn
zcfn}I#4h0-D#c_*%OBnp|1F%Af}>ul-_CMpq&=wXtOf&%2VwS2$o|62Qz0&#QSw#w
zphI1Isaf~R;EC=4<_M`m=d$-EKljnKSyuOHHtha2Z7CI0;wA6sLbnyl$Nc`MQSKXQ
zk54&+m-hFL<t6`=4(X}a55!p&RsS5S(sjg~fe)I;q-Y!qp4uo-g%XfqCl~oW?tpHE
zfctu0$TQ6eW;&1pT385;OsYj9$YI!Xhie{XjZmBlNVTmitM98&{UG5y3vI8a;gq#q
z&7;9}kS>aV=-db<@ZU3&+#~1zBnfQ5FHZ~OKu6cBngb{!0{=2%b?;vi4!{umYoru;
zdBOuvfGG)b2V#GMKhbA>aT&^G^qH@ut2LIf>@&+nI54%X8+)29yO;as!k{mC*=)o6
zqMDNpZ<vq~$iz5(G4gP<0ihZNqvnFb!&r=~|4<u&O3CLHqzZ`hQd02wNKA{ru2|hQ
zhGx4iwyNkF0pA*|8G<xp!Cma6a<w3Wfp&Y+fBZh6>;Hdc$pXWQf;M$C*hP__eaSBl
zqsZ}guVcyom>F`iIP7K0wUo|R7qMU5arqE39UCKEs;`*PmlC(&JiaPcY&~e!j{IPh
zrxtqZI}YEa*~LJS2wJFR^HIE-Tp6*8=WBW*8JW)E^!6g(K_3h{$K{6Yq|_J{H{g}W
z@(csy<oo7{;O>6nc6^}-;!rAM-<T|-T_;nO$x2QE!$Y$~bE5naN_X?sbm#ykMW~fN
zK7i%wF#?k!dPgYJe8@Js^T46*vq&!}NHp~Z$A^&TKHJ?eHd!woe1Q426AIeBD3S37
zpib?QQ2RG^(EDY~UbcPCJ?B_x2mO3nlMUIvug<OG6c!Z6cl7W+eh~4PoCY)}(e_bh
zCt!(xj9WqctZR7q`2nzF=8so9x^IY&&ZZA>Pe1!*b4Jbir`HU=6PMFLmdWAq2L9#)
z{34i~?{V|vKP#i<D+hpFP9FDGV{(b${+r}$laSkwIix}${_T*`x|Xm50<9LcWDA?R
z;gq*ENbSe6!jelkF<uv^-pTuS!eP4xMAA<T<&PO!dJO*a;<-!CVBz!A1xUN^5Q|F$
z{BN$?!zku@Ib~RdK^W5=>w%#}nHM{xq(**+=acZ+vp~PrhS{){n)>3Clu(efi0n-y
zzAyk3-qAJY6YQgV0Q9k3T_70{{55#<K}igzRp&yyk~PuQJ5XkO`3XE3==f4{K7$56
zL&%jS-r>=veiOBEsK`#t$EzU?ZedKRLE!1<DaFn(6pXYi>~Mr4X*E{YMxf}T2x)EP
zm!H!<a0<12jh~MzIYsPD`PTnc03`8|&GFnz8+QTX4yt`8YHZyGjSw7RX|VoT^y>5m
zk_HoB&wUVJo28Ar{M}ryPTG&X#psp-A{cK9|K%NTrNV3s=v7e3q_`#3Y}gcpiu$uU
zxMbVU`4vTtuc8tZcuf=zr;UJy&+6LQw3Ka?FRH5TM#tdMQ7W|V&|Ho+L2HIdG@Vr_
zOcv+m%52GhH6Yl(24e!$oRNf9<w`uyxMpzXAymdm$1qjuWl<dm=+GLaLDanf7q%Bb
zp+CcabFoEi43Ad$Y-;kWADoPF>;G2O;<(4j;4yX8-6gLp143a2H9LzSXg3O*3!i@v
zPS?V{E1erhaiQ~g+}@iew&#uf=rK)ey`Xoe?_c*9j{Da+Vxz@2*-Xm5?cNMmFpl#)
zL3}a)8MQ}gYt~QW*czCs4}0{l4nYgz`Da1(3V_T?h0;?Xc5Bu4gcTwU?)@rIuSX$f
zDTz0Y6fyluyTqJr@gSFx$eF3G>#5=nyf$uN8dQFXiGQRsr)4P?Der0R@N%gag@X~!
zeM1``qU08qPkK#MPXU!it6(A&&~7vJ5;n=GFvj$;sk<E6CI2{X2q7HElT2VM%GAbV
zoI^`W+5Or(`DDprSA6i2es{n`E*>XQ2H?3fMGO^|#odCh1G_%2lFg`xjN)MEavEkx
z_tycbv+3ZHV5q(Sf=Y!dH>fQ$PANy1mXuUg#4{A7MIjp6eV7mg&Ttfj{Gb@=={S=>
zO+-kfAn?PpymYu0BDp0P=F#x6tMl}cHA0yoMrDF5(#pf18D*qUNTVTXAYy89^g9aW
z&h-$n@>)7)8i)KM65FM9LRKl`4Hv2+p7Ra^i{A;gRJSE=Mm)5A&C}4zXj-`;PO>Xn
z_d0yYj6j`sicIr#PKtGd0{0&54@${`%Y;9?Wgb(S<Ip98;q1~3BmG=LRe>L^LN#I;
zvd?WXsYWL?ZR~|JbAeXx>5s-{NebevcOyTYEzVwDY3Sl!DcR}kOoVOgd0UBrzq|GH
z@#2s|Uj$va(|7JnD2)O6%YTKgGaE7K<h@<d<V`g=M#K~d#3P<TzE{Ba<5U8w5aTv|
zHeT%Ck$4F@nWr=J;^9wut>k^NryR7)0Fo)s{})VVtqhp5<Ps3ECz#_AutF8_vEdlk
zNNK`abC8yQT2v7j!zsT#?8+@ZXqH)bW+3p~;Yn)7rLCMj`iTeG7f`ygRH2<3%a|?E
zVsP39;VT+M=`ckYr>M%OJcG_64@PIrBCi2;H$DotpfwY0-{r^8v3VF@1sBXDPRRaP
zH&|k8X$<DgblH>)|I2FDlQj;P+ZfIRFQ<AHZ%dXP<uSe^^ewFhwC3Yj49HaEkQyyd
z_lWjA^mEKi{NQmDQY1B;r%rk}aV*CoI`T|D;7C|PgiHDnJm#5+2rj(FJYa@~=ufn3
z<hUr>T}`#@ku2cmR7`fsqJT;Me`&EQoGgQ)Eoe_pDc33TGx{-iQAu?d0E!J|L2UnZ
zJ<ue@=>s0qa2rivL9$IQX>m6z^mr=x+vy6Af!vje;;vmXwwpl-M@5plkQzj&FN@OZ
z!~d1Nci>r(wGUN4>?6H?7P4;M@uSZ8J28Do)N2^L)jur$%&5|<w8nipGkaZ++KeOh
z^?gJ#<x`P&J98i+`~<)+mQb87cNutFP4+z^)i5MV9<(Aj%Iei8=gn?B{Q#Y<HKxNE
zk`|x7u9OAqSn^W$LlIne)_!N{7`UrI4^!l_XVj$S`U$%HhMmpT^tDzUJ2MHozgj_G
z`6ZEz3673ThiN)fs$8W$>-G2zj@$hiZ{WpEePuyPmd5ZMCe7rbF0_(7)VRM*t40O;
zM*J72vK&hU60g@>Ps(v+X&D5>8bNOUWS08O+WjakuBAt1VN|Q6BYa;i^7)uqkVzJ2
z&=qhhEUOA&>(+c9u0B*~Nbf@znv|c7e!OV)QqH=!-auzI7|QstN$IaiN^Dc~vXvA>
zv(WaU+6q}ePdno<tgjm4fFbwo3#U1gn-0ZRuLbw%L5q`>K-gG&o4M3z?h)EINlf3=
z1Z{7EgMQ;kSJ{E5wF0DkFm<v@bWl3Vu!Jm`helTA8fMh<L<7_=SFUetvK$a`gy-D?
zrR|!pM%hh|SHlRg&&5ONbb}}RzMlLN5>Sl^2kKc4!g;y8@3U`%uqh-(A)!fa^39Vi
z<~#Xe>FRCBe*RU&G12>+4Np)%iUFeq`p@#+#DANu!m=E%J_OzeQP*3zj1Pw0$Gix7
z0Kqb+nq}9G4gxDB%^Lv=^4pU<RZUb<`Ohw4EwBF%^<D~pRrH5>i`#_bZO=vI(QK=2
z;GPI8oQ*H4t*N>iZuuA5mKIG~w%xyHgSy7Hzg%zGKX~kAM1(Du!(&g-%_2+Lzv+hU
zm(BRBi{x4^u)D+o1)B)%^OgK&%|jU%otdHAICx6+kXH8>z)?#VMix3I7abr9Co?DG
zH`S)PED<nIEOqZblZQGG!>cx*S24qf4wLtcXjz579}6>4ec)d#p=V4mXS)E`2wJ7t
zzD|pM;1CleEL-ikQ9=5u4o~nHr!s&w%jL>?<7~?VC{Vcc&!?AN?HSzPwH5O8z+u35
zjamHv98Vv3on%VOt4VX8<L9c7e?%InP^niy2j*AHLJh#oz8{*Guo8+7YQTR`*FwD2
z<>ek%jAx@ey8uh1T5i3gEsQ2mqP>2wX1aCrB#h#)Me-AZpnK8>K9rTJ;F|%<xAT^+
zb#=Ui9K#o^>U+)Znvo1v4C6}Q2?iZgQs|eC&?*nbYHgy{1<fSvrErE`if&?Vlbt(q
zRvs(a|C>F4o>JS|-1fUG*hcfDm~}_As}q$f`X_ifQ)gx)8cZyXJA{FFCWh~B^g%5I
zH7ovR%YCSEX;looyAef2^Bf{eA`gB5EO4!R2tD@d9`30&>}(Hf1*3@g`ox>b!}3X<
z$V)yv{(=8b8U`D)rPnm5Lt?Q%haGvQzE;-;1cR>p;D!#Ft@zq0!f`o*+V9clNxN}C
zJds7YY3Ak&3FBR9&tG-Pc)#kQyY_*8v9^r{JSXSX4<PI}yxC_7z=j8AtTn-6qBhVN
z9p?rC{7EA>+AjL_N2wk)-J>bX93u&VlvUN<Cg~{_3eh0polDAUvUP@L;459U&z$=7
zUea{b%I*31II!>Sd#y7Udwgo~(>8D$FPucxbR1un@E$UvG#=x4Uto4G*!rAG@bKU0
zQ#&TG^urd$=jYtTP7@|a<X-JDE+s3h((v$nw{s8R@wR~X6&OD*j$*oIf?*@ILKo3q
zyvPLFPVL`dvOMw=S6K~bb`>f3{vMG=Z2)=3!PCpzREGntw5<DTbzC@U<SR$QEmRGd
zr^ni%N=PVf0pVvK<EM!UMF^M$Fpt)VkBSmgksw<w#*C=fT+KzO4|t7<tD#~cl=x>0
z?DVv9y-1wtDxb_*(KS3ZMBp_4g~KOuS`Nph$UUM#KL~3l|5%%FwrwY(YIMX?+f?f_
zHs0ZN&cxmP>WnIigBQ{&oIGfY+2(|(&Zi_<MjVoLEtNzm-csM4y^-OAKlC$e<U~hc
za6pp}LaWj6d8@JlaUR3+qu_U#vD0Fg|8A^CJ_Eamw3&AI&9$9XV~SQJj(c}1mswZx
zEdsHAr@BL44sr?0yYqxC*@3bKTo?i+I8<fTZwWbjGaNH2WV04)t<rC`NTEnR1h`4H
zoN-(nrlF@bXzqMYlc@n)rQ4hcs-Z*$WZKiMtiw(G1ELR>&-3bOw1}${RD32!G<Mk{
zbU&5=cb&KZF*?q<UlC|OjpTxpNtImc&1T$l^7w9gjDq{7q>9tI%l=uDm@^uhMv^;7
z>0f{|_iuEMKUKV$2|#2T%4r82FxnL3kg142XMh7%%#k~-K=J<az6<G`Hsy6bDH9wn
zxe}~adNpwaFp47F#6(m2n`@zdMRV)D{&*A@D;km)q=i@K@-l`I#qOzn5Qaj14AeG-
z54S&W!pTGaPHhOss9u-iVz$xI2Vp_;GEK~dU<F`F@e&H<65*7uLx&EUEEFC&Y?MCH
z>CCuW=?0ekaR)-$#9eccc<97T>38*W4h@AWN6IEgD9(XR7+@!B5?7VWAyCXeQL&*f
z1Jc^)`C#c)Hy_4a6jn-;LljDG#8W?`0T+a(SJh?Ajp7-e|0bN7<$0m!{#7^B^#$qV
zYa-O?N?Uw})SG^%Q4Hc1U#&&z6%;oRH2t&{>{Ll&7fo3f%6<xw4!^UOx?s|`-G3%8
zIjnja{1$kD<*$kED~?rWRsbbfkG=MYMI~oKqVA^@xo06(fD-^Ls!<#gs{bA+U;@pr
zB)}C@bJ`tl=?riq1xt7(3S2>BSj)R!M75>kY!IUL-V6F<vL*P-A%+B^PzA2<Q{yrF
zyOqeq3da|?p-3R--05uvrup*#ioolg2*{m#ba=j)6=}k=jUv*j%3-PPr_sMY`^E>~
kPyh|Stes9jU9^ENnG`e-apMn>RGrk$ZJh-m4z!IYLV;aWz5oCK
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..54193b196c3c265bd18558ae12fecc3700ccc3df
GIT binary patch
literal 1924
zc%02tJ!lj`6rPzo6VzZXlHd<9tVB`7#J!jZQHvxOH7dd2Pa-OWb!YB&$<FSvGq+I-
zJ;B1#!p_D@6t%HYu!*2p`BS8_GyWEWU?&#mo83FJ*(72L(Pd}ny*D%Oeeb<*79rG{
zm*<PN@OltJ*a*z5lBppq(68iu#?Zfg{s#<u6o!Ms8)notwEecjv=QH<C6iHY(w3HX
zV5C2%>76~D*^a?|qa8jAy7gVEqIH|O=LH}*Jg}(p^=j<J2N)j_9={ek$KgBs;6(6*
z-uHW`DHtubM}<-{_2@{Y(s-!?@<|@BbIQh91O(OJS6@x~p}iIg#>z*r!0~kwS<|t2
z#Ff4=0m2zM5&Fd{!PloBeqJDzB_&C8Fo)Ta6&&iWuy8tC#4tv+h$o(g$2MBj@oPQ;
zn<jaKpK#mFgU}rC2yAR|6OGndsn7B;SPdoL(IOdN7V@kE^Ku~tjqUl)Tr*fCHAn=~
z7y@Cawqw<y(c?S%M{`=vgP?`^<yl)%Ez1-QQAEGmg0gTub9i8?t@0MFFTnhU=(na$
zmCNOus__~cdyi+HO=Fa{Ue<ks10y0zsUh!kL)~qax-c!SVwixr3U({lY*k;WY!SxH
z#jy>k_yFT-({p^+bksQ<p3Mj;MGQFT!i?$7pkGKN2YXB}rf(O8B2~@=vsEpctHoXb
z0clULEfr%MnP10hH<omz@a;v}h8~xd-ts)$IEQV*E4j%i<5jk01h;5x;ZK;>9x)Bw
zO)%{SbjX;O21Xe*MexuTCZhYFS_hwWQ(p@r1d;0+BKc3tNYm9itZFrf9lY4B+%AP3
z>G(i@p9{%&Yf4lq%#E(W*)hp{7JBlk<^pH3R;f9yg7*3-@$9x8Az|*iBR%D18#Thi
zVFiW^mkt2$82sXUJA1V*J-buy>FU+t4}}JcLRjHdnEd)>>cKF%_ik_7(U~8I!9<b_
IULXtf6HFc!&Hw-a
--- a/content/media/test/manifest.js
+++ b/content/media/test/manifest.js
@@ -635,24 +635,38 @@ var gMetadataTests = [
   { name:"wavedata_u8.wav", tags: { }
   },
 ];
 
 // Test files for Encrypted Media Extensions
 var gEMETests = [
   {
     name:"short-cenc.mp4",
-    type:"video/mp4",
+    type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
     keys: {
       // "keyid" : "key"
       "7e571d017e571d017e571d017e571d01" : "7e5711117e5711117e5711117e571111",
       "7e571d027e571d027e571d027e571d02" : "7e5722227e5722227e5722227e572222",
     },
     sessionType:"temporary",
+    duration:0.47
   },
+  // XXX Bug 1082239
+  //{
+  //  name:"gizmo-frag-cencinit.mp4",
+  //  fragments: [ "gizmo-frag-cencinit.mp4", "gizmo-frag-cenc1.m4s", "gizmo-frag-cenc2.m4s" ],
+  //  type:"video/mp4; codecs=\"avc1.64000d,mp4a.40.2\"",
+  //  keys: {
+  //    // "keyid" : "key"
+  //    "7e571d037e571d037e571d037e571d03" : "7e5733337e5733337e5733337e573333",
+  //    "7e571d047e571d047e571d047e571d04" : "7e5744447e5744447e5744447e574444",
+  //  },
+  //  sessionType:"temporary",
+  //  duration:2.00,
+  //},
 ];
 
 function checkMetadata(msg, e, test) {
   if (test.width) {
     is(e.videoWidth, test.width, msg + " video width");
   }
   if (test.height) {
     is(e.videoHeight, test.height, msg + " video height");
--- a/content/media/test/mochitest.ini
+++ b/content/media/test/mochitest.ini
@@ -135,16 +135,19 @@ support-files =
   detodos.opus
   detodos.opus^headers^
   detodos.webm
   detodos.webm^headers^
   dirac.ogg
   dirac.ogg^headers^
   dynamic_redirect.sjs
   dynamic_resource.sjs
+  gizmo-frag-cenc1.m4s
+  gizmo-frag-cenc2.m4s
+  gizmo-frag-cencinit.mp4
   file_access_controls.html
   fragment_noplay.js
   fragment_play.js
   gizmo.mp4
   gizmo.mp4^headers^
   huge-id3.mp3
   huge-id3.mp3^headers^
   id3tags.mp3
@@ -314,17 +317,16 @@ skip-if = buildapp == 'mulet' || os == '
 [test_bug465498.html]
 [test_bug493187.html]
 [test_bug495145.html]
 [test_bug495300.html]
 [test_bug654550.html]
 [test_bug686942.html]
 [test_bug726904.html]
 [test_bug874897.html]
-[test_bug879717.html]
 [test_bug883173.html]
 [test_bug895091.html]
 [test_bug895305.html]
 [test_bug919265.html]
 [test_bug957847.html]
 [test_bug1018933.html]
 [test_can_play_type.html]
 [test_can_play_type_mpeg.html]
deleted file mode 100644
--- a/content/media/test/test_bug879717.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <title>Test for bug 879717, check that a video element can be drawn into a canvas directly on 'play' event</title>
-  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
-  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
-  <script type="text/javascript" src="manifest.js"></script>
-</head>
-<body>
-<video id="v1" autoplay />
-<video id="v2" autoplay />
-<canvas id="c1" />
-<canvas id="c2" />
-<pre id="test">
-<script class="testbody" type="text/javascript">
-SimpleTest.waitForExplicitFinish();
-
-var media = getPlayableVideo(gSmallTests);
-
-var checkDrawImage = function(video, canvas, name) {
-  var exception = null;
-  var exceptionName = "nothing";
-  try {
-    var ctx = canvas.getContext('2d');
-    ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
-  } catch (e) {
-    exception = e;
-    exceptionName = e.name;
-  }
-  ok(exception === null || video.ended,
-    "drawImage shouldn't throw an exception on play of " + name + ", got " + exceptionName);
-};
-
-if (media == null) {
-  todo(false, "No media supported.");
-  SimpleTest.finish();
-} else {
-  v1.src = media.name;
-  v2.mozSrcObject = v1.mozCaptureStream();
-
-  var v1Tested = false;
-  var v2Tested = false;
-
-  v1.addEventListener('play', function() {
-    checkDrawImage(v1, c1, media.name);
-
-    v1Tested = true;
-    if (v2Tested) {
-      SimpleTest.finish();
-    }
-  });
-
-  v2.addEventListener('play', function() {
-    checkDrawImage(v2, c2, "stream of " + media.name);
-
-    v2Tested = true;
-    if (v1Tested) {
-      SimpleTest.finish();
-    }
-  });
-}
-</script>
-</pre>
-</body>
-</html>
--- a/content/media/test/test_encryptedMediaExtensions.html
+++ b/content/media/test/test_encryptedMediaExtensions.html
@@ -99,56 +99,141 @@ function UpdateSessionFunc(test) {
     info("sending update message to CDM: " + update);
 
     ev.target.update(StringToArrayBuffer(update)).then(function() {
       info("MediaKeySession update ok!");
     }, bail("MediaKeySession update failed"));
   }
 }
 
+function PlayFragmented(test, elem)
+{
+  var ms = new MediaSource();
+  elem.src = URL.createObjectURL(ms);
+
+  var sb;
+  var curFragment = 0;
+
+  function addNextFragment() {
+    if (curFragment >= test.fragments.length) {
+      ms.endOfStream();
+      elem.play();
+      return;
+    }
+
+    var fragmentFile = test.fragments[curFragment++];
+
+    var req = new XMLHttpRequest();
+    req.open("GET", fragmentFile);
+    req.responseType = "arraybuffer";
+
+    req.addEventListener("load", function() {
+      sb.appendBuffer(new Uint8Array(req.response));
+    });
+
+    info("fetching resource " + fragmentFile);
+    req.send(null);
+  }
+
+  ms.addEventListener("sourceopen", function () {
+    sb = ms.addSourceBuffer(test.type);
+    sb.addEventListener("updateend", addNextFragment);
+
+    addNextFragment();
+  });
+}
+
+function PlayTest(test, elem)
+{
+  if (test.fragments) {
+    PlayFragmented(test, elem);
+    return;
+  }
+
+  // This file isn't fragmented; set the media source normally.
+  elem.src = test.name;
+  elem.play();
+}
+
 function startTest(test, token)
 {
+  manager.started(test._token);
+
   var v = document.createElement("video");
-  manager.started(token);
+  var gotEncrypted = false;
+  var gotPlaying = false;
 
   v.addEventListener("encrypted", function(ev) {
-    info("got encrypted event");
+    gotEncrypted = true;
+
+    info(token + " got encrypted event");
     ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
-       "MediaKeys should support this keysystem");
+       token + " MediaKeys should support this keysystem");
 
     MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
-      info("created MediaKeys object ok");
+      info(token + " created MediaKeys object ok");
       return v.setMediaKeys(mediaKeys);
     }, bail("failed to create MediaKeys object")).then(function() {
-      info("set MediaKeys on <video> element ok");
+      info(token + " set MediaKeys on <video> element ok");
+
+      ok(MediaKeys.isTypeSupported(KEYSYSTEM_TYPE, ev.initDataType, test.type),
+         "MediaKeys should still support keysystem after CDM created...");
 
       var session = v.mediaKeys.createSession(test.sessionType);
       session.addEventListener("message", UpdateSessionFunc(test));
       session.generateRequest(ev.initDataType, ev.initData).then(function() {
-      }, bail("Failed to initialise MediaKeySession"));
+      }, bail(token + " Failed to initialise MediaKeySession"));
 
-    }, bail("Failed to set MediaKeys on <video> element"));
+    }, bail(token + " Failed to set MediaKeys on <video> element"));
   });
 
+  v.addEventListener("playing", function () { gotPlaying = true; });
+
   v.addEventListener("ended", function(ev) {
-    ok(true, "got ended event");
-    SimpleTest.finish();
+    ok(true, token + " got ended event");
+    manager.finished(test._token);
+
+    ok(gotEncrypted, token + " encrypted event should have fired");
+    ok(gotPlaying, token + " playing event should have fired");
+
+    ok(Math.abs(test.duration - v.duration) < 0.1,
+       token + " Duration of video should be corrrect");
+    ok(Math.abs(test.duration - v.currentTime) < 0.1,
+       token + " Current time should be same as duration");
   });
 
-  v.addEventListener("error", bail("got error event"));
+  v.addEventListener("error", bail(token + " got error event"));
+
+  PlayTest(test, v);
+}
 
-  v.src = test.name;
-  v.play();
+function testIsTypeSupported()
+{
+  var t = MediaKeys.isTypeSupported;
+  const clearkey = "org.w3.clearkey";
+  ok(!t("bogus", "bogon", "video/bogus"), "Invalid type.");
+  ok(t(clearkey), "ClearKey supported.");
+  ok(!t(clearkey, "bogus"), "ClearKey bogus initDataType not supported.");
+  ok(t(clearkey, "cenc"), "ClearKey/cenc should be supported.");
+  ok(!t(clearkey, "cenc", "bogus"), "ClearKey/cenc bogus content type should be supported.");
+  ok(t(clearkey, "cenc", 'video/mp4'), "ClearKey/cenc video/mp4 supported.");
+  ok(t(clearkey, "cenc", 'video/mp4; codecs="avc1.4d4015,mp4a.40.2"'), "ClearKey/cenc H.264/AAC supported.");
+  ok(t(clearkey, "cenc", 'audio/mp4'), "ClearKey/cenc audio/mp4 supported.");
+  ok(t(clearkey, "cenc", 'audio/mp4; codecs="mp4a.40.2"'), "ClearKey/cenc AAC LC supported.");
 }
 
 function beginTest() {
+  testIsTypeSupported();
   manager.runTests(gEMETests, startTest);
 }
 
-var prefs = [ ];
+var prefs = [
+  [ "media.mediasource.enabled", true ],
+  [ "media.mediasource.ignore_codecs", true ],
+];
 
 if (/Linux/.test(navigator.userAgent) ||
     !document.createElement('video').canPlayType("video/mp4")) {
   // XXX remove once we have mp4 PlatformDecoderModules on all platforms.
   prefs.push([ "media.fragmented-mp4.exposed", true ]);
   prefs.push([ "media.fragmented-mp4.use-blank-decoder", true ]);
 }
 
--- a/dom/camera/CameraPreviewMediaStream.cpp
+++ b/dom/camera/CameraPreviewMediaStream.cpp
@@ -14,32 +14,29 @@
  */
 #define MAX_INVALIDATE_PENDING 4
 
 using namespace mozilla::layers;
 using namespace mozilla::dom;
 
 namespace mozilla {
 
-static const TrackID TRACK_VIDEO = 2;
-
 void
 FakeMediaStreamGraph::DispatchToMainThreadAfterStreamStateUpdate(already_AddRefed<nsIRunnable> aRunnable)
 {
   nsRefPtr<nsIRunnable> task = aRunnable;
   NS_DispatchToMainThread(task);
 }
 
 CameraPreviewMediaStream::CameraPreviewMediaStream(DOMMediaStream* aWrapper)
   : MediaStream(aWrapper)
   , mMutex("mozilla::camera::CameraPreviewMediaStream")
   , mInvalidatePending(0)
   , mDiscardedFrames(0)
   , mRateLimit(false)
-  , mTrackCreated(false)
 {
   SetGraphImpl(MediaStreamGraph::GetInstance());
   mFakeMediaStreamGraph = new FakeMediaStreamGraph();
   mIsConsumed = false;
 }
 
 void
 CameraPreviewMediaStream::AddAudioOutput(void* aKey)
@@ -110,32 +107,16 @@ CameraPreviewMediaStream::RemoveListener
   MutexAutoLock lock(mMutex);
 
   nsRefPtr<MediaStreamListener> listener(aListener);
   mListeners.RemoveElement(aListener);
   listener->NotifyEvent(mFakeMediaStreamGraph, MediaStreamListener::EVENT_REMOVED);
 }
 
 void
-CameraPreviewMediaStream::OnPreviewStateChange(bool aActive)
-{
-  MutexAutoLock lock(mMutex);
-  if (!mTrackCreated && aActive) {
-    mTrackCreated = true;
-    VideoSegment tmpSegment;
-    uint32_t trackEvent = aActive ? MediaStreamListener::TRACK_EVENT_CREATED
-                                  : MediaStreamListener::TRACK_EVENT_ENDED;
-    for (uint32_t j = 0; j < mListeners.Length(); ++j) {
-      MediaStreamListener* l = mListeners[j];
-      l->NotifyQueuedTrackChanges(mFakeMediaStreamGraph, TRACK_VIDEO, 0, 0, trackEvent, tmpSegment);
-    }
-  }
-}
-
-void
 CameraPreviewMediaStream::Destroy()
 {
   MutexAutoLock lock(mMutex);
   DestroyImpl();
 }
 
 void
 CameraPreviewMediaStream::Invalidate()
--- a/dom/camera/CameraPreviewMediaStream.h
+++ b/dom/camera/CameraPreviewMediaStream.h
@@ -46,32 +46,30 @@ public:
   virtual void SetAudioOutputVolume(void* aKey, float aVolume) MOZ_OVERRIDE;
   virtual void RemoveAudioOutput(void* aKey) MOZ_OVERRIDE;
   virtual void AddVideoOutput(VideoFrameContainer* aContainer) MOZ_OVERRIDE;
   virtual void RemoveVideoOutput(VideoFrameContainer* aContainer) MOZ_OVERRIDE;
   virtual void ChangeExplicitBlockerCount(int32_t aDelta) MOZ_OVERRIDE;
   virtual void AddListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
   virtual void RemoveListener(MediaStreamListener* aListener) MOZ_OVERRIDE;
   virtual void Destroy();
-  void OnPreviewStateChange(bool aActive);
 
   void Invalidate();
 
   // Call these on any thread.
   void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage);
   void ClearCurrentFrame();
   void RateLimit(bool aLimit);
 
 protected:
   // mMutex protects all the class' fields.
   // This class is not registered to MediaStreamGraph.
   // It needs to protect all the fields.
   Mutex mMutex;
   int32_t mInvalidatePending;
   uint32_t mDiscardedFrames;
   bool mRateLimit;
-  bool mTrackCreated;
   nsRefPtr<FakeMediaStreamGraph> mFakeMediaStreamGraph;
 };
 
 }
 
 #endif // DOM_CAMERA_CAMERAPREVIEWMEDIASTREAM_H
--- a/dom/camera/DOMCameraControl.cpp
+++ b/dom/camera/DOMCameraControl.cpp
@@ -213,18 +213,17 @@ nsDOMCameraControl::nsDOMCameraControl(u
     config.mPreviewSize.height = aInitialConfig.mPreviewSize.mHeight;
     config.mRecorderProfile = aInitialConfig.mRecorderProfile;
   }
 
   mCameraControl = ICameraControl::Create(aCameraId);
   mCurrentConfiguration = initialConfig.forget();
 
   // Attach our DOM-facing media stream to our viewfinder stream.
-  SetHintContents(HINT_CONTENTS_VIDEO);
-  InitStreamCommon(mInput);
+  mStream = mInput;
   MOZ_ASSERT(mWindow, "Shouldn't be created with a null window!");
   if (mWindow->GetExtantDoc()) {
     CombineWithPrincipal(mWindow->GetExtantDoc()->NodePrincipal());
   }
 
   // Register a listener for camera events.
   mListener = new DOMCameraControlListener(this, mInput);
   mCameraControl->AddListener(mListener);
--- a/dom/camera/DOMCameraControlListener.cpp
+++ b/dom/camera/DOMCameraControlListener.cpp
@@ -132,17 +132,16 @@ DOMCameraControlListener::OnPreviewState
       DOM_CAMERA_LOGI("Preview started\n");
       break;
 
     default:
       DOM_CAMERA_LOGE("Unknown preview state %d\n", aState);
       MOZ_ASSERT_UNREACHABLE("Invalid preview state");
       return;
   }
-  mStream->OnPreviewStateChange(aState == kPreviewStarted);
   NS_DispatchToMainThread(new Callback(mDOMCameraControl, aState));
 }
 
 void
 DOMCameraControlListener::OnRecorderStateChange(RecorderState aState,
                                                 int32_t aStatus, int32_t aTrackNum)
 {
   class Callback : public DOMCallback
--- a/dom/camera/test/test_camera.html
+++ b/dom/camera/test/test_camera.html
@@ -104,36 +104,28 @@ var Camera = {
   takePictureSuccess: function taken_foto(blob) {
     ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
     ok("image/" + test.fileFormat ==  blob.type, "Blob Type = " + blob.type);
   },
   takePictureEvent: function taken_foto_evt(e) {
     var blob = e.data;
     var img = new Image();
     var test = this._currentTest;
-    var onPreviewStateChange = function(e) {
-      if (e.newState === 'started') {
-        ok(true, "viewfinder is ready and playing after resume");
-        Camera.cameraObj.removeEventListener('previewstatechange', onPreviewStateChange);
-        Camera._testsCompleted++;
-        if(Camera._testsCompleted == Camera._tests.length) {
-          ok(true, "test finishing");
-          SimpleTest.finish();
-        } else {
-          Camera.runTests();
-        }
-      }
-    }
-    Camera.cameraObj.addEventListener('previewstatechange', onPreviewStateChange);
     img.onload = function Imgsize() {
       ok(this.width == test.pictureSize.width, "The image taken has the width " +
                                               this.width + " pictureSize width = " + test.pictureSize.width);
       ok(this.height == test.pictureSize.height, "The image taken has the height " +
                                               this.height + " picturesize height = " + test.pictureSize.height);
-      Camera.cameraObj.resumePreview();
+      Camera._testsCompleted++;
+      if(Camera._testsCompleted == Camera._tests.length) {
+        ok(true, "test finishing");
+        SimpleTest.finish();
+      } else {
+        Camera.runTests();
+      }
     }
     ok(blob.size > 100 , "Blob Size Gathered = " + blob.size);
     ok("image/" + test.fileFormat ==  blob.type, "Blob Type = " + blob.type);
     img.src = window.URL.createObjectURL(blob);
   },
   shutter: function onShutter () {
     Camera._shutter++;
     
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -243,14 +243,13 @@ public:
 private:
 
     WebGL2Context();
 
     bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
     bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
                                 GLsizei width, GLsizei height, GLsizei depth,
                                 const char* info);
-
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGL2ContextTextures.cpp
+++ b/dom/canvas/WebGL2ContextTextures.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGL2Context.h"
+#include "WebGLContextUtils.h"
 #include "GLContext.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 bool
 WebGL2Context::ValidateSizedInternalFormat(GLenum internalformat, const char* info)
 {
@@ -110,24 +111,19 @@ WebGL2Context::ValidateTexStorage(GLenum
         return false;
 
     // GL_INVALID_VALUE is generated if width, height or levels are less than 1.
     if (width < 1)  { ErrorInvalidValue("%s: width is < 1", info);  return false; }
     if (height < 1) { ErrorInvalidValue("%s: height is < 1", info); return false; }
     if (depth < 1)  { ErrorInvalidValue("%s: depth is < 1", info);  return false; }
     if (levels < 1) { ErrorInvalidValue("%s: levels is < 1", info); return false; }
 
-    // The following check via FloorLog2 only requires a depth value if target is TEXTURE_3D.
-    bool is3D = (target != LOCAL_GL_TEXTURE_3D);
-    if (!is3D)
-        depth = 1;
-
     // GL_INVALID_OPERATION is generated if levels is greater than floor(log2(max(width, height, depth)))+1.
-    if (FloorLog2(std::max(std::max(width, height), depth))+1 < levels) {
-        ErrorInvalidOperation("%s: levels > floor(log2(max(width, height%s)))+1", info, is3D ? ", depth" : "");
+    if (FloorLog2(std::max(std::max(width, height), depth)) + 1 < levels) {
+        ErrorInvalidOperation("%s: too many levels for given texture dimensions", info);
         return false;
     }
 
     return true;
 }
 
 // -------------------------------------------------------------------------
 // Texture objects
@@ -135,56 +131,170 @@ WebGL2Context::ValidateTexStorage(GLenum
 void
 WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
 {
     if (IsContextLost())
         return;
 
     // GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
     if (target != LOCAL_GL_TEXTURE_2D && target != LOCAL_GL_TEXTURE_CUBE_MAP)
-        return ErrorInvalidEnum("texStorage2D: target is not TEXTURE_2D or TEXTURE_CUBE_MAP.");
+        return ErrorInvalidEnum("texStorage2D: target is not TEXTURE_2D or TEXTURE_CUBE_MAP");
 
     if (!ValidateTexStorage(target, levels, internalformat, width, height, 1, "texStorage2D"))
         return;
 
     WebGLTexture* tex = activeBoundTextureForTarget(target);
     tex->SetImmutable();
 
     const size_t facesCount = (target == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
     GLsizei w = width;
     GLsizei h = height;
     for (size_t l = 0; l < size_t(levels); l++) {
         for (size_t f = 0; f < facesCount; f++) {
             tex->SetImageInfo(TexImageTargetForTargetAndFace(target, f),
-                              l, w, h,
+                              l, w, h, 1,
                               internalformat,
                               WebGLImageDataStatus::UninitializedImageData);
         }
-        w = std::max(1, w/2);
-        h = std::max(1, h/2);
+        w = std::max(1, w / 2);
+        h = std::max(1, h / 2);
     }
 
     gl->fTexStorage2D(target, levels, internalformat, width, height);
 }
 
 void
 WebGL2Context::TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat,
                             GLsizei width, GLsizei height, GLsizei depth)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    // GL_INVALID_ENUM is generated if target is not one of the accepted target enumerants.
+    if (target != LOCAL_GL_TEXTURE_3D)
+        return ErrorInvalidEnum("texStorage3D: target is not TEXTURE_3D");
+
+    if (!ValidateTexStorage(target, levels, internalformat, width, height, depth, "texStorage3D"))
+        return;
+
+    WebGLTexture* tex = activeBoundTextureForTarget(target);
+    tex->SetImmutable();
+
+    GLsizei w = width;
+    GLsizei h = height;
+    GLsizei d = depth;
+    for (size_t l = 0; l < size_t(levels); l++) {
+        tex->SetImageInfo(TexImageTargetForTargetAndFace(target, 0),
+                          l, w, h, d,
+                          internalformat,
+                          WebGLImageDataStatus::UninitializedImageData);
+        w = std::max(1, w >> 1);
+        h = std::max(1, h >> 1);
+        d = std::max(1, d >> 1);
+    }
+
+    gl->fTexStorage3D(target, levels, internalformat, width, height, depth);
 }
 
 void
-WebGL2Context::TexSubImage3D(GLenum target, GLint level,
+WebGL2Context::TexSubImage3D(GLenum rawTarget, GLint level,
                              GLint xoffset, GLint yoffset, GLint zoffset,
                              GLsizei width, GLsizei height, GLsizei depth,
                              GLenum format, GLenum type, const Nullable<dom::ArrayBufferView>& pixels,
                              ErrorResult& rv)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (pixels.IsNull())
+        return ErrorInvalidValue("texSubImage3D: pixels must not be null!");
+
+    const ArrayBufferView& view = pixels.Value();
+    view.ComputeLengthAndData();
+
+    const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex3D;
+
+    if (!ValidateTexImageTarget(rawTarget, func, dims))
+        return;
+
+    TexImageTarget texImageTarget(rawTarget);
+
+    WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
+    if (!tex) {
+        return ErrorInvalidOperation("texSubImage3D: no texture bound on active texture unit");
+    }
+
+    if (!tex->HasImageInfoAt(texImageTarget, level)) {
+        return ErrorInvalidOperation("texSubImage3D: no previously defined texture image");
+    }
+
+    const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
+    const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
+    TexInternalFormat existingUnsizedInternalFormat = LOCAL_GL_NONE;
+    TexType existingType = LOCAL_GL_NONE;
+    UnsizedInternalFormatAndTypeFromEffectiveInternalFormat(existingEffectiveInternalFormat,
+                                                            &existingUnsizedInternalFormat,
+                                                            &existingType);
+
+    if (!ValidateTexImage(texImageTarget, level, existingEffectiveInternalFormat.get(),
+                          xoffset, yoffset, zoffset,
+                          width, height, depth,
+                          0, format, type, func, dims))
+    {
+        return;
+    }
+
+    if (type != existingType) {
+        return ErrorInvalidOperation("texSubImage3D: type differs from that of the existing image");
+    }
+
+    js::Scalar::Type jsArrayType = JS_GetArrayBufferViewType(view.Obj());
+    void* data = view.Data();
+    size_t dataLength = view.Length();
+
+    if (!ValidateTexInputData(type, jsArrayType, func, dims))
+        return;
+
+    const size_t bitsPerTexel = GetBitsPerTexel(existingEffectiveInternalFormat);
+    MOZ_ASSERT((bitsPerTexel % 8) == 0); // should not have compressed formats here.
+    size_t srcTexelSize = bitsPerTexel / 8;
+
+    if (width == 0 || height == 0 || depth == 0)
+        return; // no effect, we better return right now
+
+    CheckedUint32 checked_neededByteLength =
+        GetImageSize(height, width, depth, srcTexelSize, mPixelStoreUnpackAlignment);
+
+    if (!checked_neededByteLength.isValid())
+        return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
+
+    uint32_t bytesNeeded = checked_neededByteLength.value();
+
+    if (dataLength < bytesNeeded)
+        return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded, dataLength);
+
+    if (imageInfo.HasUninitializedImageData())
+        tex->DoDeferredImageInitialization(texImageTarget, level);
+
+    GLenum driverType = LOCAL_GL_NONE;
+    GLenum driverInternalFormat = LOCAL_GL_NONE;
+    GLenum driverFormat = LOCAL_GL_NONE;
+    DriverFormatsFromEffectiveInternalFormat(gl,
+                                             existingEffectiveInternalFormat,
+                                             &driverInternalFormat,
+                                             &driverFormat,
+                                             &driverType);
+
+    MakeContextCurrent();
+    gl->fTexSubImage3D(texImageTarget.get(), level,
+                       xoffset, yoffset, zoffset,
+                       width, height, depth,
+                       driverFormat, driverType, data);
+
 }
 
 void
 WebGL2Context::TexSubImage3D(GLenum target, GLint level,
                              GLint xoffset, GLint yoffset, GLint zoffset,
                              GLenum format, GLenum type, dom::ImageData* data,
                              ErrorResult& rv)
 {
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -340,16 +340,17 @@ WebGLContext::DestroyResourcesAndContext
 
     if (!gl)
         return;
 
     gl->MakeCurrent();
 
     mBound2DTextures.Clear();
     mBoundCubeMapTextures.Clear();
+    mBound3DTextures.Clear();
     mBoundArrayBuffer = nullptr;
     mBoundTransformFeedbackBuffer = nullptr;
     mCurrentProgram = nullptr;
     mBoundFramebuffer = nullptr;
     mActiveOcclusionQuery = nullptr;
     mBoundRenderbuffer = nullptr;
     mBoundVertexArray = nullptr;
     mDefaultVertexArray = nullptr;
@@ -1767,18 +1768,21 @@ WebGLContext::DidRefresh()
 bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget, GLint level,
                               GLenum internalformat, GLenum format, GLenum type,
                               mozilla::dom::Element& elt)
 {
     if (type == LOCAL_GL_HALF_FLOAT_OES) {
         type = LOCAL_GL_HALF_FLOAT;
     }
 
-    if (!ValidateTexImageFormatAndType(format, type, WebGLTexImageFunc::TexImage))
+    if (!ValidateTexImageFormatAndType(format, type,
+                                       WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
+    {
         return false;
+    }
 
     HTMLVideoElement* video = HTMLVideoElement::FromContentOrNull(&elt);
     if (!video) {
         return false;
     }
 
     uint16_t readyState;
     if (NS_SUCCEEDED(video->GetReadyState(&readyState)) &&
@@ -1820,17 +1824,17 @@ bool WebGLContext::TexImageFromVideoElem
         // we need to allocation
         gl->fTexImage2D(texImageTarget.get(), level, internalformat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr);
     }
     bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget.get(), mPixelStoreFlipY);
     if (ok) {
         TexInternalFormat effectiveinternalformat =
             EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
         MOZ_ASSERT(effectiveinternalformat != LOCAL_GL_NONE);
-        tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height,
+        tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, 1,
                           effectiveinternalformat, WebGLImageDataStatus::InitializedImageData);
         tex->Bind(TexImageTargetToTexTarget(texImageTarget));
     }
     srcImage = nullptr;
     container->UnlockCurrentImage();
     return ok;
 }
 
@@ -1864,16 +1868,17 @@ WebGLContext::ScopedMaskWorkaround::~Sco
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
   mCanvasElement,
   mExtensions,
   mBound2DTextures,
   mBoundCubeMapTextures,
+  mBound3DTextures,
   mBoundArrayBuffer,
   mBoundTransformFeedbackBuffer,
   mCurrentProgram,
   mBoundFramebuffer,
   mBoundRenderbuffer,
   mBoundVertexArray,
   mDefaultVertexArray,
   mActiveOcclusionQuery,
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -223,18 +223,26 @@ public:
     static const char *EnumName(GLenum glenum);
 
     bool IsCompressedTextureFormat(GLenum format);
     bool IsTextureFormatCompressed(TexInternalFormat format);
 
     void DummyFramebufferOperation(const char *info);
 
     WebGLTexture* activeBoundTextureForTarget(const TexTarget texTarget) const {
-        return texTarget == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
-                                                : mBoundCubeMapTextures[mActiveTexture];
+        switch (texTarget.get()) {
+            case LOCAL_GL_TEXTURE_2D:
+                return mBound2DTextures[mActiveTexture];
+            case LOCAL_GL_TEXTURE_CUBE_MAP:
+                return mBoundCubeMapTextures[mActiveTexture];
+            case LOCAL_GL_TEXTURE_3D:
+                return mBound3DTextures[mActiveTexture];
+            default:
+                MOZ_CRASH("bad target");
+        }
     }
 
     /* Use this function when you have the texture image target, for example:
      * GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_[POSITIVE|NEGATIVE]_[X|Y|Z], and
      * not the actual texture binding target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
      */
     WebGLTexture* activeBoundTextureForTexImageTarget(const TexImageTarget texImgTarget) const {
         const TexTarget texTarget = TexImageTargetToTexTarget(texImgTarget);
@@ -478,20 +486,22 @@ public:
     template<class ElementType>
     void TexImage2D(GLenum rawTexImgTarget, GLint level,
                     GLenum internalformat, GLenum format, GLenum type,
                     ElementType& elt, ErrorResult& rv)
     {
         if (IsContextLost())
             return;
 
-        auto dims = 2;
-
-        if (!ValidateTexImageTarget(dims, rawTexImgTarget, WebGLTexImageFunc::TexImage))
+        if (!ValidateTexImageTarget(rawTexImgTarget,
+                                    WebGLTexImageFunc::TexImage,
+                                    WebGLTexDimensions::Tex2D))
+        {
             return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImgTarget);
+        }
 
         const TexImageTarget texImageTarget(rawTexImgTarget);
 
         if (level < 0)
             return ErrorInvalidValue("texImage2D: level is negative");
 
         const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
         if (level > maxLevel)
@@ -515,17 +525,17 @@ public:
         if (rv.Failed() || !data)
             return;
 
         gfx::IntSize size = data->GetSize();
         uint32_t byteLength = data->Stride() * size.height;
         return TexImage2D_base(texImageTarget, level, internalformat,
                                size.width, size.height, data->Stride(),
                                0, format, type, data->GetData(), byteLength,
-                               -1, srcFormat, mPixelStorePremultiplyAlpha);
+                               js::Scalar::TypeMax, srcFormat, mPixelStorePremultiplyAlpha);
     }
 
     void TexParameterf(GLenum target, GLenum pname, GLfloat param) {
         TexParameter_base(target, pname, nullptr, &param);
     }
     void TexParameteri(GLenum target, GLenum pname, GLint param) {
         TexParameter_base(target, pname, &param, nullptr);
     }
@@ -547,18 +557,22 @@ public:
                        GLint xoffset, GLint yoffset,
                        GLenum format,
                        GLenum type,
                        ElementType& elt, ErrorResult& rv)
     {
         if (IsContextLost())
             return;
 
-        if (!ValidateTexImageTarget(2, rawTexImageTarget, WebGLTexImageFunc::TexSubImage))
+        if (!ValidateTexImageTarget(rawTexImageTarget,
+                                    WebGLTexImageFunc::TexSubImage,
+                                    WebGLTexDimensions::Tex2D))
+        {
             return ErrorInvalidEnumInfo("texSubImage2D: target", rawTexImageTarget);
+        }
 
         const TexImageTarget texImageTarget(rawTexImageTarget);
 
         if (level < 0)
             return ErrorInvalidValue("texSubImage2D: level is negative");
 
         const int32_t maxLevel = MaxTextureLevelForTexImageTarget(texImageTarget);
         if (level > maxLevel)
@@ -587,17 +601,17 @@ public:
             return;
 
         gfx::IntSize size = data->GetSize();
         uint32_t byteLength = data->Stride() * size.height;
         return TexSubImage2D_base(texImageTarget.get(), level, xoffset, yoffset,
                                   size.width, size.height,
                                   data->Stride(), format, type,
                                   data->GetData(), byteLength,
-                                  -1, srcFormat, mPixelStorePremultiplyAlpha);
+                                  js::Scalar::TypeMax, srcFormat, mPixelStorePremultiplyAlpha);
 
     }
 
     void Uniform1i(WebGLUniformLocation* location, GLint x);
     void Uniform2i(WebGLUniformLocation* location, GLint x, GLint y);
     void Uniform3i(WebGLUniformLocation* location, GLint x, GLint y,
                    GLint z);
     void Uniform4i(WebGLUniformLocation* location, GLint x, GLint y,
@@ -831,16 +845,17 @@ private:
     WebGLRefPtr<WebGLBuffer>* GetBufferSlotByTargetIndexed(GLenum target, GLuint index, const char* infos);
     bool ValidateBufferUsageEnum(GLenum target, const char* infos);
 
 // -----------------------------------------------------------------------------
 // State and State Requests (WebGLContextState.cpp)
 public:
     void Disable(GLenum cap);
     void Enable(GLenum cap);
+    bool GetStencilBits(GLint* out_stencilBits);
     JS::Value GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv);
     void GetParameter(JSContext* cx, GLenum pname,
                       JS::MutableHandle<JS::Value> retval, ErrorResult& rv) {
         retval.set(GetParameter(cx, pname, rv));
     }
     void GetParameterIndexed(JSContext* cx, GLenum pname, GLuint index,
                              JS::MutableHandle<JS::Value> retval);
     bool IsEnabled(GLenum cap);
@@ -966,16 +981,17 @@ protected:
     void UnbindFakeBlackTextures();
 
     WebGLVertexAttrib0Status WhatDoesVertexAttrib0Need();
     bool DoFakeVertexAttrib0(GLuint vertexCount);
     void UndoFakeVertexAttrib0();
 
     static CheckedUint32 GetImageSize(GLsizei height,
                                       GLsizei width,
+                                      GLsizei depth,
                                       uint32_t pixelSize,
                                       uint32_t alignment);
 
     // Returns x rounded to the next highest multiple of y.
     static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
         return ((x + y - 1) / y) * y;
     }
 
@@ -1087,83 +1103,103 @@ protected:
     bool ValidateBlendEquationEnum(GLenum cap, const char *info);
     bool ValidateBlendFuncDstEnum(GLenum mode, const char *info);
     bool ValidateBlendFuncSrcEnum(GLenum mode, const char *info);
     bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor, const char *info);
     bool ValidateTextureTargetEnum(GLenum target, const char *info);
     bool ValidateComparisonEnum(GLenum target, const char *info);
     bool ValidateStencilOpEnum(GLenum action, const char *info);
     bool ValidateFaceEnum(GLenum face, const char *info);
-    bool ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFunc func);
+    bool ValidateTexInputData(GLenum type,
+                              js::Scalar::Type jsArrayType,
+                              WebGLTexImageFunc func,
+                              WebGLTexDimensions dims);
     bool ValidateDrawModeEnum(GLenum mode, const char *info);
     bool ValidateAttribIndex(GLuint index, const char *info);
     bool ValidateStencilParamsForDrawCall();
 
     bool ValidateGLSLVariableName(const nsAString& name, const char *info);
     bool ValidateGLSLCharacter(char16_t c);
     bool ValidateGLSLString(const nsAString& string, const char *info);
 
     bool ValidateCopyTexImage(GLenum internalformat,
-                              WebGLTexImageFunc func);
-    bool ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
+                              WebGLTexImageFunc func,
+                              WebGLTexDimensions dims);
+    bool ValidateTexImage(TexImageTarget texImageTarget,
                           GLint level, GLenum internalFormat,
                           GLint xoffset, GLint yoffset, GLint zoffset,
                           GLint width, GLint height, GLint depth,
                           GLint border, GLenum format, GLenum type,
-                          WebGLTexImageFunc func);
-    bool ValidateTexImageTarget(GLuint dims, GLenum target, WebGLTexImageFunc func);
+                          WebGLTexImageFunc func,
+                          WebGLTexDimensions dims);
+    bool ValidateTexImageTarget(GLenum target,
+                                WebGLTexImageFunc func,
+                                WebGLTexDimensions dims);
     bool ValidateTexImageFormat(GLenum internalformat,
-                                WebGLTexImageFunc func);
-    bool ValidateTexImageType(GLenum type, WebGLTexImageFunc func);
-    bool ValidateTexImageFormatAndType(GLenum format, GLenum type, WebGLTexImageFunc func);
+                                WebGLTexImageFunc func,
+                                WebGLTexDimensions dims);
+    bool ValidateTexImageType(GLenum type,
+                              WebGLTexImageFunc func,
+                              WebGLTexDimensions dims);
+    bool ValidateTexImageFormatAndType(GLenum format,
+                                       GLenum type,
+                                       WebGLTexImageFunc func,
+                                       WebGLTexDimensions dims);
     bool ValidateCompTexImageInternalFormat(GLenum format,
-                                            WebGLTexImageFunc func);
+                                            WebGLTexImageFunc func,
+                                            WebGLTexDimensions dims);
     bool ValidateCopyTexImageInternalFormat(GLenum format,
-                                            WebGLTexImageFunc func);
+                                            WebGLTexImageFunc func,
+                                            WebGLTexDimensions dims);
     bool ValidateTexImageSize(TexImageTarget target, GLint level,
                               GLint width, GLint height, GLint depth,
-                              WebGLTexImageFunc func);
+                              WebGLTexImageFunc func,
+                              WebGLTexDimensions dims);
     bool ValidateTexSubImageSize(GLint x, GLint y, GLint z,
                                  GLsizei width, GLsizei height, GLsizei depth,
                                  GLsizei baseWidth, GLsizei baseHeight, GLsizei baseDepth,
-                                 WebGLTexImageFunc func);
-
+                                 WebGLTexImageFunc func,
+                                 WebGLTexDimensions dims);
     bool ValidateCompTexImageSize(GLint level,
                                   GLenum internalformat,
                                   GLint xoffset, GLint yoffset,
                                   GLsizei width, GLsizei height,
                                   GLsizei levelWidth, GLsizei levelHeight,
-                                  WebGLTexImageFunc func);
+                                  WebGLTexImageFunc func,
+                                  WebGLTexDimensions dims);
     bool ValidateCompTexImageDataSize(GLint level,
                                       GLenum internalformat,
                                       GLsizei width, GLsizei height,
-                                      uint32_t byteLength, WebGLTexImageFunc func);
+                                      uint32_t byteLength,
+                                      WebGLTexImageFunc func,
+                                      WebGLTexDimensions dims);
 
     void Invalidate();
     void DestroyResourcesAndContext();
 
     void MakeContextCurrent() const;
 
     // helpers
+
     void TexImage2D_base(TexImageTarget target,
                          GLint level,
                          GLenum internalformat,
                          GLsizei width, GLsizei height, GLsizei srcStrideOrZero, GLint border,
                          GLenum format,
                          GLenum type,
                          void *data, uint32_t byteLength,
-                         int jsArrayType,
+                         js::Scalar::Type jsArrayType, // special value TypeMax used to mean no array
                          WebGLTexelFormat srcFormat, bool srcPremultiplied);
     void TexSubImage2D_base(TexImageTarget target, GLint level,
                             GLint xoffset, GLint yoffset,
                             GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
                             GLenum format,
                             GLenum type,
                             void *pixels, uint32_t byteLength,
-                            int jsArrayType,
+                            js::Scalar::Type jsArrayType, // special value TypeMax used to mean no array
                             WebGLTexelFormat srcFormat, bool srcPremultiplied);
     void TexParameter_base(GLenum target, GLenum pname,
                            GLint *intParamPtr, GLfloat *floatParamPtr);
 
     bool ConvertImage(size_t width, size_t height, size_t srcStride, size_t dstStride,
                       const uint8_t* src, uint8_t *dst,
                       WebGLTexelFormat srcFormat, bool srcPremultiplied,
                       WebGLTexelFormat dstFormat, bool dstPremultiplied,
@@ -1250,16 +1286,17 @@ protected:
                              TexType type,
                              const GLvoid *data);
 
     void ForceLoseContext(bool simulateLosing = false);
     void ForceRestoreContext();
 
     nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
     nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
+    nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
 
     WebGLRefPtr<WebGLProgram> mCurrentProgram;
 
     uint32_t mMaxFramebufferColorAttachments;
 
     WebGLRefPtr<WebGLFramebuffer> mBoundFramebuffer;
     WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
     WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -43,16 +43,17 @@
 #include "nsCocoaFeatures.h"
 #endif
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/ImageData.h"
 #include "mozilla/dom/ToJSValue.h"
 #include "mozilla/Endian.h"
+#include "mozilla/fallible.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::gl;
 using namespace mozilla::gfx;
 
 static bool BaseTypeAndSizeFromUniformType(GLenum uType, GLenum *baseType, GLint *unitSize);
 
@@ -228,16 +229,22 @@ WebGLContext::BindTexture(GLenum rawTarg
     WebGLRefPtr<WebGLTexture>* currentTexPtr = nullptr;
     switch (rawTarget) {
         case LOCAL_GL_TEXTURE_2D:
             currentTexPtr = &mBound2DTextures[mActiveTexture];
             break;
        case LOCAL_GL_TEXTURE_CUBE_MAP:
             currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
             break;
+       case LOCAL_GL_TEXTURE_3D:
+            if (!IsWebGL2()) {
+                return ErrorInvalidEnum("bindTexture: target TEXTURE_3D is only available in WebGL version 2.0 or newer");
+            }
+            currentTexPtr = &mBound3DTextures[mActiveTexture];
+            break;
        default:
             return ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
     }
 
     if (newTex) {
         // silently ignore a deleted texture
         if (newTex->IsDeleted())
             return;
@@ -362,32 +369,35 @@ WebGLContext::CopyTexSubImage2D_base(Tex
                                      GLsizei width,
                                      GLsizei height,
                                      bool sub)
 {
     const WebGLRectangleObject* framebufferRect = CurValidFBRectObject();
     GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
     GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
 
-    const char* info = sub ? "copyTexSubImage2D" : "copyTexImage2D";
-    WebGLTexImageFunc func = sub ? WebGLTexImageFunc::CopyTexSubImage : WebGLTexImageFunc::CopyTexImage;
+    WebGLTexImageFunc func = sub
+                             ? WebGLTexImageFunc::CopyTexSubImage
+                             : WebGLTexImageFunc::CopyTexImage;
+    WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+    const char* info = InfoFrom(func, dims);
 
     // TODO: This changes with color_buffer_float. Reassess when the
     // patch lands.
-    if (!ValidateTexImage(2, texImageTarget, level, internalformat.get(),
+    if (!ValidateTexImage(texImageTarget, level, internalformat.get(),
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0,
                           LOCAL_GL_NONE, LOCAL_GL_NONE,
-                          func))
+                          func, dims))
     {
         return;
     }
 
-    if (!ValidateCopyTexImage(internalformat.get(), func))
+    if (!ValidateCopyTexImage(internalformat.get(), func, dims))
         return;
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
     MakeContextCurrent();
 
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
@@ -435,17 +445,17 @@ WebGLContext::CopyTexSubImage2D_base(Tex
         else
             gl->fCopyTexImage2D(texImageTarget.get(), level, internalformat.get(), x, y, width, height, 0);
     } else {
 
         // the rect doesn't fit in the framebuffer
 
         // first, we initialize the texture as black
         if (!sub) {
-            tex->SetImageInfo(texImageTarget, level, width, height,
+            tex->SetImageInfo(texImageTarget, level, width, height, 1,
                       effectiveInternalFormat,
                       WebGLImageDataStatus::UninitializedImageData);
             tex->DoDeferredImageInitialization(texImageTarget, level);
         }
 
         // if we are completely outside of the framebuffer, we can exit now with our black texture
         if (   x >= framebufferWidth
             || x+width <= 0
@@ -473,17 +483,17 @@ WebGLContext::CopyTexSubImage2D_base(Tex
         GLenum error = GetAndFlushUnderlyingGLErrors();
         if (error) {
             GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
             return;
         }
     }
 
     if (!sub) {
-        tex->SetImageInfo(texImageTarget, level, width, height,
+        tex->SetImageInfo(texImageTarget, level, width, height, 1,
                           effectiveInternalFormat,
                           WebGLImageDataStatus::InitializedImageData);
     }
 }
 
 void
 WebGLContext::CopyTexImage2D(GLenum rawTexImgTarget,
                              GLint level,
@@ -494,30 +504,31 @@ WebGLContext::CopyTexImage2D(GLenum rawT
                              GLsizei height,
                              GLint border)
 {
     if (IsContextLost())
         return;
 
     // copyTexImage2D only generates textures with type = UNSIGNED_BYTE
     const WebGLTexImageFunc func = WebGLTexImageFunc::CopyTexImage;
-
-    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CopyTexImage))
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+
+    if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
         return;
 
-    if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
+    if (!ValidateTexImage(rawTexImgTarget, level, internalformat,
                           0, 0, 0,
                           width, height, 0,
                           border, LOCAL_GL_NONE, LOCAL_GL_NONE,
-                          func))
+                          func, dims))
     {
         return;
     }
 
-    if (!ValidateCopyTexImage(internalformat, func))
+    if (!ValidateCopyTexImage(internalformat, func, dims))
         return;
 
     if (!mBoundFramebuffer)
         ClearBackbufferIfNeeded();
 
     CopyTexSubImage2D_base(rawTexImgTarget, level, internalformat, 0, 0, x, y, width, height, false);
 }
 
@@ -693,17 +704,18 @@ WebGLContext::DeleteTexture(WebGLTexture
         mBoundFramebuffer->DetachTexture(tex);
 
     // Invalidate framebuffer status cache
     tex->NotifyFBsStatusChanged();
 
     GLuint activeTexture = mActiveTexture;
     for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
         if ((mBound2DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_2D) ||
-            (mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP))
+            (mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP) ||
+            (mBound3DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_3D))
         {
             ActiveTexture(LOCAL_GL_TEXTURE0 + i);
             BindTexture(tex->Target().get(), static_cast<WebGLTexture*>(nullptr));
         }
     }
     ActiveTexture(LOCAL_GL_TEXTURE0 + activeTexture);
 
     tex->RequestDelete();
@@ -2139,17 +2151,17 @@ WebGLContext::ReadPixels(GLint x, GLint 
     int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
 
     // Check the pixels param type
     if (dataType != requiredDataType)
         return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
 
     // Check the pixels param size
     CheckedUint32 checked_neededByteLength =
-        GetImageSize(height, width, bytesPerPixel, mPixelStorePackAlignment);
+        GetImageSize(height, width, 1, bytesPerPixel, mPixelStorePackAlignment);
 
     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel;
 
     CheckedUint32 checked_alignedRowSize =
         RoundedToNextMultipleOf(checked_plainRowSize, mPixelStorePackAlignment);
 
     if (!checked_neededByteLength.isValid())
         return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size");
@@ -3304,37 +3316,38 @@ WebGLContext::CompressedTexImage2D(GLenu
                                    GLenum internalformat,
                                    GLsizei width, GLsizei height, GLint border,
                                    const ArrayBufferView& view)
 {
     if (IsContextLost())
         return;
 
     const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexImage;
-
-    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexImage))
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+
+    if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
         return;
 
-    if (!ValidateTexImage(2, rawTexImgTarget, level, internalformat,
+    if (!ValidateTexImage(rawTexImgTarget, level, internalformat,
                           0, 0, 0, width, height, 0,
                           border, LOCAL_GL_NONE,
                           LOCAL_GL_NONE,
-                          func))
+                          func, dims))
     {
         return;
     }
 
     view.ComputeLengthAndData();
 
     uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func)) {
+    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func, dims)) {
         return;
     }
 
-    if (!ValidateCompTexImageSize(level, internalformat, 0, 0, width, height, width, height, func))
+    if (!ValidateCompTexImageSize(level, internalformat, 0, 0, width, height, width, height, func, dims))
     {
         return;
     }
 
     const TexImageTarget texImageTarget(rawTexImgTarget);
 
     WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex);
@@ -3342,40 +3355,41 @@ WebGLContext::CompressedTexImage2D(GLenu
         return ErrorInvalidOperation(
             "compressedTexImage2D: disallowed because the texture bound to "
             "this target has already been made immutable by texStorage2D");
     }
 
     MakeContextCurrent();
     gl->fCompressedTexImage2D(texImageTarget.get(), level, internalformat, width, height, border, byteLength, view.Data());
 
-    tex->SetImageInfo(texImageTarget, level, width, height, internalformat,
+    tex->SetImageInfo(texImageTarget, level, width, height, 1, internalformat,
                       WebGLImageDataStatus::InitializedImageData);
 }
 
 void
 WebGLContext::CompressedTexSubImage2D(GLenum rawTexImgTarget, GLint level, GLint xoffset,
                                       GLint yoffset, GLsizei width, GLsizei height,
                                       GLenum internalformat,
                                       const ArrayBufferView& view)
 {
     if (IsContextLost())
         return;
 
     const WebGLTexImageFunc func = WebGLTexImageFunc::CompTexSubImage;
-
-    if (!ValidateTexImageTarget(2, rawTexImgTarget, WebGLTexImageFunc::CompTexSubImage))
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
+
+    if (!ValidateTexImageTarget(rawTexImgTarget, func, dims))
         return;
 
-    if (!ValidateTexImage(2, rawTexImgTarget,
+    if (!ValidateTexImage(rawTexImgTarget,
                           level, internalformat,
                           xoffset, yoffset, 0,
                           width, height, 0,
                           0, LOCAL_GL_NONE, LOCAL_GL_NONE,
-                          func))
+                          func, dims))
     {
         return;
     }
 
     const TexImageTarget texImageTarget(rawTexImgTarget);
 
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     MOZ_ASSERT(tex);
@@ -3383,24 +3397,24 @@ WebGLContext::CompressedTexSubImage2D(GL
 
     if (internalformat != levelInfo.EffectiveInternalFormat()) {
         return ErrorInvalidOperation("compressedTexImage2D: internalformat does not match the existing image");
     }
 
     view.ComputeLengthAndData();
 
     uint32_t byteLength = view.Length();
-    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func))
+    if (!ValidateCompTexImageDataSize(level, internalformat, width, height, byteLength, func, dims))
         return;
 
     if (!ValidateCompTexImageSize(level, internalformat,
                                   xoffset, yoffset,
                                   width, height,
                                   levelInfo.Width(), levelInfo.Height(),
-                                  func))
+                                  func, dims))
     {
         return;
     }
 
     if (levelInfo.HasUninitializedImageData())
         tex->DoDeferredImageInitialization(texImageTarget, level);
 
     MakeContextCurrent();
@@ -3642,45 +3656,46 @@ GLenum WebGLContext::CheckedTexImage2D(T
 void
 WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
                               GLenum internalformat,
                               GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
                               GLint border,
                               GLenum format,
                               GLenum type,
                               void* data, uint32_t byteLength,
-                              int jsArrayType, // a TypedArray format enum, or -1 if not relevant
+                              js::Scalar::Type jsArrayType,
                               WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
     const WebGLTexImageFunc func = WebGLTexImageFunc::TexImage;
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
 
     if (type == LOCAL_GL_HALF_FLOAT_OES) {
         type = LOCAL_GL_HALF_FLOAT;
     }
 
-    if (!ValidateTexImage(2, texImageTarget, level, internalformat,
+    if (!ValidateTexImage(texImageTarget, level, internalformat,
                           0, 0, 0,
                           width, height, 0,
-                          border, format, type, func))
+                          border, format, type, func, dims))
     {
         return;
     }
 
     const bool isDepthTexture = format == LOCAL_GL_DEPTH_COMPONENT ||
                                 format == LOCAL_GL_DEPTH_STENCIL;
 
     if (isDepthTexture && !IsWebGL2()) {
         if (data != nullptr || level != 0)
             return ErrorInvalidOperation("texImage2D: "
                                          "with format of DEPTH_COMPONENT or DEPTH_STENCIL, "
                                          "data must be nullptr, "
                                          "level must be zero");
     }
 
-    if (!ValidateTexInputData(type, jsArrayType, func))
+    if (!ValidateTexInputData(type, jsArrayType, func, dims))
         return;
 
     TexInternalFormat effectiveInternalFormat =
         EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
 
     if (effectiveInternalFormat == LOCAL_GL_NONE) {
         return ErrorInvalidOperation("texImage2D: bad combination of internalformat and type");
     }
@@ -3696,17 +3711,17 @@ WebGLContext::TexImage2D_base(TexImageTa
         const size_t srcbitsPerTexel = GetBitsPerTexel(effectiveSourceFormat);
         MOZ_ASSERT((srcbitsPerTexel % 8) == 0); // should not have compressed formats here.
         srcTexelSize = srcbitsPerTexel / 8;
     } else {
         srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(srcFormat);
     }
 
     CheckedUint32 checked_neededByteLength =
-        GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
+        GetImageSize(height, width, 1, srcTexelSize, mPixelStoreUnpackAlignment);
 
     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
     CheckedUint32 checked_alignedRowSize =
         RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
 
     if (!checked_neededByteLength.isValid())
         return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
 
@@ -3750,17 +3765,22 @@ WebGLContext::TexImage2D_base(TexImageTa
             !mPixelStoreFlipY)
         {
             // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
             pixels = data;
         }
         else
         {
             size_t convertedDataSize = height * dstStride;
-            convertedData = new uint8_t[convertedDataSize];
+            convertedData = (uint8_t*)moz_malloc(convertedDataSize);
+            if (!convertedData) {
+                ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
+                                 " a buffer for doing format conversion.");
+                return;
+            }
             if (!ConvertImage(width, height, srcStride, dstStride,
                               static_cast<uint8_t*>(data), convertedData,
                               actualSrcFormat, srcPremultiplied,
                               dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize))
             {
                 return ErrorInvalidOperation("texImage2D: Unsupported texture format conversion");
             }
             pixels = reinterpret_cast<void*>(convertedData.get());
@@ -3776,46 +3796,46 @@ WebGLContext::TexImage2D_base(TexImageTa
         return;
     }
 
     // in all of the code paths above, we should have either initialized data,
     // or allocated data and left it uninitialized, but in any case we shouldn't
     // have NoImageData at this point.
     MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
 
-    tex->SetImageInfo(texImageTarget, level, width, height,
+    tex->SetImageInfo(texImageTarget, level, width, height, 1,
                       effectiveInternalFormat, imageInfoStatusIfSuccess);
 }
 
 void
 WebGLContext::TexImage2D(GLenum rawTarget, GLint level,
                          GLenum internalformat, GLsizei width,
                          GLsizei height, GLint border, GLenum format,
                          GLenum type, const Nullable<ArrayBufferView> &pixels, ErrorResult& rv)
 {
     if (IsContextLost())
         return;
 
     void* data;
     uint32_t length;
-    int jsArrayType;
+    js::Scalar::Type jsArrayType;
     if (pixels.IsNull()) {
         data = nullptr;
         length = 0;
-        jsArrayType = -1;
+        jsArrayType = js::Scalar::TypeMax;
     } else {
         const ArrayBufferView& view = pixels.Value();
         view.ComputeLengthAndData();
 
         data = view.Data();
         length = view.Length();
-        jsArrayType = int(JS_GetArrayBufferViewType(view.Obj()));
+        jsArrayType = JS_GetArrayBufferViewType(view.Obj());
     }
 
-    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage))
+    if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
         return;
 
     return TexImage2D_base(rawTarget, level, internalformat, width, height, 0, border, format, type,
                            data, length, jsArrayType,
                            WebGLTexelFormat::Auto, false);
 }
 
 void
@@ -3834,36 +3854,37 @@ WebGLContext::TexImage2D(GLenum rawTarge
     Uint8ClampedArray arr;
     DebugOnly<bool> inited = arr.Init(pixels->GetDataObject());
     MOZ_ASSERT(inited);
     arr.ComputeLengthAndData();
 
     void* pixelData = arr.Data();
     const uint32_t pixelDataLength = arr.Length();
 
-    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexImage))
+    if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexImage, WebGLTexDimensions::Tex2D))
         return;
 
     return TexImage2D_base(rawTarget, level, internalformat, pixels->Width(),
                            pixels->Height(), 4*pixels->Width(), 0,
-                           format, type, pixelData, pixelDataLength, -1,
+                           format, type, pixelData, pixelDataLength, js::Scalar::TypeMax,
                            WebGLTexelFormat::RGBA8, false);
 }
 
 
 void
 WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
                                  GLint xoffset, GLint yoffset,
                                  GLsizei width, GLsizei height, GLsizei srcStrideOrZero,
                                  GLenum format, GLenum type,
                                  void* data, uint32_t byteLength,
-                                 int jsArrayType,
+                                 js::Scalar::Type jsArrayType,
                                  WebGLTexelFormat srcFormat, bool srcPremultiplied)
 {
     const WebGLTexImageFunc func = WebGLTexImageFunc::TexSubImage;
+    const WebGLTexDimensions dims = WebGLTexDimensions::Tex2D;
 
     if (type == LOCAL_GL_HALF_FLOAT_OES) {
         type = LOCAL_GL_HALF_FLOAT;
     }
 
     WebGLTexture *tex = activeBoundTextureForTexImageTarget(texImageTarget);
     if (!tex) {
         return ErrorInvalidOperation("texSubImage2D: no texture bound on active texture unit");
@@ -3871,26 +3892,26 @@ WebGLContext::TexSubImage2D_base(TexImag
 
     if (!tex->HasImageInfoAt(texImageTarget, level)) {
         return ErrorInvalidOperation("texSubImage2D: no previously defined texture image");
     }
 
     const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
     const TexInternalFormat existingEffectiveInternalFormat = imageInfo.EffectiveInternalFormat();
 
-    if (!ValidateTexImage(2, texImageTarget, level,
+    if (!ValidateTexImage(texImageTarget, level,
                           existingEffectiveInternalFormat.get(),
                           xoffset, yoffset, 0,
                           width, height, 0,
-                          0, format, type, func))
+                          0, format, type, func, dims))
     {
         return;
     }
 
-    if (!ValidateTexInputData(type, jsArrayType, func))
+    if (!ValidateTexInputData(type, jsArrayType, func, dims))
         return;
 
     if (type != TypeFromInternalFormat(existingEffectiveInternalFormat)) {
         return ErrorInvalidOperation("texSubImage2D: type differs from that of the existing image");
     }
 
     size_t srcTexelSize = size_t(-1);
     if (srcFormat == WebGLTexelFormat::Auto) {
@@ -3900,17 +3921,17 @@ WebGLContext::TexSubImage2D_base(TexImag
     } else {
         srcTexelSize = WebGLTexelConversions::TexelBytesForFormat(srcFormat);
     }
 
     if (width == 0 || height == 0)
         return; // ES 2.0 says it has no effect, we better return right now
 
     CheckedUint32 checked_neededByteLength =
-        GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
+        GetImageSize(height, width, 1, srcTexelSize, mPixelStoreUnpackAlignment);
 
     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
 
     CheckedUint32 checked_alignedRowSize =
         RoundedToNextMultipleOf(checked_plainRowSize.value(), mPixelStoreUnpackAlignment);
 
     if (!checked_neededByteLength.isValid())
         return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
@@ -3940,17 +3961,22 @@ WebGLContext::TexSubImage2D_base(TexImag
     // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
     bool noConversion = (actualSrcFormat == dstFormat &&
                          srcPremultiplied == mPixelStorePremultiplyAlpha &&
                          srcStride == dstStride &&
                          !mPixelStoreFlipY);
 
     if (!noConversion) {
         size_t convertedDataSize = height * dstStride;
-        convertedData = new uint8_t[convertedDataSize];
+        convertedData = (uint8_t*)moz_malloc(convertedDataSize);
+        if (!convertedData) {
+            ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
+                             " a buffer for doing format conversion.");
+            return;
+        }
         if (!ConvertImage(width, height, srcStride, dstStride,
                           static_cast<const uint8_t*>(data), convertedData,
                           actualSrcFormat, srcPremultiplied,
                           dstFormat, mPixelStorePremultiplyAlpha, dstTexelSize))
         {
             return ErrorInvalidOperation("texSubImage2D: Unsupported texture format conversion");
         }
         pixels = reinterpret_cast<void*>(convertedData.get());
@@ -3980,17 +4006,17 @@ WebGLContext::TexSubImage2D(GLenum rawTa
         return;
 
     if (pixels.IsNull())
         return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
 
     const ArrayBufferView& view = pixels.Value();
     view.ComputeLengthAndData();
 
-    if (!ValidateTexImageTarget(2, rawTarget, WebGLTexImageFunc::TexSubImage))
+    if (!ValidateTexImageTarget(rawTarget, WebGLTexImageFunc::TexSubImage, WebGLTexDimensions::Tex2D))
         return;
 
     return TexSubImage2D_base(rawTarget, level, xoffset, yoffset,
                               width, height, 0, format, type,
                               view.Data(), view.Length(),
                               JS_GetArrayBufferViewType(view.Obj()),
                               WebGLTexelFormat::Auto, false);
 }
@@ -4011,17 +4037,17 @@ WebGLContext::TexSubImage2D(GLenum targe
     DebugOnly<bool> inited = arr.Init(pixels->GetDataObject());
     MOZ_ASSERT(inited);
     arr.ComputeLengthAndData();
 
     return TexSubImage2D_base(target, level, xoffset, yoffset,
                               pixels->Width(), pixels->Height(),
                               4*pixels->Width(), format, type,
                               arr.Data(), arr.Length(),
-                              -1,
+                              js::Scalar::TypeMax,
                               WebGLTexelFormat::RGBA8, false);
 }
 
 void
 WebGLContext::LoseContext()
 {
     if (IsContextLost())
         return ErrorInvalidOperation("loseContext: Context is already lost.");
--- a/dom/canvas/WebGLContextState.cpp
+++ b/dom/canvas/WebGLContextState.cpp
@@ -65,16 +65,39 @@ StringValue(JSContext* cx, const char* c
     if (!str) {
         rv.Throw(NS_ERROR_OUT_OF_MEMORY);
         return JS::NullValue();
     }
 
     return JS::StringValue(str);
 }
 
+bool
+WebGLContext::GetStencilBits(GLint* out_stencilBits)
+{
+    *out_stencilBits = 0;
+    if (mBoundFramebuffer) {
+        if (mBoundFramebuffer->HasDepthStencilConflict()) {
+            // Error, we don't know which stencil buffer's bits to use
+            ErrorInvalidFramebufferOperation("getParameter: framebuffer has two stencil buffers bound");
+            return false;
+        }
+
+        if (mBoundFramebuffer->StencilAttachment().IsDefined() ||
+            mBoundFramebuffer->DepthStencilAttachment().IsDefined())
+        {
+            *out_stencilBits = 8;
+        }
+    } else if (mOptions.stencil) {
+        *out_stencilBits = 8;
+    }
+
+    return true;
+}
+
 JS::Value
 WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
 {
     if (IsContextLost())
         return JS::NullValue();
 
     MakeContextCurrent();
 
@@ -236,34 +259,50 @@ WebGLContext::GetParameter(JSContext* cx
             if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
                 gl->fGetIntegerv(pname, &i);
             } else {
                 i = LOCAL_GL_RGBA;
             }
             return JS::NumberValue(uint32_t(i));
         }
         // int
+        case LOCAL_GL_STENCIL_REF:
+        case LOCAL_GL_STENCIL_BACK_REF: {
+            GLint stencilBits = 0;
+            if (!GetStencilBits(&stencilBits))
+                return JS::NullValue();
+
+            // Assuming stencils have 8 bits
+            const GLint stencilMask = (1 << stencilBits) - 1;
+
+            GLint refValue = 0;
+            gl->fGetIntegerv(pname, &refValue);
+
+            return JS::Int32Value(refValue & stencilMask);
+        }
+        case LOCAL_GL_STENCIL_BITS: {
+            GLint stencilBits = 0;
+            GetStencilBits(&stencilBits);
+            return JS::Int32Value(stencilBits);
+        }
         case LOCAL_GL_STENCIL_CLEAR_VALUE:
-        case LOCAL_GL_STENCIL_REF:
-        case LOCAL_GL_STENCIL_BACK_REF:
         case LOCAL_GL_UNPACK_ALIGNMENT:
         case LOCAL_GL_PACK_ALIGNMENT:
         case LOCAL_GL_SUBPIXEL_BITS:
         case LOCAL_GL_SAMPLE_BUFFERS:
         case LOCAL_GL_SAMPLES:
         case LOCAL_GL_MAX_VERTEX_ATTRIBS:
         case LOCAL_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS:
         case LOCAL_GL_RED_BITS:
         case LOCAL_GL_GREEN_BITS:
         case LOCAL_GL_BLUE_BITS:
         case LOCAL_GL_ALPHA_BITS:
-        case LOCAL_GL_DEPTH_BITS:
-        case LOCAL_GL_STENCIL_BITS: {
+        case LOCAL_GL_DEPTH_BITS: {
             GLint i = 0;
             gl->fGetIntegerv(pname, &i);
             return JS::Int32Value(i);
         }
         case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT: {
             if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives)) {
                 GLint i = 0;
                 gl->fGetIntegerv(pname, &i);
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -55,26 +55,27 @@ FormatHasAlpha(TexInternalFormat interna
            unsizedformat == LOCAL_GL_RGBA_INTEGER;
 }
 
 TexTarget
 TexImageTargetToTexTarget(TexImageTarget texImageTarget)
 {
     switch (texImageTarget.get()) {
     case LOCAL_GL_TEXTURE_2D:
-        return LOCAL_GL_TEXTURE_2D;
+    case LOCAL_GL_TEXTURE_3D:
+        return texImageTarget.get();
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
     case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
     case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
         return LOCAL_GL_TEXTURE_CUBE_MAP;
     default:
-        MOZ_ASSERT(false, "Bad texture conversion");
+        MOZ_ASSERT(false, "Bad texture target");
         // Should be caught by the constructor for TexTarget
         return LOCAL_GL_NONE;
     }
 }
 
 GLComponents::GLComponents(TexInternalFormat internalformat)
 {
     TexInternalFormat unsizedformat = UnsizedInternalFormatFromInternalFormat(internalformat);
@@ -443,29 +444,32 @@ WebGLContext::ShouldGenerateWarnings() c
     }
 
     return mAlreadyGeneratedWarnings < mMaxWarnings;
 }
 
 CheckedUint32
 WebGLContext::GetImageSize(GLsizei height,
                            GLsizei width,
+                           GLsizei depth,
                            uint32_t pixelSize,
                            uint32_t packOrUnpackAlignment)
 {
     CheckedUint32 checked_plainRowSize = CheckedUint32(width) * pixelSize;
 
     // alignedRowSize = row size rounded up to next multiple of packAlignment
     CheckedUint32 checked_alignedRowSize = RoundedToNextMultipleOf(checked_plainRowSize, packOrUnpackAlignment);
 
     // if height is 0, we don't need any memory to store this; without this check, we'll get an overflow
-    CheckedUint32 checked_neededByteLength
+    CheckedUint32 checked_2dImageSize
         = height <= 0 ? 0 : (height-1) * checked_alignedRowSize + checked_plainRowSize;
 
-    return checked_neededByteLength;
+    // FIXME - we should honor UNPACK_IMAGE_HEIGHT
+    CheckedUint32 checked_imageSize = checked_2dImageSize * depth;
+    return checked_imageSize;
 }
 
 void
 WebGLContext::SynthesizeGLError(GLenum err)
 {
     /* ES2 section 2.5 "GL Errors" states that implementations can have
      * multiple 'flags', as errors might be caught in different parts of
      * a distributed implementation.
@@ -700,16 +704,32 @@ AssertUintParamCorrect(gl::GLContext* gl
     GLuint val = 0;
     gl->GetUIntegerv(pname, &val);
     if (val != shadow) {
       printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
                     pname, shadow, shadow, val, val);
       MOZ_ASSERT(false, "Bad cached value.");
     }
 }
+
+void
+AssertMaskedUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint mask, GLuint shadow)
+{
+    GLuint val = 0;
+    gl->GetUIntegerv(pname, &val);
+
+    const GLuint valMasked = val & mask;
+    const GLuint shadowMasked = shadow & mask;
+
+    if (valMasked != shadowMasked) {
+      printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
+                    pname, shadowMasked, shadowMasked, valMasked, valMasked);
+      MOZ_ASSERT(false, "Bad cached value.");
+    }
+}
 #else
 void
 AssertUintParamCorrect(gl::GLContext*, GLenum, GLuint)
 {
 }
 #endif
 
 void
@@ -797,18 +817,22 @@ WebGLContext::AssertCachedState()
     MOZ_ASSERT(depthWriteMask == mDepthWriteMask);
 
     GLfloat depthClearValue = 0.0f;
     gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
     MOZ_ASSERT(IsCacheCorrect(mDepthClearValue, depthClearValue));
 
     AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue);
 
-    AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_REF,      mStencilRefFront);
-    AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, mStencilRefBack);
+    GLint stencilBits = 0;
+    gl->fGetIntegerv(LOCAL_GL_STENCIL_BITS, &stencilBits);
+    const GLuint stencilRefMask = (1 << stencilBits) - 1;
+
+    AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF,      stencilRefMask, mStencilRefFront);
+    AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
 
     AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK,      mStencilValueMaskFront);
     AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, mStencilValueMaskBack);
 
     AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK,      mStencilWriteMaskFront);
     AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, mStencilWriteMaskBack);
 
     // Viewport
@@ -821,9 +845,37 @@ WebGLContext::AssertCachedState()
 
     AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStorePackAlignment);
     AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStoreUnpackAlignment);
 
     MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
 #endif
 }
 
+const char*
+InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims)
+{
+    switch (dims) {
+    case WebGLTexDimensions::Tex2D:
+        switch (func) {
+        case WebGLTexImageFunc::TexImage:        return "texImage2D";
+        case WebGLTexImageFunc::TexSubImage:     return "texSubImage2D";
+        case WebGLTexImageFunc::CopyTexImage:    return "copyTexImage2D";
+        case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
+        case WebGLTexImageFunc::CompTexImage:    return "compressedTexImage2D";
+        case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
+        default:
+            MOZ_CRASH();
+        }
+    case WebGLTexDimensions::Tex3D:
+        switch (func) {
+        case WebGLTexImageFunc::TexSubImage:     return "texSubImage3D";
+        case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage3D";
+        case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage3D";
+        default:
+            MOZ_CRASH();
+        }
+    default:
+        MOZ_CRASH();
+    }
+}
+
 } // namespace mozilla
--- a/dom/canvas/WebGLContextUtils.h
+++ b/dom/canvas/WebGLContextUtils.h
@@ -101,11 +101,18 @@ WebGLContext::WebGLObjectAsJSObject(JSCo
 {
     JS::Value v = WebGLObjectAsJSValue(cx, object, rv);
     if (v.isNull()) {
         return nullptr;
     }
     return &v.toObject();
 }
 
+/**
+ * Return the displayable name for the texture function that is the
+ * source for validation.
+ */
+const char*
+InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims);
+
 } // namespace mozilla
 
 #endif // WEBGLCONTEXTUTILS_H_
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -56,56 +56,35 @@ BlockSizeFor(GLenum format, GLint* block
 
     case LOCAL_GL_ETC1_RGB8_OES:
         // 4x4 blocks, but no 4-multiple requirement.
     default:
         break;
     }
 }
 
-/**
- * Return the displayable name for the texture function that is the
- * source for validation.
- */
-static const char*
-InfoFrom(WebGLTexImageFunc func)
-{
-    // TODO: Account for dimensions (WebGL 2)
-    switch (func) {
-    case WebGLTexImageFunc::TexImage:        return "texImage2D";
-    case WebGLTexImageFunc::TexSubImage:     return "texSubImage2D";
-    case WebGLTexImageFunc::CopyTexImage:    return "copyTexImage2D";
-    case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
-    case WebGLTexImageFunc::CompTexImage:    return "compressedTexImage2D";
-    case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
-    default:
-        MOZ_ASSERT(false, "Missing case for WebGLTexImageSource");
-        return "(error)";
-    }
-}
-
 static bool
 IsCompressedFunc(WebGLTexImageFunc func)
 {
     return func == WebGLTexImageFunc::CompTexImage ||
            func == WebGLTexImageFunc::CompTexSubImage;
 }
 
 /**
  * Same as ErrorInvalidEnum but uses WebGLContext::EnumName to print displayable
  * name for \a glenum.
  */
 static void
-ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func)
+ErrorInvalidEnumWithName(WebGLContext* ctx, const char* msg, GLenum glenum, WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     const char* name = WebGLContext::EnumName(glenum);
     if (name)
-        ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func), msg, name);
+        ctx->ErrorInvalidEnum("%s: %s %s", InfoFrom(func, dims), msg, name);
     else
-        ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func), msg, glenum);
+        ctx->ErrorInvalidEnum("%s: %s 0x%04X", InfoFrom(func, dims), msg, glenum);
 }
 
 /**
  * Return true if the format is valid for source calls.
  */
 static bool
 IsAllowedFromSource(GLenum format, WebGLTexImageFunc func)
 {
@@ -381,17 +360,17 @@ WebGLContext::ValidateFramebufferAttachm
     return false;
 }
 
 /**
  * Return true if format is a valid texture image format for source,
  * taking into account enabled WebGL extensions.
  */
 bool
-WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func)
+WebGLContext::ValidateTexImageFormat(GLenum format, WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     /* Core WebGL texture formats */
     if (format == LOCAL_GL_ALPHA ||
         format == LOCAL_GL_RGB ||
         format == LOCAL_GL_RGBA ||
         format == LOCAL_GL_LUMINANCE ||
         format == LOCAL_GL_LUMINANCE_ALPHA)
     {
@@ -404,103 +383,112 @@ WebGLContext::ValidateTexImageFormat(GLe
         format == LOCAL_GL_RED_INTEGER ||
         format == LOCAL_GL_RG_INTEGER ||
         format == LOCAL_GL_RGB_INTEGER ||
         format == LOCAL_GL_RGBA_INTEGER)
     {
         bool valid = IsWebGL2();
         if (!valid) {
             ErrorInvalidEnum("%s:  invalid format %s: requires WebGL version 2.0 or newer",
-                             InfoFrom(func), EnumName(format));
+                             InfoFrom(func, dims), EnumName(format));
         }
         return valid;
     }
 
     /* WEBGL_depth_texture added formats */
     if (format == LOCAL_GL_DEPTH_COMPONENT ||
         format == LOCAL_GL_DEPTH_STENCIL)
     {
         if (!IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture)) {
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_depth_texture enabled",
-                             InfoFrom(func), EnumName(format));
+                             InfoFrom(func, dims), EnumName(format));
             return false;
         }
 
         // If WEBGL_depth_texture is enabled, then it is not allowed to be used with the
         // copyTexImage, or copyTexSubImage methods, and it is not allowed with
         // texSubImage in WebGL1.
         if ((func == WebGLTexImageFunc::TexSubImage && !IsWebGL2()) ||
             func == WebGLTexImageFunc::CopyTexImage ||
             func == WebGLTexImageFunc::CopyTexSubImage)
         {
-            ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func), EnumName(format));
+            ErrorInvalidOperation("%s: format %s is not supported", InfoFrom(func, dims), EnumName(format));
             return false;
         }
 
         return true;
     }
 
     // Needs to be below the depth_texture check because an invalid operation
     // error needs to be generated instead of invalid enum.
     /* Only core formats are valid for CopyTex(Sub)?Image */
     // TODO: Revisit this once color_buffer_(half_)?float lands
     if (IsCopyFunc(func)) {
-        ErrorInvalidEnumWithName(this, "invalid format", format, func);
+        ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
         return false;
     }
 
     /* EXT_sRGB added formats */
     if (format == LOCAL_GL_SRGB ||
         format == LOCAL_GL_SRGB_ALPHA)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::EXT_sRGB);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need EXT_sRGB enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
-    ErrorInvalidEnumWithName(this, "invalid format", format, func);
+    ErrorInvalidEnumWithName(this, "invalid format", format, func, dims);
 
     return false;
 }
 
 /**
  * Check if the given texture target is valid for TexImage.
  */
 bool
-WebGLContext::ValidateTexImageTarget(GLuint dims,
-                                     GLenum target,
-                                     WebGLTexImageFunc func)
+WebGLContext::ValidateTexImageTarget(GLenum target,
+                                     WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     switch (dims) {
-    case 2:
+    case WebGLTexDimensions::Tex2D:
         if (target == LOCAL_GL_TEXTURE_2D ||
             IsTexImageCubemapTarget(target))
         {
             return true;
         }
 
-        ErrorInvalidEnumWithName(this, "invalid target", target, func);
+        ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
+        return false;
+
+    case WebGLTexDimensions::Tex3D:
+        if (target == LOCAL_GL_TEXTURE_3D)
+        {
+            return true;
+        }
+
+        ErrorInvalidEnumWithName(this, "invalid target", target, func, dims);
         return false;
 
     default:
         MOZ_ASSERT(false, "ValidateTexImageTarget: Invalid dims");
     }
 
     return false;
 }
 
 /**
  * Return true if type is a valid texture image type for source,
  * taking into account enabled WebGL extensions.
  */
 bool
 WebGLContext::ValidateTexImageType(GLenum type,
-                                   WebGLTexImageFunc func)
+                                   WebGLTexImageFunc func,
+                                   WebGLTexDimensions dims)
 {
     /* Core WebGL texture types */
     if (type == LOCAL_GL_UNSIGNED_BYTE ||
         type == LOCAL_GL_UNSIGNED_SHORT_5_6_5 ||
         type == LOCAL_GL_UNSIGNED_SHORT_4_4_4_4 ||
         type == LOCAL_GL_UNSIGNED_SHORT_5_5_5_1)
     {
         return true;
@@ -513,182 +501,185 @@ WebGLContext::ValidateTexImageType(GLenu
         type == LOCAL_GL_FLOAT_32_UNSIGNED_INT_24_8_REV ||
         type == LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV ||
         type == LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV ||
         type == LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV)
     {
         bool validType = IsWebGL2();
         if (!validType) {
             ErrorInvalidEnum("%s: invalid type %s: requires WebGL version 2.0 or newer",
-                             InfoFrom(func), WebGLContext::EnumName(type));
+                             InfoFrom(func, dims), WebGLContext::EnumName(type));
         }
         return validType;
     }
 
     /* OES_texture_float added types */
     if (type == LOCAL_GL_FLOAT) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_float enabled",
-                             InfoFrom(func), WebGLContext::EnumName(type));
+                             InfoFrom(func, dims), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* OES_texture_half_float add types */
     if (type == LOCAL_GL_HALF_FLOAT) {
         bool validType = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need OES_texture_half_float enabled",
-                             InfoFrom(func), WebGLContext::EnumName(type));
+                             InfoFrom(func, dims), WebGLContext::EnumName(type));
         return validType;
     }
 
     /* WEBGL_depth_texture added types */
     if (type == LOCAL_GL_UNSIGNED_SHORT ||
         type == LOCAL_GL_UNSIGNED_INT ||
         type == LOCAL_GL_UNSIGNED_INT_24_8)
     {
         bool validType = IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture);
         if (!validType)
             ErrorInvalidEnum("%s: invalid type %s: need WEBGL_depth_texture enabled",
-                             InfoFrom(func), WebGLContext::EnumName(type));
+                             InfoFrom(func, dims), WebGLContext::EnumName(type));
         return validType;
     }
 
-    ErrorInvalidEnumWithName(this, "invalid type", type, func);
+    ErrorInvalidEnumWithName(this, "invalid type", type, func, dims);
     return false;
 }
 
 /**
  * Validate texture image sizing extra constraints for
  * CompressedTex(Sub)?Image.
  */
 // TODO: WebGL 2
 bool
 WebGLContext::ValidateCompTexImageSize(GLint level,
                                        GLenum format,
                                        GLint xoffset, GLint yoffset,
                                        GLsizei width, GLsizei height,
                                        GLsizei levelWidth, GLsizei levelHeight,
-                                       WebGLTexImageFunc func)
+                                       WebGLTexImageFunc func,
+                                       WebGLTexDimensions dims)
 {
     // Negative parameters must already have been handled above
     MOZ_ASSERT(xoffset >= 0 && yoffset >= 0 &&
                width >= 0 && height >= 0);
 
     if (xoffset + width > (GLint) levelWidth) {
-        ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func));
+        ErrorInvalidValue("%s: xoffset + width must be <= levelWidth", InfoFrom(func, dims));
         return false;
     }
 
     if (yoffset + height > (GLint) levelHeight) {
-        ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func));
+        ErrorInvalidValue("%s: yoffset + height must be <= levelHeight", InfoFrom(func, dims));
         return false;
     }
 
     GLint blockWidth = 1;
     GLint blockHeight = 1;
     BlockSizeFor(format, &blockWidth, &blockHeight);
 
     /* If blockWidth || blockHeight != 1, then the compressed format
      * had block-based constraints to be checked. (For example, PVRTC is compressed but
      * isn't a block-based format)
      */
     if (blockWidth != 1 || blockHeight != 1) {
         /* offsets must be multiple of block size */
         if (xoffset % blockWidth != 0) {
             ErrorInvalidOperation("%s: xoffset must be multiple of %d",
-                                  InfoFrom(func), blockWidth);
+                                  InfoFrom(func, dims), blockWidth);
             return false;
         }
 
         if (yoffset % blockHeight != 0) {
             ErrorInvalidOperation("%s: yoffset must be multiple of %d",
-                                  InfoFrom(func), blockHeight);
+                                  InfoFrom(func, dims), blockHeight);
             return false;
         }
 
         /* The size must be a multiple of blockWidth and blockHeight,
          * or must be using offset+size that exactly hits the edge.
          * Important for small mipmap levels.
          */
         /* https://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
          * "When level equals zero width and height must be a multiple of 4. When
          *  level is greater than 0 width and height must be 0, 1, 2 or a multiple of 4.
          *  If they are not an INVALID_OPERATION error is generated."
          */
         if (level == 0) {
             if (width % blockWidth != 0) {
                 ErrorInvalidOperation("%s: width of level 0 must be multple of %d",
-                                      InfoFrom(func), blockWidth);
+                                      InfoFrom(func, dims), blockWidth);
                 return false;
             }
 
             if (height % blockHeight != 0) {
                 ErrorInvalidOperation("%s: height of level 0 must be multipel of %d",
-                                      InfoFrom(func), blockHeight);
+                                      InfoFrom(func, dims), blockHeight);
                 return false;
             }
         }
         else if (level > 0) {
             if (width % blockWidth != 0 && width > 2) {
                 ErrorInvalidOperation("%s: width of level %d must be multiple"
                                       " of %d or 0, 1, 2",
-                                      InfoFrom(func), level, blockWidth);
+                                      InfoFrom(func, dims), level, blockWidth);
                 return false;
             }
 
             if (height % blockHeight != 0 && height > 2) {
                 ErrorInvalidOperation("%s: height of level %d must be multiple"
                                       " of %d or 0, 1, 2",
-                                      InfoFrom(func), level, blockHeight);
+                                      InfoFrom(func, dims), level, blockHeight);
                 return false;
             }
         }
 
         if (IsSubFunc(func)) {
             if ((xoffset % blockWidth) != 0) {
                 ErrorInvalidOperation("%s: xoffset must be multiple of %d",
-                                      InfoFrom(func), blockWidth);
+                                      InfoFrom(func, dims), blockWidth);
                 return false;
             }
 
             if (yoffset % blockHeight != 0) {
                 ErrorInvalidOperation("%s: yoffset must be multiple of %d",
-                                      InfoFrom(func), blockHeight);
+                                      InfoFrom(func, dims), blockHeight);
                 return false;
             }
         }
     }
 
     switch (format) {
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
     case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
         if (!is_pot_assuming_nonnegative(width) ||
             !is_pot_assuming_nonnegative(height))
         {
             ErrorInvalidValue("%s: width and height must be powers of two",
-                              InfoFrom(func));
+                              InfoFrom(func, dims));
             return false;
         }
     }
 
     return true;
 }
 
 /**
  * Return true if the enough data is present to satisfy compressed
  * texture format constraints.
  */
 bool
 WebGLContext::ValidateCompTexImageDataSize(GLint level, GLenum format,
                                            GLsizei width, GLsizei height,
-                                           uint32_t byteLength, WebGLTexImageFunc func)
+                                           uint32_t byteLength,
+                                           WebGLTexImageFunc func,
+                                           WebGLTexDimensions dims)
 {
     // negative width and height must already have been handled above
     MOZ_ASSERT(width >= 0 && height >= 0);
 
     CheckedUint32 required_byteLength = 0;
 
     switch (format) {
         case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
@@ -717,33 +708,33 @@ WebGLContext::ValidateCompTexImageDataSi
         case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
         {
             required_byteLength = CheckedUint32(std::max(width, 16)) * CheckedUint32(std::max(height, 8)) / 4;
             break;
         }
     }
 
     if (!required_byteLength.isValid() || required_byteLength.value() != byteLength) {
-        ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func));
+        ErrorInvalidValue("%s: data size does not match dimensions", InfoFrom(func, dims));
         return false;
     }
 
     return true;
 }
 
 /**
  * Validate the width, height, and depth of a texture image, \return
  * true is valid, false otherwise.
  * Used by all the (Compressed|Copy)?Tex(Sub)?Image functions.
  * Target and level must have been validated before calling.
  */
 bool
 WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
                                    GLint width, GLint height, GLint depth,
-                                   WebGLTexImageFunc func)
+                                   WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     MOZ_ASSERT(level >= 0, "level should already be validated");
 
     /* Bug 966630: maxTextureSize >> level runs into "undefined"
      * behaviour depending on ISA. For example, on Intel shifts
      * amounts are mod 64 (in 64-bit mode on 64-bit dest) and mod 32
      * otherwise. This means 16384 >> 0x10000001 == 8192 which isn't
      * what would be expected. Make the required behaviour explicit by
@@ -761,405 +752,420 @@ WebGLContext::ValidateTexImageSize(TexIm
 
     if (!isSub && isCubemapTarget && (width != height)) {
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "When the target parameter to TexImage2D is one of the
          *   six cube map two-dimensional image targets, the error
          *   INVALID_VALUE is generated if the width and height
          *   parameters are not equal."
          */
-        ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func));
+        ErrorInvalidValue("%s: for cube map, width must equal height", InfoFrom(func, dims));
         return false;
     }
 
     if (texImageTarget == LOCAL_GL_TEXTURE_2D || isCubemapTarget)
     {
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "If wt and ht are the specified image width and height,
          *   and if either wt or ht are less than zero, then the error
          *   INVALID_VALUE is generated."
          */
         if (width < 0) {
-            ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func));
+            ErrorInvalidValue("%s: width must be >= 0", InfoFrom(func, dims));
             return false;
         }
 
         if (height < 0) {
-            ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func));
+            ErrorInvalidValue("%s: height must be >= 0", InfoFrom(func, dims));
             return false;
         }
 
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "The maximum allowable width and height of a
          *   two-dimensional texture image must be at least 2**(k−lod)
          *   for image arrays of level zero through k, where k is the
          *   log base 2 of MAX_TEXTURE_SIZE. and lod is the
          *   level-of-detail of the image array. It may be zero for
          *   image arrays of any level-of-detail greater than k. The
          *   error INVALID_VALUE is generated if the specified image
          *   is too large to be stored under any conditions.
          */
         if (width > (int) maxTexImageSize) {
             ErrorInvalidValue("%s: the maximum width for level %d is %u",
-                              InfoFrom(func), level, maxTexImageSize);
+                              InfoFrom(func, dims), level, maxTexImageSize);
             return false;
         }
 
         if (height > (int) maxTexImageSize) {
             ErrorInvalidValue("%s: tex maximum height for level %d is %u",
-                              InfoFrom(func), level, maxTexImageSize);
+                              InfoFrom(func, dims), level, maxTexImageSize);
             return false;
         }
 
         /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
          *   "If level is greater than zero, and either width or
          *   height is not a power-of-two, the error INVALID_VALUE is
          *   generated."
          */
         if (level > 0) {
             if (!is_pot_assuming_nonnegative(width)) {
                 ErrorInvalidValue("%s: level >= 0, width of %d must be a power of two.",
-                                  InfoFrom(func), width);
+                                  InfoFrom(func, dims), width);
                 return false;
             }
 
             if (!is_pot_assuming_nonnegative(height)) {
                 ErrorInvalidValue("%s: level >= 0, height of %d must be a power of two.",
-                                  InfoFrom(func), height);
+                                  InfoFrom(func, dims), height);
                 return false;
             }
         }
     }
 
     // TODO: WebGL 2
     if (texImageTarget == LOCAL_GL_TEXTURE_3D) {
         if (depth < 0) {
-            ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func));
+            ErrorInvalidValue("%s: depth must be >= 0", InfoFrom(func, dims));
             return false;
         }
 
-        if (!is_pot_assuming_nonnegative(depth)) {
+        if (depth > 0 && !is_pot_assuming_nonnegative(depth)) {
             ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
-                              InfoFrom(func), depth);
+                              InfoFrom(func, dims), depth);
             return false;
         }
     }
 
     return true;
 }
 
 /**
  * Validate texture image sizing for Tex(Sub)?Image variants.
  */
 // TODO: WebGL 2. Update this to handle 3D textures.
 bool
 WebGLContext::ValidateTexSubImageSize(GLint xoffset, GLint yoffset, GLint /*zoffset*/,
                                       GLsizei width, GLsizei height, GLsizei /*depth*/,
                                       GLsizei baseWidth, GLsizei baseHeight, GLsizei /*baseDepth*/,
-                                      WebGLTexImageFunc func)
+                                      WebGLTexImageFunc func, WebGLTexDimensions dims)
 {
     /* GL ES Version 2.0.25 - 3.7.1 Texture Image Specification
      *   "Taking wt and ht to be the specified width and height of the
      *   texture array, and taking x, y, w, and h to be the xoffset,
      *   yoffset, width, and height argument values, any of the
      *   following relationships generates the error INVALID_VALUE:
      *       x < 0
      *       x + w > wt
      *       y < 0
      *       y + h > ht"
      */
 
     if (xoffset < 0) {
-        ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func));
+        ErrorInvalidValue("%s: xoffset must be >= 0", InfoFrom(func, dims));
         return false;
     }
 
     if (yoffset < 0) {
-        ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func));
+        ErrorInvalidValue("%s: yoffset must be >= 0", InfoFrom(func, dims));
         return false;
     }
 
     if (!CanvasUtils::CheckSaneSubrectSize(xoffset, yoffset, width, height, baseWidth, baseHeight)) {
-        ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func));
+        ErrorInvalidValue("%s: subtexture rectangle out-of-bounds", InfoFrom(func, dims));
         return false;
     }
 
     return true;
 }
 
 /**
  * Perform validation of format/type combinations for TexImage variants.
  * Returns true if the format/type is a valid combination, false otherwise.
  */
 bool
 WebGLContext::ValidateTexImageFormatAndType(GLenum format,
-                                            GLenum type, WebGLTexImageFunc func)
+                                            GLenum type,
+                                            WebGLTexImageFunc func,
+                                            WebGLTexDimensions dims)
 {
     if (IsCompressedFunc(func) || IsCopyFunc(func))
     {
         MOZ_ASSERT(type == LOCAL_GL_NONE && format == LOCAL_GL_NONE);
         return true;
     }
-    if (!ValidateTexImageFormat(format, func) ||
-        !ValidateTexImageType(type, func))
+    if (!ValidateTexImageFormat(format, func, dims) ||
+        !ValidateTexImageType(type, func, dims))
     {
         return false;
     }
 
     // Here we're reinterpreting format as an unsized internalformat;
     // these are the same in practice and there's no point in having the
     // same code implemented twice.
     TexInternalFormat effective =
         EffectiveInternalFormatFromInternalFormatAndType(format, type);
     bool validCombo = effective != LOCAL_GL_NONE;
 
     if (!validCombo)
         ErrorInvalidOperation("%s: invalid combination of format %s and type %s",
-                              InfoFrom(func), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
+                              InfoFrom(func, dims), WebGLContext::EnumName(format), WebGLContext::EnumName(type));
 
     return validCombo;
 }
 
 bool
 WebGLContext::ValidateCompTexImageInternalFormat(GLenum format,
-                                                 WebGLTexImageFunc func)
+                                                 WebGLTexImageFunc func,
+                                                 WebGLTexDimensions dims)
 {
     if (!IsCompressedTextureFormat(format)) {
         ErrorInvalidEnum("%s: invalid compressed texture format: %s",
-                         InfoFrom(func), WebGLContext::EnumName(format));
+                         InfoFrom(func, dims), WebGLContext::EnumName(format));
         return false;
     }
 
     /* WEBGL_compressed_texture_atc added formats */
     if (format == LOCAL_GL_ATC_RGB ||
         format == LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA ||
         format == LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_atc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_atc enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     // WEBGL_compressed_texture_etc1
     if (format == LOCAL_GL_ETC1_RGB8_OES) {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_etc1);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_etc1 enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
 
     if (format == LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1 ||
         format == LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_pvrtc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_pvrtc enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
 
     if (format == LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT ||
         format == LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
     {
         bool validFormat = IsExtensionEnabled(WebGLExtensionID::WEBGL_compressed_texture_s3tc);
         if (!validFormat)
             ErrorInvalidEnum("%s: invalid format %s: need WEBGL_compressed_texture_s3tc enabled",
-                             InfoFrom(func), WebGLContext::EnumName(format));
+                             InfoFrom(func, dims), WebGLContext::EnumName(format));
         return validFormat;
     }
 
     return false;
 }
 
 bool
 WebGLContext::ValidateCopyTexImageInternalFormat(GLenum format,
-                                                 WebGLTexImageFunc func)
+                                                 WebGLTexImageFunc func,
+                                                 WebGLTexDimensions dims)
 {
     bool valid = format == LOCAL_GL_RGBA ||
                  format == LOCAL_GL_RGB ||
                  format == LOCAL_GL_LUMINANCE_ALPHA ||
                  format == LOCAL_GL_LUMINANCE ||
                  format == LOCAL_GL_ALPHA;
     if (!valid)
     {
         // in CopyTexImage, the internalformat is a function parameter,
         // so a bad value is an INVALID_ENUM error.
         // in CopyTexSubImage, the internalformat is part of existing state,
         // so this is an INVALID_OPERATION error.
         GenerateWarning("%s: invalid texture internal format: %s",
-                        InfoFrom(func), WebGLContext::EnumName(format));
+                        InfoFrom(func, dims), WebGLContext::EnumName(format));
         SynthesizeGLError(func == WebGLTexImageFunc::CopyTexImage
                           ? LOCAL_GL_INVALID_ENUM
                           : LOCAL_GL_INVALID_OPERATION);
     }
     return valid;
 }
 /**
  * Return true if format, type and jsArrayType are a valid combination.
  * Also returns the size for texel of format and type (in bytes) via
  * \a texelSize.
  *
  * It is assumed that type has previously been validated.
  */
 bool
-WebGLContext::ValidateTexInputData(GLenum type, int jsArrayType, WebGLTexImageFunc func)
+WebGLContext::ValidateTexInputData(GLenum type,
+                                   js::Scalar::Type jsArrayType,
+                                   WebGLTexImageFunc func,
+                                   WebGLTexDimensions dims)
 {
     bool validInput = false;
     const char invalidTypedArray[] = "%s: invalid typed array type for given texture data type";
 
+    // We're using js::Scalar::TypeMax as dummy value when the tex source wasn't a
+    // typed array.
+    if (jsArrayType == js::Scalar::TypeMax) {
+        return true;
+    }
+
     // First, we check for packed types
     switch (type) {
     case LOCAL_GL_UNSIGNED_BYTE:
-        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint8);
+        validInput = jsArrayType == js::Scalar::Uint8;
         break;
 
     case LOCAL_GL_BYTE:
-        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Int8);
+        validInput = jsArrayType == js::Scalar::Int8;
         break;
 
     case LOCAL_GL_HALF_FLOAT:
     case LOCAL_GL_UNSIGNED_SHORT:
     case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
     case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
     case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
-        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint16);
+        validInput = jsArrayType == js::Scalar::Uint16;
         break;
 
     case LOCAL_GL_SHORT:
-        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Int16);
+        validInput = jsArrayType == js::Scalar::Int16;
         break;
 
     case LOCAL_GL_UNSIGNED_INT:
     case LOCAL_GL_UNSIGNED_INT_24_8:
     case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
     case LOCAL_GL_UNSIGNED_INT_10F_11F_11F_REV:
     case LOCAL_GL_UNSIGNED_INT_5_9_9_9_REV:
-        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Uint32);
+        validInput = jsArrayType == js::Scalar::Uint32;
         break;
 
     case LOCAL_GL_INT:
-        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Int32);
+        validInput = jsArrayType == js::Scalar::Int32;
         break;
 
     case LOCAL_GL_FLOAT:
-        validInput = (jsArrayType == -1 || jsArrayType == js::Scalar::Float32);
+        validInput = jsArrayType == js::Scalar::Float32;
         break;
 
     default:
         break;
     }
 
     if (!validInput)
-        ErrorInvalidOperation(invalidTypedArray, InfoFrom(func));
+        ErrorInvalidOperation(invalidTypedArray, InfoFrom(func, dims));
 
     return validInput;
 }
 
 /**
  * Checks specific for the CopyTex[Sub]Image2D functions.
  * Verifies:
  * - Framebuffer is complete and has valid read planes
  * - Copy format is a subset of framebuffer format (i.e. all required components are available)
  */
 bool
 WebGLContext::ValidateCopyTexImage(GLenum format,
-                                   WebGLTexImageFunc func)
+                                   WebGLTexImageFunc func,
+                                   WebGLTexDimensions dims)
 {
     MOZ_ASSERT(IsCopyFunc(func));
 
     // Default framebuffer format
     GLenum fboFormat = bool(gl->GetPixelFormat().alpha > 0) ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
 
     if (mBoundFramebuffer) {
         if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
-            ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", InfoFrom(func));
+            ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", InfoFrom(func, dims));
             return false;
         }
 
         GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
         if (!mBoundFramebuffer->HasCompletePlanes(readPlaneBits)) {
             ErrorInvalidOperation("%s: Read source attachment doesn't have the"
-                                  " correct color/depth/stencil type.", InfoFrom(func));
+                                  " correct color/depth/stencil type.", InfoFrom(func, dims));
             return false;
         }
 
         // Get the correct format for the framebuffer, as it's not the default one
         const WebGLFramebuffer::Attachment& color0 = mBoundFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
         fboFormat = mBoundFramebuffer->GetFormatForAttachment(color0);
     }
 
     // Make sure the format of the framebuffer is a superset of
     // the format requested by the CopyTex[Sub]Image2D functions.
     const GLComponents formatComps = GLComponents(format);
     const GLComponents fboComps = GLComponents(fboFormat);
     if (!formatComps.IsSubsetOf(fboComps)) {
         ErrorInvalidOperation("%s: format %s is not a subset of the current framebuffer format, which is %s.",
-                              InfoFrom(func), EnumName(format), EnumName(fboFormat));
+                              InfoFrom(func, dims), EnumName(format), EnumName(fboFormat));
         return false;
     }
 
     return true;
 }
 
 /**
  * Test the gl(Copy|Compressed)?Tex[Sub]?Image[23]() parameters for errors.
  * Verifies each of the parameters against the WebGL standard and enabled extensions.
  */
 // TODO: Texture dims is here for future expansion in WebGL 2.0
 bool
-WebGLContext::ValidateTexImage(GLuint dims, TexImageTarget texImageTarget,
+WebGLContext::ValidateTexImage(TexImageTarget texImageTarget,
                                GLint level,
                                GLenum internalFormat,
                                GLint xoffset, GLint yoffset, GLint zoffset,
                                GLint width, GLint height, GLint depth,
                                GLint border,
                                GLenum format,
                                GLenum type,
-                               WebGLTexImageFunc func)
+                               WebGLTexImageFunc func,
+                               WebGLTexDimensions dims)
 {
-    const char* info = InfoFrom(func);
+    const char* info = InfoFrom(func, dims);
 
     /* Check level */
     if (level < 0) {
         ErrorInvalidValue("%s: level must be >= 0", info);
         return false;
     }
 
     /* Check border */
     if (border != 0) {
         ErrorInvalidValue("%s: border must be 0", info);
         return false;
     }
 
     /* Check incoming image format and type */
-    if (!ValidateTexImageFormatAndType(format, type, func))
+    if (!ValidateTexImageFormatAndType(format, type, func, dims))
         return false;
 
     if (!TexInternalFormat::IsValueLegal(internalFormat)) {
         ErrorInvalidEnum("%s: invalid internalformat enum %s", info, EnumName(internalFormat));
         return false;
     }
     TexInternalFormat unsizedInternalFormat =
         UnsizedInternalFormatFromInternalFormat(internalFormat);
 
     if (IsCompressedFunc(func)) {
-        if (!ValidateCompTexImageInternalFormat(internalFormat, func)) {
+        if (!ValidateCompTexImageInternalFormat(internalFormat, func, dims)) {
             return false;
         }
     } else if (IsCopyFunc(func)) {
-        if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(), func)) {
+        if (!ValidateCopyTexImageInternalFormat(unsizedInternalFormat.get(), func, dims)) {
             return false;
         }
     } else if (format != unsizedInternalFormat) {
         if (IsWebGL2()) {
             // In WebGL2, it's OK to have internalformat != format if internalformat is the sized
             // internal format corresponding to the (format, type) pair according to Table 3.2
             // in the OpenGL ES 3.0.3 spec.
             if (internalFormat != EffectiveInternalFormatFromInternalFormatAndType(format, type)) {
@@ -1184,17 +1190,17 @@ WebGLContext::ValidateTexImage(GLuint di
         } else {
             // in WebGL 1, format must be equal to internalformat
             ErrorInvalidOperation("%s: internalformat does not match format", info);
             return false;
         }
     }
 
     /* Check texture image size */
-    if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func))
+    if (!ValidateTexImageSize(texImageTarget, level, width, height, 0, func, dims))
         return false;
 
     /* 5.14.8 Texture objects - WebGL Spec.
      *   "If an attempt is made to call these functions with no
      *    WebGLTexture bound (see above), an INVALID_OPERATION error
      *    is generated."
      */
     WebGLTexture* tex = activeBoundTextureForTexImageTarget(texImageTarget);
@@ -1211,17 +1217,17 @@ WebGLContext::ValidateTexImage(GLuint di
             return false;
         }
 
         const WebGLTexture::ImageInfo& imageInfo = tex->ImageInfoAt(texImageTarget, level);
 
         if (!ValidateTexSubImageSize(xoffset, yoffset, zoffset,
                                      width, height, depth,
                                      imageInfo.Width(), imageInfo.Height(), 0,
-                                     func))
+                                     func, dims))
         {
             return false;
         }
     }
 
     /* Additional checks for depth textures */
     if (texImageTarget != LOCAL_GL_TEXTURE_2D &&
         (format == LOCAL_GL_DEPTH_COMPONENT ||
@@ -1497,16 +1503,17 @@ WebGLContext::InitAndValidateGL()
     // Bindings, etc.
     mActiveTexture = 0;
     mEmitContextLostErrorOnce = true;
     mWebGLError = LOCAL_GL_NO_ERROR;
     mUnderlyingGLError = LOCAL_GL_NO_ERROR;
 
     mBound2DTextures.Clear();
     mBoundCubeMapTextures.Clear();
+    mBound3DTextures.Clear();
 
     mBoundArrayBuffer = nullptr;
     mBoundTransformFeedbackBuffer = nullptr;
     mCurrentProgram = nullptr;
 
     mBoundFramebuffer = nullptr;
     mBoundRenderbuffer = nullptr;
 
@@ -1537,16 +1544,17 @@ WebGLContext::InitAndValidateGL()
     }
     if (mGLMaxTextureUnits < 8) {
         GenerateWarning("GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: %d is < 8!", mGLMaxTextureUnits);
         return false;
     }
 
     mBound2DTextures.SetLength(mGLMaxTextureUnits);
     mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
+    mBound3DTextures.SetLength(mGLMaxTextureUnits);
 
     if (MinCapabilityMode()) {
         mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
         mGLMaxCubeMapTextureSize = MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
         mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
         mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
         mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
     } else {
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -43,64 +43,77 @@ WebGLTexture::WebGLTexture(WebGLContext 
 void
 WebGLTexture::Delete() {
     mImageInfos.Clear();
     mContext->MakeContextCurrent();
     mContext->gl->fDeleteTextures(1, &mGLName);
     LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
 }
 
-int64_t
+size_t
 WebGLTexture::ImageInfo::MemoryUsage() const {
     if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
         return 0;
-    int64_t bitsPerTexel = GetBitsPerTexel(mEffectiveInternalFormat);
-    return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8;
+    size_t bitsPerTexel = GetBitsPerTexel(mEffectiveInternalFormat);
+    return size_t(mWidth) * size_t(mHeight) * size_t(mDepth) * bitsPerTexel / 8;
 }
 
-int64_t
+size_t
 WebGLTexture::MemoryUsage() const {
     if (IsDeleted())
         return 0;
-    int64_t result = 0;
+    size_t result = 0;
     for(size_t face = 0; face < mFacesCount; face++) {
         if (mHaveGeneratedMipmap) {
-            // Each mipmap level is 1/4 the size of the previous level
+            size_t level0MemoryUsage = ImageInfoAtFace(face, 0).MemoryUsage();
+            // Each mipmap level is 1/(2^d) the size of the previous level,
+            // where d is 2 or 3 depending on whether the images are 2D or 3D
             // 1 + x + x^2 + ... = 1/(1-x)
-            // for x = 1/4, we get 1/(1-1/4) = 4/3
-            result += ImageInfoAtFace(face, 0).MemoryUsage() * 4 / 3;
+            // for x = 1/(2^2), we get 1/(1-1/4) = 4/3
+            // for x = 1/(2^3), we get 1/(1-1/8) = 8/7
+            size_t allLevelsMemoryUsage =
+                mTarget == LOCAL_GL_TEXTURE_3D
+                ? level0MemoryUsage * 8 / 7
+                : level0MemoryUsage * 4 / 3;
+            result += allLevelsMemoryUsage;
         } else {
             for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
                 result += ImageInfoAtFace(face, level).MemoryUsage();
         }
     }
     return result;
 }
 
 bool
-WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const {
+WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const
+{
     if (mHaveGeneratedMipmap)
         return true;
 
     // We want a copy here so we can modify it temporarily.
     ImageInfo expected = ImageInfoAt(texImageTarget, 0);
 
     // checks if custom level>0 images are all defined up to the highest level defined
     // and have the expected dimensions
     for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
         const ImageInfo& actual = ImageInfoAt(texImageTarget, level);
         if (actual != expected)
             return false;
-        expected.mWidth = std::max(1, expected.mWidth >> 1);
-        expected.mHeight = std::max(1, expected.mHeight >> 1);
+        expected.mWidth = std::max(1, expected.mWidth / 2);
+        expected.mHeight = std::max(1, expected.mHeight / 2);
+        expected.mDepth = std::max(1, expected.mDepth / 2);
 
         // if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence
         // of extra useless levels.
-        if (actual.mWidth == 1 && actual.mHeight == 1)
+        if (actual.mWidth == 1 &&
+            actual.mHeight == 1 &&
+            actual.mDepth == 1)
+        {
             return true;
+        }
     }
 
     // if we're here, we've exhausted all levels without finding a 1x1 image
     return false;
 }
 
 void
 WebGLTexture::Bind(TexTarget aTexTarget) {
@@ -118,40 +131,39 @@ WebGLTexture::Bind(TexTarget aTexTarget)
         return;
     }
 
     GLuint name = GLName();
 
     mContext->gl->fBindTexture(aTexTarget.get(), name);
 
     if (firstTimeThisTextureIsBound) {
-        mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
+        mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? 6 : 1;
         EnsureMaxLevelWithCustomImagesAtLeast(0);
         SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
 
         // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
         // present in GLES 2, but is present in GL and it seems as if for cube maps
         // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
         if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
             mContext->gl->fTexParameteri(aTexTarget.get(), LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
     }
 }
 
 void
 WebGLTexture::SetImageInfo(TexImageTarget aTexImageTarget, GLint aLevel,
-                           GLsizei aWidth, GLsizei aHeight,
+                           GLsizei aWidth, GLsizei aHeight, GLsizei aDepth,
                            TexInternalFormat aEffectiveInternalFormat, WebGLImageDataStatus aStatus)
 {
+    MOZ_ASSERT(aDepth == 1 || aTexImageTarget == LOCAL_GL_TEXTURE_3D);
     MOZ_ASSERT(TexImageTargetToTexTarget(aTexImageTarget) == mTarget);
-    if (TexImageTargetToTexTarget(aTexImageTarget) != mTarget)
-        return;
 
     EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
 
-    ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aEffectiveInternalFormat, aStatus);
+    ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aDepth, aEffectiveInternalFormat, aStatus);
 
     if (aLevel > 0)
         SetCustomMipmap();
 
     // Invalidate framebuffer status cache
     NotifyFBsStatusChanged();
 
     SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
@@ -171,29 +183,30 @@ WebGLTexture::SetCustomMipmap() {
         // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
         // we need to compute now all the mipmap image info.
 
         // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
         // and are power-of-two.
         ImageInfo imageInfo = ImageInfoAtFace(0, 0);
         NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
 
-        GLsizei size = std::max(imageInfo.mWidth, imageInfo.mHeight);
+        GLsizei size = std::max(std::max(imageInfo.mWidth, imageInfo.mHeight), imageInfo.mDepth);
 
         // so, the size is a power of two, let's find its log in base 2.
         size_t maxLevel = 0;
         for (GLsizei n = size; n > 1; n >>= 1)
             ++maxLevel;
 
         EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
 
         for (size_t level = 1; level <= maxLevel; ++level) {
             // again, since the sizes are powers of two, no need for any max(1,x) computation
-            imageInfo.mWidth >>= 1;
-            imageInfo.mHeight >>= 1;
+            imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1);
+            imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1);
+            imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1);
             for(size_t face = 0; face < mFacesCount; ++face)
                 ImageInfoAtFace(face, level) = imageInfo;
         }
     }
     mHaveGeneratedMipmap = false;
 }
 
 bool
@@ -201,43 +214,44 @@ WebGLTexture::AreAllLevel0ImageInfosEqua
     for (size_t face = 1; face < mFacesCount; ++face) {
         if (ImageInfoAtFace(face, 0) != ImageInfoAtFace(0, 0))
             return false;
     }
     return true;
 }
 
 bool
-WebGLTexture::IsMipmapTexture2DComplete() const {
-    if (mTarget != LOCAL_GL_TEXTURE_2D)
-        return false;
-    if (!ImageInfoAt(LOCAL_GL_TEXTURE_2D, 0).IsPositive())
+WebGLTexture::IsMipmapComplete() const {
+    MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_2D ||
+               mTarget == LOCAL_GL_TEXTURE_3D);
+
+    if (!ImageInfoAtFace(0, 0).IsPositive())
         return false;
     if (mHaveGeneratedMipmap)
         return true;
-    return DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
+    return DoesMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
 }
 
 bool
 WebGLTexture::IsCubeComplete() const {
-    if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
-        return false;
+    MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_CUBE_MAP);
+
     const ImageInfo &first = ImageInfoAt(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
     if (!first.IsPositive() || !first.IsSquare())
         return false;
     return AreAllLevel0ImageInfosEqual();
 }
 
 bool
 WebGLTexture::IsMipmapCubeComplete() const {
     if (!IsCubeComplete()) // in particular, this checks that this is a cube map
         return false;
     for (int i = 0; i < 6; i++) {
         const TexImageTarget face = TexImageTargetForTargetAndFace(LOCAL_GL_TEXTURE_CUBE_MAP, i);
-        if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face))
+        if (!DoesMipmapHaveAllLevelsConsistentlyDefined(face))
             return false;
     }
     return true;
 }
 
 WebGLTextureFakeBlackStatus
 WebGLTexture::ResolvedFakeBlackStatus() {
     if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown)) {
@@ -255,44 +269,46 @@ WebGLTexture::ResolvedFakeBlackStatus() 
             return mFakeBlackStatus;
         }
     }
 
     const char *msg_rendering_as_black
         = "A texture is going to be rendered as if it were black, as per the OpenGL ES 2.0.24 spec section 3.8.2, "
           "because it";
 
-    if (mTarget == LOCAL_GL_TEXTURE_2D)
+    if (mTarget == LOCAL_GL_TEXTURE_2D ||
+        mTarget == LOCAL_GL_TEXTURE_3D)
     {
+        int dim = mTarget == LOCAL_GL_TEXTURE_2D ? 2 : 3;
         if (DoesMinFilterRequireMipmap())
         {
-            if (!IsMipmapTexture2DComplete()) {
+            if (!IsMipmapComplete()) {
                 mContext->GenerateWarning
-                    ("%s is a 2D texture, with a minification filter requiring a mipmap, "
-                      "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black);
+                    ("%s is a %dD texture, with a minification filter requiring a mipmap, "
+                      "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black, dim);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             } else if (!ImageInfoBase().IsPowerOfTwo()) {
                 mContext->GenerateWarning
-                    ("%s is a 2D texture, with a minification filter requiring a mipmap, "
+                    ("%s is a %dD texture, with a minification filter requiring a mipmap, "
                       "and either its width or height is not a power of two.", msg_rendering_as_black);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
         else // no mipmap required
         {
             if (!ImageInfoBase().IsPositive()) {
                 mContext->GenerateWarning
-                    ("%s is a 2D texture and its width or height is equal to zero.",
-                      msg_rendering_as_black);
+                    ("%s is a %dD texture and its width or height is equal to zero.",
+                      msg_rendering_as_black, dim);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             } else if (!AreBothWrapModesClampToEdge() && !ImageInfoBase().IsPowerOfTwo()) {
                 mContext->GenerateWarning
-                    ("%s is a 2D texture, with a minification filter not requiring a mipmap, "
+                    ("%s is a %dD texture, with a minification filter not requiring a mipmap, "
                       "with its width or height not a power of two, and with a wrap mode "
-                      "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
+                      "different from CLAMP_TO_EDGE.", msg_rendering_as_black, dim);
                 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
             }
         }
     }
     else // cube map
     {
         bool areAllLevel0ImagesPOT = true;
         for (size_t face = 0; face < mFacesCount; ++face)
@@ -450,18 +466,17 @@ ClearByMask(WebGLContext* context, GLbit
 
 // `mask` from glClear.
 static bool
 ClearWithTempFB(WebGLContext* context, GLuint tex,
                 TexImageTarget texImageTarget, GLint level,
                 TexInternalFormat baseInternalFormat,
                 GLsizei width, GLsizei height)
 {
-    if (texImageTarget != LOCAL_GL_TEXTURE_2D)
-        return false;
+    MOZ_ASSERT(texImageTarget == LOCAL_GL_TEXTURE_2D);
 
     gl::GLContext* gl = context->GL();
     MOZ_ASSERT(gl->IsCurrent());
 
     gl::ScopedFramebuffer fb(gl);
     gl::ScopedBindFramebuffer autoFB(gl, fb.FB());
     GLbitfield mask = 0;
 
@@ -531,60 +546,71 @@ WebGLTexture::DoDeferredImageInitializat
 {
     const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
     MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
 
     mContext->MakeContextCurrent();
 
     // Try to clear with glCLear.
 
-    bool cleared = ClearWithTempFB(mContext, GLName(),
-                                   imageTarget, level,
-                                   imageInfo.mEffectiveInternalFormat,
-                                   imageInfo.mHeight, imageInfo.mWidth);
-    if (cleared) {
-        SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
-        return;
+    if (imageTarget == LOCAL_GL_TEXTURE_2D) {
+        bool cleared = ClearWithTempFB(mContext, GLName(),
+                                       imageTarget, level,
+                                       imageInfo.mEffectiveInternalFormat,
+                                       imageInfo.mHeight, imageInfo.mWidth);
+        if (cleared) {
+            SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
+            return;
+        }
     }
 
     // That didn't work. Try uploading zeros then.
     gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget.get());
 
     size_t bitspertexel = GetBitsPerTexel(imageInfo.mEffectiveInternalFormat);
     MOZ_ASSERT((bitspertexel % 8) == 0); // that would only happen for compressed images, which
                                          // cannot use deferred initialization.
     size_t bytespertexel = bitspertexel / 8;
     CheckedUint32 checked_byteLength
         = WebGLContext::GetImageSize(
                         imageInfo.mHeight,
                         imageInfo.mWidth,
+                        imageInfo.mDepth,
                         bytespertexel,
                         mContext->mPixelStoreUnpackAlignment);
     MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
     ScopedFreePtr<void> zeros;
     zeros = calloc(1, checked_byteLength.value());
 
     gl::GLContext* gl = mContext->gl;
     GLenum driverInternalFormat = LOCAL_GL_NONE;
     GLenum driverFormat = LOCAL_GL_NONE;
     GLenum driverType = LOCAL_GL_NONE;
     DriverFormatsFromEffectiveInternalFormat(gl, imageInfo.mEffectiveInternalFormat,
                                              &driverInternalFormat, &driverFormat, &driverType);
 
     mContext->GetAndFlushUnderlyingGLErrors();
-    if (mImmutable) {
-        gl->fTexSubImage2D(imageTarget.get(), level, 0, 0,
-                           imageInfo.mWidth, imageInfo.mHeight,
-                           driverFormat, driverType,
-                           zeros);
+    if (imageTarget == LOCAL_GL_TEXTURE_3D) {
+        MOZ_ASSERT(mImmutable, "Shouldn't be possible to have non-immutable-format 3D textures in WebGL");
+        gl->fTexSubImage3D(imageTarget.get(), level, 0, 0, 0,
+                        imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth,
+                        driverFormat, driverType,
+                        zeros);
     } else {
-        gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
-                        imageInfo.mWidth, imageInfo.mHeight,
-                        0, driverFormat, driverType,
-                        zeros);
+        if (mImmutable) {
+            gl->fTexSubImage2D(imageTarget.get(), level, 0, 0,
+                            imageInfo.mWidth, imageInfo.mHeight,
+                            driverFormat, driverType,
+                            zeros);
+        } else {
+            gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
+                            imageInfo.mWidth, imageInfo.mHeight,
+                            0, driverFormat, driverType,
+                            zeros);
+        }
     }
     GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
     if (error) {
         // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
         printf_stderr("Error: 0x%4x\n", error);
         MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
     }
 
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -10,16 +10,17 @@
 #include "WebGLFramebufferAttachable.h"
 #include "WebGLObjectModel.h"
 #include "WebGLStrongTypes.h"
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/LinkedList.h"
+#include "mozilla/Assertions.h"
 #include <algorithm>
 
 namespace mozilla {
 
 // Zero is not an integer power of two.
 inline bool is_pot_assuming_nonnegative(GLsizei x)
 {
     return x && (x & (x-1)) == 0;
@@ -63,80 +64,94 @@ protected:
 public:
 
     class ImageInfo
         : public WebGLRectangleObject
     {
     public:
         ImageInfo()
             : mEffectiveInternalFormat(LOCAL_GL_NONE)
+            , mDepth(0)
             , mImageDataStatus(WebGLImageDataStatus::NoImageData)
         {}
 
         ImageInfo(GLsizei width,
                   GLsizei height,
+                  GLsizei depth,
                   TexInternalFormat effectiveInternalFormat,
                   WebGLImageDataStatus status)
             : WebGLRectangleObject(width, height)
             , mEffectiveInternalFormat(effectiveInternalFormat)
+            , mDepth(depth)
             , mImageDataStatus(status)
         {
             // shouldn't use this constructor to construct a null ImageInfo
             MOZ_ASSERT(status != WebGLImageDataStatus::NoImageData);
         }
 
         bool operator==(const ImageInfo& a) const {
             return mImageDataStatus == a.mImageDataStatus &&
                    mWidth == a.mWidth &&
                    mHeight == a.mHeight &&
+                   mDepth == a.mDepth &&
                    mEffectiveInternalFormat == a.mEffectiveInternalFormat;
         }
         bool operator!=(const ImageInfo& a) const {
             return !(*this == a);
         }
         bool IsSquare() const {
             return mWidth == mHeight;
         }
         bool IsPositive() const {
-            return mWidth > 0 && mHeight > 0;
+            return mWidth > 0 && mHeight > 0 && mDepth > 0;
         }
         bool IsPowerOfTwo() const {
             return is_pot_assuming_nonnegative(mWidth) &&
                    is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
         }
         bool HasUninitializedImageData() const {
             return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
         }
-        int64_t MemoryUsage() const;
+        size_t MemoryUsage() const;
 
         TexInternalFormat EffectiveInternalFormat() const { return mEffectiveInternalFormat; }
 
     protected:
         /*
          * This is the "effective internal format" of the texture,
          * an official OpenGL spec concept, see
          * OpenGL ES 3.0.3 spec, section 3.8.3, page 126 and below.
          */
         TexInternalFormat mEffectiveInternalFormat;
 
+        /*
+         * Used only for 3D textures.
+         * Note that mWidth and mHeight are inherited from WebGLRectangleObject.
+         * It's a pity to store a useless mDepth on non-3D texture images, but
+         * the size of GLsizei is negligible compared to the typical size of a texture image.
+         */
+        GLsizei mDepth;
+
         WebGLImageDataStatus mImageDataStatus;
 
         friend class WebGLTexture;
     };
 
 private:
     static size_t FaceForTarget(TexImageTarget texImageTarget) {
-        if (texImageTarget == LOCAL_GL_TEXTURE_2D)
+        if (texImageTarget == LOCAL_GL_TEXTURE_2D ||
+            texImageTarget == LOCAL_GL_TEXTURE_3D)
+        {
             return 0;
-
+        }
         return texImageTarget.get() - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
     }
 
     ImageInfo& ImageInfoAtFace(size_t face, GLint level) {
-        MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D and at most 5 for cube maps");
+        MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D or TEXTURE_3D, and at most 5 for cube maps");
 
         // no need to check level as a wrong value would be caught by ElementAt().
         return mImageInfos.ElementAt(level * mFacesCount + face);
     }
 
     const ImageInfo& ImageInfoAtFace(size_t face, GLint level) const {
         return const_cast<const ImageInfo&>(
             const_cast<WebGLTexture*>(this)->ImageInfoAtFace(face, level)
@@ -164,17 +179,17 @@ public:
     ImageInfo& ImageInfoBase() {
         return ImageInfoAtFace(0, 0);
     }
 
     const ImageInfo& ImageInfoBase() const {
         return ImageInfoAtFace(0, 0);
     }
 
-    int64_t MemoryUsage() const;
+    size_t MemoryUsage() const;
 
     void SetImageDataStatus(TexImageTarget imageTarget, GLint level, WebGLImageDataStatus newStatus) {
         MOZ_ASSERT(HasImageInfoAt(imageTarget, level));
         ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
         // there is no way to go from having image data to not having any
         MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
                    imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
         if (imageInfo.mImageDataStatus != newStatus) {
@@ -209,24 +224,24 @@ protected:
         return (mMagFilter == LOCAL_GL_NEAREST) &&
             (mMinFilter == LOCAL_GL_NEAREST || mMinFilter == LOCAL_GL_NEAREST_MIPMAP_NEAREST);
     }
 
     bool AreBothWrapModesClampToEdge() const {
         return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
     }
 
-    bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
+    bool DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
 
 public:
 
     void Bind(TexTarget aTexTarget);
 
     void SetImageInfo(TexImageTarget aTarget, GLint aLevel,
-                      GLsizei aWidth, GLsizei aHeight,
+                      GLsizei aWidth, GLsizei aHeight, GLsizei aDepth,
                       TexInternalFormat aFormat, WebGLImageDataStatus aStatus);
 
     void SetMinFilter(TexMinFilter aMinFilter) {
         mMinFilter = aMinFilter;
         SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
     }
     void SetMagFilter(TexMagFilter aMagFilter) {
         mMagFilter = aMagFilter;
@@ -251,17 +266,17 @@ public:
     void SetCustomMipmap();
 
     bool IsFirstImagePowerOfTwo() const {
         return ImageInfoBase().IsPowerOfTwo();
     }
 
     bool AreAllLevel0ImageInfosEqual() const;
 
-    bool IsMipmapTexture2DComplete() const;
+    bool IsMipmapComplete() const;
 
     bool IsCubeComplete() const;
 
     bool IsMipmapCubeComplete() const;
 
     void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x);
 
     bool IsImmutable() const { return mImmutable; }
@@ -272,16 +287,24 @@ public:
     // Returns the current fake-black-status, except if it was Unknown,
     // in which case this function resolves it first, so it never returns Unknown.
     WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();
 };
 
 inline TexImageTarget
 TexImageTargetForTargetAndFace(TexTarget target, size_t face)
 {
-    return target == LOCAL_GL_TEXTURE_2D
-           ? LOCAL_GL_TEXTURE_2D
-           : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+    switch (target.get()) {
+        case LOCAL_GL_TEXTURE_2D:
+        case LOCAL_GL_TEXTURE_3D:
+            MOZ_ASSERT(face == 0);
+            return target.get();
+        case LOCAL_GL_TEXTURE_CUBE_MAP:
+            MOZ_ASSERT(face < 6);
+            return LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
+        default:
+            MOZ_CRASH();
+    }
 }
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGLTypes.h
+++ b/dom/canvas/WebGLTypes.h
@@ -41,66 +41,66 @@ namespace mozilla {
  *       with zero bytes, which means it's either opaque or transparent black
  *       depending on whether the image format has alpha.
  *
  * Why are there _two_ separate enums there, WebGLContextFakeBlackStatus
  * and WebGLTextureFakeBlackStatus? That's because each texture must know the precise
  * reason why it needs to be faked (incomplete texture vs. uninitialized image data),
  * whereas the WebGL context can only know whether _any_ faking is currently needed at all.
  */
-MOZ_BEGIN_ENUM_CLASS(WebGLContextFakeBlackStatus, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLContextFakeBlackStatus, uint8_t)
   Unknown,
   NotNeeded,
   Needed
 MOZ_END_ENUM_CLASS(WebGLContextFakeBlackStatus)
 
-MOZ_BEGIN_ENUM_CLASS(WebGLTextureFakeBlackStatus, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLTextureFakeBlackStatus, uint8_t)
   Unknown,
   NotNeeded,
   IncompleteTexture,
   UninitializedImageData
 MOZ_END_ENUM_CLASS(WebGLTextureFakeBlackStatus)
 
 /*
  * Implementing WebGL (or OpenGL ES 2.0) on top of desktop OpenGL requires
  * emulating the vertex attrib 0 array when it's not enabled. Indeed,
  * OpenGL ES 2.0 allows drawing without vertex attrib 0 array enabled, but
  * desktop OpenGL does not allow that.
  */
-MOZ_BEGIN_ENUM_CLASS(WebGLVertexAttrib0Status, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLVertexAttrib0Status, uint8_t)
     Default, // default status - no emulation needed
     EmulatedUninitializedArray, // need an artificial attrib 0 array, but contents may be left uninitialized
     EmulatedInitializedArray // need an artificial attrib 0 array, and contents must be initialized
 MOZ_END_ENUM_CLASS(WebGLVertexAttrib0Status)
 
 /*
  * Enum to track the status of image data (renderbuffer or texture image) presence
  * and initialization.
  *
  * - NoImageData is the initial state before any image data is allocated.
  * - InitializedImageData is the state after image data is allocated and initialized.
  * - UninitializedImageData is an intermediate state where data is allocated but not
  *   initialized. It is the state that renderbuffers are in after a renderbufferStorage call,
  *   and it is the state that texture images are in after a texImage2D call with null data.
  */
-MOZ_BEGIN_ENUM_CLASS(WebGLImageDataStatus, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLImageDataStatus, uint8_t)
     NoImageData,
     UninitializedImageData,
     InitializedImageData
 MOZ_END_ENUM_CLASS(WebGLImageDataStatus)
 
 /*
  * The formats that may participate, either as source or destination formats,
  * in WebGL texture conversions. This includes:
  *  - all the formats accepted by WebGL.texImage2D, e.g. RGBA4444
  *  - additional formats provided by extensions, e.g. RGB32F
  *  - additional source formats, depending on browser details, used when uploading
  *    textures from DOM elements. See gfxImageSurface::Format().
  */
-MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, uint8_t)
     // returned by SurfaceFromElementResultToImageSurface to indicate absence of image data
     None,
     // common value for formats for which format conversions are not supported
     FormatNotSupportingAnyConversion,
     // dummy pseudo-format meaning "use the other format".
     // For example, if SrcFormat=Auto and DstFormat=RGB8, then the source
     // is implicitly treated as being RGB8 itself.
     Auto,
@@ -125,25 +125,30 @@ MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, i
     RGBA8,
     BGRA8, // used for DOM elements
     RGBA5551,
     RGBA4444,
     RGBA16F, // OES_texture_half_float
     RGBA32F // OES_texture_float
 MOZ_END_ENUM_CLASS(WebGLTexelFormat)
 
-MOZ_BEGIN_ENUM_CLASS(WebGLTexImageFunc, int)
+MOZ_BEGIN_ENUM_CLASS(WebGLTexImageFunc, uint8_t)
     TexImage,
     TexSubImage,
     CopyTexImage,
     CopyTexSubImage,
     CompTexImage,
     CompTexSubImage,
 MOZ_END_ENUM_CLASS(WebGLTexImageFunc)
 
+MOZ_BEGIN_ENUM_CLASS(WebGLTexDimensions, uint8_t)
+    Tex2D,
+    Tex3D
+MOZ_END_ENUM_CLASS(WebGLTexDimensions)
+
 // Please keep extensions in alphabetic order.
 MOZ_BEGIN_ENUM_CLASS(WebGLExtensionID, uint8_t)
     ANGLE_instanced_arrays,
     EXT_blend_minmax,
     EXT_color_buffer_half_float,
     EXT_frag_depth,
     EXT_sRGB,
     EXT_shader_texture_lod,
--- a/gfx/gl/ScopedGLHelpers.cpp
+++ b/gfx/gl/ScopedGLHelpers.cpp
@@ -175,16 +175,17 @@ ScopedRenderbuffer::UnwrapImpl()
 
 /* ScopedBindTexture **********************************************************/
 void
 ScopedBindTexture::Init(GLenum aTarget)
 {
     mTarget = aTarget;
     mOldTex = 0;
     GLenum bindingTarget = (aTarget == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_BINDING_2D
+                         : (aTarget == LOCAL_GL_TEXTURE_3D) ? LOCAL_GL_TEXTURE_BINDING_3D
                          : (aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) ? LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
                          : (aTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
                          : (aTarget == LOCAL_GL_TEXTURE_EXTERNAL) ? LOCAL_GL_TEXTURE_BINDING_EXTERNAL
                          : LOCAL_GL_NONE;
     MOZ_ASSERT(bindingTarget != LOCAL_GL_NONE);
     mGL->GetUIntegerv(bindingTarget, &mOldTex);
 }
 
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -169,16 +169,17 @@ AC_SUBST(JS_SHARED_LIBRARY)
 if test "$JS_STANDALONE" = no; then
   autoconfmk=autoconf-js.mk
   JS_STANDALONE=
 else
   JS_STANDALONE=1
   LIBXUL_DIST="$MOZ_BUILD_ROOT/dist"
   AC_DEFINE(JS_STANDALONE)
 fi
+
 AC_SUBST(JS_STANDALONE)
 BUILDING_JS=1
 AC_SUBST(autoconfmk)
 
 MOZ_ARG_WITH_STRING(gonk,
 [  --with-gonk=DIR
                location of gonk dir],
     gonkdir=$withval)
--- a/js/src/tests/ecma_6/Object/propertyIsEnumerable-proxy.js
+++ b/js/src/tests/ecma_6/Object/propertyIsEnumerable-proxy.js
@@ -15,17 +15,21 @@ function logProxy(object) {
                 throw new Error(`Unexpected call to trap: "${propertyKey}"`);
             }
             return target[propertyKey];
         }
     }));
     return {proxy, log};
 }
 
-for (var property of ["string-property", Symbol("symbol-property")]) {
+var properties = ["string-property"];
+if (typeof Symbol === 'function')
+    properties.push(Symbol("symbol-property"));
+
+for (var property of properties) {
     // Test 1: property is not present on object
     var {proxy, log} = logProxy({});
     var result = Object.prototype.propertyIsEnumerable.call(proxy, property);
     assertEq(result, false);
     assertDeepEq(log, [property]);
 
     // Test 2: property is present on object and enumerable
     var {proxy, log} = logProxy({[property]: 0});
new file mode 100644
new file mode 100644
--- a/layout/tables/nsTableFrame.cpp
+++ b/layout/tables/nsTableFrame.cpp
@@ -268,17 +268,17 @@ nsTableFrame::DestroyPositionedTablePart
 
 /* static */ void
 nsTableFrame::RegisterPositionedTablePart(nsIFrame* aFrame)
 {
   // Supporting relative positioning for table parts other than table cells has
   // the potential to break sites that apply 'position: relative' to those
   // parts, expecting nothing to happen. We warn at the console to make tracking
   // down the issue easy.
-  if (nsGkAtoms::tableCellFrame != aFrame->GetType()) {
+  if (!IS_TABLE_CELL(aFrame->GetType())) {
     nsIContent* content = aFrame->GetContent();
     nsPresContext* presContext = aFrame->PresContext();
     if (content && !presContext->HasWarnedAboutPositionedTableParts()) {
       presContext->SetHasWarnedAboutPositionedTableParts();
       nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
                                       NS_LITERAL_CSTRING("Layout: Tables"),
                                       content->OwnerDoc(),
                                       nsContentUtils::eLAYOUT_PROPERTIES,
--- a/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyDecryptionManager.cpp
@@ -371,32 +371,31 @@ ClearKeyDecryptor::ClearKeyDecryptor(GMP
     mThread = nullptr;
     return;
   }
 }
 
 ClearKeyDecryptor::~ClearKeyDecryptor()
 {
   CK_LOGD("ClearKeyDecryptor dtor; key ID = %08x...", *(uint32_t*)&mKey[0]);
-  if (mThread) {
-    mThread->Join();
-  }
 }
 
 uint32_t
 ClearKeyDecryptor::AddRef()
 {
   return ++mRefCnt;
 }
 
 uint32_t
 ClearKeyDecryptor::Release()
 {
-  if (!--mRefCnt) {
+  uint32_t newCount = --mRefCnt;
+  if (!newCount) {
     if (mThread) {
       mThread->Post(new DestroyTask(this));
+      mThread->Join();
     } else {
       delete this;
     }
   }
 
-  return mRefCnt;
+  return newCount;
 }
--- a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp
@@ -1,12 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include <algorithm>
 #include <assert.h>
 #include <ctype.h>
 #include <stdarg.h>
 #include <stdint.h>
 #include <vector>
 
 #include "ClearKeyUtils.h"
 #include "mozilla/Endian.h"
@@ -57,17 +58,19 @@ ClearKeyUtils::DecryptAES(const vector<u
 
   for (size_t i = 0; i < aData.size(); i += CLEARKEY_KEY_LEN) {
     size_t encLen;
     oaes_encrypt(aes, &aIV[0], CLEARKEY_KEY_LEN, nullptr, &encLen);
 
     vector<uint8_t> enc(encLen);
     oaes_encrypt(aes, &aIV[0], CLEARKEY_KEY_LEN, &enc[0], &encLen);
 
-    for (size_t j = 0; j < CLEARKEY_KEY_LEN; j++) {
+    assert(encLen >= 2 * OAES_BLOCK_SIZE + CLEARKEY_KEY_LEN);
+    size_t blockLen = std::min(aData.size() - i, CLEARKEY_KEY_LEN);
+    for (size_t j = 0; j < blockLen; j++) {
       aData[i + j] ^= enc[2 * OAES_BLOCK_SIZE + j];
     }
     IncrementIV(aIV);
   }
 
   oaes_free(&aes);
 }
 
--- a/media/gmp-clearkey/0.1/ClearKeyUtils.h
+++ b/media/gmp-clearkey/0.1/ClearKeyUtils.h
@@ -4,17 +4,17 @@
 
 #ifndef __ClearKeyUtils_h__
 #define __ClearKeyUtils_h__
 
 #include <stdint.h>
 #include <string>
 #include <vector>
 
-#define CLEARKEY_KEY_LEN 16
+#define CLEARKEY_KEY_LEN ((size_t)16)
 
 #if 0
 void CK_Log(const char* aFmt, ...);
 #define CK_LOGE(...) CK_Log(__VA_ARGS__)
 #define CK_LOGD(...) CK_Log(__VA_ARGS__)
 #define CK_LOGW(...) CK_Log(__VA_ARGS__)
 #else
 #define CK_LOGE(...)
--- a/media/gmp-clearkey/0.1/Makefile.in
+++ b/media/gmp-clearkey/0.1/Makefile.in
@@ -5,9 +5,11 @@
 INSTALL_TARGETS += CLEARKEY_CDM
 
 CLEARKEY_CDM_DEST = $(DEPTH)/dist/bin/gmp-clearkey/0.1
 CLEARKEY_CDM_FILES = \
   $(SHARED_LIBRARY) \
   clearkey.info \
   $(NULL)
 
+MOZ_GLUE_LDFLAGS =
+
 include $(topsrcdir)/config/rules.mk
--- a/media/gmp-clearkey/0.1/moz.build
+++ b/media/gmp-clearkey/0.1/moz.build
@@ -15,9 +15,11 @@ UNIFIED_SOURCES += [
     'openaes/rand.c',
 ]
 
 LOCAL_INCLUDES += [
     '/content/media/gmp',
 ]
 
 USE_STATIC_LIBS = True
-USE_LIBS += [ 'mozalloc' ]
+
+DISABLE_STL_WRAPPING = True
+DEFINES['MOZ_NO_MOZALLOC'] = True
--- a/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/frameworks/av/media/libstagefright/MPEG4Extractor.cpp
@@ -150,16 +150,26 @@ private:
         uint32_t ctsOffset;
         uint8_t iv[16];
         Vector<uint16_t> clearsizes;
         Vector<uint32_t> encryptedsizes;
     };
     Vector<Sample> mCurrentSamples;
     MPEG4Extractor::TrackExtends mTrackExtends;
 
+    // XXX hack -- demuxer expects a track's trun to be seen before saio or
+    // saiz. Here we store saiz/saio box offsets for parsing *after* the trun
+    // has been parsed.
+    struct AuxRange {
+        off64_t mStart;
+        off64_t mSize;
+    };
+    Vector<AuxRange> mDeferredSaiz;
+    Vector<AuxRange> mDeferredSaio;
+
     MPEG4Source(const MPEG4Source &);
     MPEG4Source &operator=(const MPEG4Source &);
 };
 
 // This custom data source wraps an existing one and satisfies requests
 // falling entirely within a cached range from the cache while forwarding
 // all remaining requests to the wrapped datasource.
 // This is used to cache the full sampletable metadata for a single track,
@@ -2601,26 +2611,30 @@ status_t MPEG4Source::parseChunk(off64_t
             }
 
             *offset += chunk_size;
             break;
         }
 
         case FOURCC('s', 'a', 'i', 'z'): {
             status_t err;
-            if ((err = parseSampleAuxiliaryInformationSizes(data_offset, chunk_data_size)) != OK) {
-                return err;
+            if (mLastParsedTrackId == mTrackId) {
+                if ((err = parseSampleAuxiliaryInformationSizes(data_offset, chunk_data_size)) != OK) {
+                    return err;
+                }
             }
             *offset += chunk_size;
             break;
         }
         case FOURCC('s', 'a', 'i', 'o'): {
             status_t err;
-            if ((err = parseSampleAuxiliaryInformationOffsets(data_offset, chunk_data_size)) != OK) {
-                return err;
+            if (mLastParsedTrackId == mTrackId) {
+                if ((err = parseSampleAuxiliaryInformationOffsets(data_offset, chunk_data_size)) != OK) {
+                    return err;
+                }
             }
             *offset += chunk_size;
             break;
         }
 
         case FOURCC('m', 'd', 'a', 't'): {
             // parse DRM info if present
             ALOGV("MPEG4Source::parseChunk mdat");
@@ -2635,16 +2649,28 @@ status_t MPEG4Source::parseChunk(off64_t
         }
     }
     return OK;
 }
 
 status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size) {
     ALOGV("parseSampleAuxiliaryInformationSizes");
     // 14496-12 8.7.12
+
+    if (mCurrentSamples.isEmpty()) {
+        // XXX hack -- we haven't seen trun yet; defer parsing this box until
+        // after trun.
+        ALOGW("deferring processing of saiz box");
+        AuxRange range;
+        range.mStart = offset;
+        range.mSize = size;
+        mDeferredSaiz.add(range);
+        return OK;
+    }
+
     uint8_t version;
     if (mDataSource->readAt(
             offset, &version, sizeof(version))
             < (ssize_t)sizeof(version)) {
         return ERROR_IO;
     }
 
     if (version != 0) {
@@ -2697,28 +2723,45 @@ status_t MPEG4Source::parseSampleAuxilia
 
     mDataSource->readAt(offset, mCurrentSampleInfoSizes, smplcnt);
     return OK;
 }
 
 status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size) {
     ALOGV("parseSampleAuxiliaryInformationOffsets");
     // 14496-12 8.7.13
+
+    if (mCurrentSamples.isEmpty()) {
+        // XXX hack -- we haven't seen trun yet; defer parsing this box until
+        // after trun.
+        ALOGW("deferring processing of saio box");
+        AuxRange range;
+        range.mStart = offset;
+        range.mSize = size;
+        mDeferredSaio.add(range);
+        return OK;
+    }
+
     uint8_t version;
     if (mDataSource->readAt(offset, &version, sizeof(version)) != 1) {
         return ERROR_IO;
     }
     offset++;
 
     uint32_t flags;
     if (!mDataSource->getUInt24(offset, &flags)) {
         return ERROR_IO;
     }
     offset += 3;
 
+    if (flags & 1) {
+      // Skip uint32s aux_info_type and aux_info_type_parameter
+      offset += 8;
+    }
+
     uint32_t entrycount;
     if (!mDataSource->getUInt32(offset, &entrycount)) {
         return ERROR_IO;
     }
     offset += 4;
 
     if (entrycount > mCurrentSampleInfoOffsetsAllocSize) {
         mCurrentSampleInfoOffsets = (uint64_t*) realloc(mCurrentSampleInfoOffsets, entrycount * 8);
@@ -3091,16 +3134,23 @@ status_t MPEG4Source::parseTrackFragment
         tmp.ctsOffset = sampleCtsOffset;
         mCurrentSamples.add(tmp);
 
         dataOffset += sampleSize;
     }
 
     mTrackFragmentHeaderInfo.mDataOffset = dataOffset;
 
+    for (size_t i = 0; i < mDeferredSaio.size() && i < mDeferredSaiz.size(); i++) {
+        const auto& saio = mDeferredSaio[i];
+        const auto& saiz = mDeferredSaiz[i];
+        parseSampleAuxiliaryInformationSizes(saiz.mStart, saiz.mSize);
+        parseSampleAuxiliaryInformationOffsets(saio.mStart, saio.mSize);
+    }
+
     return OK;
 }
 
 sp<MetaData> MPEG4Source::getFormat() {
     Mutex::Autolock autoLock(mLock);
 
     return mFormat;
 }
@@ -3533,16 +3583,18 @@ status_t MPEG4Source::fragmentedRead(
                     }
                     break;
                 }
                 totalTime += se->mDurationUs;
                 totalOffset += se->mSize;
             }
             mCurrentMoofOffset = totalOffset;
             mCurrentSamples.clear();
+            mDeferredSaio.clear();
+            mDeferredSaiz.clear();
             mCurrentSampleIndex = 0;
             mTrackFragmentData.mPresent = false;
             parseChunk(&totalOffset);
             mCurrentTime = totalTime * mTimescale / 1000000ll;
             if (mTrackFragmentData.mPresent) {
                 mCurrentTime += mTrackFragmentData.mBaseMediaDecodeTime;
             }
         }
@@ -3564,16 +3616,18 @@ status_t MPEG4Source::fragmentedRead(
     bool newBuffer = false;
     if (mBuffer == NULL) {
         newBuffer = true;
 
         if (mCurrentSampleIndex >= mCurrentSamples.size()) {
             // move to next fragment
             off64_t nextMoof = mNextMoofOffset; // lastSample.offset + lastSample.size;
             mCurrentSamples.clear();
+            mDeferredSaio.clear();
+            mDeferredSaiz.clear();
             mCurrentSampleIndex = 0;
             mTrackFragmentData.mPresent = false;
             uint32_t hdr[2];
             do {
                 if (mDataSource->readAt(nextMoof, hdr, 8) < 8) {
                     return ERROR_END_OF_STREAM;
                 }
                 uint64_t chunk_size = ntohl(hdr[0]);
--- a/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
+++ b/media/webrtc/signaling/src/media/VcmSIPCCBinding.cpp
@@ -198,26 +198,24 @@ int VcmSIPCCBinding::getVideoCodecsGmp()
   // XXX I'd prefer if this was all known ahead of time...
 
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_LITERAL_CSTRING("h264"));
 
   // H.264 only for now
   bool has_gmp;
   nsresult rv;
-  rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
-                                           NS_LITERAL_CSTRING("encode-video"),
+  rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING("encode-video"),
                                            &tags,
                                            &has_gmp);
   if (NS_FAILED(rv) || !has_gmp) {
     return 0;
   }
 
-  rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING(""),
-                                           NS_LITERAL_CSTRING("decode-video"),
+  rv = gSelf->mGMPService->HasPluginForAPI(NS_LITERAL_CSTRING("decode-video"),
                                            &tags,
                                            &has_gmp);
   if (NS_FAILED(rv) || !has_gmp) {
     return 0;
   }
 
   return VCM_CODEC_RESOURCE_H264;
 }
--- a/memory/build/mozmemory_wrap.h
+++ b/memory/build/mozmemory_wrap.h
@@ -54,39 +54,36 @@
  * - On MacOSX, the system libc has a zone allocator, which allows us to
  *   hook custom malloc implementation functions without exporting them.
  *   The malloc implementation functions are all prefixed with "je_" and used
  *   this way from the custom zone allocator. They are not exported.
  *   Duplication functions are not included, since they will call the custom
  *   zone allocator anyways. Jemalloc-specific functions are also left
  *   unprefixed.
  *
- * - On Android, both malloc implementation and duplication functions are
- *   prefixed with "__wrap_". Additionally, C++ allocation functions
- *   (operator new/delete) are also exported and prefixed with "__wrap_".
- *   Jemalloc specific functions are left unprefixed.
- *
- * - On Gonk, all functions are left unprefixed. Additionally, C++ allocation
- *   functions (operator new/delete) are also exported and unprefixed.
+ * - On Android and Gonk, all functions are left unprefixed. Additionally,
+ *   C++ allocation functions (operator new/delete) are also exported and
+ *   unprefixed.
  *
  * - On other systems (mostly Linux), all functions are left unprefixed.
  *
  * Only Android and Gonk add C++ allocation functions.
  *
  * Proper exporting of the various functions is done with the MOZ_MEMORY_API
  * and MOZ_JEMALLOC_API macros. MOZ_MEMORY_API is meant to be used for malloc
  * implementation and duplication functions, while MOZ_JEMALLOC_API is
  * dedicated to jemalloc specific functions.
  *
  *
  * All these functions are meant to be called with no prefix from Gecko code.
  * In most cases, this is because that's how they are available at runtime.
- * However, on Android, "__wrap_" prefixing is left to the build-time linker
- * (with -Wl,--wrap), or to the mozmemory.h header for malloc_good_size and
- * jemalloc specific functions.
+ * However, on Android, this relies on faulty.lib (the custom dynamic linker)
+ * resolving mozglue symbols before libc symbols, which is guaranteed by the
+ * way faulty.lib works (it respects the DT_NEEDED order, and libc always
+ * appears after mozglue ; which we double check when building anyways)
  *
  *
  * Within libmozglue (when MOZ_MEMORY_IMPL is defined), all the functions
  * should be suffixed with "_impl" both for declarations and use.
  * That is, the implementation declaration for e.g. strdup would look like:
  *   char* strdup_impl(const char *)
  * That implementation would call malloc by using "malloc_impl".
  *
@@ -152,23 +149,16 @@
 #        endif
 #      endif
 #    endif
 #    ifdef XP_WIN
 #      define mozmem_dup_impl(a)      wrap_ ## a
 #    endif
 #  endif
 
-#  if defined(MOZ_WIDGET_ANDROID)
-#    ifndef mozmem_malloc_impl
-#      define mozmem_malloc_impl(a)   __wrap_ ## a
-#    endif
-#    define mozmem_dup_impl(a)      __wrap_ ## a
-#  endif
-
 /* All other jemalloc3 functions are prefixed with "je_", except when
  * building against an unprefixed system jemalloc library */
 #  define je_(a) je_ ## a
 #else /* defined(MOZ_NATIVE_JEMALLOC) */
 #  define je_(a) a
 #endif
 
 #if !defined(MOZ_MEMORY_IMPL) || defined(MOZ_NATIVE_JEMALLOC)
--- a/memory/mozalloc/VolatileBufferAshmem.cpp
+++ b/memory/mozalloc/VolatileBufferAshmem.cpp
@@ -10,22 +10,18 @@
 #include <fcntl.h>
 #include <linux/ashmem.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #ifdef MOZ_MEMORY
-#ifdef MOZ_WIDGET_ANDROID
-extern "C" int __wrap_posix_memalign(void** memptr, size_t alignment, size_t size);
-#else
 extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size);
 #endif
-#endif
 
 #define MIN_VOLATILE_ALLOC_SIZE 8192
 
 namespace mozilla {
 
 VolatileBuffer::VolatileBuffer()
   : mBuf(nullptr)
   , mSize(0)
@@ -63,21 +59,17 @@ VolatileBuffer::Init(size_t aSize, size_
 heap_alloc:
   mBuf = nullptr;
   if (mFd >= 0) {
     close(mFd);
     mFd = -1;
   }
 
 #ifdef MOZ_MEMORY
-#ifdef MOZ_WIDGET_ANDROID
-  __wrap_posix_memalign(&mBuf, aAlignment, aSize);
-#else
   posix_memalign(&mBuf, aAlignment, aSize);
-#endif
 #else
   mBuf = memalign(aAlignment, aSize);
 #endif
   return !!mBuf;
 }
 
 VolatileBuffer::~VolatileBuffer()
 {
deleted file mode 100644
--- a/memory/replace/defs.mk
+++ /dev/null
@@ -1,2 +0,0 @@
-MOZ_GLUE_LDFLAGS = # Don't link against mozglue
-WRAP_LDFLAGS = # Never wrap malloc function calls with -Wl,--wrap
new file mode 100644
--- /dev/null
+++ b/memory/replace/dummy/Makefile.in
@@ -0,0 +1,6 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+MOZ_GLUE_LDFLAGS = # Don't link against mozglue
+WRAP_LDFLAGS = # Never wrap malloc function calls with -Wl,--wrap
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -99,17 +99,16 @@
 @BINPATH@/@MOZ_APP_NAME@-bin
 @BINPATH@/@MOZ_APP_NAME@
 #endif
 @BINPATH@/application.ini
 @BINPATH@/platform.ini
 @BINPATH@/blocklist.xml
 #ifdef XP_UNIX
 @BINPATH@/run-mozilla.sh
-@BINPATH@/mozilla-xremote-client
 #endif
 
 ; [Components]
 @BINPATH@/components/components.manifest
 @BINPATH@/components/alerts.xpt
 #ifdef ACCESSIBILITY
 @BINPATH@/components/accessibility.xpt
 #endif
--- a/mozglue/build/BionicGlue.cpp
+++ b/mozglue/build/BionicGlue.cpp
@@ -61,51 +61,49 @@ private:
   bool bufUsed;
 };
 
 static std::vector<AtForkFuncs, SpecialAllocator<AtForkFuncs> > atfork;
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "cpuacct.h"
-#define WRAP(x) x
 
 #if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
 extern "C" NS_EXPORT int
 timer_create(clockid_t, struct sigevent*, timer_t*)
 {
   __android_log_print(ANDROID_LOG_ERROR, "BionicGlue", "timer_create not supported!");
   abort();
   return -1;
 }
 #endif
 
 #else
 #define cpuacct_add(x)
-#define WRAP(x) __wrap_##x
 #endif
 
 #if ANDROID_VERSION < 17 || defined(MOZ_WIDGET_ANDROID)
 extern "C" NS_EXPORT int
-WRAP(pthread_atfork)(void (*prepare)(void), void (*parent)(void), void (*child)(void))
+pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
 {
   AtForkFuncs funcs;
   funcs.prepare = prepare;
   funcs.parent = parent;
   funcs.child = child;
   if (!atfork.capacity())
     atfork.reserve(1);
   atfork.push_back(funcs);
   return 0;
 }
 
 extern "C" NS_EXPORT pid_t __fork(void);
 
 extern "C" NS_EXPORT pid_t
-WRAP(fork)(void)
+fork(void)
 {
   pid_t pid;
   for (auto it = atfork.rbegin();
        it < atfork.rend(); ++it)
     if (it->prepare)
       it->prepare();
 
   switch ((pid = syscall(__NR_clone, SIGCHLD, NULL, NULL, NULL, NULL))) {
@@ -122,17 +120,17 @@ WRAP(fork)(void)
       if (it->parent)
         it->parent();
   }
   return pid;
 }
 #endif
 
 extern "C" NS_EXPORT int
-WRAP(raise)(int sig)
+raise(int sig)
 {
   // Bug 741272: Bionic incorrectly uses kill(), which signals the
   // process, and thus could signal another thread (and let this one
   // return "successfully" from raising a fatal signal).
   //
   // Bug 943170: POSIX specifies pthread_kill(pthread_self(), sig) as
   // equivalent to raise(sig), but Bionic also has a bug with these
   // functions, where a forked child will kill its parent instead.
@@ -257,8 +255,25 @@ extern "C" NS_EXPORT size_t __wrap_strlc
 extern "C" NS_EXPORT size_t __wrap_strlcpy(char * a0, const char * a1, size_t a2) { return __real_strlcpy(a0, a1, a2); }
 extern "C" NS_EXPORT size_t __wrap_strcspn(const char * a0, const char * a1) { return __real_strcspn(a0, a1); }
 extern "C" NS_EXPORT char* __wrap_strpbrk(const char * a0, const char * a1) { return __real_strpbrk(a0, a1); }
 extern "C" NS_EXPORT char* __wrap_strsep(char ** a0, const char * a1) { return __real_strsep(a0, a1); }
 extern "C" NS_EXPORT size_t __wrap_strspn(const char * a0, const char * a1) { return __real_strspn(a0, a1); }
 extern "C" NS_EXPORT int __wrap_strcoll(const char * a0, const char * a1) { return __real_strcoll(a0, a1); }
 extern "C" NS_EXPORT size_t __wrap_strxfrm(char * a0, const char * a1, size_t a2) { return __real_strxfrm(a0, a1, a2); }
 #endif
+
+/* Flash plugin uses symbols that are not present in Android >= 4.4 */
+#ifndef MOZ_WIDGET_GONK
+namespace android {
+  namespace VectorImpl {
+    NS_EXPORT void reservedVectorImpl1(void) { }
+    NS_EXPORT void reservedVectorImpl2(void) { }
+    NS_EXPORT void reservedVectorImpl3(void) { }
+    NS_EXPORT void reservedVectorImpl4(void) { }
+    NS_EXPORT void reservedVectorImpl5(void) { }
+    NS_EXPORT void reservedVectorImpl6(void) { }
+    NS_EXPORT void reservedVectorImpl7(void) { }
+    NS_EXPORT void reservedVectorImpl8(void) { }
+  }
+}
+#endif
+
--- a/mozglue/build/Makefile.in
+++ b/mozglue/build/Makefile.in
@@ -44,21 +44,16 @@ OS_LDFLAGS += \
 ifneq ($(MOZ_REPLACE_MALLOC_LINKAGE),compiler support)
 OS_LDFLAGS += -flat_namespace
 endif
 ifeq ($(MOZ_REPLACE_MALLOC_LINKAGE),dummy library)
 OS_LDFLAGS += -Wl,-weak_library,$(DEPTH)/memory/replace/dummy/$(DLL_PREFIX)replace_malloc$(DLL_SUFFIX)
 endif
 endif
 
-ifeq (android, $(MOZ_WIDGET_TOOLKIT))
-# To properly wrap jemalloc's pthread_atfork call.
-OS_LDFLAGS += -Wl,--wrap=pthread_atfork
-endif
-
 ifdef MOZ_LINKER
 ifeq (arm, $(TARGET_CPU))
 OS_LDFLAGS += -Wl,-version-script,$(srcdir)/arm-eabi-filter
 endif
 
 endif
 
 ifeq (Android, $(OS_TARGET))
--- a/mozglue/linker/CustomElf.cpp
+++ b/mozglue/linker/CustomElf.cpp
@@ -69,21 +69,16 @@ void debug_phdr(const char *type, const 
 
 static int p_flags_to_mprot(Word flags)
 {
   return ((flags & PF_X) ? PROT_EXEC : 0) |
          ((flags & PF_W) ? PROT_WRITE : 0) |
          ((flags & PF_R) ? PROT_READ : 0);
 }
 
-void
-__void_stub(void)
-{
-}
-
 } /* anonymous namespace */
 
 /**
  * RAII wrapper for a mapping of the first page off a Mappable object.
  * This calls Mappable::munmap instead of system munmap.
  */
 class Mappable1stPagePtr: public GenericMappedPtr<Mappable1stPagePtr> {
 public:
@@ -325,26 +320,16 @@ CustomElf::GetSymbolPtrInDeps(const char
 #endif
   } else if (symbol[0] == 's' && symbol[1] == 'i') {
     if (strcmp(symbol + 2, "gnal") == 0)
       return FunctionPtr(signal);
     if (strcmp(symbol + 2, "gaction") == 0)
       return FunctionPtr(sigaction);
   }
 
-#define MISSING_FLASH_SYMNAME_START "_ZN7android10VectorImpl19reservedVectorImpl"
-
-  // Android changed some symbols that Flash depended on in 4.4,
-  // so stub those out here
-  if (strncmp(symbol,
-              MISSING_FLASH_SYMNAME_START,
-              sizeof(MISSING_FLASH_SYMNAME_START) - 1) == 0) {
-    return FunctionPtr(__void_stub);
-  }
-
   void *sym;
 
   unsigned long hash = Hash(symbol);
 
   /* self_elf should never be NULL, but better safe than sorry. */
   if (ElfLoader::Singleton.self_elf) {
     /* We consider the library containing this code a permanent LD_PRELOAD,
      * so, check if the symbol exists here first. */
--- a/netwerk/base/src/ArrayBufferInputStream.cpp
+++ b/netwerk/base/src/ArrayBufferInputStream.cpp
@@ -49,18 +49,22 @@ ArrayBufferInputStream::Close()
 }
 
 NS_IMETHODIMP
 ArrayBufferInputStream::Available(uint64_t* aCount)
 {
   if (mClosed) {
     return NS_BASE_STREAM_CLOSED;
   }
-  uint32_t buflen = JS_GetArrayBufferByteLength(mArrayBuffer->get());
-  *aCount = buflen ? buflen - mPos : 0;
+  if (mArrayBuffer) {
+    uint32_t buflen = JS_GetArrayBufferByteLength(mArrayBuffer->get());
+    *aCount = buflen ? buflen - mPos : 0;
+  } else {
+    *aCount = 0;
+  }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 ArrayBufferInputStream::Read(char* aBuf, uint32_t aCount, uint32_t *aReadCount)
 {
   return ReadSegments(NS_CopySegmentToBuffer, aBuf, aCount, aReadCount);
 }
--- a/netwerk/test/mochitests/mochitest.ini
+++ b/netwerk/test/mochitests/mochitest.ini
@@ -1,14 +1,15 @@
 [DEFAULT]
 skip-if = buildapp == 'b2g' || e10s
 support-files =
   method.sjs
   partial_content.sjs
   user_agent.sjs
   user_agent_update.sjs
 
+[test_arraybufferinputstream.html]
 [test_partially_cached_content.html]
 [test_uri_scheme.html]
 [test_user_agent_overrides.html]
 [test_user_agent_updates.html]
 [test_user_agent_updates_reset.html]
-[test_xhr_method_case.html]
\ No newline at end of file
+[test_xhr_method_case.html]
new file mode 100644
--- /dev/null
+++ b/netwerk/test/mochitests/test_arraybufferinputstream.html
@@ -0,0 +1,63 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+-->
+<head>
+  <title>ArrayBuffer stream test</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+
+<script type="text/javascript">
+function neuter(ab)
+{
+  var w = new Worker("data:application/javascript,");
+  w.postMessage(ab, [ab]);
+}
+
+function test()
+{
+  var ab = new ArrayBuffer(4000);
+  var ta = new Uint8Array(ab);
+  ta[0] = 'a'.charCodeAt(0);
+
+  const Cc = SpecialPowers.Cc, Ci = SpecialPowers.Ci, Cr = SpecialPowers.Cr;
+  var abis = Cc["@mozilla.org/io/arraybuffer-input-stream;1"]
+               .createInstance(Ci.nsIArrayBufferInputStream);
+
+  var sis = Cc["@mozilla.org/scriptableinputstream;1"]
+              .createInstance(Ci.nsIScriptableInputStream);
+  sis.init(abis);
+
+  is(sis.read(1), "", "should read no data from an uninitialized ABIS");
+
+  abis.setData(ab, 0, 256 * 1024);
+
+  is(sis.read(1), "a", "should read 'a' after init");
+
+  neuter(ab);
+
+  SpecialPowers.forceGC();
+  SpecialPowers.forceGC();
+
+  try
+  {
+    sis.read(1);
+    ok(false, "reading from stream shouldn't have worked");
+  }
+  catch (e)
+  {
+    ok(e.result === Cr.NS_BASE_STREAM_CLOSED,
+       "neutering underneath an input stream should close it");
+  }
+}
+
+test();
+</script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+</pre>
+</body>
+</html>
--- a/other-licenses/android/getaddrinfo.c
+++ b/other-licenses/android/getaddrinfo.c
@@ -402,21 +402,21 @@ do { 								\
 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || 	\
 	    (y) == PF_UNSPEC)))
 #define MATCH(x, y, w) 							\
 	((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
 
 #pragma GCC visibility push(default)
 
 extern const char *
-__wrap_gai_strerror(int ecode);
+gai_strerror(int ecode);
 extern void
-__wrap_freeaddrinfo(struct addrinfo *ai);
+freeaddrinfo(struct addrinfo *ai);
 extern int
-__wrap_getaddrinfo(const char *hostname, const char *servname,
+getaddrinfo(const char *hostname, const char *servname,
     const struct addrinfo *hints, struct addrinfo **res);
 
 int android_sdk_version;
 
 #pragma GCC visibility pop
 
 int android_sdk_version = -1;
 
@@ -426,27 +426,27 @@ static int honeycomb_or_later()
 	__android_log_print(ANDROID_LOG_INFO, "getaddrinfo",
 		"I am%s Honeycomb\n",
 		(android_sdk_version >= 11) ? "" : " not");
 #endif
 	return android_sdk_version >= 11;
 }
 
 const char *
-__wrap_gai_strerror(int ecode)
+gai_strerror(int ecode)
 {
 	if (honeycomb_or_later())
 		return gai_strerror(ecode);
 	if (ecode < 0 || ecode > EAI_MAX)
 		ecode = EAI_MAX;
 	return ai_errlist[ecode];
 }
 
 void
-__wrap_freeaddrinfo(struct addrinfo *ai)
+freeaddrinfo(struct addrinfo *ai)
 {
 	struct addrinfo *next;
 
 	if (honeycomb_or_later()) {
 		freeaddrinfo(ai);
 		return;
 	}
 
@@ -528,17 +528,17 @@ static int
 		.sin_family = AF_INET,
 		.sin_addr.s_addr = __constant_htonl(0x08080808L)  // 8.8.8.8
 	};
         sockaddr_union addr = { .in = sin_test };
         return _test_connect(PF_INET, &addr.generic, sizeof(addr.in));
 }
 
 int
-__wrap_getaddrinfo(const char *hostname, const char *servname,
+getaddrinfo(const char *hostname, const char *servname,
     const struct addrinfo *hints, struct addrinfo **res)
 {
 	struct addrinfo sentinel;
 	struct addrinfo *cur;
 	int error = 0;
 	struct addrinfo ai;
 	struct addrinfo ai0;
 	struct addrinfo *pai;
@@ -726,17 +726,17 @@ int
 			*res = sentinel.ai_next;
 			return SUCCESS;
 		} else
 			error = EAI_FAIL;
 	}
  free:
  bad:
 	if (sentinel.ai_next)
-		__wrap_freeaddrinfo(sentinel.ai_next);
+		freeaddrinfo(sentinel.ai_next);
 	*res = NULL;
 	return error;
 }
 
 /*
  * FQDN hostname, DNS lookup
  */
 static int
@@ -787,17 +787,17 @@ explore_fqdn(const struct addrinfo *pai,
 	}
 
 	*res = result;
 
 	return 0;
 
 free:
 	if (result)
-		__wrap_freeaddrinfo(result);
+		freeaddrinfo(result);
 	return error;
 }
 
 /*
  * hostname == NULL.
  * passive socket -> anyaddr (0.0.0.0 or ::)
  * non-passive socket -> localhost (127.0.0.1 or ::1)
  */
@@ -855,17 +855,17 @@ explore_null(const struct addrinfo *pai,
 	}
 	cur = cur->ai_next;
 
 	*res = sentinel.ai_next;
 	return 0;
 
 free:
 	if (sentinel.ai_next)
-		__wrap_freeaddrinfo(sentinel.ai_next);
+		freeaddrinfo(sentinel.ai_next);
 	return error;
 }
 
 /*
  * numeric hostname
  */
 static int
 explore_numeric(const struct addrinfo *pai, const char *hostname,
@@ -942,17 +942,17 @@ explore_numeric(const struct addrinfo *p
 	}
 
 	*res = sentinel.ai_next;
 	return 0;
 
 free:
 bad:
 	if (sentinel.ai_next)
-		__wrap_freeaddrinfo(sentinel.ai_next);
+		freeaddrinfo(sentinel.ai_next);
 	return error;
 }
 
 /*
  * numeric hostname with scope
  */
 static int
 explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
@@ -2000,26 +2000,26 @@ static struct addrinfo *
 		if (strcasecmp(name, tname) == 0)
 			goto found;
 	}
 	goto again;
 
 found:
 	hints = *pai;
 	hints.ai_flags = AI_NUMERICHOST;
-	error = __wrap_getaddrinfo(addr, NULL, &hints, &res0);
+	error = getaddrinfo(addr, NULL, &hints, &res0);
 	if (error)
 		goto again;
 	for (res = res0; res; res = res->ai_next) {
 		/* cover it up */
 		res->ai_flags = pai->ai_flags;
 
 		if (pai->ai_flags & AI_CANONNAME) {
 			if (get_canonname(pai, res, cname) != 0) {
-				__wrap_freeaddrinfo(res0);
+				freeaddrinfo(res0);
 				goto again;
 			}
 		}
 	}
 	return res0;
 }
 
 /*ARGSUSED*/
--- a/python/mozbuild/mozbuild/mach_commands.py
+++ b/python/mozbuild/mozbuild/mach_commands.py
@@ -659,16 +659,20 @@ class GTestCommands(MachCommandBase):
         if not os.path.isdir(cwd):
             os.makedirs(cwd)
 
         # Use GTest environment variable to control test execution
         # For details see:
         # https://code.google.com/p/googletest/wiki/AdvancedGuide#Running_Test_Programs:_Advanced_Options
         gtest_env = {b'GTEST_FILTER': gtest_filter}
 
+        xre_path = os.path.join(self.topobjdir, "dist", "bin")
+        gtest_env["MOZ_XRE_DIR"] = xre_path
+        gtest_env["MOZ_GMP_PATH"] = os.path.join(xre_path, "gmp-fake", "1.0")
+
         gtest_env[b"MOZ_RUN_GTEST"] = b"True"
 
         if shuffle:
             gtest_env[b"GTEST_SHUFFLE"] = b"True"
 
         if tbpl_parser:
             gtest_env[b"MOZ_TBPL_PARSER"] = b"True"
 
--- a/security/manager/ssl/src/ScopedNSSTypes.h
+++ b/security/manager/ssl/src/ScopedNSSTypes.h
@@ -6,17 +6,19 @@
 
 #ifndef mozilla_ScopedNSSTypes_h
 #define mozilla_ScopedNSSTypes_h
 
 #include <limits>
 
 #include "NSSErrorsService.h"
 #include "mozilla/Likely.h"
+#ifndef MOZ_NO_MOZALLOC
 #include "mozilla/mozalloc_oom.h"
+#endif
 #include "mozilla/Scoped.h"
 #include "nsError.h"
 #include "nsDebug.h"
 #include "prio.h"
 #include "cert.h"
 #include "cms.h"
 #include "keyhi.h"
 #include "cryptohi.h"
@@ -252,18 +254,21 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLAT
                                           internal::PORT_FreeArena_false)
 
 // Wrapper around NSS's SECItem_AllocItem that handles OOM the same way as
 // other allocators.
 inline void
 SECITEM_AllocItem(SECItem & item, uint32_t len)
 {
   if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) {
+#ifndef MOZ_NO_MOZALLOC
     mozalloc_handle_oom(len);
-    if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len))) {
+    if (MOZ_UNLIKELY(!SECITEM_AllocItem(nullptr, &item, len)))
+#endif
+    {
       MOZ_CRASH();
     }
   }
 }
 
 class ScopedAutoSECItem MOZ_FINAL : public SECItem
 {
 public:
--- a/security/sandbox/linux/glue/SandboxCrash.cpp
+++ b/security/sandbox/linux/glue/SandboxCrash.cpp
@@ -14,22 +14,22 @@
 
 #include <unistd.h>
 #include <sys/syscall.h>
 
 #include "mozilla/NullPtr.h"
 #include "mozilla/unused.h"
 #include "mozilla/dom/Exceptions.h"
 #include "nsContentUtils.h"
-#include "nsString.h"
-#include "nsThreadUtils.h"
-
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
+#include "nsStackWalk.h"
+#include "nsString.h"
+#include "nsThreadUtils.h"
 
 namespace mozilla {
 
 // Log JS stack info in the same place as the sandbox violation
 // message.  Useful in case the responsible code is JS and all we have
 // are logs and a minidump with the C++ stacks (e.g., on TBPL).
 static void
 SandboxLogJSStack(void)
@@ -69,27 +69,56 @@ SandboxLogJSStack(void)
 
     nsCOMPtr<nsIStackFrame> nextFrame;
     nsresult rv = frame->GetCaller(getter_AddRefs(nextFrame));
     NS_ENSURE_SUCCESS_VOID(rv);
     frame = nextFrame;
   }
 }
 
+static void SandboxPrintStackFrame(uint32_t aFrameNumber, void *aPC, void *aSP,
+                                   void *aClosure)
+{
+  char buf[1024];
+  nsCodeAddressDetails details;
+
+  NS_DescribeCodeAddress(aPC, &details);
+  NS_FormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
+  SANDBOX_LOG_ERROR("frame %s", buf);
+}
+
+static void
+SandboxLogCStack()
+{
+  // Skip 3 frames: one for this module, one for the signal handler in
+  // libmozsandbox, and one for the signal trampoline.
+  //
+  // Warning: this might not print any stack frames.  NS_StackWalk
+  // can't walk past the signal trampoline on ARM (bug 968531), and
+  // x86 frame pointer walking may or may not work (bug 1082276).
+
+  NS_StackWalk(SandboxPrintStackFrame, /* skip */ 3, /* max */ 0,
+               nullptr, 0, nullptr);
+  SANDBOX_LOG_ERROR("end of stack.");
+}
+
 static void
 SandboxCrash(int nr, siginfo_t *info, void *void_context)
 {
   pid_t pid = getpid(), tid = syscall(__NR_gettid);
+  bool dumped = false;
 
 #ifdef MOZ_CRASHREPORTER
-  bool dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
+  dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
+#endif
   if (!dumped) {
-    SANDBOX_LOG_ERROR("Failed to write minidump");
+    SANDBOX_LOG_ERROR("crash reporter is disabled (or failed);"
+                      " trying stack trace:");
+    SandboxLogCStack();
   }
-#endif
 
   // Do this last, in case it crashes or deadlocks.
   SandboxLogJSStack();
 
   // Try to reraise, so the parent sees that this process crashed.
   // (If tgkill is forbidden, then seccomp will raise SIGSYS, which
   // also accomplishes that goal.)
   signal(SIGSYS, SIG_DFL);
--- a/services/sync/tps/extensions/tps/components/tps-cmdline.js
+++ b/services/sync/tps/extensions/tps/components/tps-cmdline.js
@@ -77,17 +77,17 @@ TPSCmdLineHandler.prototype = {
              "  -tpslogfile <file>        Logfile for TPS output.\n" +
              "  --ignore-unused-engines   Don't load engines not used in tests.\n",
 };
 
 
 var TPSCmdLineFactory = {
   createInstance : function(outer, iid) {
     if (outer != null) {
-      throw Components.results.NS_ERROR_NO_AGGREGATION;
+      throw new Error(Components.results.NS_ERROR_NO_AGGREGATION);
     }
 
     return new TPSCmdLineHandler().QueryInterface(iid);
   }
 };
 
 
 var TPSCmdLineModule = {
@@ -122,20 +122,20 @@ var TPSCmdLineModule = {
   },
 
   getClassObject : function(compMgr, cid, iid) {
     if (cid.equals(TPS_CMDLINE_CLSID)) {
       return TPSCmdLineFactory;
     }
 
     if (!iid.equals(Components.interfaces.nsIFactory)) {
-      throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
+      throw new Error(Components.results.NS_ERROR_NOT_IMPLEMENTED);
     }
 
-    throw Components.results.NS_ERROR_NO_INTERFACE;
+    throw new Error(Components.results.NS_ERROR_NO_INTERFACE);
   },
 
   canUnload : function(compMgr) {
     return true;
   }
 };
 
 /**
--- a/services/sync/tps/extensions/tps/resource/logger.jsm
+++ b/services/sync/tps/extensions/tps/resource/logger.jsm
@@ -69,26 +69,26 @@ var Logger = {
     if (bool) {
       return;
     }
 
     if (showPotentialError && this._potentialError) {
       msg += "; " + this._potentialError;
       this._potentialError = null;
     }
-    throw("ASSERTION FAILED! " + msg);
+    throw new Error("ASSERTION FAILED! " + msg);
   },
 
   AssertFalse: function(bool, msg, showPotentialError) {
     return this.AssertTrue(!bool, msg, showPotentialError);
   },
 
   AssertEqual: function(val1, val2, msg) {
     if (val1 != val2)
-      throw("ASSERTION FAILED! " + msg + "; expected " +
+      throw new Error("ASSERTION FAILED! " + msg + "; expected " +
             JSON.stringify(val2) + ", got " + JSON.stringify(val1));
   },
 
   log: function (msg, withoutPrefix) {
     dump(msg + "\n");
     if (withoutPrefix) {
       this.write(msg + "\n");
     }
--- a/services/sync/tps/extensions/tps/resource/modules/addons.jsm
+++ b/services/sync/tps/extensions/tps/resource/modules/addons.jsm
@@ -78,17 +78,17 @@ Addon.prototype = {
                    !addon.userDisabled);
     if (state == STATE_ENABLED) {
       Logger.AssertFalse(addon.userDisabled, "add-on is disabled: " + addon.id);
       return true;
     } else if (state == STATE_DISABLED) {
       Logger.AssertTrue(addon.userDisabled, "add-on is enabled: " + addon.id);
       return true;
     } else if (state) {
-      throw Error("Don't know how to handle state: " + state);
+      throw new Error("Don't know how to handle state: " + state);
     } else {
       // No state, so just checking that it exists.
       return true;
     }
   },
 
   install: function install() {
     // For Install, the id parameter initially passed is really the filename
--- a/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm
+++ b/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm
@@ -771,17 +771,17 @@ Livemark.prototype = {
 
     PlacesUtils.livemarks.addLivemark(livemarkObj).then(
       aLivemark => { spinningCb(null, [Components.results.NS_OK, aLivemark]) },
       () => { spinningCb(null, [Components.results.NS_ERROR_UNEXPECTED, aLivemark]) }
     );
 
     let [status, livemark] = spinningCb.wait();
     if (!Components.isSuccessCode(status)) {
-      throw status;
+      throw new Error(status);
     }
 
     this.props.item_id = livemark.id;
     return this.props.item_id;
   },
 
   /**
    * Find
--- a/services/sync/tps/extensions/tps/resource/quit.js
+++ b/services/sync/tps/extensions/tps/resource/quit.js
@@ -43,21 +43,21 @@ function goQuitApplication() {
     forceQuit  = Components.interfaces.nsIAppStartup.eForceQuit;
   }
   else if (kAppShell in Components.classes) {
     appService = Components.classes[kAppShell].
       getService(Components.interfaces.nsIAppShellService);
     forceQuit = Components.interfaces.nsIAppShellService.eForceQuit;
   }
   else {
-    throw 'goQuitApplication: no AppStartup/appShell';
+    throw new Error('goQuitApplication: no AppStartup/appShell');
   }
 
   try {
     appService.quit(forceQuit);
   }
   catch(ex) {
-    throw('goQuitApplication: ' + ex);
+    throw new Error('goQuitApplication: ' + ex);
   }
 
   return true;
 }
 
--- a/testing/gtest/rungtests.py
+++ b/testing/gtest/rungtests.py
@@ -62,22 +62,31 @@ class GTests(object):
         return result
 
     def build_core_environment(self, env = {}):
         """
         Add environment variables likely to be used across all platforms, including remote systems.
         """
         env["MOZILLA_FIVE_HOME"] = self.xre_path
         env["MOZ_XRE_DIR"] = self.xre_path
+        env["MOZ_GMP_PATH"] = os.path.join(self.xre_path, "gmp-fake", "1.0")
         env["XPCOM_DEBUG_BREAK"] = "stack-and-abort"
         env["MOZ_CRASHREPORTER_NO_REPORT"] = "1"
         env["MOZ_CRASHREPORTER"] = "1"
         env["MOZ_RUN_GTEST"] = "1"
         # Normally we run with GTest default output, override this to use the TBPL test format.
         env["MOZ_TBPL_PARSER"] = "1"
+
+        if not mozinfo.has_sandbox:
+          # Bug 1082193 - This is horrible. Our linux build boxes run CentOS 6,
+          # which is too old to support sandboxing. Disable sandbox for gtests
+          # on machines which don't support sandboxing until they can be
+          # upgraded, or gtests are run on test machines instead.
+          env["MOZ_DISABLE_GMP_SANDBOX"] = "1"
+
         return env
 
     def build_environment(self):
         """
         Create and return a dictionary of all the appropriate env variables and values.
         On a remote system, we overload this to set different values and are missing things like os.environ and PATH.
         """
         if not os.path.isdir(self.xre_path):
--- a/testing/mozbase/mozinfo/mozinfo/mozinfo.py
+++ b/testing/mozbase/mozinfo/mozinfo/mozinfo.py
@@ -3,16 +3,18 @@
 # 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/.
 
 # TODO: it might be a good idea of adding a system name (e.g. 'Ubuntu' for
 # linux) to the information; I certainly wouldn't want anyone parsing this
 # information and having behaviour depend on it
 
+import ctypes
+import errno
 import json
 import os
 import platform
 import re
 import sys
 
 import mozfile
 
@@ -27,17 +29,18 @@ class unknown(object):
         return 'UNKNOWN'
 unknown = unknown() # singleton
 
 # get system information
 info = {'os': unknown,
         'processor': unknown,
         'version': unknown,
         'os_version': unknown,
-        'bits': unknown }
+        'bits': unknown,
+        'has_sandbox': unknown }
 (system, node, release, version, machine, processor) = platform.uname()
 (bits, linkage) = platform.architecture()
 
 # get os information and related data
 if system in ["Microsoft", "Windows"]:
     info['os'] = 'win'
     # There is a Python bug on Windows to determine platform values
     # http://bugs.python.org/issue7860
@@ -88,16 +91,24 @@ elif processor.upper() == "AMD64":
     processor = "x86_64"
 elif processor == "Power Macintosh":
     processor = "ppc"
 bits = re.search('(\d+)bit', bits).group(1)
 info.update({'processor': processor,
              'bits': int(bits),
             })
 
+if info['os'] == 'linux':
+    PR_SET_SECCOMP = 22
+    SECCOMP_MODE_FILTER = 2
+    ctypes.CDLL("libc.so.6", use_errno=True).prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, 0)
+    info['has_sandbox'] = ctypes.get_errno() == errno.EFAULT
+else:
+    info['has_sandbox'] = True
+
 # standard value of choices, for easy inspection
 choices = {'os': ['linux', 'bsd', 'win', 'mac', 'unix'],
            'bits': [32, 64],
            'processor': ['x86', 'x86_64', 'ppc']}
 
 
 def sanitize(info):
     """Do some sanitization of input values, primarily
--- a/toolkit/components/remote/nsXRemoteService.cpp
+++ b/toolkit/components/remote/nsXRemoteService.cpp
@@ -35,17 +35,16 @@
 
 #include <X11/Xlib.h>
 #include <X11/Xatom.h>
 
 using namespace mozilla;
 
 #define MOZILLA_VERSION_PROP   "_MOZILLA_VERSION"
 #define MOZILLA_LOCK_PROP      "_MOZILLA_LOCK"
-#define MOZILLA_COMMAND_PROP   "_MOZILLA_COMMAND"
 #define MOZILLA_RESPONSE_PROP  "_MOZILLA_RESPONSE"
 #define MOZILLA_USER_PROP      "_MOZILLA_USER"
 #define MOZILLA_PROFILE_PROP   "_MOZILLA_PROFILE"
 #define MOZILLA_PROGRAM_PROP   "_MOZILLA_PROGRAM"
 #define MOZILLA_COMMANDLINE_PROP "_MOZILLA_COMMANDLINE"
 
 const unsigned char kRemoteVersion[] = "5.1";
 
@@ -56,28 +55,26 @@ const unsigned char kRemoteVersion[] = "
 #else
 #define TO_LITTLE_ENDIAN32(x) (x)
 #endif
 
 // Minimize the roundtrips to the X server by getting all the atoms at once
 static const char *XAtomNames[] = {
   MOZILLA_VERSION_PROP,
   MOZILLA_LOCK_PROP,
-  MOZILLA_COMMAND_PROP,
   MOZILLA_RESPONSE_PROP,
   MOZILLA_USER_PROP,
   MOZILLA_PROFILE_PROP,
   MOZILLA_PROGRAM_PROP,
   MOZILLA_COMMANDLINE_PROP
 };
 static Atom XAtoms[MOZ_ARRAY_LENGTH(XAtomNames)];
 
 Atom nsXRemoteService::sMozVersionAtom;
 Atom nsXRemoteService::sMozLockAtom;
-Atom nsXRemoteService::sMozCommandAtom;
 Atom nsXRemoteService::sMozResponseAtom;
 Atom nsXRemoteService::sMozUserAtom;
 Atom nsXRemoteService::sMozProfileAtom;
 Atom nsXRemoteService::sMozProgramAtom;
 Atom nsXRemoteService::sMozCommandLineAtom;
 
 nsXRemoteService * nsXRemoteService::sRemoteImplementation = 0;
 
@@ -177,17 +174,17 @@ bool
 nsXRemoteService::HandleNewProperty(XID aWindowId, Display* aDisplay,
                                     Time aEventTime,
                                     Atom aChangedAtom,
                                     nsIWeakReference* aDomWindow)
 {
 
   nsCOMPtr<nsIDOMWindow> window (do_QueryReferent(aDomWindow));
 
-  if (aChangedAtom == sMozCommandAtom || aChangedAtom == sMozCommandLineAtom) {
+  if (aChangedAtom == sMozCommandLineAtom) {
     // We got a new command atom.
     int result;
     Atom actual_type;
     int actual_format;
     unsigned long nitems, bytes_after;
     char *data = 0;
 
     result = XGetWindowProperty (aDisplay,
@@ -209,21 +206,17 @@ nsXRemoteService::HandleNewProperty(XID 
     if (result != Success)
       return false;
 
     // Failed to get the data off the window or it was the wrong type?
     if (!data || !TO_LITTLE_ENDIAN32(*reinterpret_cast<int32_t*>(data)))
       return false;
 
     // cool, we got the property data.
-    const char *response = nullptr;
-    if (aChangedAtom == sMozCommandAtom)
-      response = HandleCommand(data, window, aEventTime);
-    else if (aChangedAtom == sMozCommandLineAtom)
-      response = HandleCommandLine(data, window, aEventTime);
+    const char *response = HandleCommandLine(data, window, aEventTime);
 
     // put the property onto the window as the response
     XChangeProperty (aDisplay, aWindowId,
                      sMozResponseAtom, XA_STRING,
                      8, PropModeReplace,
                      (const unsigned char *)response,
                      strlen (response));
     XFree(data);
@@ -239,71 +232,16 @@ nsXRemoteService::HandleNewProperty(XID 
     // someone locked the window
     return true;
   }
 
   return false;
 }
 
 const char*
-nsXRemoteService::HandleCommand(char* aCommand, nsIDOMWindow* aWindow,
-                                uint32_t aTimestamp)
-{
-  nsresult rv;
-
-  nsCOMPtr<nsICommandLineRunner> cmdline
-    (do_CreateInstance("@mozilla.org/toolkit/command-line;1", &rv));
-  if (NS_FAILED(rv))
-    return "509 internal error";
-
-  // 1) Make sure that it looks remotely valid with parens
-  // 2) Treat ping() immediately and specially
-
-  nsAutoCString command(aCommand);
-  int32_t p1, p2;
-  p1 = command.FindChar('(');
-  p2 = command.FindChar(')');
-
-  if (p1 == kNotFound || p2 == kNotFound || p1 == 0 || p2 < p1) {
-    return "500 command not parseable";
-  }
-
-  command.Truncate(p1);
-  command.Trim(" ", true, true);
-  ToLowerCase(command);
-
-  if (!command.EqualsLiteral("ping")) {
-    nsAutoCString desktopStartupID;
-    nsDependentCString cmd(aCommand);
-    FindExtensionParameterInCommand("DESKTOP_STARTUP_ID",
-                                    cmd, '\n',
-                                    &desktopStartupID);
-
-    const char* argv[3] = {"dummyappname", "-remote", aCommand};
-    rv = cmdline->Init(3, argv, nullptr, nsICommandLine::STATE_REMOTE_EXPLICIT);
-    if (NS_FAILED(rv))
-      return "509 internal error";
-
-    if (aWindow)
-      cmdline->SetWindowContext(aWindow);
-
-    if (sRemoteImplementation)
-      sRemoteImplementation->SetDesktopStartupIDOrTimestamp(desktopStartupID, aTimestamp);
-
-    rv = cmdline->Run();
-    if (NS_ERROR_ABORT == rv)
-      return "500 command not parseable";
-    if (NS_FAILED(rv))
-      return "509 internal error";
-  }
-
-  return "200 executed command";
-}
-
-const char*
 nsXRemoteService::HandleCommandLine(char* aBuffer, nsIDOMWindow* aWindow,
                                     uint32_t aTimestamp)
 {
   nsresult rv;
 
   nsCOMPtr<nsICommandLineRunner> cmdline
     (do_CreateInstance("@mozilla.org/toolkit/command-line;1", &rv));
   if (NS_FAILED(rv))
@@ -373,15 +311,14 @@ nsXRemoteService::EnsureAtoms(void)
     return;
 
   XInternAtoms(mozilla::DefaultXDisplay(), const_cast<char**>(XAtomNames),
                ArrayLength(XAtomNames), False, XAtoms);
 
   int i = 0;
   sMozVersionAtom     = XAtoms[i++];
   sMozLockAtom        = XAtoms[i++];
-  sMozCommandAtom     = XAtoms[i++];
   sMozResponseAtom    = XAtoms[i++];
   sMozUserAtom        = XAtoms[i++];
   sMozProfileAtom     = XAtoms[i++];
   sMozProgramAtom     = XAtoms[i++];
   sMozCommandLineAtom = XAtoms[i++];
 }
--- a/toolkit/components/remote/nsXRemoteService.h
+++ b/toolkit/components/remote/nsXRemoteService.h
@@ -36,31 +36,27 @@ protected:
                                     nsIWeakReference* aDomWindow);
     
     void XRemoteBaseStartup(const char *aAppName, const char *aProfileName);
 
     void HandleCommandsFor(Window aWindowId);
     static nsXRemoteService *sRemoteImplementation;
 private:
     void EnsureAtoms();
-    static const char* HandleCommand(char* aCommand, nsIDOMWindow* aWindow,
-                                     uint32_t aTimestamp);
-
     static const char* HandleCommandLine(char* aBuffer, nsIDOMWindow* aWindow,
                                          uint32_t aTimestamp);
 
     virtual void SetDesktopStartupIDOrTimestamp(const nsACString& aDesktopStartupID,
                                                 uint32_t aTimestamp) = 0;
 
     nsCString mAppName;
     nsCString mProfileName;
 
     static Atom sMozVersionAtom;
     static Atom sMozLockAtom;
-    static Atom sMozCommandAtom;
     static Atom sMozResponseAtom;
     static Atom sMozUserAtom;
     static Atom sMozProfileAtom;
     static Atom sMozProgramAtom;
     static Atom sMozCommandLineAtom;
 };
 
 #endif // NSXREMOTESERVICE_H
--- a/toolkit/xre/nsAppRunner.cpp
+++ b/toolkit/xre/nsAppRunner.cpp
@@ -1583,76 +1583,16 @@ DumpVersion()
     printf("%s ", gAppData->vendor);
   printf("%s %s", gAppData->name, gAppData->version);
   if (gAppData->copyright)
       printf(", %s", gAppData->copyright);
   printf("\n");
 }
 
 #ifdef MOZ_ENABLE_XREMOTE
-// use int here instead of a PR type since it will be returned
-// from main - just to keep types consistent
-static int
-HandleRemoteArgument(const char* remote, const char* aDesktopStartupID)
-{
-  nsresult rv;
-  ArgResult ar;
-
-  const char *profile = 0;
-  nsAutoCString program(gAppData->name);
-  ToLowerCase(program);
-  const char *username = getenv("LOGNAME");
-
-  ar = CheckArg("p", false, &profile);
-  if (ar == ARG_BAD) {
-    PR_fprintf(PR_STDERR, "Error: argument -p requires a profile name\n");
-    return 1;
-  }
-
-  const char *temp = nullptr;
-  ar = CheckArg("a", false, &temp);
-  if (ar == ARG_BAD) {
-    PR_fprintf(PR_STDERR, "Error: argument -a requires an application name\n");
-    return 1;
-  } else if (ar == ARG_FOUND) {
-    program.Assign(temp);
-  }
-
-  ar = CheckArg("u", false, &username);
-  if (ar == ARG_BAD) {
-    PR_fprintf(PR_STDERR, "Error: argument -u requires a username\n");
-    return 1;
-  }
-
-  XRemoteClient client;
-  rv = client.Init();
-  if (NS_FAILED(rv)) {
-    PR_fprintf(PR_STDERR, "Error: Failed to connect to X server.\n");
-    return 1;
-  }
-
-  nsXPIDLCString response;
-  bool success = false;
-  rv = client.SendCommand(program.get(), username, profile, remote,
-                          aDesktopStartupID, getter_Copies(response), &success);
-  // did the command fail?
-  if (NS_FAILED(rv)) {
-    PR_fprintf(PR_STDERR, "Error: Failed to send command: %s\n",
-               response ? response.get() : "No response included");
-    return 1;
-  }
-
-  if (!success) {
-    PR_fprintf(PR_STDERR, "Error: No running window found\n");
-    return 2;
-  }
-
-  return 0;
-}
-
 static RemoteResult
 RemoteCommandLine(const char* aDesktopStartupID)
 {
   nsresult rv;
   ArgResult ar;
 
   nsAutoCString program(gAppData->name);
   ToLowerCase(program);
@@ -3605,31 +3545,21 @@ XREMain::XRE_mainStartup(bool* aExitFlag
     if (mDisableRemote) {
       newInstance = true;
     } else {
       e = PR_GetEnv("MOZ_NEW_INSTANCE");
       newInstance = (e && *e);
     }
   }
 
-  const char* xremotearg;
-  ArgResult ar = CheckArg("remote", true, &xremotearg);
-  if (ar == ARG_BAD) {
-    PR_fprintf(PR_STDERR, "Error: -remote requires an argument\n");
-    return 1;
-  }
-  const char* desktopStartupIDPtr =
-    mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
-  if (ar) {
-    *aExitFlag = true;
-    return HandleRemoteArgument(xremotearg, desktopStartupIDPtr);
-  }
-
   if (!newInstance) {
     // Try to remote the entire command line. If this fails, start up normally.
+    const char* desktopStartupIDPtr =
+      mDesktopStartupID.IsEmpty() ? nullptr : mDesktopStartupID.get();
+
     RemoteResult rr = RemoteCommandLine(desktopStartupIDPtr);
     if (rr == REMOTE_FOUND) {
       *aExitFlag = true;
       return 0;
     }
     else if (rr == REMOTE_ARG_BAD)
       return 1;
   }
deleted file mode 100755
--- a/tools/jprof/split-profile.pl
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/perl
-# 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/.
-
-
-# split-profile.pl Documentation:
-# 
-# This script uses jprof's includes (-i) and excludes (-e) options to
-# split profiles into segments.  It takes as input a single text file,
-# and from that text file creates a series of jprof profiles in the
-# directory in which it is run.  It expects the application binaries
-# with which the profile was made, including jprof, and the jprof
-# profile data, to be in a directory called "bin" that is a subdirectory
-# of the current directory, and it will output the profiles into the
-# current directory.
-#
-# The input file format looks like the following:
-#
-#   poll g_main_poll
-#   GetRuleCascade CSSRuleProcessor::GetRuleCascade(nsPresContext *, nsIAtom *)
-#   RuleProcessorData RuleProcessorData::RuleProcessorData(nsPresContext *, nsIContent *, nsRuleWalker *, nsCompatibility *)
-#
-# From this input file, the script will construct a profile called
-# 00.html that contains the whole profile, a profile called 01-poll.html
-# that includes only stacks with g_main_poll, a profile called
-# 02-GetRuleCascade.html that includes only stacks that have
-# GetRuleCascade and do not have g_main_poll, a profile called
-# 03-RuleProcessorData.html that includes only stacks that have the
-# RuleProcessorData constructor and do not have GetRuleCascade or
-# g_main_poll, and a profile called 04.html that includes only stacks
-# that do not have any of the three functions in them.
-#
-# This means that all of the segments of the profile, except 00.html,
-# are mutually exclusive.  Thus clever ordering of the functions in the
-# input file can lead to a logical splitting of the profile into
-# segments.
-
-
-use strict;
-
-my @names;
-my @sigs;
-
-sub read_info($) {
-    my ($fname) = @_;
-
-    open(INFO, "<$fname");
-    my $i = 0;
-    while (<INFO>) {
-        chop;
-        my $line = $_;
-        my $idx = index($line, " ");
-        my $name = substr($line, 0, $idx);
-        my $sig = substr($line, $idx+1);
-
-        $names[$i] = $name;
-        $sigs[$i] = $sig;
-        ++$i;
-    }
-}
-
-sub run_profile($$) {
-    my ($options, $outfile) = @_;
-
-    print  "./jprof$options mozilla-bin jprof-log > ../$outfile.html\n";
-    system "./jprof$options mozilla-bin jprof-log > ../$outfile.html";
-}
-
-sub run_profiles() {
-    run_profile("", "00");
-
-    for (my $i = 0; $i <= $#names + 1; ++$i) {
-        my $options = "";
-        for (my $j = 0; $j < $i; ++$j) {
-            $options .= " -e\"$sigs[$j]\"";
-        }
-        if ($i <= $#names) {
-            $options .= " -i\"$sigs[$i]\"";
-        }
-        my $num;
-        my $n = $i + 1;
-        if ($n < 10) {
-            $num = "0$n";
-        } else {
-            $num = "$n";
-        }
-        if ($i <= $#names) {
-            run_profile($options, "$num-$names[$i]");
-        } else {
-            run_profile($options, "$num");
-        }
-    }
-}
-
-($#ARGV == 0) || die "Usage: split-profile.pl <info-file>\n";
-
-read_info($ARGV[0]);
-chdir "bin" || die "Can't change directory to bin.";
-run_profiles();
new file mode 100755
--- /dev/null
+++ b/tools/jprof/split-profile.py
@@ -0,0 +1,136 @@
+#!/usr/bin/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/.
+
+# This program splits up a jprof profile into multiple files based on a
+# list of functions in a text file.  First, a complete profile is
+# generated.  Then, for each line in the text file, a profile is
+# generated containing only stacks that go through that line, and also
+# excluding all stacks in earlier lines in the text file.  This means
+# that the text file, from start to end, is splitting out pieces of the
+# profile in their own file.  Finally, a final profile containing the
+# remainder is produced.
+
+# The program takes four arguments:
+#   (1) The path to jprof.
+#   (2) The path to the text file describing the splits.  The output
+#       will be placed in the same directory as this file.
+#   (3) The program that was profiled.
+#   (4) The jprof-log file generated by the profile, to be split up.
+# (Really, all arguments from (3) and later are passed through to
+# jprof, so additional arguments could be provided if you want to pass
+# additional arguments to jprof.)
+
+# In slightly more detail:
+#
+# This script uses jprof's includes (-i) and excludes (-e) options to
+# split profiles into segments.  It takes as input a single text file,
+# and from that text file creates a series of jprof profiles in the
+# directory in which it is run.
+#
+# The input file format looks like the following:
+#
+#   poll g_main_poll
+#   GetRuleCascade CSSRuleProcessor::GetRuleCascade(nsPresContext *, nsIAtom *)
+#   RuleProcessorData RuleProcessorData::RuleProcessorData(nsPresContext *, nsIContent *, nsRuleWalker *, nsCompatibility *)
+#
+# From this input file, the script will construct a profile called
+# jprof-0.html that contains the whole profile, a profile called
+# jprof-1-poll.html that includes only stacks with g_main_poll, a
+# profile called jprof-2-GetRuleCascade.html that includes only stacks
+# that have GetRuleCascade and do not have g_main_poll, a profile called
+# jprof-3-RuleProcessorData.html that includes only stacks that have the
+# RuleProcessorData constructor and do not have GetRuleCascade or
+# g_main_poll, and a profile called jprof-4.html that includes only
+# stacks that do not have any of the three functions in them.
+#
+# This means that all of the segments of the profile, except
+# jprof-0.html, are mutually exclusive.  Thus clever ordering of the
+# functions in the input file can lead to a logical splitting of the
+# profile into segments.
+
+import sys
+import subprocess
+import os.path
+
+if len(sys.argv) < 5:
+    sys.stderr.write("Expected arguments: <jprof> <split-file> <program> <jprof-log>\n")
+    sys.exit(1)
+
+jprof = sys.argv[1]
+splitfile = sys.argv[2]
+passthrough = sys.argv[3:]
+
+for f in [jprof, splitfile]:
+    if not os.path.isfile(f):
+        sys.stderr.write("could not find file: {0}\n".format(f))
+        sys.exit(1)
+
+def read_splits(splitfile):
+    """
+    Read splitfile (each line of which contains a name, a space, and
+    then a function name to split on), and return a list of pairs
+    representing exactly that.  (Note that the name cannot contain
+    spaces, but the function name can, and often does.)
+    """
+    def line_to_split(line):
+        line = line.strip("\r\n")
+        idx = line.index(" ")
+        return (line[0:idx], line[idx+1:])
+
+    io = open(splitfile, "r")
+    result = [line_to_split(line) for line in io]
+    io.close()
+    return result
+
+splits = read_splits(splitfile)
+
+def generate_profile(options, destfile):
+    """
+    Run jprof to generate one split of the profile.
+    """
+    args = [jprof] + options + passthrough
+    print "Generating {0}".format(destfile)
+    destio = open(destfile, "w")
+    process = subprocess.Popen(args, stdout=destio)
+    process.wait()
+    destio.close()
+    if process.returncode != 0:
+        os.remove(destfile)
+        sys.stderr.write("Error {0} from command:\n  {1}\n".format(process.returncode, " ".join(args)))
+        sys.exit(process.returncode)
+
+def output_filename(number, splitname):
+    """
+    Return the filename (absolute path) we should use to output the
+    profile segment with the given number and splitname.  Splitname
+    should be None for the complete profile and the remainder.
+    """
+    def pad_count(i):
+        result = str(i)
+        # 0-pad to the same length
+        result = "0" * (len(str(len(splits) + 1)) - len(result)) + result
+        return result
+
+    name = pad_count(number)
+    if splitname is not None:
+        name += "-" + splitname
+
+    return os.path.join(os.path.dirname(splitfile),
+                        "jprof-{0}.html".format(name))
+
+# generate the complete profile
+generate_profile([], output_filename(0, None))
+
+# generate the listed splits
+count = 1
+excludes = []
+for (splitname, splitfunction) in splits:
+    generate_profile(excludes + ["-i" + splitfunction],
+                     output_filename(count, splitname))
+    excludes += ["-e" + splitfunction]
+    count = count + 1
+
+# generate the remainder after the splits
+generate_profile(excludes, output_filename(count, None))
--- a/widget/cocoa/nsChildView.h
+++ b/widget/cocoa/nsChildView.h
@@ -136,16 +136,25 @@ class APZCTreeManager;
 // Undocumented method of one or more of NSFrameView's subclasses.  Called
 // when one or more of the titlebar buttons needs to be repositioned, to
 // disappear, or to reappear (say if the window's style changes).  If
 // 'redisplay' is true, the entire titlebar (the window's top 22 pixels) is
 // marked as needing redisplay.  This method has been present in the same
 // format since at least OS X 10.5.
 - (void)_tileTitlebarAndRedisplay:(BOOL)redisplay;
 
+// The following undocumented methods are used to work around bug 1069658,
+// which is an Apple bug or design flaw that effects Yosemite.  None of them
+// were present prior to Yosemite (OS X 10.10).
+- (NSView *)titlebarView; // Method of NSThemeFrame
+- (NSView *)titlebarContainerView; // Method of NSThemeFrame
+- (BOOL)transparent; // Method of NSTitlebarView and NSTitlebarContainerView
+- (void)setTransparent:(BOOL)transparent; // Method of NSTitlebarView and
+                                          // NSTitlebarContainerView
+
 @end
 
 #if !defined(MAC_OS_X_VERSION_10_6) || \
 MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
 @interface NSEvent (SnowLeopardEventFeatures)
 + (NSUInteger)pressedMouseButtons;
 + (NSUInteger)modifierFlags;
 @end
--- a/widget/cocoa/nsCocoaWindow.mm
+++ b/widget/cocoa/nsCocoaWindow.mm
@@ -2251,16 +2251,39 @@ nsCocoaWindow::ExecuteNativeKeyBinding(N
 // turn will fire "fullscreen" events.
 - (void)windowDidEnterFullScreen:(NSNotification *)notification
 {
   if (!mGeckoWindow) {
     return;
   }
 
   mGeckoWindow->EnteredFullScreen(true);
+
+  // On Yosemite, the NSThemeFrame class has two new properties --
+  // titlebarView (an NSTitlebarView object) and titlebarContainerView (an
+  // NSTitlebarContainerView object).  These are used to display the titlebar
+  // in fullscreen mode.  In Safari they're not transparent.  But in Firefox
+  // for some reason they are, which causes bug 1069658.  The following code
+  // works around this Apple bug or design flaw.
+  NSWindow *window = (NSWindow *) [notification object];
+  NSView *frameView = [[window contentView] superview];
+  NSView *titlebarView = nil;
+  NSView *titlebarContainerView = nil;
+  if ([frameView respondsToSelector:@selector(titlebarView)]) {
+    titlebarView = [frameView titlebarView];
+  }
+  if ([frameView respondsToSelector:@selector(titlebarContainerView)]) {
+    titlebarContainerView = [frameView titlebarContainerView];
+  }
+  if ([titlebarView respondsToSelector:@selector(setTransparent:)]) {
+    [titlebarView setTransparent:NO];
+  }
+  if ([titlebarContainerView respondsToSelector:@selector(setTransparent:)]) {
+    [titlebarContainerView setTransparent:NO];
+  }
 }
 
 - (void)windowDidExitFullScreen:(NSNotification *)notification
 {
   if (!mGeckoWindow) {
     return;
   }
 
deleted file mode 100644
--- a/widget/xremoteclient/Makefile.in
+++ /dev/null
@@ -1,24 +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/.
-
-# NOTE: This directory is part of tier 50, and is linked directly into
-# the application binaries. The fact that it's under mozilla/widget is a fluke
-# of tree history.
-
-LIBCPPSRCS = XRemoteClient.cpp
-
-OBJS = $(LIBCPPSRCS:.cpp=.$(OBJ_SUFFIX))
-
-PROGCPPSRCS = \
-  mozilla-xremote-client.cpp \
-  XRemoteClient.cpp \
-  $(NULL)
-
-PROGOBJS = $(PROGCPPSRCS:.cpp=.$(OBJ_SUFFIX))
-
-CPPSRCS += \
-  $(filter-out $(LIBCPPSRCS),$(PROGCPPSRCS)) \
-  $(LIBCPPSRCS) \
-  $(NULL)
--- a/widget/xremoteclient/XRemoteClient.cpp
+++ b/widget/xremoteclient/XRemoteClient.cpp
@@ -21,17 +21,16 @@
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <limits.h>
 #include <X11/Xatom.h>
 
 #define MOZILLA_VERSION_PROP   "_MOZILLA_VERSION"
 #define MOZILLA_LOCK_PROP      "_MOZILLA_LOCK"
-#define MOZILLA_COMMAND_PROP   "_MOZILLA_COMMAND"
 #define MOZILLA_COMMANDLINE_PROP "_MOZILLA_COMMANDLINE"
 #define MOZILLA_RESPONSE_PROP  "_MOZILLA_RESPONSE"
 #define MOZILLA_USER_PROP      "_MOZILLA_USER"
 #define MOZILLA_PROFILE_PROP   "_MOZILLA_PROFILE"
 #define MOZILLA_PROGRAM_PROP   "_MOZILLA_PROGRAM"
 
 #ifdef IS_BIG_ENDIAN
 #define TO_LITTLE_ENDIAN32(x) \
@@ -57,17 +56,16 @@ static int (*sOldHandler)(Display *, XEr
 static bool sGotBadWindow;
 
 XRemoteClient::XRemoteClient()
 {
   mDisplay = 0;
   mInitialized = false;
   mMozVersionAtom = 0;
   mMozLockAtom = 0;
-  mMozCommandAtom = 0;
   mMozResponseAtom = 0;
   mMozWMStateAtom = 0;
   mMozUserAtom = 0;
   mLockData = 0;
   if (!sRemoteLm)
     sRemoteLm = PR_NewLogModule("XRemoteClient");
   PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::XRemoteClient"));
 }
@@ -78,17 +76,16 @@ XRemoteClient::~XRemoteClient()
   if (mInitialized)
     Shutdown();
 }
 
 // Minimize the roundtrips to the X-server
 static const char *XAtomNames[] = {
   MOZILLA_VERSION_PROP,
   MOZILLA_LOCK_PROP,
-  MOZILLA_COMMAND_PROP,
   MOZILLA_RESPONSE_PROP,
   "WM_STATE",
   MOZILLA_USER_PROP,
   MOZILLA_PROFILE_PROP,
   MOZILLA_PROGRAM_PROP,
   MOZILLA_COMMANDLINE_PROP
 };
 static Atom XAtoms[ARRAY_LENGTH(XAtomNames)];
@@ -108,17 +105,16 @@ XRemoteClient::Init()
 
   // get our atoms
   XInternAtoms(mDisplay, const_cast<char**>(XAtomNames),
                ARRAY_LENGTH(XAtomNames), False, XAtoms);
 
   int i = 0;
   mMozVersionAtom  = XAtoms[i++];
   mMozLockAtom     = XAtoms[i++];
-  mMozCommandAtom  = XAtoms[i++];
   mMozResponseAtom = XAtoms[i++];
   mMozWMStateAtom  = XAtoms[i++];
   mMozUserAtom     = XAtoms[i++];
   mMozProfileAtom  = XAtoms[i++];
   mMozProgramAtom  = XAtoms[i++];
   mMozCommandLineAtom = XAtoms[i++];
 
   mInitialized = true;
@@ -139,72 +135,44 @@ XRemoteClient::Shutdown (void)
   mDisplay = 0;
   mInitialized = false;
   if (mLockData) {
     free(mLockData);
     mLockData = 0;
   }
 }
 
-nsresult
-XRemoteClient::SendCommand (const char *aProgram, const char *aUsername,
-                            const char *aProfile, const char *aCommand,
-                            const char* aDesktopStartupID,
-                            char **aResponse, bool *aWindowFound)
-{
-  PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommand"));
-
-  return SendCommandInternal(aProgram, aUsername, aProfile,
-                             aCommand, 0, nullptr,
-                             aDesktopStartupID,
-                             aResponse, aWindowFound);
-}
-
-nsresult
-XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
-                                const char *aProfile,
-                                int32_t argc, char **argv,
-                                const char* aDesktopStartupID,
-                                char **aResponse, bool *aWindowFound)
-{
-  PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommandLine"));
-
-  return SendCommandInternal(aProgram, aUsername, aProfile,
-                             nullptr, argc, argv,
-                             aDesktopStartupID,
-                             aResponse, aWindowFound);
-}
-
 static int
 HandleBadWindow(Display *display, XErrorEvent *event)
 {
   if (event->error_code == BadWindow) {
     sGotBadWindow = true;
     return 0; // ignored
   }
   else {
     return (*sOldHandler)(display, event);
   }
 }
 
 nsresult
-XRemoteClient::SendCommandInternal(const char *aProgram, const char *aUsername,
-                                   const char *aProfile, const char *aCommand,
-                                   int32_t argc, char **argv,
-                                   const char* aDesktopStartupID,
-                                   char **aResponse, bool *aWindowFound)
+XRemoteClient::SendCommandLine (const char *aProgram, const char *aUsername,
+                                const char *aProfile,
+                                int32_t argc, char **argv,
+                                const char* aDesktopStartupID,
+                                char **aResponse, bool *aWindowFound)
 {
+  PR_LOG(sRemoteLm, PR_LOG_DEBUG, ("XRemoteClient::SendCommandLine"));
+
   *aWindowFound = false;
-  bool isCommandLine = !aCommand;
 
   // FindBestWindow() iterates down the window hierarchy, so catch X errors
   // when windows get destroyed before being accessed.
   sOldHandler = XSetErrorHandler(HandleBadWindow);
 
-  Window w = FindBestWindow(aProgram, aUsername, aProfile, isCommandLine);
+  Window w = FindBestWindow(aProgram, aUsername, aProfile);
 
   nsresult rv = NS_OK;
 
   if (w) {
     // ok, let the caller know that we at least found a window.
     *aWindowFound = true;
 
     // Ignore BadWindow errors up to this point.  The last request from
@@ -218,24 +186,18 @@ XRemoteClient::SendCommandInternal(const
 
     bool destroyed = false;
 
     // get the lock on the window
     rv = GetLock(w, &destroyed);
 
     if (NS_SUCCEEDED(rv)) {
       // send our command
-      if (isCommandLine) {
-        rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse,
-                               &destroyed);
-      }
-      else {
-        rv = DoSendCommand(w, aCommand, aDesktopStartupID, aResponse,
-                           &destroyed);
-      }
+      rv = DoSendCommandLine(w, argc, argv, aDesktopStartupID, aResponse,
+                             &destroyed);
 
       // if the window was destroyed, don't bother trying to free the
       // lock.
       if (!destroyed)
           FreeLock(w); // doesn't really matter what this returns
 
     }
   }
@@ -443,18 +405,17 @@ XRemoteClient::GetLock(Window aWindow, b
             (unsigned int) aWindow));
   }
 
   return rv;
 }
 
 Window
 XRemoteClient::FindBestWindow(const char *aProgram, const char *aUsername,
-                              const char *aProfile,
-                              bool aSupportsCommandLine)
+                              const char *aProfile)
 {
   Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mDisplay));
   Window bestWindow = 0;
   Window root2, parent, *kids;
   unsigned int nkids;
 
   // Get a list of the children of the root window, walk the list
   // looking for the best window that fits the criteria.
@@ -489,17 +450,17 @@ XRemoteClient::FindBestWindow(const char
                                     &data_return);
 
     if (!data_return)
       continue;
 
     double version = PR_strtod((char*) data_return, nullptr);
     XFree(data_return);
 
-    if (aSupportsCommandLine && !(version >= 5.1 && version < 6))
+    if (!(version >= 5.1 && version < 6))
       continue;
 
     data_return = 0;
 
     if (status != Success || type == None)
       continue;
 
     // If someone passed in a program name, check it against this one
@@ -633,56 +594,16 @@ XRemoteClient::FreeLock(Window aWindow)
       return NS_ERROR_FAILURE;
   }
 
   if (data)
       XFree(data);
   return NS_OK;
 }
 
-nsresult
-XRemoteClient::DoSendCommand(Window aWindow, const char *aCommand,
-                             const char* aDesktopStartupID,
-                             char **aResponse, bool *aDestroyed)
-{
-  *aDestroyed = false;
-
-  PR_LOG(sRemoteLm, PR_LOG_DEBUG,
-     ("(writing " MOZILLA_COMMAND_PROP " \"%s\" to 0x%x)\n",
-      aCommand, (unsigned int) aWindow));
-
-  // We add the DESKTOP_STARTUP_ID setting as an extra line of
-  // the command string. Firefox ignores all lines but the first.
-  static char desktopStartupPrefix[] = "\nDESKTOP_STARTUP_ID=";
-
-  int32_t len = strlen(aCommand);
-  if (aDesktopStartupID) {
-    len += sizeof(desktopStartupPrefix) - 1 + strlen(aDesktopStartupID);
-  }
-  char* buffer = (char*)malloc(len + 1);
-  if (!buffer)
-    return NS_ERROR_OUT_OF_MEMORY;
-
-  strcpy(buffer, aCommand);
-  if (aDesktopStartupID) {
-    strcat(buffer, desktopStartupPrefix);
-    strcat(buffer, aDesktopStartupID);
-  }
-
-  XChangeProperty (mDisplay, aWindow, mMozCommandAtom, XA_STRING, 8,
-           PropModeReplace, (unsigned char *)buffer, len);
-
-  free(buffer);
-
-  if (!WaitForResponse(aWindow, aResponse, aDestroyed, mMozCommandAtom))
-    return NS_ERROR_FAILURE;
-  
-  return NS_OK;
-}
-
 /* like strcpy, but return the char after the final null */
 static char*
 estrcpy(const char* s, char* d)
 {
   while (*s)
     *d++ = *s++;
 
   *d++ = '\0';
@@ -865,16 +786,16 @@ XRemoteClient::WaitForResponse(Window aW
     }
 
     else if (event.xany.type == PropertyNotify &&
              event.xproperty.window == aWindow &&
              event.xproperty.state == PropertyDelete &&
              event.xproperty.atom == aCommandAtom) {
       PR_LOG(sRemoteLm, PR_LOG_DEBUG,
              ("(server 0x%x has accepted "
-              MOZILLA_COMMAND_PROP ".)\n",
+              MOZILLA_COMMANDLINE_PROP ".)\n",
               (unsigned int) aWindow));
     }
     
   }
 
   return accepted;