merge fx-team to m-c
authorPaul Rouget <paul@mozilla.com>
Mon, 27 Aug 2012 00:05:32 +0200
changeset 105517 e08a67884b9b0af40492adcf7acd81a409f4e23d
parent 105516 c4d19217db8d5887ddb2b99ac0b52c2c59f072ea (current diff)
parent 105515 2b9625825da7911aba106256c48fa6750fb9cd24 (diff)
child 105535 0a9e931cdcf3ffc4f34bcd440b1f2fe087afa44a
child 105945 f77ed5fe36f0b82349db2d2b7b9700d44fda3cd9
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
milestone17.0a1
merge fx-team to m-c
browser/base/content/browser.xul
ipc/chromium/src/base/file_util_linux.cc
--- a/accessible/src/mac/mozAccessible.mm
+++ b/accessible/src/mac/mozAccessible.mm
@@ -97,17 +97,17 @@ GetClosestInterestingAccessible(id anObj
 
 - (BOOL)accessibilityIsIgnored
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
   // unknown (either unimplemented, or irrelevant) elements are marked as ignored
   // as well as expired elements.
   return !mGeckoAccessible || ([[self role] isEqualToString:NSAccessibilityUnknownRole] &&
-                               !(mGeckoAccessible->NativeInteractiveState() & states::FOCUSABLE));
+                               !(mGeckoAccessible->InteractiveState() & states::FOCUSABLE));
 
   NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
 }
 
 - (NSArray*)accessibilityAttributeNames
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
 
--- a/b2g/confvars.sh
+++ b/b2g/confvars.sh
@@ -1,18 +1,16 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 MOZ_APP_BASENAME=B2G
 MOZ_APP_VENDOR=Mozilla
 
 MOZ_APP_VERSION=17.0a1
-
-MOZ_UA_OS_AGNOSTIC=1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_BRANDING_DIRECTORY=b2g/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=b2g/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
 MOZ_SERVICES_SYNC=1
--- a/browser/base/content/browser-plugins.js
+++ b/browser/base/content/browser-plugins.js
@@ -145,66 +145,86 @@ var gPluginHandler = {
         self.addLinkClickCallback(updateLink, "openPluginUpdatePage");
         /* FALLTHRU */
 
       case "PluginVulnerableNoUpdate":
       case "PluginClickToPlay":
         self._handleClickToPlayEvent(plugin);
         break;
 
+      case "PluginPlayPreview":
+        self._handlePlayPreviewEvent(plugin);
+        break;
+
       case "PluginDisabled":
         let manageLink = doc.getAnonymousElementByAttribute(plugin, "class", "managePluginsLink");
         self.addLinkClickCallback(manageLink, "managePlugins");
         break;
     }
 
     // Hide the in-content UI if it's too big. The crashed plugin handler already did this.
     if (event.type != "PluginCrashed") {
       let overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
       /* overlay might be null, so only operate on it if it exists */
       if (overlay != null && self.isTooSmall(plugin, overlay))
           overlay.style.visibility = "hidden";
     }
   },
 
+  canActivatePlugin: function PH_canActivatePlugin(objLoadingContent) {
+    return !objLoadingContent.activated &&
+           objLoadingContent.pluginFallbackType !== Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW;
+  },
+
   activatePlugins: function PH_activatePlugins(aContentWindow) {
     let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
     browser._clickToPlayPluginsActivated = true;
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils);
     let plugins = cwu.plugins;
     for (let plugin of plugins) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      if (!objLoadingContent.activated)
+      if (gPluginHandler.canActivatePlugin(objLoadingContent))
         objLoadingContent.playPlugin();
     }
     let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
     if (notification)
       notification.remove();
   },
 
   activateSinglePlugin: function PH_activateSinglePlugin(aContentWindow, aPlugin) {
     let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
-    if (!objLoadingContent.activated)
+    if (gPluginHandler.canActivatePlugin(objLoadingContent))
       objLoadingContent.playPlugin();
 
     let cwu = aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                             .getInterface(Ci.nsIDOMWindowUtils);
     let haveUnplayedPlugins = cwu.plugins.some(function(plugin) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      return (plugin != aPlugin && !objLoadingContent.activated);
+      return (plugin != aPlugin && gPluginHandler.canActivatePlugin(objLoadingContent));
     });
     let browser = gBrowser.getBrowserForDocument(aContentWindow.document);
     let notification = PopupNotifications.getNotification("click-to-play-plugins", browser);
     if (notification && !haveUnplayedPlugins) {
       browser._clickToPlayDoorhangerShown = false;
       notification.remove();
     }
   },
 
+  stopPlayPreview: function PH_stopPlayPreview(aPlugin, aPlayPlugin) {
+    let objLoadingContent = aPlugin.QueryInterface(Ci.nsIObjectLoadingContent);
+    if (objLoadingContent.activated)
+      return;
+
+    if (aPlayPlugin)
+      objLoadingContent.playPlugin();
+    else
+      objLoadingContent.cancelPlayPreview();
+  },
+
   newPluginInstalled : function(event) {
     // browser elements are anonymous so we can't just use target.
     var browser = event.originalTarget;
     // clear the plugin list, now that at least one plugin has been installed
     browser.missingPlugins = null;
 
     var notificationBox = gBrowser.getNotificationBox(browser);
     var notification = notificationBox.getNotificationWithValue("missing-plugins");
@@ -285,32 +305,72 @@ var gPluginHandler = {
           gPluginHandler.activateSinglePlugin(aEvent.target.ownerDocument.defaultView.top, aPlugin);
       }, true);
     }
 
     if (!browser._clickToPlayDoorhangerShown)
       gPluginHandler._showClickToPlayNotification(browser);
   },
 
+  _handlePlayPreviewEvent: function PH_handlePlayPreviewEvent(aPlugin) {
+    let doc = aPlugin.ownerDocument;
+    let previewContent = doc.getAnonymousElementByAttribute(aPlugin, "class", "previewPluginContent");
+    if (!previewContent) {
+      // the XBL binding is not attached (element is display:none), fallback to click-to-play logic
+      gPluginHandler.stopPlayPreview(aPlugin, false);
+      return;
+    }
+    let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
+    if (!iframe) {
+      // lazy initialization of the iframe
+      iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
+      iframe.className = "previewPluginContentFrame";
+      previewContent.appendChild(iframe);
+
+      // Force a style flush, so that we ensure our binding is attached.
+      aPlugin.clientTop;
+    }
+    let pluginInfo = getPluginInfo(aPlugin);
+    let playPreviewUri = "data:application/x-moz-playpreview;," + pluginInfo.mimetype;
+    iframe.src = playPreviewUri;
+
+    // MozPlayPlugin event can be dispatched from the extension chrome
+    // code to replace the preview content with the native plugin
+    previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(aEvent) {
+      if (!aEvent.isTrusted)
+        return;
+
+      previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
+
+      let playPlugin = !aEvent.detail;
+      gPluginHandler.stopPlayPreview(aPlugin, playPlugin);
+
+      // cleaning up: removes overlay iframe from the DOM
+      let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
+      if (iframe)
+        previewContent.removeChild(iframe);
+    }, true);
+  },
+
   reshowClickToPlayNotification: function PH_reshowClickToPlayNotification() {
     if (!Services.prefs.getBoolPref("plugins.click_to_play"))
       return;
 
     let browser = gBrowser.selectedBrowser;
 
     let pluginsPermission = Services.perms.testPermission(browser.currentURI, "plugins");
     if (pluginsPermission == Ci.nsIPermissionManager.DENY_ACTION)
       return;
 
     let contentWindow = browser.contentWindow;
     let cwu = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
     let pluginNeedsActivation = cwu.plugins.some(function(plugin) {
       let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-      return !objLoadingContent.activated;
+      return gPluginHandler.canActivatePlugin(objLoadingContent);
     });
     if (pluginNeedsActivation)
       gPluginHandler._showClickToPlayNotification(browser);
   },
 
   _showClickToPlayNotification: function PH_showClickToPlayNotification(aBrowser) {
     aBrowser._clickToPlayDoorhangerShown = true;
     let contentWindow = aBrowser.contentWindow;
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -67,19 +67,21 @@ let SocialUI = {
   _providerReady: function SocialUI_providerReady() {
     // If we couldn't find a provider, nothing to do here.
     if (!Social.provider)
       return;
 
     this.updateToggleCommand();
 
     let toggleCommand = this.toggleCommand;
-    let label = gNavigatorBundle.getFormattedString("social.enable.label",
-                                                    [Social.provider.name]);
-    let accesskey = gNavigatorBundle.getString("social.enable.accesskey");
+    let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
+    let label = gNavigatorBundle.getFormattedString("social.toggle.label",
+                                                    [Social.provider.name,
+                                                     brandShortName]);
+    let accesskey = gNavigatorBundle.getString("social.toggle.accesskey");
     toggleCommand.setAttribute("label", label);
     toggleCommand.setAttribute("accesskey", accesskey);
 
     SocialToolbar.init();
     SocialShareButton.init();
     SocialSidebar.init();
   },
 
@@ -133,17 +135,17 @@ let SocialUI = {
     Social.lastEventReceived = now;
 
     // Enable the social functionality, and indicate that it was activated
     Social.active = true;
 
     // Show a warning, allow undoing the activation
     let description = document.getElementById("social-activation-message");
     let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
-    let message = gNavigatorBundle.getFormattedString("social.activated.message",
+    let message = gNavigatorBundle.getFormattedString("social.activated.description",
                                                       [Social.provider.name, brandShortName]);
     description.value = message;
 
     SocialUI.notificationPanel.hidden = false;
 
     setTimeout(function () {
       SocialUI.notificationPanel.openPopup(SocialToolbar.button, "bottomcenter topright");
     }.bind(this), 0);
--- a/browser/base/content/browser-tabPreviews.js
+++ b/browser/base/content/browser-tabPreviews.js
@@ -184,19 +184,24 @@ var ctrlTab = {
 
     // Rotate the list until the selected tab is first
     while (!list[0].selected)
       list.push(list.shift());
 
     list = list.filter(function (tab) !tab.closing);
 
     if (this.recentlyUsedLimit != 0) {
-      let recentlyUsedTabs = this._recentlyUsedTabs;
-      if (this.recentlyUsedLimit > 0)
-        recentlyUsedTabs = this._recentlyUsedTabs.slice(0, this.recentlyUsedLimit);
+      let recentlyUsedTabs = [];
+      for (let tab of this._recentlyUsedTabs) {
+        if (!tab.hidden && !tab.closing) {
+          recentlyUsedTabs.push(tab);
+          if (this.recentlyUsedLimit > 0 && recentlyUsedTabs.length >= this.recentlyUsedLimit)
+            break;
+        }
+      }
       for (let i = recentlyUsedTabs.length - 1; i >= 0; i--) {
         list.splice(list.indexOf(recentlyUsedTabs[i]), 1);
         list.unshift(recentlyUsedTabs[i]);
       }
     }
 
     return this._tabList = list;
   },
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1015,16 +1015,17 @@ var gBrowserInit = {
     gBrowser.addEventListener("DOMUpdatePageReport", gPopupBlockerObserver, false);
 
     gBrowser.addEventListener("PluginNotFound",     gPluginHandler, true);
     gBrowser.addEventListener("PluginCrashed",      gPluginHandler, true);
     gBrowser.addEventListener("PluginBlocklisted",  gPluginHandler, true);
     gBrowser.addEventListener("PluginOutdated",     gPluginHandler, true);
     gBrowser.addEventListener("PluginDisabled",     gPluginHandler, true);
     gBrowser.addEventListener("PluginClickToPlay",  gPluginHandler, true);
+    gBrowser.addEventListener("PluginPlayPreview",  gPluginHandler, true);
     gBrowser.addEventListener("PluginVulnerableUpdatable", gPluginHandler, true);
     gBrowser.addEventListener("PluginVulnerableNoUpdate", gPluginHandler, true);
     gBrowser.addEventListener("NewPluginInstalled", gPluginHandler.newPluginInstalled, true);
 #ifdef XP_MACOSX
     gBrowser.addEventListener("npapi-carbon-event-model-failure", gPluginHandler, true);
 #endif
 
     Services.obs.addObserver(gPluginHandler.pluginCrashed, "plugin-crashed", false);
@@ -1234,17 +1235,16 @@ var gBrowserInit = {
 
     // Misc. inits.
     CombinedStopReload.init();
     allTabs.readPref();
     TabsOnTop.init();
     BookmarksMenuButton.init();
     TabsInTitlebar.init();
     gPrivateBrowsingUI.init();
-    DownloadsButton.initializePlaceholder();
     retrieveToolbarIconsizesFromTheme();
 
     gDelayedStartupTimeoutId = setTimeout(this._delayedStartup.bind(this), 0, isLoadingBlank, mustLoadSidebar);
     gStartupRan = true;
   },
 
   _delayedStartup: function(isLoadingBlank, mustLoadSidebar) {
     let tmp = {};
@@ -3122,39 +3122,16 @@ var newWindowButtonObserver = {
     url = getShortcutOrURI(url, postData);
     if (url) {
       // allow third-party services to fixup this URL
       openNewWindowWith(url, null, postData.value, true);
     }
   }
 }
 
-var DownloadsButtonDNDObserver = {
-  onDragOver: function (aEvent)
-  {
-    var types = aEvent.dataTransfer.types;
-    if (types.contains("text/x-moz-url") ||
-        types.contains("text/uri-list") ||
-        types.contains("text/plain"))
-      aEvent.preventDefault();
-  },
-
-  onDragExit: function (aEvent)
-  {
-  },
-
-  onDrop: function (aEvent)
-  {
-    let name = { };
-    let url = browserDragAndDrop.drop(aEvent, name);
-    if (url)
-      saveURL(url, name, null, true, true);
-  }
-}
-
 const DOMLinkHandler = {
   handleEvent: function (event) {
     switch (event.type) {
       case "DOMLinkAdded":
         this.onLinkAdded(event);
         break;
     }
   },
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -517,17 +517,17 @@
       <hbox class="titlebar-placeholder" type="caption-buttons" ordinal="1000"/>
 #endif
     </toolbar>
 
     <toolbar id="nav-bar" class="toolbar-primary chromeclass-toolbar"
              toolbarname="&navbarCmd.label;" accesskey="&navbarCmd.accesskey;"
              fullscreentoolbar="true" mode="icons" customizable="true"
              iconsize="large"
-             defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,home-button,bookmarks-menu-button-container,window-controls"
+             defaultset="unified-back-forward-button,urlbar-container,reload-button,stop-button,search-container,downloads-button,home-button,bookmarks-menu-button-container,window-controls"
              context="toolbar-context-menu">
 
       <toolbaritem id="unified-back-forward-button" class="chromeclass-toolbar-additional"
                    context="backForwardMenu" removable="true"
                    forwarddisabled="true"
                    title="&backForwardItem.title;">
         <toolbarbutton id="back-button" class="toolbarbutton-1"
                        label="&backCmd.label;"
@@ -932,24 +932,24 @@
 # Update primaryToolbarButtons in browser/themes/browserShared.inc when adding
 # or removing default items with the toolbarbutton-1 class.
 
       <toolbarbutton id="print-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      label="&printButton.label;" command="cmd_print"
                      tooltiptext="&printButton.tooltip;"/>
 
       <!-- This is a placeholder for the Downloads Indicator.  It is visible
-           only during the customization of the toolbar or in the palette, and
-           is replaced when customization is done. -->
+           during the customization of the toolbar, in the palette, and before
+           the Downloads Indicator overlay is loaded. -->
       <toolbarbutton id="downloads-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
-                     observes="Tools:Downloads"
-                     ondrop="DownloadsButtonDNDObserver.onDrop(event)"
-                     ondragover="DownloadsButtonDNDObserver.onDragOver(event)"
-                     ondragenter="DownloadsButtonDNDObserver.onDragOver(event)"
-                     ondragexit="DownloadsButtonDNDObserver.onDragExit(event)"
+                     oncommand="DownloadsIndicatorView.onCommand(event);"
+                     ondrop="DownloadsIndicatorView.onDrop(event);"
+                     ondragover="DownloadsIndicatorView.onDragOver(event);"
+                     ondragenter="DownloadsIndicatorView.onDragOver(event);"
+                     ondragleave="DownloadsIndicatorView.onDragLeave(event);"
                      label="&downloads.label;"
                      tooltiptext="&downloads.tooltip;"/>
 
       <toolbarbutton id="history-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
                      observes="viewHistorySidebar" label="&historyButton.label;"
                      tooltiptext="&historyButton.tooltip;"/>
 
       <toolbarbutton id="bookmarks-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -174,16 +174,17 @@ endif
                  browser_hide_removing.js \
                  browser_overflowScroll.js \
                  browser_locationBarCommand.js \
                  browser_locationBarExternalLoad.js \
                  browser_page_style_menu.js \
                  browser_pinnedTabs.js \
                  browser_plainTextLinks.js \
                  browser_pluginnotification.js \
+                 browser_pluginplaypreview.js \
                  browser_relatedTabs.js \
                  browser_sanitize-passwordDisabledHosts.js \
                  browser_sanitize-sitepermissions.js \
                  browser_sanitize-timespans.js \
                  browser_clearplugindata.js \
                  browser_clearplugindata.html \
                  browser_clearplugindata_noage.html \
                  browser_popupUI.js \
--- a/browser/base/content/test/browser_pluginnotification.js
+++ b/browser/base/content/test/browser_pluginnotification.js
@@ -2,28 +2,16 @@ var rootDir = getRootDirectory(gTestPath
 const gTestRoot = rootDir;
 const gHttpTestRoot = rootDir.replace("chrome://mochitests/content/", "http://127.0.0.1:8888/");
 
 var gTestBrowser = null;
 var gNextTest = null;
 var gClickToPlayPluginActualEvents = 0;
 var gClickToPlayPluginExpectedEvents = 5;
 
-function get_test_plugin() {
-  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
-  var tags = ph.getPluginTags();
-
-  // Find the test plugin
-  for (var i = 0; i < tags.length; i++) {
-    if (tags[i].name == "Test Plug-in")
-      return tags[i];
-  }
-  ok(false, "Unable to find plugin");
-}
-
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 // This listens for the next opened tab and checks it is of the right url.
 // opencallback is called when the new tab is fully loaded
 // closecallback is called when the tab is closed
 function TabOpenListener(url, opencallback, closecallback) {
   this.url = url;
   this.opencallback = opencallback;
@@ -112,31 +100,31 @@ function test1() {
   ok("application/x-unknown" in gTestBrowser.missingPlugins, "Test 1, Should know about application/x-unknown");
   ok(!("application/x-test" in gTestBrowser.missingPlugins), "Test 1, Should not know about application/x-test");
 
   var pluginNode = gTestBrowser.contentDocument.getElementById("unknown");
   ok(pluginNode, "Test 1, Found plugin in page");
   var objLoadingContent = pluginNode.QueryInterface(Ci.nsIObjectLoadingContent);
   is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_UNSUPPORTED, "Test 1, plugin fallback type should be PLUGIN_UNSUPPORTED");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   ok(plugin, "Should have a test plugin");
   plugin.disabled = false;
   plugin.blocklisted = false;
   prepareTest(test2, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a working plugin in it.
 function test2() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 2, Should not have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 2, Should not have displayed the blocked plugin notification");
   ok(!gTestBrowser.missingPlugins, "Test 2, Should not be a missing plugin list");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   ok(plugin, "Should have a test plugin");
   plugin.disabled = true;
   prepareTest(test3, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a disabled plugin in it.
 function test3() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
@@ -157,17 +145,17 @@ function test3() {
 }
 
 function test4(tab, win) {
   is(win.wrappedJSObject.gViewController.currentViewId, "addons://list/plugin", "Test 4, Should have displayed the plugins pane");
   gBrowser.removeTab(tab);
 }
 
 function prepareTest5() {
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = true;
   prepareTest(test5, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a blocked plugin in it.
 function test5() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
@@ -200,17 +188,17 @@ function test6() {
 function test7() {
   var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
   ok(notificationBox.getNotificationWithValue("missing-plugins"), "Test 7, Should have displayed the missing plugin notification");
   ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 7, Should not have displayed the blocked plugin notification");
   ok(gTestBrowser.missingPlugins, "Test 7, Should be a missing plugin list");
   ok("application/x-unknown" in gTestBrowser.missingPlugins, "Test 7, Should know about application/x-unknown");
   ok("application/x-test" in gTestBrowser.missingPlugins, "Test 7, Should know about application/x-test");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = false;
   Services.prefs.setBoolPref("plugins.click_to_play", true);
 
   prepareTest(test8, gTestRoot + "plugin_test.html");
 }
 
 // Tests a page with a working plugin that is click-to-play
@@ -456,17 +444,17 @@ function test13c() {
 }
 
 // Tests that the plugin's "activated" property is true for working plugins with click-to-play disabled.
 function test14() {
   var plugin = gTestBrowser.contentDocument.getElementById("test1");
   var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
   ok(objLoadingContent.activated, "Test 14, Plugin should be activated");
 
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.disabled = false;
   plugin.blocklisted = false;
   Services.perms.removeAll();
   Services.prefs.setBoolPref("plugins.click_to_play", true);
   prepareTest(test15, gTestRoot + "plugin_alternate_content.html");
 }
 
 // Tests that the overlay is shown instead of alternate content when
@@ -635,17 +623,17 @@ function test18c() {
   is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_VULNERABLE_NO_UPDATE, "Test 18c, plugin fallback type should be PLUGIN_VULNERABLE_NO_UPDATE");
   ok(!objLoadingContent.activated, "Test 18c, Plugin should not be activated");
   var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "mainBox");
   ok(overlay.style.visibility != "hidden", "Test 18c, Plugin overlay should exist, not be hidden");
   var updateLink = doc.getAnonymousElementByAttribute(plugin, "class", "checkForUpdatesLink");
   ok(updateLink.style.display != "block", "Test 18c, Plugin should not have an update link");
 
   unregisterFakeBlocklistService();
-  var plugin = get_test_plugin();
+  var plugin = getTestPlugin();
   plugin.clicktoplay = false;
 
   prepareTest(test19a, gTestRoot + "plugin_test.html");
 }
 
 // Tests that clicking the icon of the overlay activates the plugin
 function test19a() {
   var doc = gTestBrowser.contentDocument;
new file mode 100644
--- /dev/null
+++ b/browser/base/content/test/browser_pluginplaypreview.js
@@ -0,0 +1,311 @@
+/* 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/. */
+
+var rootDir = getRootDirectory(gTestPath);
+const gTestRoot = rootDir;
+
+var gTestBrowser = null;
+var gNextTest = null;
+var gNextTestSkip = 0;
+var gPlayPreviewPluginActualEvents = 0;
+var gPlayPreviewPluginExpectedEvents = 1;
+
+var gPlayPreviewRegistration = null;
+
+function registerPlayPreview(mimeType, targetUrl) {
+
+  function StreamConverterFactory() {}
+  StreamConverterFactory.prototype = {
+    QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory]),
+    _targetConstructor: null,
+
+    register: function register(targetConstructor) {
+      this._targetConstructor = targetConstructor;
+      var proto = targetConstructor.prototype;
+      var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+      registrar.registerFactory(proto.classID, proto.classDescription,
+                                proto.contractID, this);
+    },
+
+    unregister: function unregister() {
+      var proto = this._targetConstructor.prototype;
+      var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+      registrar.unregisterFactory(proto.classID, this);
+      this._targetConstructor = null;
+    },
+
+    // nsIFactory
+    createInstance: function createInstance(aOuter, iid) {
+      if (aOuter !== null)
+        throw Cr.NS_ERROR_NO_AGGREGATION;
+      return (new (this._targetConstructor)).QueryInterface(iid);
+    },
+
+    // nsIFactory
+    lockFactory: function lockFactory(lock) {
+      // No longer used as of gecko 1.7.
+      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+    }
+  };
+
+  function OverlayStreamConverter() {}
+  OverlayStreamConverter.prototype = {
+    QueryInterface: XPCOMUtils.generateQI([
+        Ci.nsISupports,
+        Ci.nsIStreamConverter,
+        Ci.nsIStreamListener,
+        Ci.nsIRequestObserver
+    ]),
+
+    classID: Components.ID('{4c6030f7-e20a-264f-0f9b-ada3a9e97384}'),
+    classDescription: 'overlay-test-data Component',
+    contractID: '@mozilla.org/streamconv;1?from=application/x-moz-playpreview&to=*/*',
+
+    // nsIStreamConverter::convert
+    convert: function(aFromStream, aFromType, aToType, aCtxt) {
+      throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+    },
+
+    // nsIStreamConverter::asyncConvertData
+    asyncConvertData: function(aFromType, aToType, aListener, aCtxt) {
+      var isValidRequest = false;
+      try {
+        var request = aCtxt;
+        request.QueryInterface(Ci.nsIChannel);
+        var spec = request.URI.spec;
+        var expectedSpec = 'data:application/x-moz-playpreview;,' + mimeType;
+        isValidRequest = (spec == expectedSpec);
+      } catch (e) { }
+      if (!isValidRequest)
+        throw Cr.NS_ERROR_NOT_IMPLEMENTED;
+
+      // Store the listener passed to us
+      this.listener = aListener;
+    },
+
+    // nsIStreamListener::onDataAvailable
+    onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) {
+      // Do nothing since all the data loading is handled by the viewer.
+      ok(false, "onDataAvailable should not be called");
+    },
+
+    // nsIRequestObserver::onStartRequest
+    onStartRequest: function(aRequest, aContext) {
+
+      // Setup the request so we can use it below.
+      aRequest.QueryInterface(Ci.nsIChannel);
+      // Cancel the request so the viewer can handle it.
+      aRequest.cancel(Cr.NS_BINDING_ABORTED);
+
+      // Create a new channel that is viewer loaded as a resource.
+      var ioService = Services.io;
+      var channel = ioService.newChannel(targetUrl, null, null);
+      channel.asyncOpen(this.listener, aContext);
+    },
+
+    // nsIRequestObserver::onStopRequest
+    onStopRequest: function(aRequest, aContext, aStatusCode) {
+      // Do nothing.
+    }
+  };
+
+  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+  ph.registerPlayPreviewMimeType(mimeType);
+
+  var factory = new StreamConverterFactory();
+  factory.register(OverlayStreamConverter);
+
+  return (gPlayPreviewRegistration = {
+    unregister: function() {
+      ph.unregisterPlayPreviewMimeType(mimeType);
+      factory.unregister();
+      gPlayPreviewRegistration = null;
+    }
+  });
+}
+
+function unregisterPlayPreview() {
+  gPlayPreviewRegistration.unregister();
+}
+
+Components.utils.import('resource://gre/modules/XPCOMUtils.jsm');
+Components.utils.import("resource://gre/modules/Services.jsm");
+
+
+function test() {
+  waitForExplicitFinish();
+  registerCleanupFunction(function() {
+    if (gPlayPreviewRegistration)
+      gPlayPreviewRegistration.unregister();
+    Services.prefs.clearUserPref("plugins.click_to_play");
+  });
+
+  var newTab = gBrowser.addTab();
+  gBrowser.selectedTab = newTab;
+  gTestBrowser = gBrowser.selectedBrowser;
+  gTestBrowser.addEventListener("load", pageLoad, true);
+  gTestBrowser.addEventListener("PluginPlayPreview", handlePluginPlayPreview, true);
+
+  registerPlayPreview('application/x-test', 'about:');
+  prepareTest(test1a, gTestRoot + "plugin_test.html", 1);
+}
+
+function finishTest() {
+  gTestBrowser.removeEventListener("load", pageLoad, true);
+  gTestBrowser.removeEventListener("PluginPlayPreview", handlePluginPlayPreview, true);
+  gBrowser.removeCurrentTab();
+  window.focus();
+  finish();
+}
+
+function handlePluginPlayPreview() {
+  gPlayPreviewPluginActualEvents++;
+}
+
+function pageLoad() {
+  // The plugin events are async dispatched and can come after the load event
+  // This just allows the events to fire before we then go on to test the states
+
+  // iframe might triggers load event as well, making sure we skip some to let
+  // all iframes on the page be loaded as well
+  if (gNextTestSkip) {
+    gNextTestSkip--;
+    return;
+  }
+  executeSoon(gNextTest);
+}
+
+function prepareTest(nextTest, url, skip) {
+  gNextTest = nextTest;
+  gNextTestSkip = skip;
+  gTestBrowser.contentWindow.location = url;
+}
+
+// Tests a page with normal play preview registration (1/2)
+function test1a() {
+  var notificationBox = gBrowser.getNotificationBox(gTestBrowser);
+  ok(!notificationBox.getNotificationWithValue("missing-plugins"), "Test 1a, Should not have displayed the missing plugin notification");
+  ok(!notificationBox.getNotificationWithValue("blocked-plugins"), "Test 1a, Should not have displayed the blocked plugin notification");
+
+  var pluginInfo = getTestPlugin();
+  ok(pluginInfo, "Should have a test plugin");
+
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 1a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 1a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 1a, the overlay div is expected");
+
+  var iframe = overlay.getElementsByClassName("previewPluginContentFrame")[0];
+  ok(iframe && iframe.localName == "iframe", "Test 1a, the overlay iframe is expected");
+  var iframeHref = iframe.contentWindow.location.href;
+  ok(iframeHref == "about:", "Test 1a, the overlay about: content is expected");
+
+  var rect = iframe.getBoundingClientRect();
+  ok(rect.width == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px width before being replaced by actual plugin");
+  ok(rect.height == 200, "Test 1a, Plugin with id=" + plugin.id + " overlay rect should have 200px height before being replaced by actual plugin");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, null);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test1b, "Test 1a, Waited too long for plugin to stop play preview");
+}
+
+// Tests that activating via MozPlayPlugin through the notification works (part 2/2)
+function test1b() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 1b, Plugin should be activated");
+
+  is(gPlayPreviewPluginActualEvents, gPlayPreviewPluginExpectedEvents,
+     "There should be exactly one PluginPlayPreview event");
+
+  unregisterPlayPreview();
+
+  prepareTest(test2, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- the mime type was just unregistered.
+function test2() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 2, Plugin should be activated");
+
+  registerPlayPreview('application/x-unknown', 'about:');
+
+  prepareTest(test3, gTestRoot + "plugin_test.html");
+}
+
+// Tests a page with a working plugin in it -- diffent play preview type is reserved.
+function test3() {
+  var plugin = gTestBrowser.contentDocument.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 3, Plugin should be activated");
+
+  unregisterPlayPreview();
+
+  registerPlayPreview('application/x-test', 'about:');
+  Services.prefs.setBoolPref("plugins.click_to_play", true);
+  prepareTest(test4a, gTestRoot + "plugin_test.html", 1);
+}
+
+// Test a fallback to the click-to-play
+function test4a() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 4a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 4a, the overlay div is expected");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, true);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.pluginFallbackType == Ci.nsIObjectLoadingContent.PLUGIN_CLICK_TO_PLAY;
+  waitForCondition(condition, test4b, "Test 4a, Waited too long for plugin to stop play preview");
+}
+
+function test4b() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.pluginFallbackType != Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 4b, plugin fallback type should not be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 4b, Plugin should not be activated");
+
+  prepareTest(test5a, gTestRoot + "plugin_test.html", 1);
+}
+
+// Test a bypass of the click-to-play
+function test5a() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  is(objLoadingContent.pluginFallbackType, Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW, "Test 5a, plugin fallback type should be PLUGIN_PLAY_PREVIEW");
+  ok(!objLoadingContent.activated, "Test 5a, Plugin should not be activated");
+
+  var overlay = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+  ok(overlay, "Test 5a, the overlay div is expected");
+
+  var e = overlay.ownerDocument.createEvent("CustomEvent");
+  e.initCustomEvent("MozPlayPlugin", true, true, false);
+  overlay.dispatchEvent(e);
+  var condition = function() objLoadingContent.activated;
+  waitForCondition(condition, test5b, "Test 5a, Waited too long for plugin to stop play preview");
+}
+
+function test5b() {
+  var doc = gTestBrowser.contentDocument;
+  var plugin = doc.getElementById("test");
+  var objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+  ok(objLoadingContent.activated, "Test 5b, Plugin should be activated");
+
+  finishTest();
+}
+
--- a/browser/base/content/test/head.js
+++ b/browser/base/content/test/head.js
@@ -92,16 +92,29 @@ function waitForCondition(condition, nex
 // in history, will not appear in about:newtab or auto-complete, etc.)
 function ensureSocialUrlNotRemembered(url) {
   let gh = Cc["@mozilla.org/browser/global-history;2"]
            .getService(Ci.nsIGlobalHistory2);
   let uri = Services.io.newURI(url, null, null);
   ok(!gh.isVisited(uri), "social URL " + url + " should not be in global history");
 }
 
+function getTestPlugin() {
+  var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
+  var tags = ph.getPluginTags();
+
+  // Find the test plugin
+  for (var i = 0; i < tags.length; i++) {
+    if (tags[i].name == "Test Plug-in")
+      return tags[i];
+  }
+  ok(false, "Unable to find plugin");
+  return null;
+}
+
 function runSocialTestWithProvider(manifest, callback) {
   let SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
 
   // Check that none of the provider's content ends up in history.
   registerCleanupFunction(function () {
     for (let what of ['sidebarURL', 'workerURL', 'iconURL']) {
       if (manifest[what]) {
         ensureSocialUrlNotRemembered(manifest[what]);
--- a/browser/components/downloads/content/download.xml
+++ b/browser/components/downloads/content/download.xml
@@ -10,52 +10,41 @@
 
 <bindings id="downloadBindings"
           xmlns="http://www.mozilla.org/xbl"
           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           xmlns:xbl="http://www.mozilla.org/xbl">
 
   <binding id="download"
            extends="chrome://global/content/bindings/richlistbox.xml#richlistitem">
-    <resources>
-      <stylesheet src="chrome://browser/skin/downloads/downloads.css"/>
-    </resources>
-    <content orient="horizontal">
-      <xul:hbox class="downloadInfo"
-                align="center"
-                flex="1"
-                onclick="DownloadsView.onDownloadClick(event);">
-        <xul:vbox pack="center">
-          <xul:image class="downloadTypeIcon"
-                     validate="always"
-                     xbl:inherits="src=image"/>
-          <xul:image class="downloadTypeIcon blockedIcon"/>
-        </xul:vbox>
-        <xul:vbox pack="center"
-                  flex="1">
-          <xul:description class="downloadTarget"
-                           crop="center"
-                           xbl:inherits="value=target,tooltiptext=target"/>
-          <xul:progressmeter anonid="progressmeter"
-                             class="downloadProgress"
-                             min="0"
-                             max="100"
-                             xbl:inherits="mode=progressmode,value=progress"/>
-          <xul:description class="downloadDetails"
-                           crop="end"
-                           xbl:inherits="value=status,tooltiptext=statusTip"/>
-        </xul:vbox>
-      </xul:hbox>
-      <xul:hbox class="downloadButtonContainer"
-                align="center">
-        <xul:button class="downloadButton downloadCancel"
-                    tooltiptext="&cmd.cancel.label;"
-                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_cancel');"/>
-        <xul:button class="downloadButton downloadRetry"
-                    tooltiptext="&cmd.retry.label;"
-                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
-        <xul:button class="downloadButton downloadShow"
-                    tooltiptext="&cmd.show.label;"
-                    oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
-      </xul:hbox>
+    <content orient="horizontal"
+             align="center"
+             onclick="DownloadsView.onDownloadClick(event);">
+      <xul:image class="downloadTypeIcon"
+                 validate="always"
+                 xbl:inherits="src=image"/>
+      <xul:image class="downloadTypeIcon blockedIcon"/>
+      <xul:vbox pack="center"
+                flex="1">
+        <xul:description class="downloadTarget"
+                         crop="center"
+                         xbl:inherits="value=target,tooltiptext=target"/>
+        <xul:progressmeter anonid="progressmeter"
+                           class="downloadProgress"
+                           min="0"
+                           max="100"
+                           xbl:inherits="mode=progressmode,value=progress"/>
+        <xul:description class="downloadDetails"
+                         crop="end"
+                         xbl:inherits="value=status,tooltiptext=statusTip"/>
+      </xul:vbox>
+      <xul:button class="downloadButton downloadCancel"
+                  tooltiptext="&cmd.cancel.label;"
+                  oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_cancel');"/>
+      <xul:button class="downloadButton downloadRetry"
+                  tooltiptext="&cmd.retry.label;"
+                  oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_retry');"/>
+      <xul:button class="downloadButton downloadShow"
+                  tooltiptext="&cmd.show.label;"
+                  oncommand="DownloadsView.onDownloadCommand(event, 'downloadsCmd_show');"/>
     </content>
   </binding>
 </bindings>
--- a/browser/components/downloads/content/downloads.js
+++ b/browser/components/downloads/content/downloads.js
@@ -255,22 +255,21 @@ const DownloadsPanel = {
   //////////////////////////////////////////////////////////////////////////////
   //// Related operations
 
   /**
    * Shows or focuses the user interface dedicated to downloads history.
    */
   showDownloadsHistory: function DP_showDownloadsHistory()
   {
-    // Hide the panel before invoking the Library window, otherwise focus will
-    // return to the browser window when the panel closes automatically.
+    // Hide the panel before showing another window, otherwise focus will return
+    // to the browser window when the panel closes automatically.
     this.hidePanel();
 
-    // Open the Library window and select the Downloads query.
-    PlacesCommandHook.showPlacesOrganizer("Downloads");
+    BrowserDownloadsUI();
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// Internal functions
 
   /**
    * Move focus to the main element in the downloads panel, unless another
    * element in the panel is already focused.
@@ -351,17 +350,17 @@ const DownloadsOverlayLoader = {
   _loadedOverlays: {},
 
   /**
    * Loads the specified overlay and invokes the given callback when finished.
    *
    * @param aOverlay
    *        String containing the URI of the overlay to load in the current
    *        window.  If this overlay has already been loaded using this
-   *        function, then the overlay is not loaded again. 
+   *        function, then the overlay is not loaded again.
    * @param aCallback
    *        Invoked when loading is completed.  If the overlay is already
    *        loaded, the function is called immediately.
    */
   ensureOverlayLoaded: function DOL_ensureOverlayLoaded(aOverlay, aCallback)
   {
     // The overlay is already loaded, invoke the callback immediately.
     if (aOverlay in this._loadedOverlays) {
@@ -420,47 +419,79 @@ const DownloadsOverlayLoader = {
  * download state and real-time data.  In addition, handles part of the user
  * interaction events raised by the downloads list widget.
  */
 const DownloadsView = {
   //////////////////////////////////////////////////////////////////////////////
   //// Functions handling download items in the list
 
   /**
+   * Maximum number of items shown by the list at any given time.
+   */
+  kItemCountLimit: 3,
+
+  /**
    * Indicates whether we are still loading downloads data asynchronously.
    */
   loading: false,
 
   /**
-   * Object containing all the available DownloadsViewItem objects, indexed by
-   * their numeric download identifier.
+   * Ordered array of all DownloadsDataItem objects.  We need to keep this array
+   * because only a limited number of items are shown at once, and if an item
+   * that is currently visible is removed from the list, we might need to take
+   * another item from the array and make it appear at the bottom.
+   */
+  _dataItems: [],
+
+  /**
+   * Object containing the available DownloadsViewItem objects, indexed by their
+   * numeric download identifier.  There is a limited number of view items in
+   * the panel at any given time.
    */
   _viewItems: {},
 
   /**
    * Called when the number of items in the list changes.
    */
   _itemCountChanged: function DV_itemCountChanged()
   {
-    if (Object.keys(this._viewItems).length > 0) {
+    let count = this._dataItems.length;
+    let hiddenCount = count - this.kItemCountLimit;
+
+    if (count > 0) {
       DownloadsPanel.panel.setAttribute("hasdownloads", "true");
     } else {
       DownloadsPanel.panel.removeAttribute("hasdownloads");
     }
+
+    let s = DownloadsCommon.strings;
+    this.downloadsHistory.label = (hiddenCount > 0)
+                                  ? s.showMoreDownloads(hiddenCount)
+                                  : s.showAllDownloads;
+    this.downloadsHistory.accessKey = s.showDownloadsAccessKey;
   },
 
   /**
    * Element corresponding to the list of downloads.
    */
   get richListBox()
   {
     delete this.richListBox;
     return this.richListBox = document.getElementById("downloadsListBox");
   },
 
+  /**
+   * Element corresponding to the button for showing more downloads.
+   */
+  get downloadsHistory()
+  {
+    delete this.downloadsHistory;
+    return this.downloadsHistory = document.getElementById("downloadsHistory");
+  },
+
   //////////////////////////////////////////////////////////////////////////////
   //// Callback functions from DownloadsData
 
   /**
    * Called before multiple downloads are about to be loaded.
    */
   onDataLoadStarting: function DV_onDataLoadStarting()
   {
@@ -469,16 +500,20 @@ const DownloadsView = {
 
   /**
    * Called after data loading finished.
    */
   onDataLoadCompleted: function DV_onDataLoadCompleted()
   {
     this.loading = false;
 
+    // We suppressed item count change notifications during the batch load, at
+    // this point we should just call the function once.
+    this._itemCountChanged();
+
     // Notify the panel that all the initially available downloads have been
     // loaded.  This ensures that the interface is visible, if still required.
     DownloadsPanel.onViewLoadCompleted();
   },
 
   /**
    * Called when the downloads database becomes unavailable (for example,
    * entering Private Browsing Mode).  References to existing data should be
@@ -488,16 +523,17 @@ const DownloadsView = {
   {
     DownloadsPanel.terminate();
 
     // Clear the list by replacing with a shallow copy.
     let emptyView = this.richListBox.cloneNode(false);
     this.richListBox.parentNode.replaceChild(emptyView, this.richListBox);
     this.richListBox = emptyView;
     this._viewItems = {};
+    this._dataItems = [];
   },
 
   /**
    * Called when a new download data item is available, either during the
    * asynchronous data load or when a new download is started.
    *
    * @param aDataItem
    *        DownloadsDataItem object that was just added.
@@ -505,59 +541,119 @@ const DownloadsView = {
    *        When true, indicates that this item is the most recent and should be
    *        added in the topmost position.  This happens when a new download is
    *        started.  When false, indicates that the item is the least recent
    *        and should be appended.  The latter generally happens during the
    *        asynchronous data load.
    */
   onDataItemAdded: function DV_onDataItemAdded(aDataItem, aNewest)
   {
-    // Make the item and add it in the appropriate place in the list.
-    let element = document.createElement("richlistitem");
-    let viewItem = new DownloadsViewItem(aDataItem, element);
-    this._viewItems[aDataItem.downloadId] = viewItem;
     if (aNewest) {
-      this.richListBox.insertBefore(element, this.richListBox.firstChild);
+      this._dataItems.unshift(aDataItem);
     } else {
-      this.richListBox.appendChild(element);
+      this._dataItems.push(aDataItem);
     }
 
-    this._itemCountChanged();
+    let itemsNowOverflow = this._dataItems.length > this.kItemCountLimit;
+    if (aNewest || !itemsNowOverflow) {
+      // The newly added item is visible in the panel and we must add the
+      // corresponding element.  This is either because it is the first item, or
+      // because it was added at the bottom but the list still doesn't overflow.
+      this._addViewItem(aDataItem, aNewest);
+    }
+    if (aNewest && itemsNowOverflow) {
+      // If the list overflows, remove the last item from the panel to make room
+      // for the new one that we just added at the top.
+      this._removeViewItem(this._dataItems[this.kItemCountLimit]);
+    }
+
+    // For better performance during batch loads, don't update the count for
+    // every item, because the interface won't be visible until load finishes.
+    if (!this.loading) {
+      this._itemCountChanged();
+    }
   },
 
   /**
    * Called when a data item is removed.  Ensures that the widget associated
    * with the view item is removed from the user interface.
    *
    * @param aDataItem
    *        DownloadsDataItem object that is being removed.
    */
   onDataItemRemoved: function DV_onDataItemRemoved(aDataItem)
   {
-    let element = this.getViewItem(aDataItem)._element;
-    let previousSelectedIndex = this.richListBox.selectedIndex;
-    this.richListBox.removeChild(element);
-    this.richListBox.selectedIndex = Math.min(previousSelectedIndex,
-                                              this.richListBox.itemCount - 1);
-    delete this._viewItems[aDataItem.downloadId];
+    let itemIndex = this._dataItems.indexOf(aDataItem);
+    this._dataItems.splice(itemIndex, 1);
+
+    if (itemIndex < this.kItemCountLimit) {
+      // The item to remove is visible in the panel.
+      this._removeViewItem(aDataItem);
+      if (this._dataItems.length >= this.kItemCountLimit) {
+        // Reinsert the next item into the panel.
+        this._addViewItem(this._dataItems[this.kItemCountLimit - 1], false);
+      }
+    }
 
     this._itemCountChanged();
   },
 
   /**
    * Returns the view item associated with the provided data item for this view.
    *
    * @param aDataItem
    *        DownloadsDataItem object for which the view item is requested.
    *
    * @return Object that can be used to notify item status events.
    */
   getViewItem: function DV_getViewItem(aDataItem)
   {
-    return this._viewItems[aDataItem.downloadId];
+    // If the item is visible, just return it, otherwise return a mock object
+    // that doesn't react to notifications.
+    if (aDataItem.downloadId in this._viewItems) {
+      return this._viewItems[aDataItem.downloadId];
+    }
+    return this._invisibleViewItem;
+  },
+
+  /**
+   * Mock DownloadsDataItem object that doesn't react to notifications.
+   */
+  _invisibleViewItem: Object.freeze({
+    onStateChange: function () { },
+    onProgressChange: function () { }
+  }),
+
+  /**
+   * Creates a new view item associated with the specified data item, and adds
+   * it to the top or the bottom of the list.
+   */
+  _addViewItem: function DV_addViewItem(aDataItem, aNewest)
+  {
+    let element = document.createElement("richlistitem");
+    let viewItem = new DownloadsViewItem(aDataItem, element);
+    this._viewItems[aDataItem.downloadId] = viewItem;
+    if (aNewest) {
+      this.richListBox.insertBefore(element, this.richListBox.firstChild);
+    } else {
+      this.richListBox.appendChild(element);
+    }
+  },
+
+  /**
+   * Removes the view item associated with the specified data item.
+   */
+  _removeViewItem: function DV_removeViewItem(aDataItem)
+  {
+    let element = this.getViewItem(aDataItem)._element;
+    let previousSelectedIndex = this.richListBox.selectedIndex;
+    this.richListBox.removeChild(element);
+    this.richListBox.selectedIndex = Math.min(previousSelectedIndex,
+                                              this.richListBox.itemCount - 1);
+    delete this._viewItems[aDataItem.downloadId];
   },
 
   //////////////////////////////////////////////////////////////////////////////
   //// User interface event functions
 
   /**
    * Helper function to do commands on a specific download item.
    *
@@ -574,18 +670,19 @@ const DownloadsView = {
     while (target.nodeName != "richlistitem") {
       target = target.parentNode;
     }
     new DownloadsViewItemController(target).doCommand(aCommand);
   },
 
   onDownloadClick: function DV_onDownloadClick(aEvent)
   {
-    // Handle primary clicks only.
-    if (aEvent.button == 0) {
+    // Handle primary clicks only, and exclude the action button.
+    if (aEvent.button == 0 &&
+        !aEvent.originalTarget.hasAttribute("oncommand")) {
       goDoCommand("downloadsCmd_open");
     }
   },
 
   onDownloadKeyPress: function DV_onDownloadKeyPress(aEvent)
   {
     // Handle unmodified keys only.
     if (aEvent.altKey || aEvent.ctrlKey || aEvent.shiftKey || aEvent.metaKey) {
--- a/browser/components/downloads/content/downloadsOverlay.xul
+++ b/browser/components/downloads/content/downloadsOverlay.xul
@@ -103,14 +103,12 @@
                    flex="1"
                    context="downloadsContextMenu"
                    onkeypress="DownloadsView.onDownloadKeyPress(event);"
                    oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
                    ondragstart="DownloadsView.onDownloadDragStart(event);"/>
 
       <button id="downloadsHistory"
               class="plain"
-              label="&downloadshistory.label;"
-              accesskey="&downloadshistory.accesskey;"
               oncommand="DownloadsPanel.showDownloadsHistory();"/>
     </panel>
   </popupset>
 </overlay>
--- a/browser/components/downloads/content/indicator.js
+++ b/browser/components/downloads/content/indicator.js
@@ -48,40 +48,16 @@ const DownloadsButton = {
    * if not available because it has been removed from the toolbars.
    */
   get _placeholder()
   {
     return document.getElementById("downloads-button");
   },
 
   /**
-   * This function is called synchronously at window initialization.  It only
-   * sets the visibility of user interface elements to avoid flickering.
-   *
-   * NOTE: To keep startup time to a minimum, this function should not perform
-   *       any expensive operations or input/output, and should not cause the
-   *       Download Manager service to start.
-   */
-  initializePlaceholder: function DB_initializePlaceholder()
-  {
-    // Exit now if the feature is disabled.  To improve startup time, we don't
-    // load the DownloadsCommon module yet, but check the preference directly.
-    if (gPrefService.getBoolPref("browser.download.useToolkitUI")) {
-      return;
-    }
-
-    // We must hide the placeholder used for toolbar customization, unless it
-    // has been removed from the toolbars and is now located in the palette.
-    let placeholder = this._placeholder;
-    if (placeholder) {
-      placeholder.collapsed = true;
-    }
-  },
-
-  /**
    * This function is called asynchronously just after window initialization.
    *
    * NOTE: This function should limit the input/output it performs to improve
    *       startup time, and in particular should not cause the Download Manager
    *       service to start.
    */
   initializeIndicator: function DB_initializeIndicator()
   {
@@ -136,22 +112,18 @@ const DownloadsButton = {
    *
    * NOTE: This function is also called on startup, thus it should limit the
    *       input/output it performs, and in particular should not cause the
    *       Download Manager service to start.
    */
   _update: function DB_update() {
     this._updatePositionInternal();
 
-    let placeholder = this._placeholder;
     if (!DownloadsCommon.useToolkitUI) {
       DownloadsIndicatorView.ensureInitialized();
-      if (placeholder) {
-        placeholder.collapsed = true;
-      }
     } else {
       DownloadsIndicatorView.ensureTerminated();
     }
   },
 
   /**
    * Determines the position where the indicator should appear, and moves its
    * associated element to the new position.  This does not happen if the
@@ -176,57 +148,49 @@ const DownloadsButton = {
   {
     let indicator = DownloadsIndicatorView.indicator;
     if (!indicator) {
       // Exit now if the indicator overlay isn't loaded yet.
       return null;
     }
 
     let placeholder = this._placeholder;
-
-    // Firstly, determine if we should always hide the indicator.
-    if (!placeholder && !this._anchorRequested &&
-        !DownloadsIndicatorView.hasDownloads) {
+    if (!placeholder) {
+      // The placeholder has been removed from the browser window.
       indicator.collapsed = true;
       return null;
     }
+
+    // Position the indicator where the placeholder is located.  We should
+    // update the position even if the placeholder is located on an invisible
+    // toolbar, because the toolbar may be displayed later.
+    placeholder.parentNode.insertBefore(indicator, placeholder);
+    placeholder.collapsed = true;
     indicator.collapsed = false;
 
     indicator.open = this._anchorRequested;
 
-    // Determine if we should display the indicator in a known position.
-    if (placeholder) {
-      placeholder.parentNode.insertBefore(indicator, placeholder);
-      // Determine if the placeholder is located on a visible toolbar.
-      if (isElementVisible(placeholder.parentNode)) {
-        return DownloadsIndicatorView.indicatorAnchor;
-      }
-    }
-
-    // If not customized, the indicator is normally in the navigation bar.
-    // Always place it in the default position, unless we need an anchor.
-    if (!this._anchorRequested) {
-      this._navBar.appendChild(indicator);
+    // Determine if the placeholder is located on an invisible toolbar.
+    if (!isElementVisible(placeholder.parentNode)) {
       return null;
     }
 
-    // Show the indicator temporarily in the navigation bar, if visible.
-    if (isElementVisible(this._navBar)) {
-      this._navBar.appendChild(indicator);
-      return DownloadsIndicatorView.indicatorAnchor;
-    }
+    return DownloadsIndicatorView.indicatorAnchor;
+  },
 
-    // Show the indicator temporarily in the tab bar, if visible.
-    if (!this._tabsToolbar.collapsed) {
-      this._tabsToolbar.appendChild(indicator);
-      return DownloadsIndicatorView.indicatorAnchor;
+  /**
+   * Indicates whether the indicator is visible in the browser window.
+   */
+  get isVisible()
+  {
+    if (!this._placeholder) {
+      return false;
     }
-
-    // The temporary anchor cannot be shown.
-    return null;
+    let element = DownloadsIndicatorView.indicator || this._placeholder;
+    return isElementVisible(element.parentNode);
   },
 
   /**
    * Indicates whether we should try and show the indicator temporarily as an
    * anchor for the panel, even if the indicator would be hidden by default.
    */
   _anchorRequested: false,
 
@@ -379,16 +343,20 @@ const DownloadsIndicatorView = {
       return;
     }
 
     function DIV_SEN_callback() {
       if (this._notificationTimeout) {
         clearTimeout(this._notificationTimeout);
       }
 
+      // Now that the overlay is loaded, place the indicator in its final
+      // position.
+      DownloadsButton.updatePosition();
+
       let indicator = this.indicator;
       indicator.setAttribute("notification", "true");
       this._notificationTimeout = setTimeout(
         function () indicator.removeAttribute("notification"), 1000);
     }
 
     this._ensureOperational(DIV_SEN_callback.bind(this));
   },
@@ -525,17 +493,17 @@ const DownloadsIndicatorView = {
 
   onCommand: function DIV_onCommand(aEvent)
   {
     if (DownloadsCommon.useToolkitUI) {
       // The panel won't suppress attention for us, we need to clear now.
       DownloadsCommon.indicatorData.attention = false;
     }
 
-    BrowserDownloadsUI();
+    DownloadsPanel.showPanel();
 
     aEvent.stopPropagation();
   },
 
   onDragOver: function DIV_onDragOver(aEvent)
   {
     browserDragAndDrop.dragOver(aEvent);
   },
--- a/browser/components/downloads/src/DownloadsCommon.jsm
+++ b/browser/components/downloads/src/DownloadsCommon.jsm
@@ -47,16 +47,18 @@ const Cr = Components.results;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "gBrowserGlue",
                                    "@mozilla.org/browser/browserglue;1",
                                    "nsIBrowserGlue");
 XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
                                   "resource://gre/modules/NetUtil.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
+                                  "resource://gre/modules/PluralForm.jsm");
 
 const nsIDM = Ci.nsIDownloadManager;
 
 const kDownloadsStringBundleUrl =
   "chrome://browser/locale/downloads/downloads.properties";
 
 const kDownloadsStringsRequiringFormatting = {
   sizeWithUnits: true,
@@ -64,16 +66,20 @@ const kDownloadsStringsRequiringFormatti
   shortTimeLeftMinutes: true,
   shortTimeLeftHours: true,
   shortTimeLeftDays: true,
   statusSeparator: true,
   statusSeparatorBeforeNumber: true,
   fileExecutableSecurityWarning: true
 };
 
+const kDownloadsStringsRequiringPluralForm = {
+  showMoreDownloads: true
+};
+
 XPCOMUtils.defineLazyGetter(this, "DownloadsLocalFileCtor", function () {
   return Components.Constructor("@mozilla.org/file/local;1",
                                 "nsILocalFile", "initWithPath");
 });
 
 ////////////////////////////////////////////////////////////////////////////////
 //// DownloadsCommon
 
@@ -97,16 +103,24 @@ const DownloadsCommon = {
       let stringName = string.key;
       if (stringName in kDownloadsStringsRequiringFormatting) {
         strings[stringName] = function () {
           // Convert "arguments" to a real array before calling into XPCOM.
           return sb.formatStringFromName(stringName,
                                          Array.slice(arguments, 0),
                                          arguments.length);
         };
+      } else if (stringName in kDownloadsStringsRequiringPluralForm) {
+        strings[stringName] = function (aCount) {
+          // Convert "arguments" to a real array before calling into XPCOM.
+          let formattedString = sb.formatStringFromName(stringName,
+                                         Array.slice(arguments, 0),
+                                         arguments.length);
+          return PluralForm.get(aCount, formattedString);
+        };
       } else {
         strings[stringName] = string.value;
       }
     }
     delete this.strings;
     return this.strings = strings;
   },
 
@@ -430,33 +444,36 @@ const DownloadsData = {
 
     if (aActiveOnly) {
       if (this._loadState == this.kLoadNone) {
         // Indicate to the views that a batch loading operation is in progress.
         this._views.forEach(
           function (view) view.onDataLoadStarting()
         );
 
-        // Reload the list using the Download Manager service.
+        // Reload the list using the Download Manager service.  The list is
+        // returned in no particular order.
         let downloads = Services.downloads.activeDownloads;
         while (downloads.hasMoreElements()) {
           let download = downloads.getNext().QueryInterface(Ci.nsIDownload);
           this._getOrAddDataItem(download, true);
         }
         this._loadState = this.kLoadActive;
 
         // Indicate to the views that the batch loading operation is complete.
         this._views.forEach(
           function (view) view.onDataLoadCompleted()
         );
       }
     } else {
       if (this._loadState != this.kLoadAll) {
         // Load only the relevant columns from the downloads database.  The
-        // columns are read in the init_FromDataRow method of DownloadsDataItem.
+        // columns are read in the _initFromDataRow method of DownloadsDataItem.
+        // Order by descending download identifier so that the most recent
+        // downloads are notified first to the listening views.
         let statement = Services.downloads.DBConnection.createAsyncStatement(
           "SELECT id, target, name, source, referrer, state, "
         +        "startTime, endTime, currBytes, maxBytes "
         + "FROM moz_downloads "
         + "ORDER BY id DESC"
         );
         try {
           this._pendingStatement = statement.executeAsync(this);
--- a/browser/components/downloads/src/DownloadsUI.js
+++ b/browser/components/downloads/src/DownloadsUI.js
@@ -63,62 +63,32 @@ DownloadsUI.prototype = {
       return;
     }
 
     if (!aReason) {
       aReason = Ci.nsIDownloadManagerUI.REASON_USER_INTERACTED;
     }
 
     if (aReason == Ci.nsIDownloadManagerUI.REASON_NEW_DOWNLOAD) {
-      // New download notifications are already handled by the panel service.
-      // We don't handle them here because we don't want them to depend on the
-      // "browser.download.manager.showWhenStarting" and
-      // "browser.download.manager.focusWhenStarting" preferences.
-      return;
+      // If the indicator is visible, then new download notifications are
+      // already handled by the panel service.
+      let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
+      if (browserWin &&
+          browserWin.windowState != Ci.nsIDOMChromeWindow.STATE_MINIMIZED &&
+          browserWin.DownloadsButton.isVisible) {
+        return;
+      }
     }
 
-    // Show the panel in the most recent browser window, if present.
-    let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
-    if (browserWin) {
-      // The most recent browser window could have been minimized, in that case
-      // it must be restored to allow the panel to open properly.
-      if (browserWin.windowState == Ci.nsIDOMChromeWindow.STATE_MINIMIZED) {
-        browserWin.restore();
-      }
-      browserWin.focus();
-      browserWin.DownloadsPanel.showPanel();
-      return;
-    }
-
-    // If no browser window is visible and the user requested to show the
-    // current downloads, try and open a new window.  We'll open the panel when
-    // delayed loading is finished.
-    Services.obs.addObserver(function DUIO_observe(aSubject, aTopic, aData) {
-      Services.obs.removeObserver(DUIO_observe, aTopic);
-      aSubject.DownloadsPanel.showPanel();
-    }, "browser-delayed-startup-finished", false);
-
-    // We must really build an empty arguments list for the new window.
-    let windowFirstArg = Cc["@mozilla.org/supports-string;1"]
-                         .createInstance(Ci.nsISupportsString);
-    let windowArgs = Cc["@mozilla.org/supports-array;1"]
-                     .createInstance(Ci.nsISupportsArray);
-    windowArgs.AppendElement(windowFirstArg);
-    Services.ww.openWindow(null, "chrome://browser/content/browser.xul",
-                           null, "chrome,dialog=no,all", windowArgs);
+    this._toolkitUI.show(aWindowContext, aID, aReason);
   },
 
   get visible()
   {
-    if (DownloadsCommon.useToolkitUI) {
-      return this._toolkitUI.visible;
-    }
-
-    let browserWin = gBrowserGlue.getMostRecentBrowserWindow();
-    return browserWin ? browserWin.DownloadsPanel.isPanelShowing : false;
+    return this._toolkitUI.visible;
   },
 
   getAttention: function DUI_getAttention()
   {
     if (DownloadsCommon.useToolkitUI) {
       this._toolkitUI.getAttention();
     }
   }
--- a/browser/components/downloads/test/browser/browser_basic_functionality.js
+++ b/browser/components/downloads/test/browser/browser_basic_functionality.js
@@ -19,16 +19,23 @@ function gen_test()
     { endTime: 1180493839859234, state: nsIDM.DOWNLOAD_FINISHED },
     { endTime: 1180493839859233, state: nsIDM.DOWNLOAD_FAILED },
     { endTime: 1180493839859232, state: nsIDM.DOWNLOAD_CANCELED },
     { endTime: 1180493839859231, state: nsIDM.DOWNLOAD_BLOCKED_PARENTAL },
     { endTime: 1180493839859230, state: nsIDM.DOWNLOAD_DIRTY },
     { endTime: 1180493839859229, state: nsIDM.DOWNLOAD_BLOCKED_POLICY },
   ];
 
+  // For testing purposes, show all the download items at once.
+  var originalCountLimit = DownloadsView.kItemCountLimit;
+  DownloadsView.kItemCountLimit = DownloadData.length;
+  registerCleanupFunction(function () {
+    DownloadsView.kItemCountLimit = originalCountLimit;
+  });
+
   try {
     // Ensure that state is reset in case previous tests didn't finish.
     for (let yy in gen_resetState()) yield;
 
     // Populate the downloads database with the data required by this test.
     for (let yy in gen_addDownloadRows(DownloadData)) yield;
 
     // Open the user interface and wait for data to be fully loaded.
--- a/browser/components/nsBrowserGlue.js
+++ b/browser/components/nsBrowserGlue.js
@@ -1180,17 +1180,17 @@ BrowserGlue.prototype = {
     var notifyBox = browser.getNotificationBox();
     var notification = notifyBox.appendNotification(text, title, null,
                                                     notifyBox.PRIORITY_CRITICAL_MEDIUM,
                                                     buttons);
     notification.persistence = -1; // Until user closes it
   },
 
   _migrateUI: function BG__migrateUI() {
-    const UI_VERSION = 6;
+    const UI_VERSION = 7;
     const BROWSER_DOCURL = "chrome://browser/content/browser.xul#";
     let currentUIVersion = 0;
     try {
       currentUIVersion = Services.prefs.getIntPref("browser.migration.version");
     } catch(ex) {}
     if (currentUIVersion >= UI_VERSION)
       return;
 
@@ -1278,16 +1278,53 @@ BrowserGlue.prototype = {
       // convert tabsontop attribute to pref
       let toolboxResource = this._rdf.GetResource(BROWSER_DOCURL + "navigator-toolbox");
       let tabsOnTopResource = this._rdf.GetResource("tabsontop");
       let tabsOnTopAttribute = this._getPersist(toolboxResource, tabsOnTopResource);
       if (tabsOnTopAttribute)
         Services.prefs.setBoolPref("browser.tabs.onTop", tabsOnTopAttribute == "true");
     }
 
+    // This migration step is executed only if the Downloads Panel feature is
+    // enabled.  By default, the feature is enabled only in the Nightly channel.
+    // This means that, unless the preference that enables the feature is
+    // changed manually, the Downloads button is added to the toolbar only if
+    // migration happens while running a build from the Nightly channel.  This
+    // migration code will be updated when the feature will be enabled on all
+    // channels, see bug 748381 for details.
+    if (currentUIVersion < 7 &&
+        !Services.prefs.getBoolPref("browser.download.useToolkitUI")) {
+      // This code adds the customizable downloads buttons.
+      let currentsetResource = this._rdf.GetResource("currentset");
+      let toolbarResource = this._rdf.GetResource(BROWSER_DOCURL + "nav-bar");
+      let currentset = this._getPersist(toolbarResource, currentsetResource);
+
+      // Since the Downloads button is located in the navigation bar by default,
+      // migration needs to happen only if the toolbar was customized using a
+      // previous UI version, and the button was not already placed on the
+      // toolbar manually.
+      if (currentset &&
+          currentset.indexOf("downloads-button") == -1) {
+        // The element is added either after the search bar or before the home
+        // button. As a last resort, the element is added just before the
+        // non-customizable window controls.
+        if (currentset.indexOf("search-container") != -1) {
+          currentset = currentset.replace(/(^|,)search-container($|,)/,
+                                          "$1search-container,downloads-button$2")
+        } else if (currentset.indexOf("home-button") != -1) {
+          currentset = currentset.replace(/(^|,)home-button($|,)/,
+                                          "$1downloads-button,home-button$2")
+        } else {
+          currentset = currentset.replace(/(^|,)window-controls($|,)/,
+                                          "$1downloads-button,window-controls$2")
+        }
+        this._setPersist(toolbarResource, currentsetResource, currentset);
+      }
+    }
+
     if (this._dirty)
       this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
 
     delete this._rdf;
     delete this._dataSource;
 
     // Update the migration version.
     Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
--- a/browser/components/preferences/main.js
+++ b/browser/components/preferences/main.js
@@ -18,35 +18,22 @@ var gMainPane = {
     this._pane = document.getElementById("paneMain");
 
     // set up the "use current page" label-changing listener
     this._updateUseCurrentButton();
     window.addEventListener("focus", this._updateUseCurrentButton.bind(this), false);
 
     this.updateBrowserStartupLastSession();
 
-    this.setupDownloadsWindowOptions();
-
     // Notify observers that the UI is now ready
     Components.classes["@mozilla.org/observer-service;1"]
               .getService(Components.interfaces.nsIObserverService)
               .notifyObservers(window, "main-pane-loaded", null);
   },
 
-  setupDownloadsWindowOptions: function ()
-  {
-    var showWhenDownloading = document.getElementById("showWhenDownloading");
-    var closeWhenDone = document.getElementById("closeWhenDone");
-
-    // These radio-buttons should not be visible if we have enabled the Downloads Panel.
-    let shouldHide = !DownloadsCommon.useToolkitUI;
-    showWhenDownloading.hidden = shouldHide;
-    closeWhenDone.hidden = shouldHide;
-  },
-
   // HOME PAGE
 
   /*
    * Preferences:
    *
    * browser.startup.homepage
    * - the user's home page, as a string; if the home page is a set of tabs,
    *   this will be those URLs separated by the pipe character "|"
--- a/browser/config/mozconfigs/win32/debug
+++ b/browser/config/mozconfigs/win32/debug
@@ -1,17 +1,21 @@
 ac_add_options --enable-debug
 ac_add_options --enable-trace-malloc
 ac_add_options --enable-signmar
 ENABLE_MARIONETTE=1
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
-mk_add_options MOZ_MAKE_FLAGS=-j1
+if test -n "${_PYMAKE}"; then
+  mk_add_options MOZ_MAKE_FLAGS=-j4
+else
+  mk_add_options MOZ_MAKE_FLAGS=-j1
+fi
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Package js shell.
--- a/browser/config/mozconfigs/win32/nightly
+++ b/browser/config/mozconfigs/win32/nightly
@@ -10,17 +10,21 @@ ac_add_options --enable-profiling
 # Nightlies only since this has a cost in performance
 ac_add_options --enable-js-diagnostics
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
-mk_add_options MOZ_MAKE_FLAGS=-j1
+if test -n "${_PYMAKE}"; then
+  mk_add_options MOZ_MAKE_FLAGS=-j4
+else
+  mk_add_options MOZ_MAKE_FLAGS=-j1
+fi
 
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Package js shell.
--- a/browser/config/mozconfigs/win32/release
+++ b/browser/config/mozconfigs/win32/release
@@ -7,16 +7,22 @@ ac_add_options --enable-update-packaging
 ac_add_options --enable-jemalloc
 ac_add_options --enable-official-branding
 
 # Needed to enable breakpad in application.ini
 export MOZILLA_OFFICIAL=1
 
 export MOZ_TELEMETRY_REPORTING=1
 
+if test -n "${_PYMAKE}"; then
+  mk_add_options MOZ_MAKE_FLAGS=-j4
+else
+  mk_add_options MOZ_MAKE_FLAGS=-j1
+fi
+
 if test "$PROCESSOR_ARCHITECTURE" = "AMD64" -o "$PROCESSOR_ARCHITEW6432" = "AMD64"; then
   . $topsrcdir/build/win32/mozconfig.vs2010-win64
 else
   . $topsrcdir/build/win32/mozconfig.vs2010
 fi
 
 # Package js shell.
 export MOZ_PACKAGE_JSSHELL=1
--- a/browser/locales/en-US/chrome/browser/browser.properties
+++ b/browser/locales/en-US/chrome/browser/browser.properties
@@ -371,22 +371,22 @@ telemetryOptOutPrompt = %1$S sends infor
 fullscreen.entered=%S is now fullscreen.
 # LOCALIZATION NOTE (fullscreen.rememberDecision): displayed when we enter HTML5 fullscreen mode, %S is the domain name of the focused website (e.g. mozilla.com).
 fullscreen.rememberDecision=Remember decision for %S
 
 social.shareButton.tooltip=Share this
 social.shareButton.sharedtooltip=You shared this
 social.pageShared.label=Page shared
 
-# LOCALIZATION NOTE (social.enable.label): %S = Social networking provider
-social.enable.label=%S integration
-social.enable.accesskey=n
+# LOCALIZATION NOTE (social.toggle.label): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
+social.toggle.label=%1$S for %2$S
+social.toggle.accesskey=f
 
-# LOCALIZATION NOTE (social.enabled.message): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
-social.activated.message=%1$S integration with %2$S has been activated.
+# LOCALIZATION NOTE (social.activated.description): %1$S is the name of the social provider, %2$S is brandShortName (e.g. Firefox)
+social.activated.description=You've turned on %1$S for %2$S.
 
 # LOCALIZATION NOTE (social.error.message): %1$S is brandShortName (e.g. Firefox), %2$S is the name of the social provider
 social.error.message=%1$S is unable to connect with %2$S right now.
 social.error.tryAgain.label=Try Again
 social.error.tryAgain.accesskey=T
 social.error.ok.label=OK
 social.error.ok.accesskey=O
 social.error.closeSidebar.label=Close This Sidebar
--- a/browser/locales/en-US/chrome/browser/downloads/downloads.dtd
+++ b/browser/locales/en-US/chrome/browser/downloads/downloads.dtd
@@ -39,10 +39,8 @@
 <!ENTITY cmd.goToDownloadPage.accesskey   "G">
 <!ENTITY cmd.copyDownloadLink.label       "Copy Download Link">
 <!ENTITY cmd.copyDownloadLink.accesskey   "L">
 <!ENTITY cmd.removeFromList.label         "Remove From List">
 <!ENTITY cmd.removeFromList.accesskey     "e">
 <!ENTITY cmd.clearList.label              "Clear List">
 <!ENTITY cmd.clearList.accesskey          "a">
 
-<!ENTITY downloadshistory.label           "Show All Downloads">
-<!ENTITY downloadshistory.accesskey       "S">
--- a/browser/locales/en-US/chrome/browser/downloads/downloads.properties
+++ b/browser/locales/en-US/chrome/browser/downloads/downloads.properties
@@ -62,11 +62,25 @@ shortTimeLeftDays=%1$Sd
 # that we use a wider space after the separator when it is followed by a number,
 # just to avoid visually confusing it with with a minus sign with some fonts.
 # If you use a different separator, this might not be necessary.  However, there
 # is usually no need to change the separator or the order of the substitutions,
 # even for right-to-left languages, unless the defaults are not suitable.
 statusSeparator=%1$S \u2014 %2$S
 statusSeparatorBeforeNumber=%1$S \u2014  %2$S
 
+# LOCALIZATION NOTE (showMoreDownloads):
+# This string is shown in the Downloads Panel when there are more active
+# downloads than can fit in the available space.  The phrase should be read as
+# "Show N more of my recent downloads".  Use a semi-colon list of plural forms.
+# See: http://developer.mozilla.org/en/Localization_and_Plurals
+showMoreDownloads=Show 1 More Recent Download;Show %1$S More Recent Downloads
+# LOCALIZATION NOTE (showAllDownloads):
+# This string is shown in place of showMoreDownloads when all the downloads fit
+# in the available space, or when there are no downloads in the panel at all.
+showAllDownloads=Show All Downloads
+# LOCALIZATION NOTE (showDownloadsAccessKey):
+# This access key applies to both showMoreDownloads and showAllDownloads.
+showDownloadsAccessKey=S
+
 fileExecutableSecurityWarning="%S" is an executable file. Executable files may contain viruses or other malicious code that could harm your computer. Use caution when opening this file. Are you sure you want to launch "%S"?
 fileExecutableSecurityWarningTitle=Open Executable File?
 fileExecutableSecurityWarningDontAsk=Don't ask me this again
index abff1bc4e26a27dae77a48b861179a1024829ab0..735804b44f1625ffc5c35dcb1678fca0c4c39b6c
GIT binary patch
literal 2485
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
--- a/browser/themes/gnomestripe/downloads/downloads.css
+++ b/browser/themes/gnomestripe/downloads/downloads.css
@@ -36,17 +36,18 @@
 /*** List items ***/
 
 richlistitem[type="download"] {
   height: 6em;
   margin: 0;
   border-top: 1px solid hsla(0,0%,100%,.2);
   border-bottom: 1px solid hsla(0,0%,0%,.15);
   background: transparent;
-  padding: 0;
+  padding: 8px;
+  -moz-padding-end: 0;
   color: inherit;
 }
 
 richlistitem[type="download"]:first-child {
   border-top: 1px solid transparent;
 }
 
 richlistitem[type="download"]:last-child {
@@ -54,21 +55,16 @@ richlistitem[type="download"]:last-child
 }
 
 #downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
   outline: 1px #999 dotted;
   outline-offset: -1px;
   -moz-outline-radius: 3px;
 }
 
-.downloadInfo {
-  padding: 8px;
-  -moz-padding-end: 0;
-}
-
 .downloadTypeIcon {
   -moz-margin-end: 8px;
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
 
 .blockedIcon {
@@ -86,75 +82,79 @@ richlistitem[type="download"]:last-child
   font-size: 90%;
   cursor: inherit;
 }
 
 .downloadButton {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  margin: 6px;
+  margin: 3px;
   border: none;
   background: transparent;
   padding: 5px;
   list-style-image: url("chrome://browser/skin/downloads/buttons.png");
 }
 
 .downloadButton > .button-box {
   padding: 0;
 }
 
 /*** Highlighted list items ***/
 
-richlistitem[type="download"][state="1"] > .downloadInfo {
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
-  -moz-padding-end: 8px;
-}
-
-richlistitem[type="download"][state="1"] > .downloadInfo:hover {
+richlistitem[type="download"][state="1"]:hover {
   border-radius: 3px;
   border-top: 1px solid hsla(0,0%,100%,.3);
   border-bottom: 1px solid hsla(0,0%,0%,.2);
   background-color: Highlight;
   background-image: -moz-linear-gradient(hsla(0,0%,100%,.1), hsla(0,0%,100%,0));
   color: HighlightText;
   cursor: pointer;
 }
 
 /*** Button icons ***/
 
 .downloadButton.downloadCancel {
-  -moz-image-region: rect(0px, 14px, 14px, 0px);
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 .downloadButton.downloadCancel:hover {
-  -moz-image-region: rect(0px, 28px, 14px, 14px);
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 .downloadButton.downloadCancel:active {
-  -moz-image-region: rect(0px, 42px, 14px, 28px);
+  -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 .downloadButton.downloadShow {
-  -moz-image-region: rect(14px, 14px, 28px, 0px);
+  -moz-image-region: rect(16px, 16px, 32px, 0px);
 }
 .downloadButton.downloadShow:hover {
-  -moz-image-region: rect(14px, 28px, 28px, 14px);
+  -moz-image-region: rect(16px, 32px, 32px, 16px);
 }
 .downloadButton.downloadShow:active {
-  -moz-image-region: rect(14px, 42px, 28px, 28px);
+  -moz-image-region: rect(16px, 48px, 32px, 32px);
 }
 
 .downloadButton.downloadRetry {
-  -moz-image-region: rect(28px, 14px, 42px, 0px);
+  -moz-image-region: rect(32px, 16px, 48px, 0px);
 }
 .downloadButton.downloadRetry:hover {
-  -moz-image-region: rect(28px, 28px, 42px, 14px);
+  -moz-image-region: rect(32px, 32px, 48px, 16px);
 }
 .downloadButton.downloadRetry:active {
-  -moz-image-region: rect(28px, 42px, 42px, 28px);
+  -moz-image-region: rect(32px, 48px, 48px, 32px);
+}
+
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow {
+  -moz-image-region: rect(48px, 16px, 64px, 0px);
+}
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:hover {
+  -moz-image-region: rect(48px, 32px, 64px, 16px);
+}
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:active {
+  -moz-image-region: rect(48px, 48px, 64px, 32px);
 }
 
 /*** Status and progress indicator ***/
 
 #downloads-indicator {
   width: 35px;
 }
 
@@ -223,56 +223,56 @@ richlistitem[type="download"][state="1"]
 
 #downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
   animation-name: downloadsIndicatorNotificationLeft;
 }
 
 /*** Progress bar and text ***/
 
 #downloads-indicator-counter {
-  height: 12px;
+  height: 10px;
   margin: 0;
   color: hsl(0,0%,30%);
   text-shadow: 0 1px 0 hsla(0,0%,100%,.5);
   font-size: 10px;
   line-height: 10px;
   text-align: center;
 }
 
 #downloads-indicator-progress {
-  width: 24px;
-  height: 4px;
+  width: 16px;
+  height: 6px;
   min-width: 0;
   min-height: 0;
   margin-top: 1px;
   margin-bottom: 2px;
   border-radius: 2px;
   box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
 }
 
 #downloads-indicator-progress > .progress-bar {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#41a0ff, #2090ff);
+  background-image: -moz-linear-gradient(#5ab9ff, #37a4ff);
   border: 1px solid;
-  border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
+  border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
   border-radius: 2px 0 0 2px;
 }
 
 #downloads-indicator-progress > .progress-remainder {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
+  background-image: -moz-linear-gradient(#505050, #575757);
   border: 1px solid;
-  border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
+  border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.4) hsla(0,0%,0%,.4);
   -moz-border-start: none;
   border-radius: 0 2px 2px 0;
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
-  background-image: -moz-linear-gradient(#a0a000, #909000);
+  background-image: -moz-linear-gradient(#dce651, #dae631);
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
-  background-image: -moz-linear-gradient(#9a9a00, #a1a100);
+  background-image: -moz-linear-gradient(#4b5000, #515700);
 }
index 0b5161ff01e345592da15d696a7f8de985f5db5d..ce6ab03484051df84b7f9ed159cc74fbc442905b
GIT binary patch
literal 1756
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
--- a/browser/themes/pinstripe/downloads/downloads.css
+++ b/browser/themes/pinstripe/downloads/downloads.css
@@ -55,17 +55,18 @@
 /*** List items ***/
 
 richlistitem[type="download"] {
   height: 7em;
   margin: 0;
   border-top: 1px solid hsla(0,0%,100%,.07);
   border-bottom: 1px solid hsla(0,0%,0%,.2);
   background: transparent;
-  padding: 0;
+  padding: 8px;
+  -moz-padding-end: 0;
   color: inherit;
 }
 
 richlistitem[type="download"]:first-child {
   border-top: 1px solid transparent;
 }
 
 richlistitem[type="download"]:last-child {
@@ -73,21 +74,16 @@ richlistitem[type="download"]:last-child
 }
 
 #downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
   outline: 1px #999 dotted;
   outline-offset: -1px;
   -moz-outline-radius: 3px;
 }
 
-.downloadInfo {
-  padding: 8px;
-  -moz-padding-end: 0;
-}
-
 .downloadTypeIcon {
   -moz-margin-end: 8px;
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
 
 .blockedIcon {
@@ -104,75 +100,69 @@ richlistitem[type="download"]:last-child
   font-size: 95%;
   cursor: inherit;
 }
 
 .downloadButton {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  margin: 6px;
+  margin: 3px;
   border: none;
   background: transparent;
   padding: 5px;
   list-style-image: url("chrome://browser/skin/downloads/buttons.png");
 }
 
 .downloadButton > .button-box {
   padding: 0;
 }
 
 /*** Highlighted list items ***/
 
-richlistitem[type="download"][state="1"] .downloadInfo {
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
-  -moz-padding-end: 8px;
-}
-
-richlistitem[type="download"][state="1"] .downloadInfo:hover {
+richlistitem[type="download"][state="1"]:hover {
   border-radius: 3px;
   border-top: 1px solid hsla(0,0%,100%,.2);
   border-bottom: 1px solid hsla(0,0%,0%,.4);
   background-color: Highlight;
   background-image: -moz-linear-gradient(hsl(210,100%,50%), hsl(210,96%,41%));
   color: HighlightText;
   cursor: pointer;
 }
 
 /*** Button icons ***/
 
 .downloadButton.downloadCancel {
-  -moz-image-region: rect(0px, 14px, 14px, 0px);
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 .downloadButton.downloadCancel:hover {
-  -moz-image-region: rect(0px, 28px, 14px, 14px);
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 .downloadButton.downloadCancel:active {
-  -moz-image-region: rect(0px, 42px, 14px, 28px);
+  -moz-image-region: rect(0px, 48px, 16px, 28px);
 }
 
 .downloadButton.downloadShow {
-  -moz-image-region: rect(14px, 14px, 28px, 0px);
+  -moz-image-region: rect(16px, 16px, 32px, 0px);
 }
 .downloadButton.downloadShow:hover {
-  -moz-image-region: rect(14px, 28px, 28px, 14px);
+  -moz-image-region: rect(16px, 32px, 32px, 16px);
 }
 .downloadButton.downloadShow:active {
-  -moz-image-region: rect(14px, 42px, 28px, 28px);
+  -moz-image-region: rect(16px, 48px, 32px, 32px);
 }
 
 .downloadButton.downloadRetry {
-  -moz-image-region: rect(28px, 14px, 42px, 0px);
+  -moz-image-region: rect(32px, 16px, 48px, 0px);
 }
 .downloadButton.downloadRetry:hover {
-  -moz-image-region: rect(28px, 28px, 42px, 14px);
+  -moz-image-region: rect(32px, 32px, 48px, 16px);
 }
 .downloadButton.downloadRetry:active {
-  -moz-image-region: rect(28px, 42px, 42px, 28px);
+  -moz-image-region: rect(32px, 48px, 48px, 32px);
 }
 
 /*** Status and progress indicator ***/
 
 #downloads-indicator {
   width: 35px;
 }
 
@@ -244,56 +234,56 @@ richlistitem[type="download"][state="1"]
 
 #downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
   animation-name: downloadsIndicatorNotificationLeft;
 }
 
 /*** Progress bar and text ***/
 
 #downloads-indicator-counter {
-  height: 12px;
+  height: 10px;
   margin: 0;
   color: hsl(0,0%,30%);
   text-shadow: 0 1px 0 hsla(0,0%,100%,.5);
   font-size: 10px;
   line-height: 10px;
   text-align: center;
 }
 
 #downloads-indicator-progress {
-  width: 24px;
-  height: 4px;
+  width: 16px;
+  height: 6px;
   min-width: 0;
   min-height: 0;
   margin-top: 1px;
   margin-bottom: 2px;
   border-radius: 2px;
   box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
 }
 
 #downloads-indicator-progress > .progress-bar {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#41a0ff, #2090ff);
+  background-image: -moz-linear-gradient(#5ab9ff, #37a4ff);
   border: 1px solid;
-  border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
+  border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
   border-radius: 2px 0 0 2px;
 }
 
 #downloads-indicator-progress > .progress-remainder {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
+  background-image: -moz-linear-gradient(#505050, #575757);
   border: 1px solid;
-  border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
+  border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.4) hsla(0,0%,0%,.4);
   -moz-border-start: none;
   border-radius: 0 2px 2px 0;
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
-  background-image: -moz-linear-gradient(#a0a000, #909000);
+  background-image: -moz-linear-gradient(#dce651, #dae631);
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
-  background-image: -moz-linear-gradient(#9a9a00, #a1a100);
+  background-image: -moz-linear-gradient(#4b5000, #515700);
 }
index 22592cd6c991067145b4571f1b056ee553f92438..68b342bbf6edd2874f6f641a6dbc043594c310f1
GIT binary patch
literal 3185
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
Xi=?)Rgw%<=00000NkvXXu0mjfW4!x!
index 586e59bdc4d5e21f5ac56c258d9a14c31a09d946..63ad7fdea8fadecbbe1f23b49a7425edf78f9c51
GIT binary patch
literal 3286
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
Uho>Vc>Hq)$07*qoM6N<$f@gy(j{pDw
--- a/browser/themes/winstripe/downloads/downloads-aero.css
+++ b/browser/themes/winstripe/downloads/downloads-aero.css
@@ -11,22 +11,17 @@
     background-color: #f1f5fb;
   }
 
   richlistitem[type="download"] {
     border: 1px solid transparent;
     border-bottom: 1px solid hsl(213,40%,90%);
   }
 
-  richlistitem[type="download"][state="1"] > .downloadInfo {
-    border: 1px solid transparent;
-    -moz-padding-end: 8px;
-  }
-
-  richlistitem[type="download"][state="1"] > .downloadInfo:hover {
+  richlistitem[type="download"][state="1"]:hover {
     border: 1px solid hsl(213,45%,65%);
     box-shadow: 0 0 0 1px hsla(0,0%,100%,.5) inset,
                 0 1px 0 hsla(0,0%,100%,.3) inset;
     background-image: -moz-linear-gradient(hsl(212,86%,92%), hsl(212,91%,86%));
     color: black;
   }
 }
 
--- a/browser/themes/winstripe/downloads/downloads.css
+++ b/browser/themes/winstripe/downloads/downloads.css
@@ -48,17 +48,18 @@
 /*** List items ***/
 
 richlistitem[type="download"] {
   height: 7em;
   margin: 0;
   border-top: 1px solid hsla(0,0%,100%,.3);
   border-bottom: 1px solid hsla(220,18%,51%,.25);
   background: transparent;
-  padding: 0;
+  padding: 8px;
+  -moz-padding-end: 0;
   color: inherit;
 }
 
 richlistitem[type="download"]:first-child {
   border-top: 1px solid transparent;
 }
 
 @media (-moz-windows-default-theme) {
@@ -68,21 +69,16 @@ richlistitem[type="download"]:first-chil
 }
 
 #downloadsListBox:-moz-focusring > richlistitem[type="download"][selected] {
   outline: 1px #999 dotted;
   outline-offset: -1px;
   -moz-outline-radius: 3px;
 }
 
-.downloadInfo {
-  padding: 8px;
-  -moz-padding-end: 0;
-}
-
 .downloadTypeIcon {
   -moz-margin-end: 8px;
   /* Prevent flickering when changing states. */
   min-height: 32px;
   min-width: 32px;
 }
 
 .blockedIcon {
@@ -99,83 +95,87 @@ richlistitem[type="download"]:first-chil
   font-size: 90%;
   cursor: inherit;
 }
 
 .downloadButton {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  margin: 6px;
+  margin: 3px;
   border: none;
   background: transparent;
   padding: 5px;
   list-style-image: url("chrome://browser/skin/downloads/buttons.png");
 }
 
 .downloadButton > .button-box {
   padding: 0;
 }
 
 /*** Highlighted list items ***/
 
-%ifdef WINSTRIPE_AERO
-@media not all and (-moz-windows-default-theme) {
-%endif
-
-richlistitem[type="download"][state="1"] > .downloadInfo {
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
-  -moz-padding-end: 8px;
-}
-
-%ifdef WINSTRIPE_AERO
-}
-%endif
-
-richlistitem[type="download"][state="1"] > .downloadInfo:hover {
+richlistitem[type="download"][state="1"]:hover {
   border-radius: 3px;
   border-top: 1px solid hsla(0,0%,100%,.2);
   border-bottom: 1px solid hsla(0,0%,0%,.2);
   background-color: Highlight;
   color: HighlightText;
   cursor: pointer;
 }
 
 /*** Button icons ***/
 
 .downloadButton.downloadCancel {
-  -moz-image-region: rect(0px, 14px, 14px, 0px);
+  -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 .downloadButton.downloadCancel:hover {
-  -moz-image-region: rect(0px, 28px, 14px, 14px);
+  -moz-image-region: rect(0px, 32px, 16px, 16px);
 }
 .downloadButton.downloadCancel:active {
-  -moz-image-region: rect(0px, 42px, 14px, 28px);
+  -moz-image-region: rect(0px, 48px, 16px, 32px);
 }
 
 .downloadButton.downloadShow {
-  -moz-image-region: rect(14px, 14px, 28px, 0px);
+  -moz-image-region: rect(16px, 16px, 32px, 0px);
 }
 .downloadButton.downloadShow:hover {
-  -moz-image-region: rect(14px, 28px, 28px, 14px);
+  -moz-image-region: rect(16px, 32px, 32px, 16px);
 }
 .downloadButton.downloadShow:active {
-  -moz-image-region: rect(14px, 42px, 28px, 28px);
+  -moz-image-region: rect(16px, 48px, 32px, 32px);
 }
 
 .downloadButton.downloadRetry {
-  -moz-image-region: rect(28px, 14px, 42px, 0px);
+  -moz-image-region: rect(32px, 16px, 48px, 0px);
 }
 .downloadButton.downloadRetry:hover {
-  -moz-image-region: rect(28px, 28px, 42px, 14px);
+  -moz-image-region: rect(32px, 32px, 48px, 16px);
 }
 .downloadButton.downloadRetry:active {
-  -moz-image-region: rect(28px, 42px, 42px, 28px);
+  -moz-image-region: rect(32px, 48px, 48px, 32px);
+}
+
+%ifdef WINSTRIPE_AERO
+@media not all and (-moz-windows-default-theme) {
+%endif
+
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow {
+  -moz-image-region: rect(48px, 16px, 64px, 0px);
 }
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:hover {
+  -moz-image-region: rect(48px, 32px, 64px, 16px);
+}
+richlistitem[type="download"][state="1"]:hover > .downloadButton.downloadShow:active {
+  -moz-image-region: rect(48px, 48px, 64px, 32px);
+}
+
+%ifdef WINSTRIPE_AERO
+}
+%endif
 
 /*** Status and progress indicator ***/
 
 #downloads-indicator {
   width: 35px;
 }
 
 #downloads-indicator-anchor {
@@ -243,62 +243,62 @@ richlistitem[type="download"][state="1"]
 
 #downloads-indicator[notification]:-moz-locale-dir(rtl) > #downloads-indicator-anchor > #downloads-indicator-notification {
   animation-name: downloadsIndicatorNotificationLeft;
 }
 
 /*** Progress bar and text ***/
 
 #downloads-indicator-counter {
-  height: 12px;
+  height: 10px;
   margin: 0;
   color: hsl(0,0%,30%);
   text-shadow: hsla(0,0%,100%,.5) 0 1px;
   font-size: 10px;
   line-height: 10px;
   text-align: center;
 }
 
 #downloads-indicator-counter:-moz-lwtheme-brighttext {
   color: white;
   text-shadow: 0 0 1px rgba(0,0,0,.7),
                0 1px 1.5px rgba(0,0,0,.5);
 }
 
 #downloads-indicator-progress {
-  width: 24px;
-  height: 4px;
+  width: 16px;
+  height: 6px;
   min-width: 0;
   min-height: 0;
   margin-top: 1px;
   margin-bottom: 2px;
   border-radius: 2px;
   box-shadow: 0 1px 0 hsla(0,0%,100%,.4);
 }
 
 #downloads-indicator-progress > .progress-bar {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#92DDA0, #6FC483 49%, #5EB272 51%, #80CE91);
+  background-image: -moz-linear-gradient(#5ab9ff, #37a4ff);
   border: 1px solid;
-  border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.2) hsla(0,0%,0%,.2);
+  border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
   border-radius: 2px 0 0 2px;
 }
 
 #downloads-indicator-progress > .progress-remainder {
   -moz-appearance: none;
   min-width: 0;
   min-height: 0;
-  background-image: -moz-linear-gradient(#9a9a9a, #a1a1a1);
+  background-image: -moz-linear-gradient(#505050, #575757);
   border: 1px solid;
-  border-color: hsla(0,0%,0%,.4) hsla(0,0%,0%,.3) hsla(0,0%,0%,.2);
+  border-color: hsla(0,0%,0%,.6) hsla(0,0%,0%,.4) hsla(0,0%,0%,.4);
   -moz-border-start: none;
   border-radius: 0 2px 2px 0;
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-bar {
-  background-image: -moz-linear-gradient(#DDDD00, #C4C400 49%, #B2B200 51%, #CECE00);
+  background-image: -moz-linear-gradient(#dce651, #dae631);
 }
 
 #downloads-indicator[paused] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-progress > .progress-remainder {
-  background-image: -moz-linear-gradient(#9a9a00, #a1a100);
+  background-image: -moz-linear-gradient(#4b5000, #515700);
 }
--- a/configure.in
+++ b/configure.in
@@ -7654,17 +7654,17 @@ MOZ_ARG_DISABLE_BOOL(md,
      _cpp_md_flag=1
    fi
   dnl Default is to use -xM if using Sun Studio on Solaris
    if test "$SOLARIS_SUNPRO_CC"; then
      _cpp_md_flag=1
    fi])
 if test "$_cpp_md_flag"; then
   COMPILER_DEPEND=1
-  _DEPEND_CFLAGS='$(filter-out %/.pp,-MMD -MF $(MDDEPDIR)/$(@F).pp)'
+  _DEPEND_CFLAGS='$(filter-out %/.pp,-MD -MF $(MDDEPDIR)/$(@F).pp)'
   dnl Sun Studio on Solaris use -xM instead of -MD, see config/rules.mk
   if test "$SOLARIS_SUNPRO_CC"; then
     _DEPEND_CFLAGS=
   fi
 else
   COMPILER_DEPEND=
   dnl Don't override this for MSVC
   if test -z "$_WIN32_MSVC"; then
--- a/content/base/public/nsIObjectLoadingContent.idl
+++ b/content/base/public/nsIObjectLoadingContent.idl
@@ -16,17 +16,17 @@ interface nsIURI;
 #include "nsNPAPIPluginInstance.h"
 %}
 [ptr] native nsNPAPIPluginInstancePtr(nsNPAPIPluginInstance);
 
 /**
  * This interface represents a content node that loads objects.
  */
 
-[scriptable, uuid(8ed953b4-5022-4a49-bed4-6818f85dc113)]
+[scriptable, uuid(a812424b-4820-4e28-96c8-dd2b69e36496)]
 interface nsIObjectLoadingContent : nsISupports
 {
   /**
    * See notes in nsObjectLoadingContent.h
    */
   const unsigned long TYPE_LOADING  = 0;
   const unsigned long TYPE_IMAGE    = 1;
   const unsigned long TYPE_PLUGIN   = 2;
@@ -50,16 +50,18 @@ interface nsIObjectLoadingContent : nsIS
   // Blocked by content policy
   const unsigned long PLUGIN_USER_DISABLED        = 7;
   // The plugin is disabled until the user clicks on it
   const unsigned long PLUGIN_CLICK_TO_PLAY        = 8;
   // The plugin is vulnerable (update available)
   const unsigned long PLUGIN_VULNERABLE_UPDATABLE = 9;
   // The plugin is vulnerable (no update available)
   const unsigned long PLUGIN_VULNERABLE_NO_UPDATE = 10;
+  // The plugin is in play preview mode
+  const unsigned long PLUGIN_PLAY_PREVIEW         = 11;
 
   /**
    * The actual mime type (the one we got back from the network
    * request) for the element.
    */
   readonly attribute ACString actualType;
 
   /**
@@ -108,26 +110,31 @@ interface nsIObjectLoadingContent : nsIS
 
   /**
    * This method will play a plugin that has been stopped by the
    * click-to-play plugins feature.
    */
   void playPlugin();
 
   /**
-   * This attribute will return true if the plugin has been activated
-   * and false if the plugin is still in the click-to-play state.
+   * This attribute will return true if the plugin has been activated and
+   * false if the plugin is still in the click-to-play or play preview state.
    */
   readonly attribute boolean activated;
 
   [noscript] void stopPluginInstance();
 
   [noscript] void syncStartPluginInstance();
   [noscript] void asyncStartPluginInstance();
 
   /**
    * The URL of the data/src loaded in the object. This may be null (i.e.
    * an <embed> with no src).
    */
   readonly attribute nsIURI srcURI;
 
   readonly attribute unsigned long pluginFallbackType;
+
+  /**
+   * This method will disable the play-preview plugin state.
+   */
+  void cancelPlayPreview();
 };
--- a/content/base/src/nsObjectLoadingContent.cpp
+++ b/content/base/src/nsObjectLoadingContent.cpp
@@ -183,16 +183,19 @@ nsPluginErrorEvent::Run()
       type = NS_LITERAL_STRING("PluginVulnerableUpdatable");
       break;
     case nsObjectLoadingContent::eFallbackVulnerableNoUpdate:
       type = NS_LITERAL_STRING("PluginVulnerableNoUpdate");
       break;
     case nsObjectLoadingContent::eFallbackClickToPlay:
       type = NS_LITERAL_STRING("PluginClickToPlay");
       break;
+    case nsObjectLoadingContent::eFallbackPlayPreview:
+      type = NS_LITERAL_STRING("PluginPlayPreview");
+      break;
     case nsObjectLoadingContent::eFallbackUnsupported:
       type = NS_LITERAL_STRING("PluginNotFound");
       break;
     case nsObjectLoadingContent::eFallbackDisabled:
       type = NS_LITERAL_STRING("PluginDisabled");
       break;
     case nsObjectLoadingContent::eFallbackBlocklisted:
       type = NS_LITERAL_STRING("PluginBlocklisted");
@@ -654,16 +657,17 @@ nsObjectLoadingContent::nsObjectLoadingC
   : mPendingInstantiateEvent(nullptr)
   , mChannel(nullptr)
   , mType(eType_Loading)
   , mFallbackType(eFallbackAlternate)
   , mChannelLoaded(false)
   , mInstantiating(false)
   , mNetworkCreated(true)
   , mActivated(false)
+  , mPlayPreviewCanceled(false)
   , mIsStopping(false)
   , mIsLoading(false)
   , mSrcStreamLoading(false) {}
 
 nsObjectLoadingContent::~nsObjectLoadingContent()
 {
   // Should have been unbound from the tree at this point, and InDocCheckEvent
   // keeps us alive
@@ -1036,16 +1040,18 @@ nsObjectLoadingContent::ObjectState() co
     case eType_Null:
       switch (mFallbackType) {
         case eFallbackSuppressed:
           return NS_EVENT_STATE_SUPPRESSED;
         case eFallbackUserDisabled:
           return NS_EVENT_STATE_USERDISABLED;
         case eFallbackClickToPlay:
           return NS_EVENT_STATE_TYPE_CLICK_TO_PLAY;
+        case eFallbackPlayPreview:
+          return NS_EVENT_STATE_TYPE_PLAY_PREVIEW;
         case eFallbackDisabled:
           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_DISABLED;
         case eFallbackBlocklisted:
           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_BLOCKED;
         case eFallbackCrashed:
           return NS_EVENT_STATE_BROKEN | NS_EVENT_STATE_HANDLER_CRASHED;
         case eFallbackUnsupported: {
           // Check to see if plugins are blocked on this platform.
@@ -1422,16 +1428,17 @@ nsObjectLoadingContent::UpdateObjectPara
   //   eAllowPluginSkipChannel, meaning it is possible that we have a URI, but
   //   are not going to open a channel for it. The old objLC code did this (in a
   //   less obviously-intended way), so it's probably best not to change our
   //   behavior at this point.
   //
 
   if (stateInvalid) {
     newType = eType_Null;
+    newMime.Truncate();
   } else if (useChannel) {
       // If useChannel is set above, we considered it in setting newMime
       newType = GetTypeOfContent(newMime);
       LOG(("OBJLC [%p]: Using channel type", this));
   } else if (((caps & eAllowPluginSkipChannel) || !newURI) &&
              (GetTypeOfContent(newMime) == eType_Plugin)) {
     newType = eType_Plugin;
     LOG(("OBJLC [%p]: Skipping loading channel, type plugin", this));
@@ -1640,16 +1647,25 @@ nsObjectLoadingContent::LoadObject(bool 
         //            reject plugins
         fallbackType = eFallbackUserDisabled;
       } else {
         fallbackType = eFallbackSuppressed;
       }
     }
   }
 
+  // Items resolved as Image/Document will not be checked for previews, as well
+  // as invalid plugins (they will not have the mContentType set).
+  if ((mType == eType_Null || mType == eType_Plugin) && ShouldPreview()) {
+    // If plugin preview exists, we shall use it
+    LOG(("OBJLC [%p]: Using plugin preview", this));
+    mType = eType_Null;
+    fallbackType = eFallbackPlayPreview;
+  }
+
   // If we're a plugin but shouldn't start yet, load fallback with
   // reason click-to-play instead
   FallbackType clickToPlayReason;
   if (mType == eType_Plugin && !ShouldPlay(clickToPlayReason)) {
     LOG(("OBJLC [%p]: Marking plugin as click-to-play", this));
     mType = eType_Null;
     fallbackType = clickToPlayReason;
   }
@@ -2446,28 +2462,53 @@ nsObjectLoadingContent::PlayPlugin()
   mActivated = true;
   return LoadObject(true, true);
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetActivated(bool *aActivated)
 {
   FallbackType reason;
-  *aActivated = ShouldPlay(reason);
+  *aActivated = ShouldPlay(reason) && !ShouldPreview();
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsObjectLoadingContent::GetPluginFallbackType(uint32_t* aPluginFallbackType)
 {
   NS_ENSURE_TRUE(nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
   *aPluginFallbackType = mFallbackType;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsObjectLoadingContent::CancelPlayPreview()
+{
+  if (!nsContentUtils::IsCallerChrome())
+    return NS_ERROR_NOT_AVAILABLE;
+
+  if (mPlayPreviewCanceled || mActivated)
+    return NS_OK;
+
+  mPlayPreviewCanceled = true;
+  return LoadObject(true, true);
+}
+
+bool
+nsObjectLoadingContent::ShouldPreview()
+{
+  if (mPlayPreviewCanceled || mActivated)
+    return false;
+
+  nsRefPtr<nsPluginHost> pluginHost =
+    already_AddRefed<nsPluginHost>(nsPluginHost::GetInst());
+
+  return pluginHost->IsPluginPlayPreviewForType(mContentType.get());
+}
+
 bool
 nsObjectLoadingContent::ShouldPlay(FallbackType &aReason)
 {
   // mActivated is true if we've been activated via PlayPlugin() (e.g. user has
   // clicked through). Otherwise, only play if click-to-play is off or if page
   // is whitelisted
 
   nsRefPtr<nsPluginHost> pluginHost =
--- a/content/base/src/nsObjectLoadingContent.h
+++ b/content/base/src/nsObjectLoadingContent.h
@@ -77,17 +77,20 @@ class nsObjectLoadingContent : public ns
       eFallbackSuppressed = nsIObjectLoadingContent::PLUGIN_SUPPRESSED,
       // Blocked by content policy
       eFallbackUserDisabled = nsIObjectLoadingContent::PLUGIN_USER_DISABLED,
       // The plugin is disabled until the user clicks on it
       eFallbackClickToPlay = nsIObjectLoadingContent::PLUGIN_CLICK_TO_PLAY,
       // The plugin is vulnerable (update available)
       eFallbackVulnerableUpdatable = nsIObjectLoadingContent::PLUGIN_VULNERABLE_UPDATABLE,
       // The plugin is vulnerable (no update available)
-      eFallbackVulnerableNoUpdate = nsIObjectLoadingContent::PLUGIN_VULNERABLE_NO_UPDATE
+      eFallbackVulnerableNoUpdate = nsIObjectLoadingContent::PLUGIN_VULNERABLE_NO_UPDATE,
+      // The plugin is disabled and play preview content is displayed until
+      // the extension code enables it by sending the MozPlayPlugin event
+      eFallbackPlayPreview = nsIObjectLoadingContent::PLUGIN_PLAY_PREVIEW
     };
 
     nsObjectLoadingContent();
     virtual ~nsObjectLoadingContent();
 
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSIFRAMELOADEROWNER
@@ -286,16 +289,21 @@ class nsObjectLoadingContent : public ns
     /**
      * If this object is allowed to play plugin content, or if it would display
      * click-to-play instead.
      * NOTE that this does not actually check if the object is a loadable plugin
      */
     bool ShouldPlay(FallbackType &aReason);
 
     /**
+     * If the object should display preview content for the current mContentType
+     */
+    bool ShouldPreview();
+
+    /**
      * Helper to check if our current URI passes policy
      *
      * @param aContentPolicy [out] The result of the content policy decision
      *
      * @return true if call succeeded and NS_CP_ACCEPTED(*aContentPolicy)
      */
     bool CheckLoadPolicy(int16_t *aContentPolicy);
 
@@ -418,16 +426,19 @@ class nsObjectLoadingContent : public ns
     // created using NS_FROM_PARSER_NETWORK flag. If the element is modified,
     // it may lose the flag.
     bool                        mNetworkCreated : 1;
 
     // Used to keep track of whether or not a plugin has been explicitly
     // activated by PlayPlugin(). (see ShouldPlay())
     bool                        mActivated : 1;
 
+    // Used to keep track of whether or not a plugin is blocked by play-preview.
+    bool                        mPlayPreviewCanceled : 1;
+
     // Protects DoStopPlugin from reentry (bug 724781).
     bool                        mIsStopping : 1;
 
     // Protects LoadObject from re-entry
     bool                        mIsLoading : 1;
 
     // Used to track when we might try to instantiate a plugin instance based on
     // a src data stream being delivered to this object. When this is true we
--- a/content/events/public/nsEventStates.h
+++ b/content/events/public/nsEventStates.h
@@ -247,16 +247,18 @@ private:
 // Handler for click to play plugin (vulnerable w/no update)
 #define NS_EVENT_STATE_VULNERABLE_NO_UPDATE NS_DEFINE_EVENT_STATE_MACRO(41)
 // Platform does not support plugin content (some mobile platforms)
 #define NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM NS_DEFINE_EVENT_STATE_MACRO(42)
 // Element is ltr (for :dir pseudo-class)
 #define NS_EVENT_STATE_LTR NS_DEFINE_EVENT_STATE_MACRO(43)
 // Element is rtl (for :dir pseudo-class)
 #define NS_EVENT_STATE_RTL NS_DEFINE_EVENT_STATE_MACRO(44)
+// Handler for play preview plugin
+#define NS_EVENT_STATE_TYPE_PLAY_PREVIEW NS_DEFINE_EVENT_STATE_MACRO(45)
 
 /**
  * NOTE: do not go over 63 without updating nsEventStates::InternalType!
  */
 
 #define DIRECTION_STATES (NS_EVENT_STATE_LTR | NS_EVENT_STATE_RTL)
 
 #define ESM_MANAGED_STATES (NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_FOCUS |     \
--- a/content/media/nsBuiltinDecoderReader.cpp
+++ b/content/media/nsBuiltinDecoderReader.cpp
@@ -213,28 +213,25 @@ VideoData* VideoData::Create(nsVideoInfo
     return nullptr;
   }
   NS_ASSERTION(v->mImage->GetFormat() == PLANAR_YCBCR ||
                v->mImage->GetFormat() == GRALLOC_PLANAR_YCBCR,
                "Wrong format?");
   PlanarYCbCrImage* videoImage = static_cast<PlanarYCbCrImage*>(v->mImage.get());
 
   PlanarYCbCrImage::Data data;
-  data.mYChannel = Y.mData;
+  data.mYChannel = Y.mData + Y.mOffset;
   data.mYSize = gfxIntSize(Y.mWidth, Y.mHeight);
   data.mYStride = Y.mStride;
-  data.mYOffset = Y.mOffset;
   data.mYSkip = Y.mSkip;
-  data.mCbChannel = Cb.mData;
-  data.mCrChannel = Cr.mData;
+  data.mCbChannel = Cb.mData + Cb.mOffset;
+  data.mCrChannel = Cr.mData + Cr.mOffset;
   data.mCbCrSize = gfxIntSize(Cb.mWidth, Cb.mHeight);
   data.mCbCrStride = Cb.mStride;
-  data.mCbOffset = Cb.mOffset;
   data.mCbSkip = Cb.mSkip;
-  data.mCrOffset = Cr.mOffset;
   data.mCrSkip = Cr.mSkip;
   data.mPicX = aPicture.x;
   data.mPicY = aPicture.y;
   data.mPicSize = gfxIntSize(aPicture.width, aPicture.height);
   data.mStereoMode = aInfo.mStereoMode;
 
   videoImage->SetData(data);
   return v.forget();
--- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
+++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.cpp
@@ -196,36 +196,41 @@ ToPreserveAspectRatio(const nsAString &a
   }
 
   *aValue = val;
   return NS_OK;
 }
 
 nsresult
 SVGAnimatedPreserveAspectRatio::SetBaseValueString(
-  const nsAString &aValueAsString, nsSVGElement *aSVGElement)
+  const nsAString &aValueAsString, nsSVGElement *aSVGElement, bool aDoSetAttr)
 {
   SVGPreserveAspectRatio val;
   nsresult res = ToPreserveAspectRatio(aValueAsString, &val);
   if (NS_FAILED(res)) {
     return res;
   }
 
+  nsAttrValue emptyOrOldValue;
+  if (aDoSetAttr) {
+    emptyOrOldValue = aSVGElement->WillChangePreserveAspectRatio();
+  }
+
   mBaseVal = val;
   mIsBaseSet = true;
+
   if (!mIsAnimated) {
     mAnimVal = mBaseVal;
   }
-  else {
+  if (aDoSetAttr) {
+    aSVGElement->DidChangePreserveAspectRatio(emptyOrOldValue);
+  }
+  if (mIsAnimated) {
     aSVGElement->AnimationNeedsResample();
   }
-
-  // We don't need to call DidChange* here - we're only called by
-  // nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
-  // which takes care of notifying.
   return NS_OK;
 }
 
 void
 SVGAnimatedPreserveAspectRatio::GetBaseValueString(
   nsAString& aValueAsString) const
 {
   nsAutoString tmpString;
--- a/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
+++ b/content/svg/content/src/SVGAnimatedPreserveAspectRatio.h
@@ -87,17 +87,18 @@ public:
     mBaseVal.mMeetOrSlice = nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET;
     mBaseVal.mDefer = false;
     mAnimVal = mBaseVal;
     mIsAnimated = false;
     mIsBaseSet = false;
   }
 
   nsresult SetBaseValueString(const nsAString& aValue,
-                              nsSVGElement *aSVGElement);
+                              nsSVGElement *aSVGElement,
+                              bool aDoSetAttr);
   void GetBaseValueString(nsAString& aValue) const;
 
   void SetBaseValue(const SVGPreserveAspectRatio &aValue,
                     nsSVGElement *aSVGElement);
   nsresult SetBaseAlign(uint16_t aAlign, nsSVGElement *aSVGElement) {
     if (aAlign < nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE ||
         aAlign > nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX) {
       return NS_ERROR_FAILURE;
--- a/content/svg/content/src/SVGFragmentIdentifier.cpp
+++ b/content/svg/content/src/SVGFragmentIdentifier.cpp
@@ -1,31 +1,36 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "SVGFragmentIdentifier.h"
-#include "mozilla/CharTokenizer.h"
 #include "nsIDOMSVGDocument.h"
 #include "nsSVGSVGElement.h"
 #include "nsSVGViewElement.h"
 
 using namespace mozilla;
 
 static bool
 IsMatchingParameter(const nsAString &aString, const nsAString &aParameterName)
 {
   // The first two tests ensure aString.Length() > aParameterName.Length()
   // so it's then safe to do the third test
   return StringBeginsWith(aString, aParameterName) &&
          aString.Last() == ')' &&
          aString.CharAt(aParameterName.Length()) == '(';
 }
 
+inline bool
+IgnoreWhitespace(PRUnichar aChar)
+{
+  return false;
+}
+
 static nsSVGViewElement*
 GetViewElement(nsIDocument *aDocument, const nsAString &aId)
 {
   dom::Element* element = aDocument->GetElementById(aId);
   return (element && element->IsSVG(nsGkAtoms::view)) ?
             static_cast<nsSVGViewElement*>(element) : nullptr;
 }
 
@@ -89,29 +94,30 @@ SVGFragmentIdentifier::RestoreOldZoomAnd
 bool
 SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString &aViewSpec,
                                           nsSVGSVGElement *root)
 {
   if (!IsMatchingParameter(aViewSpec, NS_LITERAL_STRING("svgView"))) {
     return false;
   }
 
-  // SVGViewAttribute may occur in any order, but each type may only occur at most one time
-  // in a correctly formed SVGViewSpec.
-  // If we encounter any element more than once or get any syntax errors we're going to
-  // return without updating the root element
-
-  const nsAString *viewBoxParams = nullptr;
-  const nsAString *preserveAspectRatioParams = nullptr;
-  const nsAString *zoomAndPanParams = nullptr;
+  // SVGViewAttributes may occur in any order, but each type may only occur
+  // at most one time in a correctly formed SVGViewSpec.
+  // If we encounter any attribute more than once or get any syntax errors
+  // we're going to return false and cancel any changes.
+  
+  bool viewBoxFound = false;
+  bool preserveAspectRatioFound = false;
+  bool zoomAndPanFound = false;
 
   // Each token is a SVGViewAttribute
   int32_t bracketPos = aViewSpec.FindChar('(');
-  CharTokenizer<';'>tokenizer(
-    Substring(aViewSpec, bracketPos + 1, aViewSpec.Length() - bracketPos - 2));
+  uint32_t lengthOfViewSpec = aViewSpec.Length() - bracketPos - 2;
+  nsCharSeparatedTokenizerTemplate<IgnoreWhitespace> tokenizer(
+    Substring(aViewSpec, bracketPos + 1, lengthOfViewSpec), ';');
 
   if (!tokenizer.hasMoreTokens()) {
     return false;
   }
   do {
 
     nsAutoString token(tokenizer.nextToken());
 
@@ -120,60 +126,72 @@ SVGFragmentIdentifier::ProcessSVGViewSpe
       // invalid SVGViewAttribute syntax
       return false;
     }
 
     const nsAString &params =
       Substring(token, bracketPos + 1, token.Length() - bracketPos - 2);
 
     if (IsMatchingParameter(token, NS_LITERAL_STRING("viewBox"))) {
-      if (viewBoxParams) {
+      if (viewBoxFound ||
+          NS_FAILED(root->mViewBox.SetBaseValueString(
+                      params, root, true))) {
+        return false;
+      }
+      viewBoxFound = true;
+    } else if (IsMatchingParameter(token, NS_LITERAL_STRING("preserveAspectRatio"))) {
+      if (preserveAspectRatioFound ||
+          NS_FAILED(root->mPreserveAspectRatio.SetBaseValueString(
+                      params, root, true))) {
+        return false;
+      }
+      preserveAspectRatioFound = true;
+    } else if (IsMatchingParameter(token, NS_LITERAL_STRING("zoomAndPan"))) {
+      if (zoomAndPanFound) {
         return false;
       }
-      viewBoxParams = &params;
-    } else if (IsMatchingParameter(token, NS_LITERAL_STRING("preserveAspectRatio"))) {
-      if (preserveAspectRatioParams) {
+      nsIAtom *valAtom = NS_GetStaticAtom(params);
+      if (!valAtom) {
         return false;
       }
-      preserveAspectRatioParams = &params;
-    } else if (IsMatchingParameter(token, NS_LITERAL_STRING("zoomAndPan"))) {
-      if (zoomAndPanParams) {
-        return false;
+      const nsSVGEnumMapping *mapping = nsSVGSVGElement::sZoomAndPanMap;
+      while (mapping->mKey) {
+        if (valAtom == *(mapping->mKey)) {
+          // If we've got a valid zoomAndPan value, then set it on our root element.
+          if (NS_FAILED(root->mEnumAttributes[nsSVGSVGElement::ZOOMANDPAN].SetBaseValue(
+                          mapping->mVal, root))) {
+            return false;
+          }
+          break;
+        }
+        mapping++;
       }
-      zoomAndPanParams = &params;
+      if (!mapping->mKey) {
+          // Unrecognised zoomAndPan value
+          return false;
+      }
+      zoomAndPanFound = true;
     } else {
       // We don't support transform or viewTarget currently
       return false;
     }
   } while (tokenizer.hasMoreTokens());
 
-  if (viewBoxParams) {
-    root->mViewBox.SetBaseValueString(*viewBoxParams, root);
-  } else {
-    RestoreOldViewBox(root);
-  }
-
-  if (preserveAspectRatioParams) {
-    root->mPreserveAspectRatio.SetBaseValueString(*preserveAspectRatioParams, root);
-  } else {
-    RestoreOldPreserveAspectRatio(root);
-  }
-
-  if (zoomAndPanParams) {
-    nsCOMPtr<nsIAtom> valAtom = do_GetAtom(*zoomAndPanParams);
-    const nsSVGEnumMapping *mapping = root->sZoomAndPanMap;
-    while (mapping->mKey) {
-      if (valAtom == *(mapping->mKey)) {
-        root->mEnumAttributes[nsSVGSVGElement::ZOOMANDPAN].SetBaseValue(mapping->mVal, root);
-        break;
-      }
-      mapping++;
+  if (root->mUseCurrentView) {
+    // A previous SVGViewSpec may have overridden some attributes.
+    // If they are no longer overridden we need to restore the old values.
+    if (!viewBoxFound) {
+      RestoreOldViewBox(root);
     }
-  } else {
-    RestoreOldZoomAndPan(root);
+    if (!preserveAspectRatioFound) {
+      RestoreOldPreserveAspectRatio(root);
+    }
+    if (!zoomAndPanFound) {
+      RestoreOldZoomAndPan(root);
+    }
   }
 
   return true;
 }
 
 bool
 SVGFragmentIdentifier::ProcessFragmentIdentifier(nsIDocument *aDocument,
                                                  const nsAString &aAnchorName)
--- a/content/svg/content/src/nsSVGElement.cpp
+++ b/content/svg/content/src/nsSVGElement.cpp
@@ -516,31 +516,31 @@ nsSVGElement::ParseAttribute(int32_t aNa
       }
     }
 
     if (!foundMatch) {
       // Check for nsSVGViewBox attribute
       if (aAttribute == nsGkAtoms::viewBox) {
         nsSVGViewBox* viewBox = GetViewBox();
         if (viewBox) {
-          rv = viewBox->SetBaseValueString(aValue, this);
+          rv = viewBox->SetBaseValueString(aValue, this, false);
           if (NS_FAILED(rv)) {
             viewBox->Init();
           } else {
             aResult.SetTo(*viewBox, &aValue);
             didSetResult = true;
           }
           foundMatch = true;
         }
       // Check for SVGAnimatedPreserveAspectRatio attribute
       } else if (aAttribute == nsGkAtoms::preserveAspectRatio) {
         SVGAnimatedPreserveAspectRatio *preserveAspectRatio =
           GetPreserveAspectRatio();
         if (preserveAspectRatio) {
-          rv = preserveAspectRatio->SetBaseValueString(aValue, this);
+          rv = preserveAspectRatio->SetBaseValueString(aValue, this, false);
           if (NS_FAILED(rv)) {
             preserveAspectRatio->Init();
           } else {
             aResult.SetTo(*preserveAspectRatio, &aValue);
             didSetResult = true;
           }
           foundMatch = true;
         }
--- a/content/svg/content/src/nsSVGViewBox.cpp
+++ b/content/svg/content/src/nsSVGViewBox.cpp
@@ -143,30 +143,35 @@ ToSVGViewBoxRect(const nsAString& aStr, 
   aViewBox->width = vals[2];
   aViewBox->height = vals[3];
 
   return NS_OK;
 }
 
 nsresult
 nsSVGViewBox::SetBaseValueString(const nsAString& aValue,
-                                 nsSVGElement *aSVGElement)
+                                 nsSVGElement *aSVGElement,
+                                 bool aDoSetAttr)
 {
   nsSVGViewBoxRect viewBox;
   nsresult res = ToSVGViewBoxRect(aValue, &viewBox);
   if (NS_SUCCEEDED(res)) {
+    nsAttrValue emptyOrOldValue;
+    if (aDoSetAttr) {
+      emptyOrOldValue = aSVGElement->WillChangeViewBox();
+    }
     mBaseVal = nsSVGViewBoxRect(viewBox.x, viewBox.y, viewBox.width, viewBox.height);
     mHasBaseVal = true;
 
+    if (aDoSetAttr) {
+      aSVGElement->DidChangeViewBox(emptyOrOldValue);
+    }
     if (mAnimVal) {
       aSVGElement->AnimationNeedsResample();
     }
-    // We don't need to call Will/DidChange* here - we're only called by
-    // nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
-    // which takes care of notifying.
   }
   return res;
 }
 
 void
 nsSVGViewBox::GetBaseValueString(nsAString& aValue) const
 {
   PRUnichar buf[200];
--- a/content/svg/content/src/nsSVGViewBox.h
+++ b/content/svg/content/src/nsSVGViewBox.h
@@ -59,24 +59,25 @@ public:
                     nsSVGElement *aSVGElement)
     { SetBaseValue(nsSVGViewBoxRect(aX, aY, aWidth, aHeight), aSVGElement); }
   const nsSVGViewBoxRect& GetAnimValue() const
     { return mAnimVal ? *mAnimVal : mBaseVal; }
   void SetAnimValue(float aX, float aY, float aWidth, float aHeight,
                     nsSVGElement *aSVGElement);
 
   nsresult SetBaseValueString(const nsAString& aValue,
-                              nsSVGElement *aSVGElement);
+                              nsSVGElement *aSVGElement,
+                              bool aDoSetAttr);
   void GetBaseValueString(nsAString& aValue) const;
 
   nsresult ToDOMAnimatedRect(nsIDOMSVGAnimatedRect **aResult,
                              nsSVGElement *aSVGElement);
   // Returns a new nsISMILAttr object that the caller must delete
   nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
-  
+
 private:
 
   nsSVGViewBoxRect mBaseVal;
   nsAutoPtr<nsSVGViewBoxRect> mAnimVal;
   bool mHasBaseVal;
 
   struct DOMBaseVal MOZ_FINAL : public nsIDOMSVGRect
   {
--- a/content/svg/content/test/test_fragments.html
+++ b/content/svg/content/test/test_fragments.html
@@ -14,46 +14,69 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none"></div>
 
 <iframe id="svg" src="fragments-helper.svg"></iframe>
 
 <pre id="test">
 <script class="testbody" type="application/javascript">
 SimpleTest.waitForExplicitFinish();
 
-function Test(svgFragmentIdentifier, valid) {
+function Test(svgFragmentIdentifier, valid, viewBoxString,
+              preserveAspectRatioString, zoomAndPanString)
+{
     this.svgFragmentIdentifier = svgFragmentIdentifier;
     this.valid = valid;
+    this.viewBoxString = viewBoxString;
+    this.preserveAspectRatioString = preserveAspectRatioString;
+    this.zoomAndPanString = zoomAndPanString;
 }
 
 function runTests()
 {
   var svg = $("svg");
   var doc = svg.contentWindow.document;
   
   var tests = [
-      new Test("view", true),
-      new Test("unknown", false),
-      new Test("svgView(viewBox(0,0,200,200)))", true),
-      new Test("svgView(preserveAspectRatio(xMaxYMin slice))", true),
-      new Test("svgView(viewBox(1,2,3,4);preserveAspectRatio(xMaxYMin))", true),
-      new Test("svgView(zoomAndPan(disable))", true),
-      new Test("svgView", false),
-      new Test("svgView(", false),
-      new Test("svgView()", false)
+      new Test("view", true, "0 200 100 100", "none", null),
+      new Test("unknown", false, null, null, null),
+      new Test("svgView(viewBox(0,0,200,200))", true, "0 0 200 200", null, null),
+      new Test("svgView(preserveAspectRatio(xMaxYMin slice))", true, null, "xMaxYMin slice", null),
+      new Test("svgView(viewBox(1,2,3,4);preserveAspectRatio(xMinYMax))", true, "1 2 3 4", "xMinYMax meet", null),
+      new Test("svgView(zoomAndPan(disable))", true, null, null, "disable"),
+      new Test("svgView(viewBox(bad)", false, null, null, null),
+      new Test("svgView(preserveAspectRatio(bad))", false, null, null, null),
+      new Test("svgView(zoomAndPan(bad))", false, null, null, null),
+      new Test("svgView", false, null, null, null),
+      new Test("svgView(", false, null, null, null),
+      new Test("svgView()", false, null, null, null),
+      // Be sure we verify that there's a closing paren for svgView()
+      // (and not too many closing parens)
+      new Test("svgView(zoomAndPan(disable)", false, null, null, null),
+      new Test("svgView(zoomAndPan(disable) ", false, null, null, null),
+      new Test("svgView(zoomAndPan(disable)]", false, null, null, null),
+      new Test("svgView(zoomAndPan(disable)))", false, null, null, null)
   ];
 
- var src = svg.getAttribute("src");
- for (var i = 0; i < tests.length; i++) {
-   var test = tests[i];
-   svg.setAttribute("src", src + "#" + test.svgFragmentIdentifier);
-   is(doc.rootElement.useCurrentView, test.valid,
-      "Expected " + test.svgFragmentIdentifier + " to be " +
-      (test.valid ? "valid" : "invalid"));
- }
+  var src = svg.getAttribute("src");
+  for (var i = 0; i < tests.length; i++) {
+    var test = tests[i];
+    svg.setAttribute("src", src + "#" + test.svgFragmentIdentifier);
+    is(doc.rootElement.useCurrentView, test.valid,
+       "Expected " + test.svgFragmentIdentifier + " to be " +
+       (test.valid ? "valid" : "invalid"));
+
+    is(doc.rootElement.getAttribute("viewBox"),
+       test.viewBoxString, "unexpected viewBox");
+
+    is(doc.rootElement.getAttribute("preserveAspectRatio"),
+       test.preserveAspectRatioString, "unexpected preserveAspectRatio");
+
+    is(doc.rootElement.getAttribute("zoomAndPan"),
+       test.zoomAndPanString, "unexpected zoomAndPan");
+  }
 
   SimpleTest.finish();
 }
 
 window.addEventListener("load", runTests, false);
 </script>
 </pre>
 </body>
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -8682,16 +8682,27 @@ nsDocShell::InternalLoad(nsIURI * aURI,
         // that history.go(0) and the like trigger full refreshes, rather than
         // short-circuited loads.
         bool doShortCircuitedLoad =
           (historyNavBetweenSameDoc && mOSHE != aSHEntry) ||
           (!aSHEntry && aPostData == nullptr &&
            sameExceptHashes && !newHash.IsEmpty());
 
         if (doShortCircuitedLoad) {
+            // Cancel any outstanding loads if this is a history load.
+            //
+            // We can't cancel the oustanding load unconditionally, because if a page does
+            //   - load a.html
+            //   - start loading b.html
+            //   - load a.html#h
+            // we break the web if we cancel the load of b.html.
+            if (aSHEntry) {
+                Stop(nsIWebNavigation::STOP_NETWORK);
+            }
+
             // Save the current URI; we need it if we fire a hashchange later.
             nsCOMPtr<nsIURI> oldURI = mCurrentURI;
 
             // Save the position of the scrollers.
             nscoord cx = 0, cy = 0;
             GetCurScrollPos(ScrollOrientation_X, &cx);
             GetCurScrollPos(ScrollOrientation_Y, &cy);
 
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1846,16 +1846,17 @@ jsid nsDOMClassInfo::sName_id           
 jsid nsDOMClassInfo::sScrollX_id         = JSID_VOID;
 jsid nsDOMClassInfo::sScrollY_id         = JSID_VOID;
 jsid nsDOMClassInfo::sScrollMaxX_id      = JSID_VOID;
 jsid nsDOMClassInfo::sScrollMaxY_id      = JSID_VOID;
 jsid nsDOMClassInfo::sItem_id            = JSID_VOID;
 jsid nsDOMClassInfo::sNamedItem_id       = JSID_VOID;
 jsid nsDOMClassInfo::sEnumerate_id       = JSID_VOID;
 jsid nsDOMClassInfo::sNavigator_id       = JSID_VOID;
+jsid nsDOMClassInfo::sTop_id             = JSID_VOID;
 jsid nsDOMClassInfo::sDocument_id        = JSID_VOID;
 jsid nsDOMClassInfo::sFrames_id          = JSID_VOID;
 jsid nsDOMClassInfo::sSelf_id            = JSID_VOID;
 jsid nsDOMClassInfo::sOpener_id          = JSID_VOID;
 jsid nsDOMClassInfo::sAll_id             = JSID_VOID;
 jsid nsDOMClassInfo::sTags_id            = JSID_VOID;
 jsid nsDOMClassInfo::sAddEventListener_id= JSID_VOID;
 jsid nsDOMClassInfo::sBaseURIObject_id   = JSID_VOID;
@@ -2125,16 +2126,17 @@ nsDOMClassInfo::DefineStaticJSVals(JSCon
   SET_JSID_TO_STRING(sScrollX_id,         cx, "scrollX");
   SET_JSID_TO_STRING(sScrollY_id,         cx, "scrollY");
   SET_JSID_TO_STRING(sScrollMaxX_id,      cx, "scrollMaxX");
   SET_JSID_TO_STRING(sScrollMaxY_id,      cx, "scrollMaxY");
   SET_JSID_TO_STRING(sItem_id,            cx, "item");
   SET_JSID_TO_STRING(sNamedItem_id,       cx, "namedItem");
   SET_JSID_TO_STRING(sEnumerate_id,       cx, "enumerateProperties");
   SET_JSID_TO_STRING(sNavigator_id,       cx, "navigator");
+  SET_JSID_TO_STRING(sTop_id,             cx, "top");
   SET_JSID_TO_STRING(sDocument_id,        cx, "document");
   SET_JSID_TO_STRING(sFrames_id,          cx, "frames");
   SET_JSID_TO_STRING(sSelf_id,            cx, "self");
   SET_JSID_TO_STRING(sOpener_id,          cx, "opener");
   SET_JSID_TO_STRING(sAll_id,             cx, "all");
   SET_JSID_TO_STRING(sTags_id,            cx, "tags");
   SET_JSID_TO_STRING(sAddEventListener_id,cx, "addEventListener");
   SET_JSID_TO_STRING(sBaseURIObject_id,   cx, "baseURIObject");
@@ -5241,16 +5243,17 @@ nsDOMClassInfo::ShutDown()
   sName_id            = JSID_VOID;
   sScrollX_id         = JSID_VOID;
   sScrollY_id         = JSID_VOID;
   sScrollMaxX_id      = JSID_VOID;
   sScrollMaxY_id      = JSID_VOID;
   sItem_id            = JSID_VOID;
   sEnumerate_id       = JSID_VOID;
   sNavigator_id       = JSID_VOID;
+  sTop_id             = JSID_VOID;
   sDocument_id        = JSID_VOID;
   sFrames_id          = JSID_VOID;
   sSelf_id            = JSID_VOID;
   sOpener_id          = JSID_VOID;
   sAll_id             = JSID_VOID;
   sTags_id            = JSID_VOID;
   sAddEventListener_id= JSID_VOID;
   sBaseURIObject_id   = JSID_VOID;
@@ -7345,16 +7348,39 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
                                    JSPROP_ENUMERATE)) {
         return NS_ERROR_FAILURE;
       }
       *objp = obj;
 
       return NS_OK;
     }
 
+    if (sTop_id == id) {
+      nsCOMPtr<nsIDOMWindow> top;
+      rv = win->GetScriptableTop(getter_AddRefs(top));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      jsval v;
+      nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+      rv = WrapNative(cx, obj, top, &NS_GET_IID(nsIDOMWindow), true,
+                      &v, getter_AddRefs(holder));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      // Hold on to the top window object as a global property so we
+      // don't need to worry about losing expando properties etc.
+      if (!::JS_DefinePropertyById(cx, obj, id, v, nullptr, nullptr,
+                                   JSPROP_READONLY | JSPROP_PERMANENT |
+                                   JSPROP_ENUMERATE)) {
+        return NS_ERROR_FAILURE;
+      }
+      *objp = obj;
+
+      return NS_OK;
+    }
+
     if (sDocument_id == id) {
       nsCOMPtr<nsIDocument> document = win->GetDoc();
       JS::Value v;
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
       rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), document, document,
                       &NS_GET_IID(nsIDOMDocument), &v, getter_AddRefs(holder),
                       false);
       NS_ENSURE_SUCCESS(rv, rv);
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -238,16 +238,17 @@ public:
   static jsid sScrollX_id;
   static jsid sScrollY_id;
   static jsid sScrollMaxX_id;
   static jsid sScrollMaxY_id;
   static jsid sItem_id;
   static jsid sNamedItem_id;
   static jsid sEnumerate_id;
   static jsid sNavigator_id;
+  static jsid sTop_id;
   static jsid sDocument_id;
   static jsid sFrames_id;
   static jsid sSelf_id;
   static jsid sOpener_id;
   static jsid sAll_id;
   static jsid sTags_id;
   static jsid sAddEventListener_id;
   static jsid sBaseURIObject_id;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -471,35 +471,35 @@ nsDOMWindowUtils::SendMouseEvent(const n
                                  int32_t aButton,
                                  int32_t aClickCount,
                                  int32_t aModifiers,
                                  bool aIgnoreRootScrollFrame,
                                  float aPressure,
                                  unsigned short aInputSourceArg)
 {
   return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
-                              aIgnoreRootScrollFrame, false, aPressure,
-                              aInputSourceArg);
+                              aIgnoreRootScrollFrame, aPressure,
+                              aInputSourceArg, false);
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::SendMouseEventToWindow(const nsAString& aType,
                                          float aX,
                                          float aY,
                                          int32_t aButton,
                                          int32_t aClickCount,
                                          int32_t aModifiers,
                                          bool aIgnoreRootScrollFrame,
                                          float aPressure,
                                          unsigned short aInputSourceArg)
 {
   SAMPLE_LABEL("nsDOMWindowUtils", "SendMouseEventToWindow");
   return SendMouseEventCommon(aType, aX, aY, aButton, aClickCount, aModifiers,
-                              aIgnoreRootScrollFrame, true, aPressure,
-                              aInputSourceArg);
+                              aIgnoreRootScrollFrame, aPressure,
+                              aInputSourceArg, true);
 }
 
 static nsIntPoint
 ToWidgetPoint(float aX, float aY, const nsPoint& aOffset,
               nsPresContext* aPresContext)
 {
   double appPerDev = aPresContext->AppUnitsPerDevPixel();
   nscoord appPerCSS = nsPresContext::AppUnitsPerCSSPixel();
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -16,16 +16,17 @@
 #include "nsIDOMDOMRequest.h"
 #include "nsIPermissionManager.h"
 #include "nsDOMClassInfo.h"
 #include "nsDOMEvent.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCIDInternal.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
+#include "nsIDOMDOMRequest.h"
 
 using namespace mozilla;
 
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothManager, BluetoothManager)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothManager)
--- a/dom/bluetooth/BluetoothReplyRunnable.cpp
+++ b/dom/bluetooth/BluetoothReplyRunnable.cpp
@@ -2,19 +2,39 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "BluetoothTypes.h"
 #include "BluetoothReplyRunnable.h"
+#include "nsIDOMDOMRequest.h"
 
 USING_BLUETOOTH_NAMESPACE
 
+BluetoothReplyRunnable::BluetoothReplyRunnable(nsIDOMDOMRequest* aReq)
+  : mDOMRequest(aReq)
+{}
+
+void
+BluetoothReplyRunnable::SetReply(BluetoothReply* aReply)
+{
+  mReply = aReply;
+}
+
+void
+BluetoothReplyRunnable::ReleaseMembers()
+{
+  mDOMRequest = nullptr;
+}
+
+BluetoothReplyRunnable::~BluetoothReplyRunnable()
+{}
+
 nsresult
 BluetoothReplyRunnable::FireReply(const jsval& aVal)
 {
   nsCOMPtr<nsIDOMRequestService> rs =
     do_GetService("@mozilla.org/dom/dom-request-service;1");
   
   if (!rs) {
     NS_WARNING("No DOMRequest Service!");
@@ -67,8 +87,16 @@ BluetoothReplyRunnable::Run()
 
   ReleaseMembers();
   if (mDOMRequest) {
     NS_WARNING("mDOMRequest still alive! Deriving class should call BluetoothReplyRunnable::ReleaseMembers()!");
   }
 
   return rv;
 }
+
+BluetoothVoidReplyRunnable::BluetoothVoidReplyRunnable(nsIDOMDOMRequest* aReq)
+  : BluetoothReplyRunnable(aReq)
+{}
+
+BluetoothVoidReplyRunnable::~BluetoothVoidReplyRunnable()
+{}
+
--- a/dom/bluetooth/BluetoothReplyRunnable.h
+++ b/dom/bluetooth/BluetoothReplyRunnable.h
@@ -4,80 +4,64 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
 #define mozilla_dom_bluetooth_bluetoothreplyrunnable_h__
 
 #include "BluetoothCommon.h"
 #include "nsThreadUtils.h"
-#include "nsIDOMDOMRequest.h"
 #include "jsapi.h"
 
+class nsIDOMDOMRequest;
+
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothReply;
 
 class BluetoothReplyRunnable : public nsRunnable
 {
 public:
   NS_DECL_NSIRUNNABLE
 
-  BluetoothReplyRunnable(nsIDOMDOMRequest* aReq) :
-    mDOMRequest(aReq)
-  {
-  }
+  BluetoothReplyRunnable(nsIDOMDOMRequest* aReq);
 
-  void SetReply(BluetoothReply* aReply)
-  {
-    mReply = aReply;
-  }
+  void SetReply(BluetoothReply* aReply);
 
   void SetError(const nsAString& aError)
   {
     mErrorString = aError;
   }
 
-  virtual void ReleaseMembers()
-  {
-    mDOMRequest = nullptr;
-  }
+  virtual void ReleaseMembers();
 
 protected:
-  virtual ~BluetoothReplyRunnable()
-  {
-  }
-  
+  virtual ~BluetoothReplyRunnable();
+
   virtual bool ParseSuccessfulReply(jsval* aValue) = 0;
 
   // This is an autoptr so we don't have to bring the ipdl include into the
   // header. We assume we'll only be running this once and it should die on
   // scope out of Run() anyways.
   nsAutoPtr<BluetoothReply> mReply;
 
 private:
   nsresult FireReply(const jsval& aVal);
   nsresult FireErrorString();
-  
+
   nsCOMPtr<nsIDOMDOMRequest> mDOMRequest;
   nsString mErrorString;
 };
 
 class BluetoothVoidReplyRunnable : public BluetoothReplyRunnable
 {
 public:
-  BluetoothVoidReplyRunnable(nsIDOMDOMRequest* aReq) :
-    BluetoothReplyRunnable(aReq)
-  {
-  }
+  BluetoothVoidReplyRunnable(nsIDOMDOMRequest* aReq);
+ ~BluetoothVoidReplyRunnable();
 
-  virtual void ReleaseMembers()
-  {
-    BluetoothReplyRunnable::ReleaseMembers();
-  }
 protected:
   virtual bool ParseSuccessfulReply(jsval* aValue)
   {
     *aValue = JSVAL_VOID;
     return true;
   }
 };
 
--- a/dom/ipc/AppProcessPermissions.cpp
+++ b/dom/ipc/AppProcessPermissions.cpp
@@ -31,18 +31,21 @@ AppProcessHasPermission(PBrowserParent* 
   // isBrowser frames inherit their app descriptor to identify their
   // data storage, but they don't inherit the permissions associated
   // with that descriptor.
   if (!app || tab->IsBrowserElement()) {
     return false;
   }
 
   bool hasPermission = false;
-  return (NS_SUCCEEDED(app->HasPermission(aPermission, &hasPermission)) &&
-          hasPermission);
+  if (!NS_SUCCEEDED(app->HasPermission(aPermission, &hasPermission)) ||
+      !hasPermission) {
+    printf_stderr("Security problem: App process does not have `%s' permission.  It will be killed.", aPermission);
+  }
+  return hasPermission;
 }
 
 bool
 AppProcessHasPermission(PContentParent* aActor, const char* aPermission)
 {
   const InfallibleTArray<PBrowserParent*>& browsers =
     aActor->ManagedPBrowserParent();
   for (uint32_t i = 0; i < browsers.Length(); ++i) {
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -308,16 +308,19 @@ child:
                int32_t aClickCount,
                int32_t aModifiers,
                bool aIgnoreRootScrollFrame);
 
     RealMouseEvent(nsMouseEvent event);
     RealKeyEvent(nsKeyEvent event);
     MouseWheelEvent(WheelEvent event);
     RealTouchEvent(nsTouchEvent event);
+    // We use a separate message for touchmove events only to apply
+    // compression to them.
+    RealTouchMoveEvent(nsTouchEvent event) compress;
 
     /**
      * @see nsIDOMWindowUtils sendKeyEvent.
      */
     KeyEvent(nsString aType,
              int32_t aKeyCode,
              int32_t aCharCode,
              int32_t aModifiers,
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -862,16 +862,22 @@ TabChild::RecvRealTouchEvent(const nsTou
         event.clickCount = 1;
     }
 
     DispatchWidgetEvent(event);
     return true;
 }
 
 bool
+TabChild::RecvRealTouchMoveEvent(const nsTouchEvent& aEvent)
+{
+    return RecvRealTouchEvent(aEvent);
+}
+
+bool
 TabChild::RecvRealKeyEvent(const nsKeyEvent& event)
 {
   nsKeyEvent localEvent(event);
   DispatchWidgetEvent(localEvent);
   return true;
 }
 
 bool
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -185,16 +185,17 @@ public:
                                 const int32_t&  aButton,
                                 const int32_t&  aClickCount,
                                 const int32_t&  aModifiers,
                                 const bool&     aIgnoreRootScrollFrame);
     virtual bool RecvRealMouseEvent(const nsMouseEvent& event);
     virtual bool RecvRealKeyEvent(const nsKeyEvent& event);
     virtual bool RecvMouseWheelEvent(const mozilla::widget::WheelEvent& event);
     virtual bool RecvRealTouchEvent(const nsTouchEvent& event);
+    virtual bool RecvRealTouchMoveEvent(const nsTouchEvent& event);
     virtual bool RecvKeyEvent(const nsString& aType,
                               const int32_t&  aKeyCode,
                               const int32_t&  aCharCode,
                               const int32_t&  aModifiers,
                               const bool&     aPreventDefault);
     virtual bool RecvCompositionEvent(const nsCompositionEvent& event);
     virtual bool RecvTextEvent(const nsTextEvent& event);
     virtual bool RecvSelectionEvent(const nsSelectionEvent& event);
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -353,17 +353,19 @@ bool TabParent::SendRealKeyEvent(nsKeyEv
   MaybeForwardEventToRenderFrame(event, &e);
   return PBrowserParent::SendRealKeyEvent(e);
 }
 
 bool TabParent::SendRealTouchEvent(nsTouchEvent& event)
 {
   nsTouchEvent e(event);
   MaybeForwardEventToRenderFrame(event, &e);
-  return PBrowserParent::SendRealTouchEvent(e);
+  return (e.message == NS_TOUCH_MOVE) ?
+    PBrowserParent::SendRealTouchMoveEvent(e) :
+    PBrowserParent::SendRealTouchEvent(e);
 }
 
 bool
 TabParent::RecvSyncMessage(const nsString& aMessage,
                            const ClonedMessageData& aData,
                            InfallibleTArray<nsString>* aJSONRetVal)
 {
   const SerializedStructuredCloneBuffer& buffer = aData.data();
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -370,34 +370,32 @@ MediaManager::GetUserMedia(nsPIDOMWindow
    * If we were asked to get a picture, before getting a snapshot, we check if
    * the calling page is allowed to open a popup. We do this because
    * {picture:true} will open a new "window" to let the user preview or select
    * an image, on Android. The desktop UI for {picture:true} is TBD, at which
    * may point we can decide whether to extend this test there as well.
    */
 #if !defined(MOZ_WEBRTC)
   if (picture) {
-    if (aWindow->GetPopupControlState() <= openControlled) {
-      return NS_ERROR_FAILURE;
-    }
-    nsCOMPtr<nsIPopupWindowManager> pm =
-      do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
-    if (!pm) {
-      return NS_ERROR_FAILURE;
-    }
+    if (aWindow->GetPopupControlState() > openControlled) {
+      nsCOMPtr<nsIPopupWindowManager> pm =
+        do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
+      if (!pm)
+        return NS_OK;
 
-    uint32_t permission;
-    nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
-    pm->TestPermission(doc->NodePrincipal(), &permission);
-    if (aWindow && (permission == nsIPopupWindowManager::DENY_POPUP)) {
-      nsCOMPtr<nsIDOMDocument> domDoc = aWindow->GetExtantDocument();
-      nsGlobalWindow::FirePopupBlockedEvent(
-        domDoc, aWindow, nullptr, EmptyString(), EmptyString()
-      );
-      return NS_ERROR_FAILURE;
+      uint32_t permission;
+      nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
+      pm->TestPermission(doc->NodePrincipal(), &permission);
+      if ((permission == nsIPopupWindowManager::DENY_POPUP)) {
+        nsCOMPtr<nsIDOMDocument> domDoc = aWindow->GetExtantDocument();
+        nsGlobalWindow::FirePopupBlockedEvent(
+          domDoc, aWindow, nullptr, EmptyString(), EmptyString()
+                                              );
+        return NS_OK;
+      }
     }
   }
 #endif
 
   rv = aParams->GetAudio(&audio);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aParams->GetVideo(&video);
@@ -418,23 +416,28 @@ MediaManager::GetUserMedia(nsPIDOMWindow
   }
 
   // Pass runnables along to GetUserMediaRunnable so it can add the
   // MediaStreamListener to the runnable list.
   nsCOMPtr<nsIRunnable> gUMRunnable = new GetUserMediaRunnable(
     audio, video, picture, onSuccess, onError, listeners, windowID
   );
 
-  // Reuse the same thread to save memory.
-  if (!mMediaThread) {
-    rv = NS_NewThread(getter_AddRefs(mMediaThread));
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (picture) {
+    // ShowFilePickerForMimeType() must run on the Main Thread! (on Android)
+    NS_DispatchToMainThread(gUMRunnable);
+  } else {
+    // Reuse the same thread to save memory.
+    if (!mMediaThread) {
+      rv = NS_NewThread(getter_AddRefs(mMediaThread));
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL);
   }
-
-  mMediaThread->Dispatch(gUMRunnable, NS_DISPATCH_NORMAL);
   return NS_OK;
 }
 
 MediaEngine*
 MediaManager::GetBackend()
 {
   // Plugin backends as appropriate. The default engine also currently
   // includes picture support for Android.
--- a/dom/plugins/base/nsIPluginHost.idl
+++ b/dom/plugins/base/nsIPluginHost.idl
@@ -7,17 +7,17 @@
 #include "nsISupports.idl"
 #include "nsIPluginTag.idl"
 
 %{C++
 #define MOZ_PLUGIN_HOST_CONTRACTID \
   "@mozilla.org/plugin/host;1"
 %}
 
-[scriptable, uuid(28F1F9E1-CD23-4FE2-BCC8-BBB0B2D49A4A)]
+[scriptable, uuid(fdb56ce3-89ac-4293-be64-9f4be88004cc)]
 interface nsIPluginHost : nsISupports
 {
   /**
    * Causes the plugins directory to be searched again for new plugin 
    * libraries.
    *
    * @param reloadPages - indicates whether currently visible pages should 
    * also be reloaded
@@ -67,10 +67,19 @@ interface nsIPluginHost : nsISupports
    * @param plugin: the plugin to query, such as one returned by
    *                nsIPluginHost.getPluginTags.
    * @param domain: the domain to test. If this argument is null, test if data
    *                is stored for any site. The base domain for the given domain
    *                will be determined; if any data for the base domain or its
    *                subdomains is found, return true.
    */
   boolean siteHasData(in nsIPluginTag plugin, in AUTF8String domain);
+
+  /**
+   * Registers the play preview plugin mode for specific mime type
+   *
+   * @param mimeType - specified mime type
+   */
+  void registerPlayPreviewMimeType(in AUTF8String mimeType);
+
+  void unregisterPlayPreviewMimeType(in AUTF8String mimeType);
 };
 
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -1304,16 +1304,27 @@ nsPluginHost::IsPluginClickToPlayForType
       (plugin->HasFlag(NS_PLUGIN_FLAG_CLICKTOPLAY) || mPluginsClickToPlay)) {
     return true;
   }
   else {
     return false;
   }
 }
 
+bool
+nsPluginHost::IsPluginPlayPreviewForType(const char* aMimeType)
+{
+  for (uint32_t i = 0; i < mPlayPreviewMimeTypes.Length(); i++) {
+    nsCString mt = mPlayPreviewMimeTypes[i];
+    if (PL_strcasecmp(mt.get(), aMimeType) == 0)
+      return true;
+  }
+  return false;
+}
+
 nsresult
 nsPluginHost::GetBlocklistStateForType(const char *aMimeType, uint32_t *aState) 
 {
   nsPluginTag *plugin = FindPluginForType(aMimeType, true);
   if (plugin) {
     nsCOMPtr<nsIBlocklistService> blocklist = do_GetService("@mozilla.org/extensions/blocklist;1");
     if (blocklist) {
       // The EmptyString()s are so we use the currently running application
@@ -1811,16 +1822,37 @@ nsPluginHost::EnumerateSiteData(const ns
       break;
     }
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
+nsPluginHost::RegisterPlayPreviewMimeType(const nsACString& mimeType)
+{
+  mPlayPreviewMimeTypes.AppendElement(mimeType);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginHost::UnregisterPlayPreviewMimeType(const nsACString& mimeType)
+{
+  nsCAutoString mimeTypeToRemove(mimeType);
+  for (uint32_t i = mPlayPreviewMimeTypes.Length(); i > 0;) {
+    nsCString mt = mPlayPreviewMimeTypes[--i];
+    if (PL_strcasecmp(mt.get(), mimeTypeToRemove.get()) == 0) {
+      mPlayPreviewMimeTypes.RemoveElementAt(i);
+      break;
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 nsPluginHost::ClearSiteData(nsIPluginTag* plugin, const nsACString& domain,
                             uint64_t flags, int64_t maxAge)
 {
   // maxAge must be either a nonnegative integer or -1.
   NS_ENSURE_ARG(maxAge >= 0 || maxAge == -1);
 
   // Caller may give us a tag object that is no longer live.
   if (!IsLiveTag(plugin)) {
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -81,16 +81,17 @@ public:
   nsresult UnloadPlugins();
 
   nsresult SetUpPluginInstance(const char *aMimeType,
                                nsIURI *aURL,
                                nsIPluginInstanceOwner *aOwner);
   nsresult IsPluginEnabledForType(const char* aMimeType);
   nsresult IsPluginEnabledForExtension(const char* aExtension, const char* &aMimeType);
   bool     IsPluginClickToPlayForType(const char *aMimeType);
+  bool     IsPluginPlayPreviewForType(const char *aMimeType);
   nsresult GetBlocklistStateForType(const char *aMimeType, uint32_t *state);
 
   nsresult GetPluginCount(uint32_t* aPluginCount);
   nsresult GetPlugins(uint32_t aPluginCount, nsIDOMPlugin** aPluginArray);
 
   nsresult GetURL(nsISupports* pluginInst,
                   const char* url,
                   const char* target,
@@ -276,16 +277,17 @@ private:
 
   nsresult EnsurePrivateDirServiceProvider();
 
   void OnPluginInstanceDestroyed(nsPluginTag* aPluginTag);
 
   nsRefPtr<nsPluginTag> mPlugins;
   nsRefPtr<nsPluginTag> mCachedPlugins;
   nsRefPtr<nsInvalidPluginTag> mInvalidPlugins;
+  nsTArray<nsCString> mPlayPreviewMimeTypes;
   bool mPluginsLoaded;
   bool mDontShowBadPluginMessage;
 
   // set by pref plugin.override_internal_types
   bool mOverrideInternalTypes;
 
   // set by pref plugin.disable
   bool mPluginsDisabled;
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1775,18 +1775,20 @@ let RILNetworkInterface = {
          datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED)) {
       this.connecting = false;
       this.cid = datacall.cid;
       this.name = datacall.ifname;
       this.ip = datacall.ip;
       this.netmask = datacall.netmask;
       this.broadcast = datacall.broadcast;
       this.gateway = datacall.gw;
-      this.dns1 = datacall.dns[0];
-      this.dns2 = datacall.dns[1];
+      if (datacall.dns) {
+        this.dns1 = datacall.dns[0];
+        this.dns2 = datacall.dns[1];
+      }
       if (!this.registeredAsNetworkInterface) {
         let networkManager = Cc["@mozilla.org/network/manager;1"]
                                .getService(Ci.nsINetworkManager);
         networkManager.registerNetworkInterface(this);
         this.registeredAsNetworkInterface = true;
       }
     }
     if (this.cid != datacall.cid) {
--- a/dom/tests/mochitest/whatwg/test_bug500328.html
+++ b/dom/tests/mochitest/whatwg/test_bug500328.html
@@ -111,17 +111,17 @@ function onChildLoad(e) {
     statusMsg("Got load for " + getURLFromEvent(e) + ", but not calling gGen.next() because gCallbackOnIframeLoad was false.");
   }
 }
 
 function onChildPageShow(e) {
   if(gCallbackOnIframePageShow) {
     statusMsg("Got pageshow for " + getURLFromEvent(e) + ".  About to call gGen.next().");
     gCallbackOnIframePageShow = false;
-    gGen.next();
+    SimpleTest.executeSoon(function() { gGen.next(); });
   }
   else {
     statusMsg("Got pageshow for " + getURLFromEvent(e) + ", but not calling gGen.next() because gCallbackOnIframePageShow was false.");
   }
 }
 
 function enableChildLoadCallback() {
   gCallbackOnIframeLoad = true;
--- a/extensions/spellcheck/hunspell/src/README.hunspell
+++ b/extensions/spellcheck/hunspell/src/README.hunspell
@@ -31,17 +31,17 @@
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 ******* END LICENSE BLOCK *******
 
 Hunspell Version:   1.3.2
-Additional Patches: 694002, 710967, 710940
+Additional Patches: 694002, 710967, 710940, 784776
 
 Hunspell Author: László Németh
 MySpell Author: Kevin Hendricks & David Einstein
 
 Hunspell is a spell checker and morphological analyser library. Hunspell
 is based on OpenOffice.org's Myspell. Documentation, tests, and examples
 are available at http://hunspell.sourceforge.net.
 
--- a/extensions/spellcheck/hunspell/src/affentry.hxx
+++ b/extensions/spellcheck/hunspell/src/affentry.hxx
@@ -79,17 +79,17 @@ public:
 
   PfxEntry(AffixMgr* pmgr, affentry* dp );
   ~PfxEntry();
 
   inline bool          allowCross() { return ((opts & aeXPRODUCT) != 0); }
   struct hentry *      checkword(const char * word, int len, char in_compound, 
                             const FLAG needflag = FLAG_NULL);
 
-  struct hentry *      check_twosfx(const char * word, int len, char in_compound, const FLAG needflag = NULL);
+  struct hentry *      check_twosfx(const char * word, int len, char in_compound, const FLAG needflag = FLAG_NULL);
 
   char *      check_morph(const char * word, int len, char in_compound,
                             const FLAG needflag = FLAG_NULL);
 
   char *      check_twosfx_morph(const char * word, int len,
                   char in_compound, const FLAG needflag = FLAG_NULL);
 
   inline FLAG getFlag()   { return aflag;   }
@@ -142,17 +142,17 @@ public:
   ~SfxEntry();
 
   inline bool          allowCross() { return ((opts & aeXPRODUCT) != 0); }
   struct hentry *   checkword(const char * word, int len, int optflags, 
                     PfxEntry* ppfx, char ** wlst, int maxSug, int * ns,
 //                    const FLAG cclass = FLAG_NULL, const FLAG needflag = FLAG_NULL, char in_compound=IN_CPD_NOT);
                     const FLAG cclass = FLAG_NULL, const FLAG needflag = FLAG_NULL, const FLAG badflag = 0);
 
-  struct hentry *   check_twosfx(const char * word, int len, int optflags, PfxEntry* ppfx, const FLAG needflag = NULL);
+  struct hentry *   check_twosfx(const char * word, int len, int optflags, PfxEntry* ppfx, const FLAG needflag = FLAG_NULL);
 
   char *      check_twosfx_morph(const char * word, int len, int optflags,
                  PfxEntry* ppfx, const FLAG needflag = FLAG_NULL);
   struct hentry * get_next_homonym(struct hentry * he);
   struct hentry * get_next_homonym(struct hentry * word, int optflags, PfxEntry* ppfx, 
     const FLAG cclass, const FLAG needflag);
 
 
--- a/gfx/layers/ImageContainer.cpp
+++ b/gfx/layers/ImageContainer.cpp
@@ -408,41 +408,35 @@ PlanarYCbCrImage::~PlanarYCbCrImage()
 uint8_t* 
 PlanarYCbCrImage::AllocateBuffer(uint32_t aSize)
 {
   return mRecycleBin->GetBuffer(aSize); 
 }
 
 static void
 CopyPlane(uint8_t *aDst, uint8_t *aSrc,
-          const gfxIntSize &aSize, int32_t aStride,
-          int32_t aOffset, int32_t aSkip)
+          const gfxIntSize &aSize, int32_t aStride, int32_t aSkip)
 {
-  if (!aOffset && !aSkip) {
+  if (!aSkip) {
     // Fast path: planar input.
     memcpy(aDst, aSrc, aSize.height * aStride);
   } else {
     int32_t height = aSize.height;
     int32_t width = aSize.width;
     for (int y = 0; y < height; ++y) {
-      uint8_t *src = aSrc + aOffset;
+      uint8_t *src = aSrc;
       uint8_t *dst = aDst;
-      if (!aSkip) {
-        // Fast path: offset only, no per-pixel skip.
-        memcpy(dst, src, width);
-      } else {
-        // Slow path
-        for (int x = 0; x < width; ++x) {
-          *dst++ = *src++;
-          src += aSkip;
-        }
+      // Slow path
+      for (int x = 0; x < width; ++x) {
+        *dst++ = *src++;
+        src += aSkip;
       }
-      aSrc += aStride;
-      aDst += aStride;
     }
+    aSrc += aStride;
+    aDst += aStride;
   }
 }
 
 void
 PlanarYCbCrImage::CopyData(const Data& aData)
 {
   mData = aData;
 
@@ -455,24 +449,21 @@ PlanarYCbCrImage::CopyData(const Data& a
   if (!mBuffer)
     return;
 
   mData.mYChannel = mBuffer;
   mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height;
   mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height;
 
   CopyPlane(mData.mYChannel, aData.mYChannel,
-            mData.mYSize, mData.mYStride,
-            mData.mYOffset, mData.mYSkip);
+            mData.mYSize, mData.mYStride, mData.mYSkip);
   CopyPlane(mData.mCbChannel, aData.mCbChannel,
-            mData.mCbCrSize, mData.mCbCrStride,
-            mData.mCbOffset, mData.mCbSkip);
+            mData.mCbCrSize, mData.mCbCrStride, mData.mCbSkip);
   CopyPlane(mData.mCrChannel, aData.mCrChannel,
-            mData.mCbCrSize, mData.mCbCrStride,
-            mData.mCrOffset, mData.mCrSkip);
+            mData.mCbCrSize, mData.mCbCrStride, mData.mCrSkip);
 
   mSize = aData.mPicSize;
 }
 
 void
 PlanarYCbCrImage::SetData(const Data &aData)
 {
   CopyData(aData);
--- a/gfx/layers/ImageContainer.h
+++ b/gfx/layers/ImageContainer.h
@@ -604,38 +604,47 @@ private:
  *
  * The color format is detected based on the height/width ratios
  * defined above.
  * 
  * The Image that is rendered is the picture region defined by
  * mPicX, mPicY and mPicSize. The size of the rendered image is
  * mPicSize, not mYSize or mCbCrSize.
  *
- * mYOffset, mYSkip, mCbOffset, mCbSkip, mCrOffset, mCrSkip are added
- * to support various output formats from hardware decoder. m*Offset
- * are the extra left stride and m*Skip are per-pixel skips in the
+ * mYSkip, mCbSkip, mCrSkip are added to support various output
+ * formats from hardware decoder. They are per-pixel skips in the
  * source image.
+ *
+ * For example when image width is 640, mYStride is 670, mYSkip is 3,
+ * the mYChannel buffer looks like:
+ *
+ * |<----------------------- mYStride ----------------------------->|
+ * |<----------------- mYSize.width --------------->|
+ *  0   3   6   9   12  15  18  21                659             669
+ * |----------------------------------------------------------------|
+ * |Y___Y___Y___Y___Y___Y___Y___Y...                      |%%%%%%%%%|
+ * |Y___Y___Y___Y___Y___Y___Y___Y...                      |%%%%%%%%%|
+ * |Y___Y___Y___Y___Y___Y___Y___Y...                      |%%%%%%%%%|
+ * |            |<->|
+ *                mYSkip
  */
 class THEBES_API PlanarYCbCrImage : public Image {
 public:
   struct Data {
     // Luminance buffer
     uint8_t* mYChannel;
     int32_t mYStride;
     gfxIntSize mYSize;
-    int32_t mYOffset;
     int32_t mYSkip;
     // Chroma buffers
     uint8_t* mCbChannel;
     uint8_t* mCrChannel;
     int32_t mCbCrStride;
     gfxIntSize mCbCrSize;
-    int32_t mCbOffset;
     int32_t mCbSkip;
-    int32_t mCrOffset;
     int32_t mCrSkip;
     // Picture region
     uint32_t mPicX;
     uint32_t mPicY;
     gfxIntSize mPicSize;
     StereoMode mStereoMode;
 
     nsIntRect GetPictureRect() const {
--- a/gfx/layers/Makefile.in
+++ b/gfx/layers/Makefile.in
@@ -28,16 +28,17 @@ DEFINES += -DD3D_DEBUG_INFO
 endif
 
 EXPORTS = \
         BasicLayers.h \
         BasicTiledThebesLayer.h \
         BasicImplData.h \
         GonkIOSurfaceImage.h \
         FrameMetrics.h \
+        CompositorChild.h \
         CompositorParent.h \
         ImageContainer.h \
         ImageLayers.h \
         ImageTypes.h \
         Layers.h \
         LayersTypes.h \
         LayerManagerOGLShaders.h \
         LayerManagerOGL.h \
--- a/gfx/layers/ipc/CompositorChild.h
+++ b/gfx/layers/ipc/CompositorChild.h
@@ -30,16 +30,17 @@ public:
    * or Bridge() request from our parent process.  The Transport is to
    * the compositor's context.
    */
   static PCompositorChild*
   Create(Transport* aTransport, ProcessId aOtherProcess);
 
   static PCompositorChild* Get();
 
+  static bool ChildProcessHasCompositor() { return sCompositor != nullptr; }
 protected:
   virtual PLayersChild* AllocPLayers(const LayersBackend& aBackendHint,
                                      const uint64_t& aId,
                                      LayersBackend* aBackend,
                                      int* aMaxTextureSize);
   virtual bool DeallocPLayers(PLayersChild *aChild);
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -318,16 +318,28 @@ CompositorParent::ScheduleTask(Cancelabl
   if (time == 0) {
     MessageLoop::current()->PostTask(FROM_HERE, task);
   } else {
     MessageLoop::current()->PostDelayedTask(FROM_HERE, task, time);
   }
 }
 
 void
+CompositorParent::NotifyShadowTreeTransaction()
+{
+  if (mLayerManager) {
+    ShadowLayerManager *shadow = mLayerManager->AsShadowManager();
+    if (shadow) {
+      shadow->NotifyShadowTreeTransaction();
+    }
+  }
+  ScheduleComposition();
+}
+
+void
 CompositorParent::ScheduleComposition()
 {
   if (mCurrentCompositeTask) {
     return;
   }
 
   bool initialComposition = mLastCompose.IsNull();
   TimeDuration delta;
@@ -882,16 +894,20 @@ CompositorParent::ShadowLayersUpdated(Sh
   mIsFirstPaint = mIsFirstPaint || isFirstPaint;
   mLayersUpdated = true;
   Layer* root = aLayerTree->GetRoot();
   mLayerManager->SetRoot(root);
   if (root) {
     SetShadowProperties(root);
   }
   ScheduleComposition();
+  ShadowLayerManager *shadow = mLayerManager->AsShadowManager();
+  if (shadow) {
+    shadow->NotifyShadowTreeTransaction();
+  }
 }
 
 PLayersParent*
 CompositorParent::AllocPLayers(const LayersBackend& aBackendHint,
                                const uint64_t& aId,
                                LayersBackend* aBackend,
                                int32_t* aMaxTextureSize)
 {
@@ -1189,17 +1205,17 @@ CrossProcessCompositorParent::ShadowLaye
   uint64_t id = aLayerTree->GetId();
   MOZ_ASSERT(id != 0);
   Layer* shadowRoot = aLayerTree->GetRoot();
   if (shadowRoot) {
     SetShadowProperties(shadowRoot);
   }
   UpdateIndirectTree(id, shadowRoot, isFirstPaint);
 
-  sCurrentCompositor->ScheduleComposition();
+  sCurrentCompositor->NotifyShadowTreeTransaction();
 }
 
 void
 CrossProcessCompositorParent::DeferredDestroy()
 {
   mSelfRef = NULL;
   // |this| was just destroyed, hands off
 }
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -81,17 +81,18 @@ public:
   void AsyncRender();
 
   // Can be called from any thread
   void ScheduleRenderOnCompositorThread();
   void SchedulePauseOnCompositorThread();
   void ScheduleResumeOnCompositorThread(int width, int height);
 
   virtual void ScheduleComposition();
-  
+  void NotifyShadowTreeTransaction();
+
   /**
    * Returns a pointer to the compositor corresponding to the given ID. 
    */
   static CompositorParent* GetCompositor(uint64_t id);
 
   /**
    * Returns the compositor thread's message loop.
    *
--- a/gfx/layers/ipc/ShadowLayers.h
+++ b/gfx/layers/ipc/ShadowLayers.h
@@ -406,16 +406,18 @@ public:
   virtual already_AddRefed<ShadowImageLayer> CreateShadowImageLayer() = 0;
   /** CONSTRUCTION PHASE ONLY */
   virtual already_AddRefed<ShadowColorLayer> CreateShadowColorLayer() = 0;
   /** CONSTRUCTION PHASE ONLY */
   virtual already_AddRefed<ShadowCanvasLayer> CreateShadowCanvasLayer() = 0;
   /** CONSTRUCTION PHASE ONLY */
   virtual already_AddRefed<ShadowRefLayer> CreateShadowRefLayer() { return nullptr; }
 
+  virtual void NotifyShadowTreeTransaction() {}
+
   /**
    * Try to open |aDescriptor| for direct texturing.  If the
    * underlying surface supports direct texturing, a non-null
    * TextureImage is returned.  Otherwise null is returned.
    */
   static already_AddRefed<TextureImage>
   OpenDescriptorForDirectTexturing(GLContext* aContext,
                                    const SurfaceDescriptor& aDescriptor,
--- a/gfx/layers/opengl/LayerManagerOGL.cpp
+++ b/gfx/layers/opengl/LayerManagerOGL.cpp
@@ -509,31 +509,44 @@ LayerManagerOGL::RootLayer() const
     return nullptr;
   }
 
   return static_cast<LayerOGL*>(mRoot->ImplData());
 }
 
 bool LayerManagerOGL::sDrawFPS = false;
 
+void
+LayerManagerOGL::FPSState::NotifyShadowTreeTransaction()
+{
+  contentFCount++;
+}
+
 /* This function tries to stick to portable C89 as much as possible
  * so that it can be easily copied into other applications */
 void
 LayerManagerOGL::FPSState::DrawFPS(GLContext* context, ShaderProgramOGL* copyprog)
 {
   fcount++;
 
   int rate = 30;
   if (fcount >= rate) {
     TimeStamp now = TimeStamp::Now();
     TimeDuration duration = now - last;
     last = now;
     fps = rate / duration.ToSeconds() + .5;
     fcount = 0;
   }
+  if (contentFCount >= rate) {
+    TimeStamp now = TimeStamp::Now();
+    TimeDuration duration = now - contentLast;
+    contentLast = now;
+    contentFps = contentFCount / duration.ToSeconds() + .5;
+    contentFCount = 0;
+  }
 
   GLint viewport[4];
   context->fGetIntegerv(LOCAL_GL_VIEWPORT, viewport);
 
   static GLuint texture;
   if (!initialized) {
     // Bind the number of textures we need, in this case one.
     context->fGenTextures(1, &texture);
@@ -578,23 +591,44 @@ LayerManagerOGL::FPSState::DrawFPS(GLCon
     {  -1.0f + 22.f / viewport[2], 1.0f - 42.f / viewport[3] },
     {  -1.0f + 22.f / viewport[2], 1.0f },
     {  -1.0f + 44.f / viewport[2], 1.0f - 42.f / viewport[3] },
     {  -1.0f + 44.f / viewport[2], 1.0f },
 
     { -1.0f + 44.f / viewport[2], 1.0f - 42.f / viewport[3] },
     { -1.0f + 44.f / viewport[2], 1.0f },
     { -1.0f + 66.f / viewport[2], 1.0f - 42.f / viewport[3] },
-    { -1.0f + 66.f / viewport[2], 1.0f }
+    { -1.0f + 66.f / viewport[2], 1.0f },
+  };
+    
+  const Vertex2D vertices2[] = {
+    { -1.0f + 80.f / viewport[2], 1.0f - 42.f / viewport[3] },
+    { -1.0f + 80.f / viewport[2], 1.0f },
+    { -1.0f + 102.f / viewport[2], 1.0f - 42.f / viewport[3] },
+    { -1.0f + 102.f / viewport[2], 1.0f },
+    
+    { -1.0f + 102.f / viewport[2], 1.0f - 42.f / viewport[3] },
+    { -1.0f + 102.f / viewport[2], 1.0f },
+    { -1.0f + 124.f / viewport[2], 1.0f - 42.f / viewport[3] },
+    { -1.0f + 124.f / viewport[2], 1.0f },
+    
+    { -1.0f + 124.f / viewport[2], 1.0f - 42.f / viewport[3] },
+    { -1.0f + 124.f / viewport[2], 1.0f },
+    { -1.0f + 146.f / viewport[2], 1.0f - 42.f / viewport[3] },
+    { -1.0f + 146.f / viewport[2], 1.0f },
   };
 
   int v1   = fps % 10;
   int v10  = (fps % 100) / 10;
   int v100 = (fps % 1000) / 100;
 
+  int content1 = contentFps % 10;
+  int content10  = (contentFps % 100) / 10;
+  int content100 = (contentFps % 1000) / 100;
+
   // Feel free to comment these texture coordinates out and use one
   // of the ones below instead, or play around with your own values.
   const GLfloat texCoords[] = {
     (v100 * 4.f) / 64, 7.f / 8,
     (v100 * 4.f) / 64, 0.0f,
     (v100 * 4.f + 4) / 64, 7.f / 8,
     (v100 * 4.f + 4) / 64, 0.0f,
 
@@ -603,16 +637,33 @@ LayerManagerOGL::FPSState::DrawFPS(GLCon
     (v10 * 4.f + 4) / 64, 7.f / 8,
     (v10 * 4.f + 4) / 64, 0.0f,
 
     (v1 * 4.f) / 64, 7.f / 8,
     (v1 * 4.f) / 64, 0.0f,
     (v1 * 4.f + 4) / 64, 7.f / 8,
     (v1 * 4.f + 4) / 64, 0.0f,
   };
+    
+  const GLfloat texCoords2[] = {
+    (content100 * 4.f) / 64, 7.f / 8,
+    (content100 * 4.f) / 64, 0.0f,
+    (content100 * 4.f + 4) / 64, 7.f / 8,
+    (content100 * 4.f + 4) / 64, 0.0f,
+
+    (content10 * 4.f) / 64, 7.f / 8,
+    (content10 * 4.f) / 64, 0.0f,
+    (content10 * 4.f + 4) / 64, 7.f / 8,
+    (content10 * 4.f + 4) / 64, 0.0f,
+
+    (content1 * 4.f) / 64, 7.f / 8,
+    (content1 * 4.f) / 64, 0.0f,
+    (content1 * 4.f + 4) / 64, 7.f / 8,
+    (content1 * 4.f + 4) / 64, 0.0f,
+  };
 
   // Turn necessary features on
   context->fEnable(LOCAL_GL_BLEND);
   context->fBlendFunc(LOCAL_GL_ONE, LOCAL_GL_SRC_COLOR);
 
   context->fActiveTexture(LOCAL_GL_TEXTURE0);
   context->fBindTexture(LOCAL_GL_TEXTURE_2D, texture);
 
@@ -640,16 +691,28 @@ LayerManagerOGL::FPSState::DrawFPS(GLCon
                                 0, vertices);
 
   context->fVertexAttribPointer(tcattr,
                                 2, LOCAL_GL_FLOAT,
                                 LOCAL_GL_FALSE,
                                 0, texCoords);
 
   context->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 12);
+  
+  context->fVertexAttribPointer(vcattr,
+                                2, LOCAL_GL_FLOAT,
+                                LOCAL_GL_FALSE,
+                                0, vertices2);
+
+  context->fVertexAttribPointer(tcattr,
+                                2, LOCAL_GL_FLOAT,
+                                LOCAL_GL_FALSE,
+                                0, texCoords2);
+
+  context->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 12);
 }
 
 // |aTexCoordRect| is the rectangle from the texture that we want to
 // draw using the given program.  The program already has a necessary
 // offset and scale, so the geometry that needs to be drawn is a unit
 // square from 0,0 to 1,1.
 //
 // |aTexSize| is the actual size of the texture, as it can be larger
@@ -718,16 +781,22 @@ LayerManagerOGL::BindAndDrawQuadWithText
 
       mGLContext->fDisableVertexAttribArray(vertAttribIndex);
     }
     mGLContext->fDisableVertexAttribArray(texCoordAttribIndex);
   }
 }
 
 void
+LayerManagerOGL::NotifyShadowTreeTransaction()
+{
+  mFPS.NotifyShadowTreeTransaction();
+}
+
+void
 LayerManagerOGL::Render()
 {
   SAMPLE_LABEL("LayerManagerOGL", "Render");
   if (mDestroyed) {
     NS_WARNING("Call on destroyed layer manager");
     return;
   }
 
--- a/gfx/layers/opengl/LayerManagerOGL.h
+++ b/gfx/layers/opengl/LayerManagerOGL.h
@@ -98,16 +98,17 @@ public:
 
   void BeginTransaction();
 
   void BeginTransactionWithTarget(gfxContext* aTarget);
 
   void EndConstruction();
 
   virtual bool EndEmptyTransaction(EndTransactionFlags aFlags = END_DEFAULT);
+  virtual void NotifyShadowTreeTransaction();
   virtual void EndTransaction(DrawThebesLayerCallback aCallback,
                               void* aCallbackData,
                               EndTransactionFlags aFlags = END_DEFAULT);
 
   virtual void SetRoot(Layer* aLayer) { mRoot = aLayer; }
 
   virtual bool CanUseCanvasLayerForSize(const gfxIntSize &aSize)
   {
@@ -441,25 +442,32 @@ private:
   struct FPSState
   {
       GLuint texture;
       int fps;
       bool initialized;
       int fcount;
       TimeStamp last;
 
+      int contentFps;
+      int contentFCount;
+      TimeStamp contentLast;
+
       FPSState()
         : texture(0)
         , fps(0)
         , initialized(false)
         , fcount(0)
+        , contentFps(0)
+        , contentFCount(0)
       {
-        last = TimeStamp::Now();
+        contentLast = last = TimeStamp::Now();
       }
       void DrawFPS(GLContext*, ShaderProgramOGL*);
+      void NotifyShadowTreeTransaction();
   } mFPS;
 
   static bool sDrawFPS;
 };
 
 /**
  * General information and tree management for OGL layers.
  */
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -2,16 +2,17 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifdef MOZ_LOGGING
 #define FORCE_PR_LOG /* Allow logging in the release build */
 #endif
 
+#include "mozilla/layers/CompositorChild.h"
 #include "mozilla/layers/CompositorParent.h"
 #include "mozilla/layers/ImageBridgeChild.h"
 
 #include "prlog.h"
 #include "prenv.h"
 
 #include "gfxPlatform.h"
 
@@ -1227,16 +1228,24 @@ gfxPlatform::UseAzureContentDrawing()
     sAzureContentDrawingPrefCached = true;
     mozilla::Preferences::AddBoolVarCache(&sAzureContentDrawingEnabled,
                                           "gfx.content.azure.enabled");
   }
 
   return sAzureContentDrawingEnabled;
 }
 
+bool
+gfxPlatform::OffMainThreadCompositingEnabled()
+{
+  return XRE_GetProcessType() == GeckoProcessType_Default ?
+    CompositorParent::CompositorLoop() != nullptr :
+    CompositorChild::ChildProcessHasCompositor();
+}
+
 eCMSMode
 gfxPlatform::GetCMSMode()
 {
     if (gCMSInitialized == false) {
         gCMSInitialized = true;
         nsresult rv;
 
         int32_t mode;
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -373,17 +373,19 @@ public:
         // platform-specific override, by default do nothing
     }
 
     // Break large OMTC tiled thebes layer painting into small paints.
     static bool UseProgressiveTilePainting();
 
     // helper method to indicate if we want to use Azure content drawing
     static bool UseAzureContentDrawing();
-    
+
+    static bool OffMainThreadCompositingEnabled();
+
     /**
      * Are we going to try color management?
      */
     static eCMSMode GetCMSMode();
 
     /**
      * Determines the rendering intent for color management.
      *
--- a/hal/HalTypes.h
+++ b/hal/HalTypes.h
@@ -24,22 +24,24 @@ enum LightType {
     eHalLightID_Notifications = 4,
     eHalLightID_Attention = 5,
     eHalLightID_Bluetooth = 6,
     eHalLightID_Wifi = 7,
     eHalLightID_Count = 8         // This should stay at the end
 };
 enum LightMode {
     eHalLightMode_User = 0,       // brightness is managed by user setting
-    eHalLightMode_Sensor = 1      // brightness is managed by a light sensor
+    eHalLightMode_Sensor = 1,     // brightness is managed by a light sensor
+    eHalLightMode_Count
 };
 enum FlashMode {
     eHalLightFlash_None = 0,
     eHalLightFlash_Timed = 1,     // timed flashing.  Use flashOnMS and flashOffMS for timing
-    eHalLightFlash_Hardware = 2   // hardware assisted flashing
+    eHalLightFlash_Hardware = 2,  // hardware assisted flashing
+    eHalLightFlash_Count
 };
 
 class SwitchEvent;
 
 enum SwitchDevice {
   SWITCH_DEVICE_UNKNOWN = -1,
   SWITCH_HEADPHONES,
   SWITCH_USB,
@@ -64,16 +66,17 @@ enum ProcessPriority {
 
 /**
  * Used by ModifyWakeLock
  */
 enum WakeLockControl {
   WAKE_LOCK_REMOVE_ONE = -1,
   WAKE_LOCK_NO_CHANGE  = 0,
   WAKE_LOCK_ADD_ONE    = 1,
+  NUM_WAKE_LOCK
 };
 
 } // namespace hal
 } // namespace mozilla
 
 namespace IPC {
 
 /**
@@ -88,37 +91,37 @@ struct ParamTraits<mozilla::hal::LightTy
 
 /**
  * Light mode serializer.
  */
 template <>
 struct ParamTraits<mozilla::hal::LightMode>
   : public EnumSerializer<mozilla::hal::LightMode,
                           mozilla::hal::eHalLightMode_User,
-                          mozilla::hal::eHalLightMode_Sensor>
+                          mozilla::hal::eHalLightMode_Count>
 {};
 
 /**
  * Flash mode serializer.
  */
 template <>
 struct ParamTraits<mozilla::hal::FlashMode>
   : public EnumSerializer<mozilla::hal::FlashMode,
                           mozilla::hal::eHalLightFlash_None,
-                          mozilla::hal::eHalLightFlash_Hardware>
+                          mozilla::hal::eHalLightFlash_Count>
 {};
 
 /**
  * WakeLockControl serializer.
  */
 template <>
 struct ParamTraits<mozilla::hal::WakeLockControl>
   : public EnumSerializer<mozilla::hal::WakeLockControl,
                           mozilla::hal::WAKE_LOCK_REMOVE_ONE,
-                          mozilla::hal::WAKE_LOCK_ADD_ONE>
+                          mozilla::hal::NUM_WAKE_LOCK>
 {};
 
 /**
  * Serializer for SwitchState
  */
 template <>
 struct ParamTraits<mozilla::hal::SwitchState>:
   public EnumSerializer<mozilla::hal::SwitchState,
--- a/hal/sandbox/SandboxHal.cpp
+++ b/hal/sandbox/SandboxHal.cpp
@@ -569,29 +569,25 @@ public:
     unused << SendNotifySensorChange(aSensorData);
   }
 
   virtual bool
   RecvModifyWakeLock(const nsString &aTopic,
                      const WakeLockControl &aLockAdjust,
                      const WakeLockControl &aHiddenAdjust) MOZ_OVERRIDE
   {
-    if (!AppProcessHasPermission(this, "power")) {
-      return false;
-    }
+    // We allow arbitrary content to use wake locks.
     hal::ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust);
     return true;
   }
 
   virtual bool
   RecvEnableWakeLockNotifications() MOZ_OVERRIDE
   {
-    if (!AppProcessHasPermission(this, "power")) {
-      return false;
-    }
+    // We allow arbitrary content to use wake locks.
     hal::RegisterWakeLockObserver(this);
     return true;
   }
    
   virtual bool
   RecvDisableWakeLockNotifications() MOZ_OVERRIDE
   {
     hal::UnregisterWakeLockObserver(this);
--- a/intl/locale/src/unix/nsDateTimeFormatUnix.cpp
+++ b/intl/locale/src/unix/nsDateTimeFormatUnix.cpp
@@ -95,17 +95,17 @@ nsresult nsDateTimeFormatUnix::Initializ
 
 void nsDateTimeFormatUnix::LocalePreferred24hour()
 {
   char str[100];
   time_t tt;
   struct tm *tmc;
   int i;
 
-  tt = time((time_t)0);
+  tt = time(nullptr);
   tmc = localtime(&tt);
 
   tmc->tm_hour=22;    // put the test sample hour to 22:00 which is 10PM
   tmc->tm_min=0;      // set the min & sec other number than '2'
   tmc->tm_sec=0;
 
   char *temp = setlocale(LC_TIME, mPlatformLocale.get());
   strftime(str, (size_t)99, "%X", (struct tm *)tmc);
--- a/ipc/chromium/Makefile.in
+++ b/ipc/chromium/Makefile.in
@@ -210,17 +210,16 @@ CPPSRCS += \
 
 endif # } OS_MACOSX
 
 ifdef OS_LINUX # {
 
 CPPSRCS += \
   atomicops_internals_x86_gcc.cc \
   base_paths_linux.cc \
-  file_util_linux.cc \
   file_version_info_linux.cc \
   idle_timer_none.cc \
   process_util_linux.cc \
   time_posix.cc \
   $(NULL)
 
 ifdef MOZ_ENABLE_GTK2
 CPPSRCS += \
deleted file mode 100644
--- a/ipc/chromium/src/base/file_util_linux.cc
+++ /dev/null
@@ -1,85 +0,0 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/file_util.h"
-
-#include <fcntl.h>
-#if defined(ANDROID) || defined(OS_POSIX)
-#include <unistd.h>
-#endif
-
-#include <string>
-#include <vector>
-
-#include "base/eintr_wrapper.h"
-#include "base/file_path.h"
-#include "base/string_util.h"
-
-namespace file_util {
-
-bool GetTempDir(FilePath* path) {
-  const char* tmp = getenv("TMPDIR");
-  if (tmp)
-    *path = FilePath(tmp);
-  else
-    *path = FilePath("/tmp");
-  return true;
-}
-
-bool GetShmemTempDir(FilePath* path) {
-#ifdef ANDROID
-  return GetTempDir(path);
-#else
-  *path = FilePath("/dev/shm");
-  return true;
-#endif
-}
-
-bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
-  int infile = open(from_path.value().c_str(), O_RDONLY);
-  if (infile < 0)
-    return false;
-
-  int outfile = creat(to_path.value().c_str(), 0666);
-  if (outfile < 0) {
-    close(infile);
-    return false;
-  }
-
-  const size_t kBufferSize = 32768;
-  std::vector<char> buffer(kBufferSize);
-  bool result = true;
-
-  while (result) {
-    ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
-    if (bytes_read < 0) {
-      result = false;
-      break;
-    }
-    if (bytes_read == 0)
-      break;
-    // Allow for partial writes
-    ssize_t bytes_written_per_read = 0;
-    do {
-      ssize_t bytes_written_partial = HANDLE_EINTR(write(
-          outfile,
-          &buffer[bytes_written_per_read],
-          bytes_read - bytes_written_per_read));
-      if (bytes_written_partial < 0) {
-        result = false;
-        break;
-      }
-      bytes_written_per_read += bytes_written_partial;
-    } while (bytes_written_per_read < bytes_read);
-  }
-
-  if (HANDLE_EINTR(close(infile)) < 0)
-    result = false;
-  if (HANDLE_EINTR(close(outfile)) < 0)
-    result = false;
-
-  return result;
-}
-
-}  // namespace file_util
--- a/ipc/chromium/src/base/file_util_posix.cc
+++ b/ipc/chromium/src/base/file_util_posix.cc
@@ -17,16 +17,18 @@
 #include <sys/errno.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
 
 #include <fstream>
+#include <string>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/eintr_wrapper.h"
 #include "base/file_path.h"
 #include "base/logging.h"
 #include "base/string_util.h"
 #include "base/time.h"
 
@@ -514,16 +516,82 @@ bool GetCurrentDirectory(FilePath* dir) 
 }
 
 // Sets the current working directory for the process.
 bool SetCurrentDirectory(const FilePath& path) {
   int ret = chdir(path.value().c_str());
   return !ret;
 }
 
+#if !defined(OS_MACOSX)
+bool GetTempDir(FilePath* path) {
+  const char* tmp = getenv("TMPDIR");
+  if (tmp)
+    *path = FilePath(tmp);
+  else
+    *path = FilePath("/tmp");
+  return true;
+}
+
+bool GetShmemTempDir(FilePath* path) {
+#if defined(OS_LINUX) && !defined(ANDROID)
+  *path = FilePath("/dev/shm");
+  return true;
+#else
+  return GetTempDir(path);
+#endif
+}
+
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+  int infile = open(from_path.value().c_str(), O_RDONLY);
+  if (infile < 0)
+    return false;
+
+  int outfile = creat(to_path.value().c_str(), 0666);
+  if (outfile < 0) {
+    close(infile);
+    return false;
+  }
+
+  const size_t kBufferSize = 32768;
+  std::vector<char> buffer(kBufferSize);
+  bool result = true;
+
+  while (result) {
+    ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
+    if (bytes_read < 0) {
+      result = false;
+      break;
+    }
+    if (bytes_read == 0)
+      break;
+    // Allow for partial writes
+    ssize_t bytes_written_per_read = 0;
+    do {
+      ssize_t bytes_written_partial = HANDLE_EINTR(write(
+          outfile,
+          &buffer[bytes_written_per_read],
+          bytes_read - bytes_written_per_read));
+      if (bytes_written_partial < 0) {
+        result = false;
+        break;
+      }
+      bytes_written_per_read += bytes_written_partial;
+    } while (bytes_written_per_read < bytes_read);
+  }
+
+  if (HANDLE_EINTR(close(infile)) < 0)
+    result = false;
+  if (HANDLE_EINTR(close(outfile)) < 0)
+    result = false;
+
+  return result;
+}
+#endif // !defined(OS_MACOSX)
+
 ///////////////////////////////////////////////
 // FileEnumerator
 
 FileEnumerator::FileEnumerator(const FilePath& root_path,
                                bool recursive,
                                FileEnumerator::FILE_TYPE file_type)
     : recursive_(recursive),
       file_type_(file_type),
--- a/ipc/chromium/src/chrome/common/ipc_message.cc
+++ b/ipc/chromium/src/chrome/common/ipc_message.cc
@@ -23,21 +23,23 @@ Message::Message()
   header()->routing = header()->type = header()->flags = 0;
 #if defined(OS_POSIX)
   header()->num_fds = 0;
 #endif
   InitLoggingVariables();
 }
 
 Message::Message(int32 routing_id, msgid_t type, PriorityValue priority,
-                 const char* const name)
+                 MessageCompression compression, const char* const name)
     : Pickle(sizeof(Header)) {
   header()->routing = routing_id;
   header()->type = type;
   header()->flags = priority;
+  if (compression == COMPRESSION_ENABLED)
+    header()->flags |= COMPRESS_BIT;
 #if defined(OS_POSIX)
   header()->num_fds = 0;
 #endif
   header()->rpc_remote_stack_depth_guess = static_cast<uint32>(-1);
   header()->rpc_local_stack_depth = static_cast<uint32>(-1);
   header()->seqno = 0;
   InitLoggingVariables(name);
 }
--- a/ipc/chromium/src/chrome/common/ipc_message.h
+++ b/ipc/chromium/src/chrome/common/ipc_message.h
@@ -49,23 +49,29 @@ class Message : public Pickle {
   };
 
   enum PriorityValue {
     PRIORITY_LOW = 1,
     PRIORITY_NORMAL,
     PRIORITY_HIGH
   };
 
+  enum MessageCompression {
+    COMPRESSION_NONE,
+    COMPRESSION_ENABLED
+  };
+
   virtual ~Message();
 
   Message();
 
   // Initialize a message with a user-defined type, priority value, and
   // destination WebView ID.
   Message(int32 routing_id, msgid_t type, PriorityValue priority,
+          MessageCompression compression = COMPRESSION_NONE,
           const char* const name="???");
 
   // Initializes a message from a const block of data.  The data is not copied;
   // instead the data is merely referenced by this message.  Only const methods
   // should be used on the message when initialized this way.
   Message(const char* data, int data_len);
 
   Message(const Message& other);
@@ -80,16 +86,21 @@ class Message : public Pickle {
     return (header()->flags & SYNC_BIT) != 0;
   }
 
   // True if this is a synchronous message.
   bool is_rpc() const {
     return (header()->flags & RPC_BIT) != 0;
   }
 
+  // True if compression is enabled for this message.
+  bool compress() const {
+    return (header()->flags & COMPRESS_BIT) != 0;
+  }
+
   // Set this on a reply to a synchronous message.
   void set_reply() {
     header()->flags |= REPLY_BIT;
   }
 
   bool is_reply() const {
     return (header()->flags & REPLY_BIT) != 0;
   }
@@ -258,17 +269,18 @@ class Message : public Pickle {
   enum {
     PRIORITY_MASK   = 0x0003,
     SYNC_BIT        = 0x0004,
     REPLY_BIT       = 0x0008,
     REPLY_ERROR_BIT = 0x0010,
     UNBLOCK_BIT     = 0x0020,
     PUMPING_MSGS_BIT= 0x0040,
     HAS_SENT_TIME_BIT = 0x0080,
-    RPC_BIT        = 0x0100
+    RPC_BIT         = 0x0100,
+    COMPRESS_BIT    = 0x0200
   };
 
 #pragma pack(push, 2)
   struct Header : Pickle::Header {
     int32 routing;  // ID of the view that this message is destined for
     msgid_t type;   // specifies the user-defined message type
     uint32 flags;   // specifies control flags for the message
 #if defined(OS_POSIX)
--- a/ipc/glue/CrossProcessMutex_unimplemented.cpp
+++ b/ipc/glue/CrossProcessMutex_unimplemented.cpp
@@ -35,12 +35,12 @@ CrossProcessMutex::Unlock()
 {
   NS_RUNTIMEABORT("Cross-process mutices not allowed on this platform - woah! We should've aborted by now!");
 }
 
 CrossProcessMutexHandle
 CrossProcessMutex::ShareToProcess(base::ProcessHandle aHandle)
 {
   NS_RUNTIMEABORT("Cross-process mutices not allowed on this platform - woah! We should've aborted by now!");
-  return NULL;
+  return 0;
 }
 
 }
--- a/ipc/glue/MessagePump.cpp
+++ b/ipc/glue/MessagePump.cpp
@@ -78,19 +78,20 @@ MessagePump::Run(MessagePump::Delegate* 
 
   for (;;) {
     autoReleasePool.Recycle();
 
     bool did_work = NS_ProcessNextEvent(mThread, false) ? true : false;
     if (!keep_running_)
       break;
 
-    did_work |= aDelegate->DoWork();
-    if (!keep_running_)
-      break;
+    // NB: it is crucial *not* to directly call |aDelegate->DoWork()|
+    // here.  To ensure that MessageLoop tasks and XPCOM events have
+    // equal priority, we sensitively rely on processing exactly one
+    // Task per DoWorkRunnable XPCOM event.
 
 #ifdef MOZ_WIDGET_ANDROID
     // This processes messages in the Android Looper. Note that we only
     // get here if the normal Gecko event loop has been awoken above.
     // Bug 750713
     AndroidBridge::Bridge()->PumpMessageLoop();
 #endif
 
@@ -202,11 +203,30 @@ MessagePumpForChildProcess::Run(MessageP
     gFirstDelegate = nullptr;
 #endif
     return;
   }
 
 #ifdef DEBUG
   NS_ASSERTION(aDelegate && aDelegate == gFirstDelegate, "Huh?!");
 #endif
+
+  // We can get to this point in startup with Tasks in our loop's
+  // incoming_queue_ or pending_queue_, but without a matching
+  // DoWorkRunnable().  In MessagePump::Run() above, we sensitively
+  // depend on *not* directly calling delegate->DoWork(), because that
+  // prioritizes Tasks above XPCOM events.  However, from this point
+  // forward, any Task posted to our loop is guaranteed to have a
+  // DoWorkRunnable enqueued for it.
+  //
+  // So we just flush the pending work here and move on.
+  MessageLoop* loop = MessageLoop::current();
+  bool nestableTasksAllowed = loop->NestableTasksAllowed();
+  loop->SetNestableTasksAllowed(true);
+
+  while (aDelegate->DoWork());
+
+  loop->SetNestableTasksAllowed(nestableTasksAllowed);
+
+
   // Really run.
   mozilla::ipc::MessagePump::Run(aDelegate);
 }
--- a/ipc/glue/RPCChannel.cpp
+++ b/ipc/glue/RPCChannel.cpp
@@ -190,17 +190,17 @@ RPCChannel::Call(Message* _msg, Message*
         if (!mOutOfTurnReplies.empty() &&
             ((it = mOutOfTurnReplies.find(mStack.top().seqno())) !=
             mOutOfTurnReplies.end())) {
             recvd = it->second;
             mOutOfTurnReplies.erase(it);
         }
         else if (!mPending.empty()) {
             recvd = mPending.front();
-            mPending.pop();
+            mPending.pop_front();
         }
         else {
             // because of subtleties with nested event loops, it's
             // possible that we got here and nothing happened.  or, we
             // might have a deferred in-call that needs to be
             // processed.  either way, we won't break the inner while
             // loop again until something new happens.
             continue;
@@ -305,17 +305,17 @@ RPCChannel::MaybeUndeferIncall()
     // maybe time to process this message
     Message call = mDeferred.top();
     mDeferred.pop();
 
     // fix up fudge factor we added to account for race
     RPC_ASSERT(0 < mRemoteStackDepthGuess, "fatal logic error");
     --mRemoteStackDepthGuess;
 
-    mPending.push(call);
+    mPending.push_back(call);
 }
 
 void
 RPCChannel::EnqueuePendingMessages()
 {
     AssertWorkerThread();
     mMonitor->AssertCurrentThreadOwns();
 
@@ -377,17 +377,17 @@ RPCChannel::OnMaybeDequeueOne()
 
         if (!mDeferred.empty())
             MaybeUndeferIncall();
 
         if (mPending.empty())
             return false;
 
         recvd = mPending.front();
-        mPending.pop();
+        mPending.pop_front();
     }
 
     if (IsOnCxxStack() && recvd.is_rpc() && recvd.is_reply()) {
         // We probably just received a reply in a nested loop for an
         // RPC call sent before entering that loop.
         mOutOfTurnReplies[recvd.seqno()] = recvd;
         return false;
     }
@@ -572,17 +572,17 @@ RPCChannel::BlockOnParent()
         if (!Connected()) {
             mBlockedOnParent = false;
             ReportConnectionError("RPCChannel");
             break;
         }
 
         if (!mPending.empty()) {
             Message recvd = mPending.front();
-            mPending.pop();
+            mPending.pop_front();
 
             MonitorAutoUnlock unlock(*mMonitor);
 
             CxxStackFrame f(*this, IN_MESSAGE, &recvd);
             if (recvd.is_rpc()) {
                 // stack depth must be 0 here
                 Incall(recvd, 0);
             }
@@ -645,17 +645,17 @@ RPCChannel::DebugAbort(const char* file,
             mPending.size());
 
     MessageQueue pending = mPending;
     while (!pending.empty()) {
         fprintf(stderr, "    [ %s%s ]\n",
                 pending.front().is_rpc() ? "rpc" :
                 (pending.front().is_sync() ? "sync" : "async"),
                 pending.front().is_reply() ? "reply" : "");
-        pending.pop();
+        pending.pop_front();
     }
 
     NS_RUNTIMEABORT(why);
 }
 
 void
 RPCChannel::DumpRPCStack(FILE* outfile, const char* const pfx) const
 {
@@ -696,22 +696,36 @@ RPCChannel::OnMessageReceivedFromLink(co
     // know that it needs to be immediately handled to unblock us.
     if (AwaitingSyncReply() && msg.is_sync()) {
         // wake up worker thread waiting at SyncChannel::Send
         mRecvd = msg;
         NotifyWorkerThread();
         return;
     }
 
-    mPending.push(msg);
+    bool compressMessage = (msg.compress() && !mPending.empty() &&
+                            mPending.back().type() == msg.type() &&
+                            mPending.back().routing_id() == msg.routing_id());
+    if (compressMessage) {
+        // This message type has compression enabled, and the back of
+        // the queue was the same message type and routed to the same
+        // destination.  Replace it with the newer message.
+        MOZ_ASSERT(mPending.back().compress());
+        mPending.pop_back();
+    }
+
+    mPending.push_back(msg);
 
     if (0 == StackDepth() && !mBlockedOnParent) {
         // the worker thread might be idle, make sure it wakes up
-        mWorkerLoop->PostTask(FROM_HERE,
-                                     new DequeueTask(mDequeueOneTask));
+        if (!compressMessage) {
+            // If we compressed away the previous message, we'll reuse
+            // its pending task.
+            mWorkerLoop->PostTask(FROM_HERE, new DequeueTask(mDequeueOneTask));
+        }
     }
     else if (!AwaitingSyncReply())
         NotifyWorkerThread();
 }
 
 
 void
 RPCChannel::OnChannelErrorFromLink()
--- a/ipc/glue/RPCChannel.h
+++ b/ipc/glue/RPCChannel.h
@@ -4,18 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef ipc_glue_RPCChannel_h
 #define ipc_glue_RPCChannel_h 1
 
 #include <stdio.h>
 
-// FIXME/cjones probably shouldn't depend on STL
-#include <queue>
+#include <deque>
 #include <stack>
 #include <vector>
 
 #include "base/basictypes.h"
 
 #include "nsAtomicRefcnt.h"
 
 #include "mozilla/ipc/SyncChannel.h"
@@ -333,17 +332,17 @@ private:
     // |?{mStack.size() == 1}|, then other side "finished with us,"
     // and went back to its own business.  That business might have
     // included sending any number of async message |A<*| until
     // sending a blocking message |(S< | C<)|.  If we had more than
     // one RPC call on our stack, the other side *better* not have
     // sent us another blocking message, because it's blocked on a
     // reply from us.
     //
-    typedef std::queue<Message> MessageQueue;
+    typedef std::deque<Message> MessageQueue;
     MessageQueue mPending;
 
     // 
     // Stack of all the RPC out-calls on which this RPCChannel is
     // awaiting a response.
     //
     std::stack<Message> mStack;
 
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -310,16 +310,17 @@ class ManagesStmt(Node):
 class MessageDecl(Node):
     def __init__(self, loc):
         Node.__init__(self, loc)
         self.name = None
         self.sendSemantics = ASYNC
         self.direction = None
         self.inParams = [ ]
         self.outParams = [ ]
+        self.compress = ''
 
     def addInParams(self, inParamsList):
         self.inParams += inParamsList
 
     def addOutParams(self, outParamsList):
         self.outParams += outParamsList
 
     def hasReply(self):
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -1545,23 +1545,25 @@ class _GenerateProtocolCode(ipdl.ast.Vis
         tfDecl, tfDefn = _splitFuncDeclDefn(self.genTransitionFunc())
         ns.addstmts([ tfDecl, Whitespace.NL ])
         self.funcDefns.append(tfDefn)
 
         typedefs = self.protocol.decl.cxxtypedefs
         for md in p.messageDecls:
             ns.addstmts([
                 _generateMessageClass(md.msgClass(), md.msgId(),
-                                      typedefs, md.prettyMsgName(p.name+'::')),
+                                      typedefs, md.prettyMsgName(p.name+'::'),
+                                      md.decl.type.compress),
                 Whitespace.NL ])
             if md.hasReply():
                 ns.addstmts([
                     _generateMessageClass(
                         md.replyClass(), md.replyId(),
-                        typedefs, md.prettyReplyName(p.name+'::')),
+                        typedefs, md.prettyReplyName(p.name+'::'),
+                        md.decl.type.compress),
                     Whitespace.NL ])
 
         ns.addstmts([ Whitespace.NL, Whitespace.NL ])
 
 
     def genBridgeFunc(self, bridge):
         p = self.protocol
         parentHandleType = _cxxBareType(ActorType(bridge.parent.ptype),
@@ -1739,35 +1741,40 @@ class _GenerateProtocolCode(ipdl.ast.Vis
             # all --> Error transitions break to here
             StmtExpr(ExprAssn(ExprDeref(nextvar), _errorState())),
             StmtReturn(ExprLiteral.FALSE)
         ])
         return transitionfunc
 
 ##--------------------------------------------------
 
-def _generateMessageClass(clsname, msgid, typedefs, prettyName):
+def _generateMessageClass(clsname, msgid, typedefs, prettyName, compress):
     cls = Class(name=clsname, inherits=[ Inherit(Type('IPC::Message')) ])
     cls.addstmt(Label.PRIVATE)
     cls.addstmts(typedefs)
     cls.addstmt(Whitespace.NL)
 
     cls.addstmt(Label.PUBLIC)
 
     idenum = TypeEnum()
     idenum.addId('ID', msgid)
     cls.addstmt(StmtDecl(Decl(idenum, '')))
 
     # make the message constructor
+    if compress:
+        compression = ExprVar('COMPRESSION_ENABLED')
+    else:
+        compression = ExprVar('COMPRESSION_NONE')
     ctor = ConstructorDefn(
         ConstructorDecl(clsname),
         memberinits=[ ExprMemberInit(ExprVar('IPC::Message'),
                                      [ ExprVar('MSG_ROUTING_NONE'),
                                        ExprVar('ID'),
                                        ExprVar('PRIORITY_NORMAL'),
+                                       compression,
                                        ExprLiteral.String(prettyName) ]) ])
     cls.addstmts([ ctor, Whitespace.NL ])
 
     # generate a logging function
     # 'pfx' will be something like "[FooParent] sent"
     pfxvar = ExprVar('__pfx')
     outfvar = ExprVar('__outf')
     logger = MethodDefn(MethodDecl(
--- a/ipc/ipdl/ipdl/parser.py
+++ b/ipc/ipdl/ipdl/parser.py
@@ -116,16 +116,17 @@ def locFromTok(p, num):
 reserved = set((
         'answer',
         'as',
         'async',
         'both',
         'bridges',
         'call',
         'child',
+        'compress',
         '__delete__',
         'delete',                       # reserve 'delete' to prevent its use
         'goto',
         'include',
         'manager',
         'manages',
         'namespace',
         'nullable',
@@ -479,23 +480,25 @@ def p_MessageDecl(p):
 
     if Parser.current.direction is None:
         _error(msg.loc, 'missing message direction')
     msg.direction = Parser.current.direction
 
     p[0] = msg
 
 def p_MessageBody(p):
-    """MessageBody : MessageId MessageInParams MessageOutParams"""
+    """MessageBody : MessageId MessageInParams MessageOutParams OptionalMessageCompress"""
     # FIXME/cjones: need better loc info: use one of the quals
     loc, name = p[1]
     msg = MessageDecl(loc)
     msg.name = name
     msg.addInParams(p[2])
     msg.addOutParams(p[3])
+    msg.compress = p[4]
+
     p[0] = msg
 
 def p_MessageId(p):
     """MessageId : ID
                  | __DELETE__
                  | DELETE
                  | '~' ID"""
     loc = locFromTok(p, 1)
@@ -512,16 +515,24 @@ def p_MessageInParams(p):
 def p_MessageOutParams(p):
     """MessageOutParams : RETURNS '(' ParamList ')'
                         | """
     if 1 == len(p):
         p[0] = [ ]
     else:
         p[0] = p[3]
 
+def p_OptionalMessageCompress(p):
+    """OptionalMessageCompress : COMPRESS
+                               | """
+    if 1 == len(p):
+        p[0] = ''
+    else:
+        p[0] = 'compress'
+
 ##--------------------
 ## State machine
 
 def p_TransitionStmtsOpt(p):
     """TransitionStmtsOpt : TransitionStmt TransitionStmtsOpt
                           |"""
     if 1 == len(p):
         # we fill in |loc| in the Protocol rule
--- a/ipc/ipdl/ipdl/type.py
+++ b/ipc/ipdl/ipdl/type.py
@@ -223,27 +223,28 @@ class StateType(IPDLType):
     def isState(self): return True
     def name(self):
         return self.name
     def fullname(self):
         return self.name()
 
 class MessageType(IPDLType):
     def __init__(self, sendSemantics, direction,
-                 ctor=False, dtor=False, cdtype=None):
+                 ctor=False, dtor=False, cdtype=None, compress=False):
         assert not (ctor and dtor)
         assert not (ctor or dtor) or type is not None
 
         self.sendSemantics = sendSemantics
         self.direction = direction
         self.params = [ ]
         self.returns = [ ]
         self.ctor = ctor
         self.dtor = dtor
         self.cdtype = cdtype
+        self.compress = compress
     def isMessage(self): return True
 
     def isCtor(self): return self.ctor
     def isDtor(self): return self.dtor
     def constructedType(self):  return self.cdtype
 
     def isIn(self): return self.direction is IN
     def isOut(self): return self.direction is OUT
@@ -1063,17 +1064,18 @@ class GatherDecls(TcheckVisitor):
             isdtor = True
             cdtype = self.currentProtocolDecl.type
 
 
         # enter message scope
         self.symtab.enterScope(md)
 
         msgtype = MessageType(md.sendSemantics, md.direction,
-                              ctor=isctor, dtor=isdtor, cdtype=cdtype)
+                              ctor=isctor, dtor=isdtor, cdtype=cdtype,
+                              compress=(md.compress == 'compress'))
 
         # replace inparam Param nodes with proper Decls
         def paramToDecl(param):
             ptname = param.typespec.basename()
             ploc = param.typespec.loc
 
             ptdecl = self.symtab.lookup(ptname)
             if ptdecl is None:
@@ -1453,16 +1455,23 @@ class CheckTypes(TcheckVisitor):
                 mname, pname)
 
         if mtype.isAsync() and len(mtype.returns):
             # XXX/cjones could modify grammar to disallow this ...
             self.error(loc,
                        "asynchronous message `%s' declares return values",
                        mname)
 
+        if (mtype.compress and
+            (not mtype.isAsync() or mtype.isCtor() or mtype.isDtor())):
+            self.error(
+                loc,
+                "message `%s' in protocol `%s' requests compression but is not async or is special (ctor or dtor)",
+                mname[:-len('constructor')], pname)
+
         if mtype.isCtor() and not ptype.isManagerOf(mtype.constructedType()):
             self.error(
                 loc,
                 "ctor for protocol `%s', which is not managed by protocol `%s'", 
                 mname[:-len('constructor')], pname)
 
 
     def visitTransition(self, t):
--- a/ipc/ipdl/test/cxx/PTestLatency.ipdl
+++ b/ipc/ipdl/test/cxx/PTestLatency.ipdl
@@ -7,16 +7,19 @@ rpc protocol PTestLatency {
 
 child:
     __delete__();
     Ping();
     Ping5();
     rpc Rpc();
     Spam();
     rpc Synchro();
+    CompressedSpam(uint32_t seqno) compress;
+    rpc Synchro2() returns (uint32_t lastSeqno,
+                            uint32_t numMessagesDispatched);
 
 parent:
     Pong();
     Pong5();
 
 state START:
     // if the timing resolution is too low, abort the test
     send __delete__;
@@ -47,19 +50,26 @@ state PONG3: recv Pong5 goto PONG4;
 state PONG4: recv Pong5 goto PONG5;
 state PONG5: recv Pong5 goto PING5;
 
     // Trial 3: lotsa RPC
 state RPC:
     call Rpc goto RPC;
     send Spam goto SPAM;
 
+    // Trial 4: lots of sequential asyn messages, which tests pipelining
 state SPAM:
     send Spam goto SPAM;
-    call Synchro goto DONE;
+    call Synchro goto COMPRESSED_SPAM;
+
+    // Trial 5: lots of async spam, but compressed to cut down on
+    // dispatch overhead
+state COMPRESSED_SPAM:          // compressed spam, mmm
+    send CompressedSpam goto COMPRESSED_SPAM;
+    call Synchro2 goto DONE;
 
 state DONE:
     send __delete__;
 };
 
 
 } // namespace mozilla
 } // namespace _ipdltest
--- a/ipc/ipdl/test/cxx/TestLatency.cpp
+++ b/ipc/ipdl/test/cxx/TestLatency.cpp
@@ -14,17 +14,17 @@ namespace _ipdltest {
 
 TestLatencyParent::TestLatencyParent() :
     mStart(),
     mPPTimeTotal(),
     mPP5TimeTotal(),
     mRpcTimeTotal(),
     mPPTrialsToGo(NR_TRIALS),
     mPP5TrialsToGo(NR_TRIALS),
-    mSpamsToGo(NR_TRIALS)
+    mNumChildProcessedCompressedSpams(0)
 {
     MOZ_COUNT_CTOR(TestLatencyParent);
 }
 
 TestLatencyParent::~TestLatencyParent()
 {
     MOZ_COUNT_DTOR(TestLatencyParent);
 }
@@ -137,29 +137,57 @@ TestLatencyParent::SpamTrial()
     // been processed.  This adds the overhead of a reply message from
     // child-->here, but should be insignificant compared to >>
     // NR_SPAMS.
     if (!CallSynchro())
         fail("calling Synchro()");
 
     mSpamTimeTotal = (TimeStamp::Now() - start);
 
+    CompressedSpamTrial();
+}
+
+void
+TestLatencyParent::CompressedSpamTrial()
+{
+    for (int i = 0; i < NR_SPAMS; ++i) {
+        if (!SendCompressedSpam(i + 1))
+            fail("sending CompressedSpam()");
+        if (0 == (i % 10000))
+            printf("  CompressedSpam trial %d\n", i);
+    }
+
+    uint32_t lastSeqno;
+    if (!CallSynchro2(&lastSeqno, &mNumChildProcessedCompressedSpams))
+        fail("calling Synchro2()");
+
+    if (lastSeqno != NR_SPAMS)
+        fail("last seqno was %u, expected %u", lastSeqno, NR_SPAMS);
+
+    // NB: since this is testing an optimization, it's somewhat bogus.
+    // Need to make a warning if it actually intermittently fails in
+    // practice, which is doubtful.
+    if (!(mNumChildProcessedCompressedSpams < NR_SPAMS))
+        fail("Didn't compress any messages?");
+
     Exit();
 }
 
 void
 TestLatencyParent::Exit()
 {
     Close();
 }
 
 //-----------------------------------------------------------------------------
 // child
 
 TestLatencyChild::TestLatencyChild()
+    : mLastSeqno(0)
+    , mNumProcessedCompressedSpams(0)
 {
     MOZ_COUNT_CTOR(TestLatencyChild);
 }
 
 TestLatencyChild::~TestLatencyChild()
 {
     MOZ_COUNT_DTOR(TestLatencyChild);
 }
@@ -201,10 +229,30 @@ TestLatencyChild::RecvSpam()
 }
 
 bool
 TestLatencyChild::AnswerSynchro()
 {
     return true;
 }
 
+bool
+TestLatencyChild::RecvCompressedSpam(const uint32_t& seqno)
+{
+    if (seqno <= mLastSeqno)
+        fail("compressed seqnos must monotonically increase");
+
+    mLastSeqno = seqno;
+    ++mNumProcessedCompressedSpams;
+    return true;
+}
+
+bool
+TestLatencyChild::AnswerSynchro2(uint32_t* lastSeqno,
+                                 uint32_t* numMessagesDispatched)
+{
+    *lastSeqno = mLastSeqno;
+    *numMessagesDispatched = mNumProcessedCompressedSpams;
+    return true;
+}
+
 } // namespace _ipdltest
 } // namespace mozilla
--- a/ipc/ipdl/test/cxx/TestLatency.h
+++ b/ipc/ipdl/test/cxx/TestLatency.h
@@ -4,17 +4,17 @@
 #include "mozilla/_ipdltest/IPDLUnitTests.h"
 
 #include "mozilla/_ipdltest/PTestLatencyParent.h"
 #include "mozilla/_ipdltest/PTestLatencyChild.h"
 
 #include "mozilla/TimeStamp.h"
 
 #define NR_TRIALS 10000
-#define NR_SPAMS  50000
+#define NR_SPAMS  25000
 
 namespace mozilla {
 namespace _ipdltest {
 
 class TestLatencyParent :
     public PTestLatencyParent
 {
 private:
@@ -38,64 +38,74 @@ protected:
     {
         if (NormalShutdown != why)
             fail("unexpected destruction!");  
 
         passed("\n"
                "  average #ping-pong/sec:        %g\n"
                "  average #ping5-pong5/sec:      %g\n"
                "  average #RPC call-answer/sec:  %g\n"
-               "  average #spams/sec:            %g\n",
+               "  average #spams/sec:            %g\n"
+               "  pct. spams compressed away:    %g\n",
                double(NR_TRIALS) / mPPTimeTotal.ToSecondsSigDigits(),
                double(NR_TRIALS) / mPP5TimeTotal.ToSecondsSigDigits(),
                double(NR_TRIALS) / mRpcTimeTotal.ToSecondsSigDigits(),
-               double(NR_SPAMS) / mSpamTimeTotal.ToSecondsSigDigits());
+               double(NR_SPAMS) / mSpamTimeTotal.ToSecondsSigDigits(),
+               100.0 * (double(NR_SPAMS - mNumChildProcessedCompressedSpams) /
+                        double(NR_SPAMS)));
 
         QuitParent();
     }
 
 private:
     void PingPongTrial();
     void Ping5Pong5Trial();
     void RpcTrials();
     void SpamTrial();
+    void CompressedSpamTrial();
     void Exit();
 
     TimeStamp mStart;
     TimeDuration mPPTimeTotal;
     TimeDuration mPP5TimeTotal;
     TimeDuration mRpcTimeTotal;
     TimeDuration mSpamTimeTotal;
 
     int mPPTrialsToGo;
     int mPP5TrialsToGo;
-    int mSpamsToGo;
+    uint32_t mNumChildProcessedCompressedSpams;
 };
 
 
 class TestLatencyChild :
     public PTestLatencyChild
 {
 public:
     TestLatencyChild();
     virtual ~TestLatencyChild();
 
 protected:
     virtual bool RecvPing() MOZ_OVERRIDE;
     virtual bool RecvPing5() MOZ_OVERRIDE;
     virtual bool AnswerRpc() MOZ_OVERRIDE;
     virtual bool RecvSpam() MOZ_OVERRIDE;
     virtual bool AnswerSynchro() MOZ_OVERRIDE;
+    virtual bool RecvCompressedSpam(const uint32_t& seqno) MOZ_OVERRIDE;
+    virtual bool AnswerSynchro2(uint32_t* lastSeqno,
+                                uint32_t* numMessagesDispatched) MOZ_OVERRIDE;
 
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE
     {
         if (NormalShutdown != why)
             fail("unexpected destruction!");
         QuitChild();
     }
+
+    uint32_t mLastSeqno;
+    uint32_t mNumProcessedCompressedSpams;
 };
 
 
 } // namespace _ipdltest
 } // namespace mozilla
 
 
 #endif // ifndef mozilla__ipdltest_TestLatency_h
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/compressCtor.ipdl
@@ -0,0 +1,8 @@
+include protocol compressCtorManagee;
+
+rpc protocol compressCtor {
+    manages compressCtorManagee;
+
+parent:
+    async compressCtorManagee() compress;
+};
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/compressCtorManagee.ipdl
@@ -0,0 +1,8 @@
+include protocol compressCtor;
+
+rpc protocol compressCtorManagee {
+    manager compressCtor;
+
+child:
+    async __delete__() compress;
+};
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/rpcMessageCompress.ipdl
@@ -0,0 +1,6 @@
+rpc protocol rpcMessageCompress {
+parent:
+    rpc foo() compress;
+child:
+    rpc bar() compress;
+};
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/error/syncMessageCompress.ipdl
@@ -0,0 +1,4 @@
+sync protocol syncMessageCompress {
+parent:
+    sync foo() compress;
+};
new file mode 100644
--- /dev/null
+++ b/ipc/ipdl/test/ipdl/ok/messageCompress.ipdl
@@ -0,0 +1,4 @@
+rpc protocol messageCompress {
+child:
+    async foo() compress;
+};
--- a/js/src/configure.in
+++ b/js/src/configure.in
@@ -4088,17 +4088,17 @@ MOZ_ARG_DISABLE_BOOL(md,
      _cpp_md_flag=1
    fi
   dnl Default is to use -xM if using Sun Studio on Solaris
    if test "$SOLARIS_SUNPRO_CC"; then
      _cpp_md_flag=1
    fi])
 if test "$_cpp_md_flag"; then
   COMPILER_DEPEND=1
-  _DEPEND_CFLAGS='$(filter-out %/.pp,-MMD -MF $(MDDEPDIR)/$(@F).pp)'
+  _DEPEND_CFLAGS='$(filter-out %/.pp,-MD -MF $(MDDEPDIR)/$(@F).pp)'
   dnl Sun Studio on Solaris use -xM instead of -MD, see config/rules.mk
   if test "$SOLARIS_SUNPRO_CC"; then
     _DEPEND_CFLAGS=
   fi
 else
   COMPILER_DEPEND=
   dnl Don't override this for MSVC
   if test -z "$_WIN32_MSVC"; then
--- a/js/src/jsinfer.cpp
+++ b/js/src/jsinfer.cpp
@@ -1059,18 +1059,17 @@ PropertyAccess(JSContext *cx, JSScript *
      * time for typed arrays. Propagate the possible element types of the array
      * to sites reading from it.
      */
     if (object->singleton && object->singleton->isTypedArray() && JSID_IS_VOID(id)) {
         if (access != PROPERTY_WRITE) {
             int arrayKind = object->proto->getClass() - TypedArray::protoClasses;
             JS_ASSERT(arrayKind >= 0 && arrayKind < TypedArray::TYPE_MAX);
 
-            bool maybeDouble = (arrayKind == TypedArray::TYPE_UINT32 ||
-                                arrayKind == TypedArray::TYPE_FLOAT32 ||
+            bool maybeDouble = (arrayKind == TypedArray::TYPE_FLOAT32 ||
                                 arrayKind == TypedArray::TYPE_FLOAT64);
             target->addType(cx, maybeDouble ? Type::DoubleType() : Type::Int32Type());
         }
         return;
     }
 
     /*
      * Try to resolve reads from the VM state ahead of time, e.g. for reads
--- a/js/xpconnect/crashtests/603858-1.html
+++ b/js/xpconnect/crashtests/603858-1.html
@@ -1,7 +1,8 @@
 <!DOCTYPE html>
 <html class="reftest-wait">
 <script>
-setTimeout(XML, 0);
+if (typeof window.XML === 'function')
+    setTimeout(XML, 0);
 setTimeout(function(){document.documentElement.removeAttribute("class");}, 0);
 </script>
 </html>
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -42,16 +42,17 @@
 #include "nsTransitionManager.h"
 #include "nsIViewManager.h"
 #include "ImageLayers.h"
 #include "ImageContainer.h"
 
 #include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
+using namespace mozilla::css;
 using namespace mozilla::layers;
 typedef FrameMetrics::ViewID ViewID;
 
 static void AddTransformFunctions(nsCSSValueList* aList,
                                   nsStyleContext* aContext,
                                   nsPresContext* aPresContext,
                                   nsRect& aBounds,
                                   float aAppUnitsPerPixel,
@@ -341,26 +342,16 @@ AddAnimationsAndTransitionsToLayer(Layer
 
   if (!ea && !et) {
     return;
   }
 
   // If the frame is not prerendered, bail out.  Layout will still perform the
   // animation.
   if (!aItem->CanUseAsyncAnimations(aBuilder)) {
-    if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
-      printf_stderr("Performance warning: Async animation disabled because the frame for element '%s'",
-                    nsAtomCString(aContent->Tag()).get());
-      nsIAtom* id = aContent->GetID();
-      if (id) {
-        printf_stderr(" with id '%s'",
-                      nsAtomCString(aContent->GetID()).get());
-      }
-      printf_stderr(" is not prerendered\n");
-    }
     return;
   }
 
   mozilla::TimeStamp currentTime =
     frame->PresContext()->RefreshDriver()->MostRecentRefresh();
   AnimationData data;
   if (aProperty == eCSSProperty_transform) {
     nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(frame);
@@ -3335,33 +3326,82 @@ nsDisplayTransform::GetResultingTransfor
       return nsLayoutUtils::ChangeMatrixBasis(newOrigin + toMozOrigin, result) * parent;
   }
 
   return nsLayoutUtils::ChangeMatrixBasis
     (newOrigin + toMozOrigin, result);
 }
 
 bool
+nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
+{
+  if (GetUnderlyingFrame()->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer)) {
+    return true;
+  }
+
+  if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
+    nsCString message;
+    message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for opacity animation");
+    CommonElementAnimationData::LogAsyncAnimationFailure(message,
+                                                         GetUnderlyingFrame()->GetContent());
+  }
+  return false;
+}
+
+bool
+nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
+{
+  return ShouldPrerenderTransformedContent(aBuilder,
+                                           GetUnderlyingFrame(),
+                                           nsLayoutUtils::IsAnimationLoggingEnabled());
+}
+
+/* static */ bool
 nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
-                                                      nsIFrame* aFrame)
+                                                      nsIFrame* aFrame,
+                                                      bool aLogAnimations)
 {
-  if (aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
-    nsSize refSize = aBuilder->ReferenceFrame()->GetSize();
-    // Only prerender if the transformed frame's size is <= the
-    // reference frame size (~viewport), allowing a 1/8th fuzz factor
-    // for shadows, borders, etc.
-    refSize += nsSize(refSize.width / 8, refSize.height / 8);
-    if (aFrame->GetVisualOverflowRectRelativeToSelf().Size() <= refSize) {
-      // Bug 717521 - pre-render max 4096 x 4096 device pixels.
-      nscoord max = aFrame->PresContext()->DevPixelsToAppUnits(4096);
-      nsRect visual = aFrame->GetVisualOverflowRect();
-      if (visual.width <= max && visual.height <= max) {
-        return true;
-      }
+  if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
+    if (aLogAnimations) {
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
+      CommonElementAnimationData::LogAsyncAnimationFailure(message,
+                                                           aFrame->GetContent());
     }
+    return false;
+  }
+
+  nsSize refSize = aBuilder->ReferenceFrame()->GetSize();
+  // Only prerender if the transformed frame's size is <= the
+  // reference frame size (~viewport), allowing a 1/8th fuzz factor
+  // for shadows, borders, etc.
+  refSize += nsSize(refSize.width / 8, refSize.height / 8);
+  nsSize frameSize = aFrame->GetVisualOverflowRectRelativeToSelf().Size();
+  if (frameSize <= refSize) {
+    // Bug 717521 - pre-render max 4096 x 4096 device pixels.
+    nscoord max = aFrame->PresContext()->DevPixelsToAppUnits(4096);
+    nsRect visual = aFrame->GetVisualOverflowRect();
+    if (visual.width <= max && visual.height <= max) {
+      return true;
+    }
+  }
+
+  if (aLogAnimations) {
+    nsCString message;
+    message.AppendLiteral("Performance warning: Async animation disabled because frame size (");
+    message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize.width));
+    message.AppendLiteral(", ");
+    message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize.height));
+    message.AppendLiteral(") is bigger than the viewport (");
+    message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.width));
+    message.AppendLiteral(", ");
+    message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.height));
+    message.AppendLiteral(")");
+    CommonElementAnimationData::LogAsyncAnimationFailure(message,
+                                                         aFrame->GetContent());
   }
   return false;
 }
 
 /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
 static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix)
 {
   if (aMatrix.IsSingular()) {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1902,19 +1902,17 @@ public:
                                    LayerManager* aManager,
                                    const ContainerParameters& aParameters);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);  
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
   NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
 
-  bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
-    return GetUnderlyingFrame()->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer);
-  }
+  bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder);
 };
 
 /**
  * A display item that has no purpose but to ensure its contents get
  * their own layer.
  */
 class nsDisplayOwnLayer : public nsDisplayWrapList {
 public:
@@ -2415,21 +2413,19 @@ public:
                                                  gfxPoint3D* aToPerspectiveOrigin = nullptr,
                                                  nscoord* aChildPerspective = nullptr,
                                                  nsIFrame** aOutAncestor = nullptr);
   /**
    * Return true when we should try to prerender the entire contents of the
    * transformed frame even when it's not completely visible (yet).
    */
   static bool ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
-                                                nsIFrame* aFrame);
-  bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
-    return nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder,
-                                                                 GetUnderlyingFrame());
-  }
+                                                nsIFrame* aFrame,
+                                                bool aLogAnimations = false);
+  bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder);
 
 private:
   nsDisplayWrapList mStoredList;
   gfx3DMatrix mTransform;
   float mCachedAppUnitsPerPixel;
   uint32_t mIndex;
 };
 
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -66,17 +66,16 @@
 #include "mozilla/dom/Element.h"
 #include "nsCanvasFrame.h"
 #include "gfxDrawable.h"
 #include "gfxUtils.h"
 #include "nsDataHashtable.h"
 #include "nsTextFrame.h"
 #include "nsFontFaceList.h"
 #include "nsFontInflationData.h"
-#include "CompositorParent.h"
 #include "nsSVGUtils.h"
 #include "nsSVGIntegrationUtils.h"
 #include "nsSVGForeignObjectFrame.h"
 #include "nsSVGOuterSVGFrame.h"
 #include "nsStyleStructInlines.h"
 
 #include "mozilla/Preferences.h"
 
@@ -167,32 +166,34 @@ nsLayoutUtils::AreOpacityAnimationsEnabl
   static bool sOpacityPrefCached = false;
 
   if (!sOpacityPrefCached) {
     sOpacityPrefCached = true;
     Preferences::AddBoolVarCache(&sAreOpacityAnimationsEnabled,
                                  "layers.offmainthreadcomposition.animate-opacity");
   }
 
-  return sAreOpacityAnimationsEnabled && CompositorParent::CompositorLoop();
+  return sAreOpacityAnimationsEnabled &&
+    gfxPlatform::OffMainThreadCompositingEnabled();
 }
 
 bool
 nsLayoutUtils::AreTransformAnimationsEnabled()
 {
   static bool sAreTransformAnimationsEnabled;
   static bool sTransformPrefCached = false;
 
   if (!sTransformPrefCached) {
     sTransformPrefCached = true;
     Preferences::AddBoolVarCache(&sAreTransformAnimationsEnabled,
                                  "layers.offmainthreadcomposition.animate-transform");
   }
 
-  return sAreTransformAnimationsEnabled && CompositorParent::CompositorLoop();
+  return sAreTransformAnimationsEnabled &&
+    gfxPlatform::OffMainThreadCompositingEnabled();
 }
 
 bool
 nsLayoutUtils::IsAnimationLoggingEnabled()
 {
   static bool sShouldLog;
   static bool sShouldLogPrefCached;
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-width/cell-pref-width-border-box-ref.html
@@ -0,0 +1,29 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <title>
+        Test minimum cell width calculation
+    </title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+</head>
+<body>
+<style type="text/css">
+table
+{
+    vertical-align:top;
+    empty-cells:show;
+    border-collapse:collapse;
+}
+
+td
+{
+    border: solid 1px black;
+}
+</style>
+<table>
+	<tr>
+		<td>Test wrapping</td>
+	</tr>
+</table>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/table-width/cell-pref-width-border-box.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <title>
+        Test minimum cell width calculation
+    </title>
+    <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
+</head>
+<body>
+<style type="text/css">
+table
+{
+    vertical-align:top;
+    empty-cells:show;
+    border-collapse:collapse;
+}
+
+td
+{
+    -moz-box-sizing: border-box;
+    border: solid 1px black;
+}
+</style>
+<table>
+	<tr>
+		<td>Test wrapping</td>
+	</tr>
+</table>
+</body>
+</html>
--- a/layout/reftests/table-width/reftest.list
+++ b/layout/reftests/table-width/reftest.list
@@ -54,8 +54,9 @@ fails == default-box-sizing-collapse-qui
 == spanning-cell-sort-2-large.html spanning-cell-sort-2-ref.html
 == spanning-cell-sort-2-small-fixed.html spanning-cell-sort-2-fixed-ref.html
 == spanning-cell-sort-2-large-fixed.html spanning-cell-sort-2-fixed-ref.html
 == colgroup-vs-column-1.html colgroup-vs-column-1-ref.html
 == colgroup-vs-column-2.html colgroup-vs-column-2-ref.html
 == colgroup-vs-column-3.html colgroup-vs-column-3-ref.html
 == colgroup-vs-column-4.html colgroup-vs-column-4-ref.html
 == dynamic-fixed-layout-1.html dynamic-fixed-layout-1-ref.html
+== cell-pref-width-border-box.html cell-pref-width-border-box-ref.html
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -1,13 +1,14 @@
 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "gfxPlatform.h"
 #include "AnimationCommon.h"
 #include "nsRuleData.h"
 #include "nsCSSValue.h"
 #include "nsStyleContext.h"
 #include "nsIFrame.h"
 #include "nsAnimationManager.h"
 #include "nsLayoutUtils.h"
 
@@ -233,55 +234,93 @@ ComputedTimingFunction::GetValue(double 
 }
 
 bool
 CommonElementAnimationData::CanAnimatePropertyOnCompositor(const dom::Element *aElement,
                                                            nsCSSProperty aProperty,
                                                            bool aHasGeometricProperties)
 {
   bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
+  if (shouldLog && !gfxPlatform::OffMainThreadCompositingEnabled()) {
+    nsCString message;
+    message.AppendLiteral("Performance warning: Compositor disabled");
+    LogAsyncAnimationFailure(message);
+    return false;
+  }
+
   nsIFrame* frame = aElement->GetPrimaryFrame();
   if (IsGeometricProperty(aProperty)) {
     if (shouldLog) {
-      printf_stderr("Performance warning: Async animation of geometric property '%s' is disabled\n", aProperty);
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animation of geometric property '");
+      message.Append(aProperty);
+      message.AppendLiteral(" is disabled");
+      LogAsyncAnimationFailure(message, aElement);
     }
     return false;
   }
   if (aProperty == eCSSProperty_opacity) {
     bool enabled = nsLayoutUtils::AreOpacityAnimationsEnabled();
     if (!enabled && shouldLog) {
-      printf_stderr("Performance warning: Async animation of 'opacity' is disabled\n");
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animation of 'opacity' is disabled");
+      LogAsyncAnimationFailure(message);
     }
     return enabled;
   }
   if (aProperty == eCSSProperty_transform) {
     if (frame->Preserves3D() &&
         frame->Preserves3DChildren()) {
       if (shouldLog) {
-        printf_stderr("Gecko bug: Async animation of 'preserve-3d' transforms is not supported.  See bug 779598\n");
+        nsCString message;
+        message.AppendLiteral("Gecko bug: Async animation of 'preserve-3d' transforms is not supported.  See bug 779598");
+        LogAsyncAnimationFailure(message, aElement);
       }
       return false;
     }
     if (frame->IsSVGTransformed()) {
       if (shouldLog) {
-        printf_stderr("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported.  See bug 779599\n");
+        nsCString message;
+        message.AppendLiteral("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported.  See bug 779599");
+        LogAsyncAnimationFailure(message, aElement);
       }
       return false;
     }
     if (aHasGeometricProperties) {
       if (shouldLog) {
-        printf_stderr("Performance warning: Async animation of 'transform' not possible due to presence of geometric properties\n");
+        nsCString message;
+        message.AppendLiteral("Performance warning: Async animation of 'transform' not possible due to presence of geometric properties");
+        LogAsyncAnimationFailure(message, aElement);
       }
       return false;
     }
     bool enabled = nsLayoutUtils::AreTransformAnimationsEnabled();
     if (!enabled && shouldLog) {
-      printf_stderr("Performance warning: Async animation of 'transform' is disabled\n");
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animation of 'transform' is disabled");
+      LogAsyncAnimationFailure(message);
     }
     return enabled;
   }
   return true;
 }
 
+/* static */ void
+CommonElementAnimationData::LogAsyncAnimationFailure(nsCString& aMessage,
+                                                     const nsIContent* aContent)
+{
+  if (aContent) {
+    aMessage.AppendLiteral(" [");
+    aMessage.Append(nsAtomCString(aContent->Tag()));
 
+    nsIAtom* id = aContent->GetID();
+    if (id) {
+      aMessage.AppendLiteral(" with id '");
+      aMessage.Append(nsAtomCString(aContent->GetID()));
+      aMessage.AppendLiteral("'");
+    }
+    aMessage.AppendLiteral("]");
+  }
+  printf_stderr(aMessage.get());
+}
 
 }
 }
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -151,16 +151,19 @@ struct CommonElementAnimationData : publ
     mElement->DeleteProperty(mElementProperty);
   }
 
   static bool
   CanAnimatePropertyOnCompositor(const dom::Element *aElement,
                                  nsCSSProperty aProperty,
                                  bool aHasGeometricProperties);
 
+  static void LogAsyncAnimationFailure(nsCString& aMessage,
+                                       const nsIContent* aContent = nullptr);
+
   dom::Element *mElement;
 
   // the atom we use in mElement's prop table (must be a static atom,
   // i.e., in an atom list)
   nsIAtom *mElementProperty;
 
   CommonAnimationManager *mManager;
 
--- a/layout/style/ImageLoader.h
+++ b/layout/style/ImageLoader.h
@@ -8,28 +8,29 @@
 #include "nsAutoPtr.h"
 #include "nsClassHashtable.h"
 #include "nsHashKeys.h"
 #include "nsInterfaceHashtable.h"
 #include "nsCSSValue.h"
 #include "imgIRequest.h"
 #include "imgIOnloadBlocker.h"
 #include "nsStubImageDecoderObserver.h"
+#include "mozilla/Attributes.h"
 
 class nsIFrame;
 class nsIDocument;
 class nsPresContext;
 class nsIURI;
 class nsIPrincipal;
 
 namespace mozilla {
 namespace css {
 
-class ImageLoader : public nsStubImageDecoderObserver,
-                    public imgIOnloadBlocker {
+class ImageLoader MOZ_FINAL : public nsStubImageDecoderObserver,
+                              public imgIOnloadBlocker {
 public:
   typedef mozilla::css::ImageValue Image;
 
   ImageLoader(nsIDocument* aDocument)
   : mDocument(aDocument),
     mInClone(false)
   {
     MOZ_ASSERT(mDocument);
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -294,55 +294,77 @@ ElementAnimations::HasAnimationOfPropert
     }
   }
   return false;
 }
 
 bool
 ElementAnimations::CanPerformOnCompositorThread() const
 {
+  nsIFrame* frame = mElement->GetPrimaryFrame();
+  if (!frame) {
+    return false;
+  }
+
   if (mElementProperty != nsGkAtoms::animationsProperty) {
     if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
-      printf_stderr("Gecko bug: Async animation of pseudoelements not supported.  See bug 771367\n");
+      nsCString message;
+      message.AppendLiteral("Gecko bug: Async animation of pseudoelements not supported.  See bug 771367");
+      LogAsyncAnimationFailure(message, mElement);
     }
     return false;
   }
-  bool hasGeometricProperty = false;
-  nsIFrame* frame = mElement->GetPrimaryFrame();
+
   TimeStamp now = frame->PresContext()->RefreshDriver()->MostRecentRefresh();
 
+  bool hasGeometricProperty = false;
   for (uint32_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
     const ElementAnimation& anim = mAnimations[animIdx];
     for (uint32_t propIdx = 0, propEnd = anim.mProperties.Length();
          propIdx != propEnd; ++propIdx) {
       if (IsGeometricProperty(anim.mProperties[propIdx].mProperty) &&
           anim.IsRunningAt(now)) {
         hasGeometricProperty = true;
         break;
       }
     }
   }
 
+  bool hasOpacity = false;
+  bool hasTransform = false;
   for (uint32_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
     const ElementAnimation& anim = mAnimations[animIdx];
     if (anim.mIterationDuration.ToMilliseconds() <= 0.0) {
       // No animation data
       continue;
     }
 
     for (uint32_t propIdx = 0, propEnd = anim.mProperties.Length();
          propIdx != propEnd; ++propIdx) {
       const AnimationProperty& prop = anim.mProperties[propIdx];
       if (!CanAnimatePropertyOnCompositor(mElement,
                                           prop.mProperty,
                                           hasGeometricProperty)) {
         return false;
       }
+      if (prop.mProperty == eCSSProperty_opacity) {
+        hasOpacity = true;
+      } else if (prop.mProperty == eCSSProperty_transform) {
+        hasTransform = true;
+      }
     }
   }
+  // This animation can be done on the compositor.  Mark the frame as active, in
+  // case we are able to throttle this animation.
+  if (hasOpacity) {
+    frame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
+  }
+  if (hasTransform) {
+    frame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
+  }
   return true;
 }
 
 ElementAnimations*
 nsAnimationManager::GetElementAnimations(dom::Element *aElement,
                                          nsCSSPseudoElements::Type aPseudoType,
                                          bool aCreateIfNeeded)
 {
--- a/layout/style/nsCSSPseudoClassList.h
+++ b/layout/style/nsCSSPseudoClassList.h
@@ -149,16 +149,18 @@ CSS_STATE_PSEUDO_CLASS(mozSuppressed, ":
                        NS_EVENT_STATE_SUPPRESSED)
 CSS_STATE_PSEUDO_CLASS(mozLoading, ":-moz-loading", NS_EVENT_STATE_LOADING)
 CSS_STATE_PSEUDO_CLASS(mozTypeUnsupported, ":-moz-type-unsupported",
                        NS_EVENT_STATE_TYPE_UNSUPPORTED)
 CSS_STATE_PSEUDO_CLASS(mozTypeUnsupportedPlatform, ":-moz-type-unsupported-platform",
                        NS_EVENT_STATE_TYPE_UNSUPPORTED_PLATFORM)
 CSS_STATE_PSEUDO_CLASS(mozHandlerClickToPlay, ":-moz-handler-clicktoplay",
                        NS_EVENT_STATE_TYPE_CLICK_TO_PLAY)
+CSS_STATE_PSEUDO_CLASS(mozHandlerPlayPreview, ":-moz-handler-playpreview",
+                       NS_EVENT_STATE_TYPE_PLAY_PREVIEW)
 CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableUpdatable, ":-moz-handler-vulnerable-updatable",
                        NS_EVENT_STATE_VULNERABLE_UPDATABLE)
 CSS_STATE_PSEUDO_CLASS(mozHandlerVulnerableNoUpdate, ":-moz-handler-vulnerable-no-update",
                        NS_EVENT_STATE_VULNERABLE_NO_UPDATE)
 CSS_STATE_PSEUDO_CLASS(mozHandlerDisabled, ":-moz-handler-disabled",
                        NS_EVENT_STATE_HANDLER_DISABLED)
 CSS_STATE_PSEUDO_CLASS(mozHandlerBlocked, ":-moz-handler-blocked",
                        NS_EVENT_STATE_HANDLER_BLOCKED)
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -122,44 +122,66 @@ ElementTransitions::HasTransitionOfPrope
     }
   }
   return false;
 }
 
 bool
 ElementTransitions::CanPerformOnCompositorThread() const
 {
+  nsIFrame* frame = mElement->GetPrimaryFrame();
+  if (!frame) {
+    return false;
+  }
+
   if (mElementProperty != nsGkAtoms::transitionsProperty) {
     if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
-      printf_stderr("Gecko bug: Async transition of pseudoelements not supported.  See bug 771367\n");
+      nsCString message;
+      message.AppendLiteral("Gecko bug: Async transition of pseudoelements not supported.  See bug 771367");
+      LogAsyncAnimationFailure(message, mElement);
     }
     return false;
   }
-  bool hasGeometricProperty = false;
-  nsIFrame* frame = mElement->GetPrimaryFrame();
+
   TimeStamp now = frame->PresContext()->RefreshDriver()->MostRecentRefresh();
 
+  bool hasGeometricProperty = false;
   for (uint32_t i = 0, i_end = mPropertyTransitions.Length(); i < i_end; ++i) {
     const ElementPropertyTransition& pt = mPropertyTransitions[i];
     if (css::IsGeometricProperty(pt.mProperty) && pt.IsRunningAt(now)) {
       hasGeometricProperty = true;
       break;
     }
   }
 
+  bool hasOpacity = false;
+  bool hasTransform = false;
   for (uint32_t i = 0, i_end = mPropertyTransitions.Length(); i < i_end; ++i) {
     const ElementPropertyTransition& pt = mPropertyTransitions[i];
     if (pt.IsRemovedSentinel()) {
       continue;
     }
     if (!css::CommonElementAnimationData::CanAnimatePropertyOnCompositor(mElement,
                                                                          pt.mProperty,
                                                                          hasGeometricProperty)) {
       return false;
     }
+    if (pt.mProperty == eCSSProperty_opacity) {
+      hasOpacity = true;
+    } else if (pt.mProperty == eCSSProperty_transform) {
+      hasTransform = true;
+    }
+  }
+  // This transition can be done on the compositor.  Mark the frame as active, in
+  // case we are able to throttle this transition.
+  if (hasOpacity) {
+    frame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
+  }
+  if (hasTransform) {
+    frame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
   }
   return true;
 }
 
 /*****************************************************************************
  * nsTransitionManager                                                       *
  *****************************************************************************/
 
--- a/mobile/android/app/mobile.js
+++ b/mobile/android/app/mobile.js
@@ -514,36 +514,16 @@ pref("app.update.interval", 3600);
 pref("app.update.url.manual", "http://www.mozilla.com/%LOCALE%/mobile/");
 pref("app.update.url.details", "http://www.mozilla.com/%LOCALE%/mobile/");
 #endif
 #endif
 
 // replace newlines with spaces on paste into single-line text boxes
 pref("editor.singleLine.pasteNewlines", 2);
 
-#ifdef MOZ_SERVICES_SYNC
-// sync service
-pref("services.sync.client.type", "mobile");
-pref("services.sync.registerEngines", "Tab,Bookmarks,Form,History,Password,Prefs");
-pref("services.sync.autoconnectDelay", 5);
-
-// prefs to sync by default
-pref("services.sync.prefs.sync.browser.startup.homepage.title", true);
-pref("services.sync.prefs.sync.browser.startup.homepage", true);
-pref("services.sync.prefs.sync.browser.tabs.warnOnClose", true);
-pref("services.sync.prefs.sync.devtools.errorconsole.enabled", true);
-pref("services.sync.prefs.sync.javascript.enabled", true);
-pref("services.sync.prefs.sync.lightweightThemes.isThemeSelected", true);
-pref("services.sync.prefs.sync.lightweightThemes.usedThemes", true);
-pref("services.sync.prefs.sync.network.cookie.cookieBehavior", true);
-pref("services.sync.prefs.sync.permissions.default.image", true);
-pref("services.sync.prefs.sync.privacy.donottrackheader.enabled", true);
-pref("services.sync.prefs.sync.signon.rememberSignons", true);
-#endif
-
 // threshold where a tap becomes a drag, in 1/240" reference pixels
 // The names of the preferences are to be in sync with nsEventStateManager.cpp
 pref("ui.dragThresholdX", 25);
 pref("ui.dragThresholdY", 25);
 
 pref("layers.acceleration.disabled", false);
 pref("layers.offmainthreadcomposition.enabled", true);
 pref("layers.async-video.enabled", true);
--- a/mobile/android/base/BrowserToolbar.java
+++ b/mobile/android/base/BrowserToolbar.java
@@ -20,38 +20,46 @@ import android.view.ContextMenu;
 import android.view.LayoutInflater;
 import android.view.MenuInflater;
 import android.view.MotionEvent;
 import android.view.TouchDelegate;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.DecelerateInterpolator;
 import android.view.animation.TranslateAnimation;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.Button;
 import android.widget.ImageButton;
 import android.widget.ImageView;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.PopupWindow;
 import android.widget.RelativeLayout;
 import android.widget.TextSwitcher;
 import android.widget.TextView;
 import android.widget.ViewSwitcher;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
 public class BrowserToolbar implements ViewSwitcher.ViewFactory,
                                        Tabs.OnTabsChangedListener,
-                                       GeckoMenu.ActionItemBarPresenter {
+                                       GeckoMenu.ActionItemBarPresenter,
+                                       Animation.AnimationListener {
     private static final String LOGTAG = "GeckoToolbar";
     private LinearLayout mLayout;
     private Button mAwesomeBar;
+    private TextView mTitle;
+    private int mTitlePadding;
+    private boolean mSiteSecurityVisible;
     private ImageButton mTabs;
     private ImageView mBack;
     private ImageView mForward;
     public ImageButton mFavicon;
     public ImageButton mStop;
     public ImageButton mSiteSecurity;
     public ImageButton mReader;
     private AnimationDrawable mProgressSpinner;
@@ -60,30 +68,33 @@ public class BrowserToolbar implements V
     private ImageButton mMenu;
     private LinearLayout mActionItemBar;
     private MenuPopup mMenuPopup;
     private List<View> mFocusOrder;
 
     final private BrowserApp mActivity;
     private LayoutInflater mInflater;
     private Handler mHandler;
-    private int[] mPadding;
     private boolean mHasSoftMenuButton;
 
     private boolean mShowSiteSecurity;
     private boolean mShowReader;
 
     private static List<View> sActionItems;
 
     private int mDuration;
     private TranslateAnimation mSlideUpIn;
     private TranslateAnimation mSlideUpOut;
     private TranslateAnimation mSlideDownIn;
     private TranslateAnimation mSlideDownOut;
 
+    private AlphaAnimation mLockFadeIn;
+    private TranslateAnimation mTitleSlideLeft;
+    private TranslateAnimation mTitleSlideRight;
+
     private int mCount;
 
     private static final int TABS_CONTRACTED = 1;
     private static final int TABS_EXPANDED = 2;
 
     public BrowserToolbar(BrowserApp activity) {
         // BrowserToolbar is attached to BrowserApp only.
         mActivity = activity;
@@ -94,16 +105,21 @@ public class BrowserToolbar implements V
     }
 
     public void from(LinearLayout layout) {
         mLayout = layout;
 
         mShowSiteSecurity = false;
         mShowReader = false;
 
+        mTitle = (TextView) mLayout.findViewById(R.id.awesome_bar_title);
+        mTitlePadding = mTitle.getPaddingRight();
+        if (Build.VERSION.SDK_INT >= 16)
+            mTitle.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+
         mAwesomeBar = (Button) mLayout.findViewById(R.id.awesome_bar);
         mAwesomeBar.setOnClickListener(new Button.OnClickListener() {
             public void onClick(View v) {
                 mActivity.autoHideTabs();
                 onAwesomeBarSearch();
             }
         });
         mAwesomeBar.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
@@ -129,21 +145,16 @@ public class BrowserToolbar implements V
                     // if there is no tab, remove anything tab dependent
                     menu.findItem(R.id.copyurl).setVisible(false);
                     menu.findItem(R.id.share).setVisible(false);
                     menu.findItem(R.id.add_to_launcher).setVisible(false);
                 }
             }
         });
 
-        mPadding = new int[] { mAwesomeBar.getPaddingLeft(),
-                               mAwesomeBar.getPaddingTop(),
-                               mAwesomeBar.getPaddingRight(),
-                               mAwesomeBar.getPaddingBottom() };
-
         mTabs = (ImageButton) mLayout.findViewById(R.id.tabs);
         mTabs.setOnClickListener(new Button.OnClickListener() {
             public void onClick(View v) {
                 toggleTabs();
             }
         });
         mTabs.setImageLevel(0);
 
@@ -173,31 +184,33 @@ public class BrowserToolbar implements V
 
         mForward = (ImageButton) mLayout.findViewById(R.id.forward);
         mForward.setOnClickListener(new Button.OnClickListener() {
             public void onClick(View view) {
                 Tabs.getInstance().getSelectedTab().doForward();
             }
         });
 
-        mFavicon = (ImageButton) mLayout.findViewById(R.id.favicon);
-        mSiteSecurity = (ImageButton) mLayout.findViewById(R.id.site_security);
-        mSiteSecurity.setOnClickListener(new Button.OnClickListener() {
+        Button.OnClickListener faviconListener = new Button.OnClickListener() {
             public void onClick(View view) {
-                int[] lockLocation = new int[2];
-                view.getLocationOnScreen(lockLocation);
+                if (mSiteSecurity.getVisibility() != View.VISIBLE)
+                    return;
+
+                SiteIdentityPopup.getInstance().show(mSiteSecurity);
+            }
+        };
 
-                RelativeLayout.LayoutParams iconsLayoutParams =
-                        (RelativeLayout.LayoutParams) ((View) view.getParent()).getLayoutParams();
+        mFavicon = (ImageButton) mLayout.findViewById(R.id.favicon);
+        mFavicon.setOnClickListener(faviconListener);
+        if (Build.VERSION.SDK_INT >= 16)
+            mFavicon.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
 
-                // Calculate the left margin for the arrow based on the position of the lock icon.
-                int leftMargin = lockLocation[0] - iconsLayoutParams.rightMargin;
-                SiteIdentityPopup.getInstance().show(mSiteSecurity, leftMargin);
-            }
-        });
+        mSiteSecurity = (ImageButton) mLayout.findViewById(R.id.site_security);
+        mSiteSecurity.setOnClickListener(faviconListener);
+        mSiteSecurityVisible = (mSiteSecurity.getVisibility() == View.VISIBLE);
 
         mProgressSpinner = (AnimationDrawable) mActivity.getResources().getDrawable(R.drawable.progress_spinner);
         
         mStop = (ImageButton) mLayout.findViewById(R.id.stop);
         mStop.setOnClickListener(new Button.OnClickListener() {
             public void onClick(View v) {
                 Tab tab = Tabs.getInstance().getSelectedTab();
                 if (tab != null)
@@ -223,16 +236,36 @@ public class BrowserToolbar implements V
         mSlideDownOut = new TranslateAnimation(0, 0, 0, 40);
 
         mDuration = 750;
         mSlideUpIn.setDuration(mDuration);
         mSlideUpOut.setDuration(mDuration);
         mSlideDownIn.setDuration(mDuration);
         mSlideDownOut.setDuration(mDuration);
 
+        float slideWidth = mActivity.getResources().getDimension(R.dimen.browser_toolbar_lock_width);
+
+        LinearLayout.LayoutParams siteSecParams = (LinearLayout.LayoutParams) mSiteSecurity.getLayoutParams();
+        final float scale = mActivity.getResources().getDisplayMetrics().density;
+        slideWidth += (siteSecParams.leftMargin + siteSecParams.rightMargin) * scale + 0.5f;
+
+        mLockFadeIn = new AlphaAnimation(0.0f, 1.0f);
+        mLockFadeIn.setAnimationListener(this);
+
+        mTitleSlideLeft = new TranslateAnimation(slideWidth, 0, 0, 0);
+        mTitleSlideLeft.setAnimationListener(this);
+
+        mTitleSlideRight = new TranslateAnimation(-slideWidth, 0, 0, 0);
+        mTitleSlideRight.setAnimationListener(this);
+
+        final int lockAnimDuration = 300;
+        mLockFadeIn.setDuration(lockAnimDuration);
+        mTitleSlideLeft.setDuration(lockAnimDuration);
+        mTitleSlideRight.setDuration(lockAnimDuration);
+
         mMenu = (ImageButton) mLayout.findViewById(R.id.menu);
         mActionItemBar = (LinearLayout) mLayout.findViewById(R.id.menu_items);
         mHasSoftMenuButton = !mActivity.hasPermanentMenuKey();
 
         if (mHasSoftMenuButton) {
             mMenu.setVisibility(View.VISIBLE);
             mMenu.setOnClickListener(new Button.OnClickListener() {
                 public void onClick(View view) {
@@ -322,16 +355,37 @@ public class BrowserToolbar implements V
                 updateTabCountAndAnimate(Tabs.getInstance().getCount());
                 updateBackButton(false);
                 updateForwardButton(false);
                 break;
         }
     }
 
     @Override
+    public void onAnimationStart(Animation animation) {
+        if (animation.equals(mLockFadeIn)) {
+            if (mSiteSecurityVisible)
+                mSiteSecurity.setVisibility(View.VISIBLE);
+        }
+    }
+
+    @Override
+    public void onAnimationRepeat(Animation animation) {
+    }
+
+    @Override
+    public void onAnimationEnd(Animation animation) {
+        if (animation.equals(mTitleSlideLeft)) {
+            mSiteSecurity.setVisibility(View.GONE);
+        } else if (animation.equals(mTitleSlideRight)) {
+            mSiteSecurity.startAnimation(mLockFadeIn);
+        }
+    }
+
+    @Override
     public View makeView() {
         // This returns a TextView for the TextSwitcher.
         return mInflater.inflate(R.layout.tabs_counter, null);
     }
 
     private void onAwesomeBarSearch() {
         mActivity.onSearchRequested();
     }
@@ -431,30 +485,50 @@ public class BrowserToolbar implements V
         }
     }
 
     public void setPageActionVisibility(boolean isLoading) {
         // Handle the loading mode page actions
         mStop.setVisibility(isLoading ? View.VISIBLE : View.GONE);
 
         // Handle the viewing mode page actions
-        mSiteSecurity.setVisibility(mShowSiteSecurity && !isLoading ? View.VISIBLE : View.GONE);
+        setSiteSecurityVisibility(mShowSiteSecurity && !isLoading);
         mReader.setVisibility(mShowReader && !isLoading ? View.VISIBLE : View.GONE);
 
-        if (!isLoading && !mShowSiteSecurity && !mShowReader) {
-            // No visible page actions
-            mAwesomeBar.setPadding(mPadding[0], mPadding[1], mPadding[2], mPadding[3]);
-        } else {
-            // At least one visible page action
-            mAwesomeBar.setPadding(mPadding[0], mPadding[1], mPadding[0], mPadding[3]);
-        }
+        // We want title to fill the whole space available for it when there are icons
+        // being shown on the right side of the toolbar as the icons already have some
+        // padding in them. This is just to avoid wasting space when icons are shown.
+        mTitle.setPadding(0, 0, (!mShowReader && !isLoading ? mTitlePadding : 0), 0);
 
         updateFocusOrder();
     }
 
+    private void setSiteSecurityVisibility(final boolean visible) {
+        if (visible == mSiteSecurityVisible)
+            return;
+
+        mSiteSecurityVisible = visible;
+
+        mTitle.clearAnimation();
+        mSiteSecurity.clearAnimation();
+
+        // If any of these animations were cancelled as a result of the
+        // clearAnimation() calls above, we need to reset them.
+        mLockFadeIn.reset();
+        mTitleSlideLeft.reset();
+        mTitleSlideRight.reset();
+
+        if (visible)
+            mSiteSecurity.setVisibility(View.INVISIBLE);
+        else
+            mSiteSecurity.setVisibility(View.GONE);
+
+        mTitle.startAnimation(visible ? mTitleSlideRight : mTitleSlideLeft);
+    }
+
     private void updateFocusOrder() {
         View prevView = null;
 
         for (View view : mFocusOrder) {
             if (view.getVisibility() != View.VISIBLE)
                 continue;
 
             if (prevView != null) {
@@ -478,17 +552,18 @@ public class BrowserToolbar implements V
         if (tab != null && "about:empty".equals(tab.getURL()))
             return;
 
         // Setting a null title for about:home will ensure we just see
         // the "Enter Search or Address" placeholder text
         if (tab != null && "about:home".equals(tab.getURL()))
             title = null;
 
-        mAwesomeBar.setText(title);
+        mTitle.setText(title);
+        mAwesomeBar.setContentDescription(title != null ? title : mTitle.getHint());
     }
 
     public void setFavicon(Drawable image) {
         if (Tabs.getInstance().getSelectedTab().getState() == Tab.STATE_LOADING)
             return;
 
         if (image != null)
             mFavicon.setImageDrawable(image);
--- a/mobile/android/base/SiteIdentityPopup.java
+++ b/mobile/android/base/SiteIdentityPopup.java
@@ -73,17 +73,17 @@ public class SiteIdentityPopup extends P
         mEncrypted = (TextView) layout.findViewById(R.id.encrypted);
 
         mLarry = (ImageView) layout.findViewById(R.id.larry);
         mArrow = (ImageView) layout.findViewById(R.id.arrow);
 
         mInflated = true;
     }
 
-    public void show(View v, int leftMargin) {
+    public void show(View v) {
         Tab selectedTab = Tabs.getInstance().getSelectedTab();
         if (selectedTab == null) {
             Log.e(LOGTAG, "Selected tab is null");
             return;
         }
 
         JSONObject identityData = selectedTab.getIdentityData();
         if (identityData == null) {
@@ -141,23 +141,25 @@ public class SiteIdentityPopup extends P
         } else {
             // Use a green theme for EV
             mLarry.setImageResource(R.drawable.larry_green);
             mHost.setTextColor(mResources.getColor(R.color.identity_identified));
             mOwner.setTextColor(mResources.getColor(R.color.identity_identified));
             mSupplemental.setTextColor(mResources.getColor(R.color.identity_identified));
         }
 
+        int[] anchorLocation = new int[2];
+        v.getLocationOnScreen(anchorLocation);
+
+        int arrowWidth = mResources.getDimensionPixelSize(R.dimen.doorhanger_arrow_width);
+        int leftMargin = anchorLocation[0] + (v.getWidth() - arrowWidth) / 2;
+
         int offset = 0;
         if (GeckoApp.mAppContext.isTablet()) {
             int popupWidth = mResources.getDimensionPixelSize(R.dimen.site_identity_popup_width);
-            int arrowWidth = mResources.getDimensionPixelSize(R.dimen.doorhanger_arrow_width);
-
-            // Double arrowWidth to leave extra space on the right side of the arrow
-            leftMargin = popupWidth - arrowWidth*2;
             offset = 0 - popupWidth + arrowWidth*3/2 + v.getWidth()/2;
         }
 
         LayoutParams layoutParams = (LayoutParams) mArrow.getLayoutParams();
         LayoutParams newLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
         newLayoutParams.setMargins(leftMargin, layoutParams.topMargin, 0, 0);
         mArrow.setLayoutParams(newLayoutParams);
 
index d0d66a912b9dcdc56c8b8b85795e1ae4d28f5fef..8e166b99720133c0eb277718eab7234a937557f3
GIT binary patch
literal 1436
zc%17D@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFlS_jM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L;Oh%FIIkEQP{1J5uShJ=H`FuG&&}0`sV*)FN=?JBx;Uh=AXPsowK%`DC>a<Z
zY05}e;nxaM2y~5=e^DkdQWA4q@{>z*Q}aqZU2K(rGI}YQDOPS4=5B_D<|YQ_Mh0dU
zhK3df7RGK)MwX72&aOsA#)dF6u<3PiF>-Zrb8~eubu=+FbTxD|adEbEGjlbwG%~X^
zadU?0^~@_SNz6-5h3U;i=yk!X*UGslHL)bWC?r2W2bKZ?GV)9Ei!<^I6r6+26f}Gj
zlQZ)`0-B%*g1R-eD6=dz#jPkmR{<QtR+(5_U~cB<W^QKeWN3)+xvQI*rHhjj&?%NK
zN>IHi<b;|&&@uXG$pt0^OoJdMJn;iL@a&VC2h1}?z|7J2uBeHDf$@~5i(^Q|t)xHy
z|Jxr<VCq@Sr^GNr!*s#AmCd;UEdgb9nwvLlIH99p%-FGd_N!CYY&tEEgf2Vu&16qe
zb3B`|KKs=gIRo~;KR()i`~SbbFyoN!l>(7SzF(i7o?csB{{9b>RTpFT;;a|%7Ua&p
zE?@osU#tk9yJ_$vjjm05r{^bZSg_!Nk!q@_nVTEW{;N#FRor(^D`r`DX|XDs%DQfy
zG%KoaQPx#QUUx&o06~W0`%$T)TQwFW*CkF=)B2v+5>OPiZR3`nJ7NmKO>SS+?@c%)
z=A>s*!eg?;YL!Q!fb!be68Ula^VpV|hvgLMykL^Iulu2|q;>4Tp+in}AI~2-(x4jH
zeDJpUdPzCE9p>UQ?$rrDU66l&-`gEEFP*d|Xu9+z@7TFh^2(L1J7&z3ys^>p*}=cN
zxf@rSP0rIj_Ue~ea9Y~4yAEphe8*LoouBK+%DAjdUhzsH%c3odZ_%{m6^|6MtlE;;
z18*COSaQ6OFkX;c7I@h(C43#{NlB?K1w1$Tsy;v4dU?A3{FUz{HpzZ@e}6yg_WU^e
zPd`7aud-@eWWusWrcy#ua(iJx!Hv5A|7sZnG+Kj>2Q0qMxN76o2ELtERx-w~793<^
bVB%r8zA^03`P(+XLFJ{VtDnm{r-UW|hG_uW
index a756892579ab570419ff74d87bea7124b64b71cf..fcbf13199df820f93d24a32eeab5ff087bec11e2
GIT binary patch
literal 1909
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
F@E7I!@3Q~^
index 295c5768adec201d6b8cbeb4d461cdeb92145bc8..423a20a62c54fd23e147965d86036a09fee6f685
GIT binary patch
literal 1649
zc%17D@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFlS_jM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L;Oh%FIIkEQP{1J5uShJ=H`FuG&&}0`sV*)FN=?JBx;Uh=AXPsowK%`DC>a<Z
zY05}e;nxaM2y~5=e^DkdQWA4q@{>z*Q}aqZU2K(rGI}YQDOPS4=5B_D<|YQ_Mh0dU
zhK3df7RGK)MwX72&aOsA#)dF6u<3PiF>-Y^Ffem5bu=+FbTxD|adEbEGjlbwG%~X^
zadU?0^~@_SNz6-5h3U;i=rzTw*UGslHL)bWC?r2W2bKZ?GV)9Ei!<^I6r6+26f}Gj
zlQZ)`0-B%*g1R-eD6=dz#jPkmR{<QtR+(5_U~cB<W^QKeWN3)+xvQI*rHhjj&?%NK
zN>IHi<b;|&&@uXG$pt0^OoJdMJn;iL@a&VC2h1}?z|3*J@pd``1Jis@7srr_TS<TZ
z|F=J!z~sZz%+q6)am8^l-y+ilNAVTeukNrfk?FkhU$n#j&+qT+pB?+Et=`h=DtS~@
z<#A(@ro$S>BZpYNyw6{yU4H1bf{+X|(;bI5XO0|6(bQE=KYISWJo^*zi3{#eOyE##
zHeT-kz_hn{ZnL9{Pmg0v%%txA{{2%M8!vwT{rx?U|9qRIA75T7GaEeF@XFY5tAgFB
z2?w{GeJ%O%Wc5!rE&Iwp8jn9O_h;2w^(rrZUrpMs+RwkH?*IQUlzC}6^T%?TsQ;6n
zDmXE`c(B`HmB@<?wfghyZ~u68wOiTYcm>nZeF3_Gi<=uB6j=J|&h<V}a;RVL`}_O<
z`_0$IUSu}fZeRUt2ltD&E2mhrX|VtO_4W1tqukFOc5+5H{b&?n|LX8c|LSJjX&IF~
zOO|jhQDw`rNXroEd7)rn;S?7g{@zGf*jPVJ>euhDubz6}a(L#v%kstZ_4EIqpKIIe
z{Y!qIj?Ze7FB~2p1t+#ixaCMqVqUgT`^M!9_6btEJieP8;qY<Z;WSCG>*cIAhkef#
zO?fvO7zf{XJg{w|0^{HM#<w&5lae0stdHB9l8~I5JYm|@WB~zzl!UZ2u_ay24zliU
zZWTIvlv5ZkT<m}PM0EGRe}AoAor1i&CQn|?tntQQBmL2;FNQK-J{|pRzbGlmWh>K+
zgBK5JaI2_!d!F8tp8i~edDB+~x!>)ZZCSp*-M#%kht-Rdlil|^%yFC2JY&WWme!V;
zOH)%M8~QR?xHR|I|L=Qv^z(9_`}=Btv+}%M&(agoI?-F><!xqR;}selY01giS1(+d
zSoQmx>4vR8DtH6d2zTf+e3Vx*;{7Vq^28uAE^c3Pyj^`1kICAuBW`kEqk23Ze0+X>
sep2I?L@(YX8QDI`(hCK}0uBv~45o=+19nVHmjP7*p00i_>zopr0AO=-p#T5?
index 1581c6993cce8b8e69c45ec923947d7441df78d9..d64e3bdba84adff87b81be67b8d23e62c964abe5
GIT binary patch
literal 1342
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z~$s7@Ih|x>&jzI~y7rx*9rJS{k`px|%tgIvKgS
zSXjXHdgc|EB<3Zj!t`b$^jhH6Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|Ft>DcGdDAKGBiZ^+||v@(#6Ti#o5x*
zMG2}mg`7~+2RcR{ExEvifN2oKgeQI=2cCUW^MHA#2$(te&u_ZVz`&T}>EaktaVzQ1
z|Nr*Px{Siiy^Lpd6BOMp9{GImp2I4M4&Q}N%Nur>-!FJ;=2RugdGz3s;)7=$R<RxV
z_w})UL{D$Cq}ts%`CGR2<#6BP|Iu3TY16uY-{0FGo@=~bGS2?jCngm=we#8wlXMOp
zIC12}hrgfSPw;B@%|6-1%qMqEY{FmvyqX_hUp<^&p%Bg05^wio&W|6*+V3k^PLSH9
zWLdkYSM9JpTd6`?#qS^4-)HrG?r!*DFQU)TRoeKZA%b~D*z6SU8#^OS9rRcd&G@EG
zeep@baE495TB(yOJshJwB;PnGT-Y*Y!fR`}Gi^HjB9j|VHea12bn>oyll9CQ5~n>p
z-~a#j@4eR6*l52H0bo2m`^&zoPvp#r6EnO^1Q<;VCQQt<^xW8R%$0Sm?t(N<I|Iir
z{FAgij5wyR->7zZI=|gtM$v)|bG$g3uk73L|D*mzyNZIJXL%IPDQw%v&}8pm)4JwY
i!WO?}J6RbR*%+cbjxJSQedao-MDuj@b6Mw<&;$TgaN5)W
index 3ead437165e867464097a71e31fc71687945f65b..afdef0680a82a6e1ac184fbffa802f9814f18934
GIT binary patch
literal 1307
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z~$s7@Ih|x|q5eI~y7rx*9rJS{k`px|%tgIvKgS
zSXjXHdgc|EB<3Zj!t`b$^qSz+Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|Ft>DcGdDAKGBiZ^+||v@(#6Ti#o5x*
zMG2}mg`7~+2RcR{ExEvifN2oKgeQI=2cCUW^MHA#2$(ru{j5o4U|{t0ba4!+xRvzh
z|9^XCUB<^JHY`}T^0KstDDy_mkQX8X-_5R0&0l<jX~Dy@4y)LX{QLXcJfdgnR8h6N
zJX@CZ<#3-`CFN{kVG;KK|Ns7n2me;{<lo;{$tWZ)C^&UOctBD@N=nL)kB_T8!lMsI
z#iSWL+$@_>!QD~!@y}2F1rI+uEED0_U-{YU<I&IQ`xUb+qECEsEQ#5)Y*W`QQ-R;N
zrh2c<4%1!hIE|mPJMZG9i>ui-zQ4C~>E@D)cUG(XY?wROnfX{+YI1a^UcU}o$m+J!
zGGZ}8Mw^OG8EjiMt4+pW)6EG_8<T`?ToDp=+1mSdZcmR->XIej>;L~N-D(mtO<2^$
z;qYgVvjILnK0B8jVPuz_Ic@Tj6fa(bEXGQ)3E?gO)$cW3UmyQZ@u<**ThsO9|EOB2
y+gJTaU=v7xaQbD&1AYO2$%CQK7HnfsIKXf-r|ZGeO<DG!;>y$2&t;ucLK6Vyz|H{x
index 8f15c8edf2c41239a8b110d31e4896695e922729..d2167fa3a4bd723fed272ec8da165a3e47caacd7
GIT binary patch
literal 1506
zc%17D@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFlS_jM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L;Oh%FIIkEQP{1J5uShJ=H`FuG&&}0`sV*)FN=?JBx;Uh=AXPsowK%`DC>a<Z
zY05}e;nxaM2y~5=e^DkdQWA4q@{>z*Q}aqZU2K(rGI}YQDOPS4=5B_D<|YQ_Mh0dU
zhK3df7RGK)MwX72&aOsA#)dF6u<3PiF>-Y^Ffej4bu=+FbTxD|adEbEGjlbwG%~X^
zadU?0^~@_SNz6-5h3U;i=rzQv*UGslHL)bWC?r2W2bKZ?GV)9Ei!<^I6r6+26f}Gj
zlQZ)`0-B%*g1R-eD6=dz#jPkmR{<QtR+(5_U~cB<W^QKeWN3)+xvQI*rHhjj&?%NK
zN>IHi<b;|&&@uXG$pt0^OoJdMJn;iL@a&VC2h1}?z|5h#XU;hW1||Vd7srr_TS<TZ
z|F=J!z|^ytPpb67ie|Q3j-|eHSshj}by&}ObxM6gQblNNw;VV3Ya4~ncYc3=ze)Xj
z`M+f+9375NVOpuDve0P3;$593J$4ricQ^V3uDCGk`T6;7XXn{*u3tQ(z|-ZZTIFI(
zHkMrr`c$qODhMzg;cfZysN_OB|9i>#c9ku@T<aGXShO)pr1G4fXP2mO+wr#9`um^$
z{M^hHB-47{@cX-aam+q)Uq#fj^zR=i^7LHEmnmtPbLoSLYfG|H<Ger4Q*-=J1pfc`
z_wLanM|?IWduX+DSiIsE_#E&`ViLC-Q{SQ+h84o5eJ%Gmy<V)3+jn5)v)|wIQ>@!k
z*bmC6s_58oPPb84zph$X=($P8d0O*=oti@ZLbj5TJDqlgtlP24j4yysM`%}unA49_
zGnf0zC11Y8sbh0G<B`IgzRK@na~c|_riu0m%}sGP416-9x;)IeIM{k#R-20ZLtkeX
z3pFlFb3u*e9bUmdX2};Vv0&Rd=a6WSq-85-iuH@f?cb~N@9$H*Wth>Y<z9Yedw#s*
zS^nfrvMfC(a{1rgjr{WMY_`FFS;0QXq7d;Df&Oy#P1et@oqhfM|DT`Ek)N4osLg1+
zB4cK@ttEbc-CBlC$)1{xjlaBaM%=Wj|Npa=FQZ>N;JtO0seMZ072ySqD&>I<RZAPM
sXfL>TKSY0}`|nh6q!$zjI5aRaNIpEWs`7D~IjGe2boFyt=akR{0JJL}d;kCd
index d959c90954d63e7b83cb8ce24eb2becbd821c694..b59b289e06927c6eb852f8d255ad9afb800b9fab
GIT binary patch
literal 1411
zc%17D@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z{UBn^?HGnHjs7I+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^cvySYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCHcCD8Ge)fpMd!i(^Q|t)xHy
z|JxsSU{GsgWMWP;<lfaVJzpV?*U9M+PnVZg)&GBge^<PIwzWNef1T^Z``apQzt)~P
zefs!<C2NFEoj6f3ZRX6Mi)QVbrfF_&{<eA6)Tvh|HZ~Sonk@OzIPJaK^`c2Sb>H8u
z{qZ^7f9AxN6WiuoIkNT9%ge{lI-Hi&*g9uUNNoH0qNsHB2~Txz=&WCtZ@jeBZr#!&
zMLgY-j-EiXBVvAkI=XpU`1-gBIhM**k+D&c=g*uxdDMN;``HZ^?7nXv-``&!8!f%s
zPxxu_f~C(LE!$n@G#|~`V|QHa_^uG0Nk3=KkSJ$wbvY%l<;Uym`XQUY{{LUkQ=WG}
z>Ho*i?A8ap9{t*?t=>4rQd6v>v(xy*N$sS~UydK|muG4eJsz9Xbc<=$j?P04-ja>e
z(wg2JN_@$;>iY43`DqL@FE8LzJQdWXv+PLFCf&BES)S{brbPCnybLMQRlS+S$mqCd
z8q-ee4%2Rx?nYlZ`K$=9O-J9~-=AFj=LIA4(rHP$4jc_%_2c(x{QCE|`u=_U`ntNm
z-=^w#pWG<HqE_?k%SWv(MHb$9WhpXm4_)A9V3A;$oXY9!n)CS=s95xL^>bP0l+XkK
DVTlN3
index f928d5635f36720e38baa3e40783b684aab406f5..b64f56cc5e4a776b1cd469989ced26d5c6f17c96
GIT binary patch
literal 1818
zc%17D@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z{UBn^?HGnYy`{I+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^t$5JYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCI;xNOT)8&v|&dIEGZ*dNb{|
zcZj3R@#k|k?|!##-P^l&OY`%lm3>v^Xqq5b#c4FDX@Qc56Av@5ww6Hf8(k&E6>&=x
zUMOxdYWmk!^{VYw*0SBJw_Vq(zP9)K+`F3-7w)X~sXEap|M~aXGc(Wsd3NT#`Qen!
zk)QOrHnZK^{{MmgHXk)*x5b?+Or?~jYd^^da(EV)G|{8u$Ma_%HiG{x|NZ<B5SVas
zzLl>U_r{RuT%FU~4(Bvoxp>rRQ_;>Ep1+4fLzm5tJOAa$n>Rk5a+|$NE#~SS%i27j
zxkThyrAMvN%#;c{uSq9alyw$$C*BZTeYWu0!xfsGdsZC(&~#C{XZyl=i^^1Fl<d~G
ze=wZ4>uK|hsa#8s#^kC>^={+&X4<@QmDuk3s4d5ZI$3UKTL(7;Ex2uK#*)G8!=1vu
zMC#kO!tXbn*O%}5kQu%8>OD=V90Q53GRMCL{q<Jysj>6tzmj(1_5HSejWY8-R_<1o
zm_EBF^>=jCZQVr&USF9d7WH(`*UI?|cWpW&Q)_H@Uf3~w#pnCe`P@#(EGSi*takCm
z_kBrfoo<W&zAVx557U@+<lp1oEq+Ub?g#AE`80j6ms;?{KV`+Giw>*|37Q?>VA3-~
zQ)}(TLZg``4y6_AoP-{Eu^mq`++PsDv+9)BItc?=c7NZH=aqInZ>H)=%J8w?7v<wR
zv}$7Hz38NE5z?CR9WC1zZL^a2VDHp+>ZPdYDm(Yy?qrEH&lQJXJ_=cNYTh5S<(>!r
z|J<liU^Q8C&b(Q3M9;)l?fvNYcbTqG3uj_0>xEgjzRuoWbfRGUg)OtUDgWF5>PwsB
zMonWWE>`PPr=IW^*a!ShsjNJ@?G|t8-wW{%KAb6@({eAUT5-CfwfMih*>@{tz8>&e
zceMM&;qbQ}|AJO-x!}g`u8@_uJoAPk(~hP{iOUyn*Cr;Ye*dT_bDeRmUw&Bj7MGPF
zmoE1`nWShqPu(Q+kq^to<?9O9KKE+W|1IF4*)G$3q34={4NH>KJGr(yi)*ds{(GnN
z!S6tR2dj8=-!!K5|BsAc)fq@wd@M||*{ksIqG-(f7rU<Pn)Sf-VW-QSpC*<U_uNYO
zb>sBG<9FpRefiMaw`YFW@yEHV`ScDPet1Ffd;7)Z4euIlH-202|NjAd76}HP_HaJ=
S*vPG*+RD?_&t;ucLK6T!OV+^v
index b35fcf47c13f29208a2fc35966c7a9eec1f90719..638ef2813822801725d286a20d85529fc7349cac
GIT binary patch
literal 1550
zc%17D@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z{UBn>d-8ni#p5I+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^cv#TYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCD#zd-gp81Cx!Xi(^Q|t)xHy
z|JxsSU{GsgWLhl7U*8>hf%Vlat8xa-a*6-<_wVPKFy;J-182_s;XGmS_xJbpP0Rh|
z;sXOh`WQZWH%9Q!jttnaW#u}XwgpEOy#N3Ed%ED?olJ@U+5-QXlG4n=%<M8FEz=Vd
zC(0Ua`czu~@6XKNKQ1!2eSd$?=+EIvy1qWT4k0E2#|5OX$RCVrNsv<zV@moLzrWt|
z{{Hgxi?_|!FO`&(+?{uC$FFy9Z<`l7cv~jE+MXN7e_Vyt)F>eMa>9eh;tpa}Y&?&C
zxcAHb`Ty&y_k-{6@2_o03eTLlV;l3wdXpH|o~}LN>*K;EWotUh-``crJY7U%qVM9Y
zRc>snvZUtyS>bq=fhVi&`T6;m%;f+7{#}0i{{H%Z%E<}eRxR<gb7L!ifA1g9l6#9e
z>lg1ldLTshoVkGGU-|4+|KeSX<?rt+eJsCi#qyO$b<UhoI3*qV=KcP9o*Pj*K0Q4=
zK0ZEEqIuTvNbvUfux|9I{rU6r^Y`ig^2RlPKFo6r^J{F3cbL%F+S<yiah!K;%8AVq
z5h6wf#h*Vg&V0WiGa)^F|N0e6V!l5-+`g8Hsj1dMQC>mpU@GH@MwiH%zqh6aJDlQ~
zofH-p#<n1}>%gqc#)gIiVha}jJ8)?B!{6WYBeK;qn(jE|1k8S1^!NS!{YT^X*FF9J
z_VsnWLQYTl1mCTa8AZ$iuei3nN@2L>HD!60&I46}^S^$*eSMSt`+G4a-Ckw$sgrMi
svE=5trQ)?o>~ThO-Ib&$#s&svhCJ3EuL}>$uL70Op00i_>zopr0CosQq5uE@
index fbb6f9dd9fe346224b24618020fd4d8b21ba431b..74f29cdbb68d81c115cb6414f297b4fa506617ad
GIT binary patch
literal 1221
zc$}S7U2NM_6m}K0RAtqmdnrr|%i&>2i|y+)PHdW`b{wafmQbY;jS3n#_Dy58{+WG4
z(u$vmf}mnz+5_qk5_y=!3j!e_CJ@s0zyt%dzAyxuc-h0$hY9-7iZNCeu1iu7n)<+%
z?R(F;-*?Wr=bq!0sX}&m=;0xPAck|3N)gW^!8<sBzfY~bHG`*zP^OHgohoW*9wa2g
zsX#JkX>+g$HDmGQH*lOFLN&8gM&<l*QFkm_3ovxka*1G!r<$&&&qG93;GAhEsf{l#
zQlx1lshL=w&AVw>GbfikIK5OT=}YsvU{I-}<akrW1}um)vS}^YzSvAsJ9b694%7@q
z?m*CdlKMNSa(;?TJ02usbTp!~0FXRSgRvOTgCiuz0*+zv!$-iF7~@4QPId={y?I7e
zEGlZ(7nYJ#4Ix)#m`0;PH=?xT%`rd_gun*JMKB`bFWN|JMr=Rav!Fm<_e>X=j!g!#
zR&nYmNm0EcSZ+SQYuNU?iNYyknwrZ1nq@4D>7jj8gw?&#ereH#OcDA{-P7@XRKx#r
zwKp{Y;%LMtJriGwwxBqA-GVmCDM<?N(1vM<Y9g)z5FcaX9LpyFNU({hDszG)q%#~B
z1w9-0;!3h0$?_PRiKYPn86XP+mk~02Iwo_fl1TKpIon5?t-~JI+~r2qJ-K4qgBo(Y
zlH)A&DqyPSAjhvcE}5R@$-{X~H|;?2cyK}8SfOV=4-M6GEOIBqqIr)9;)0~c`KS!Q
zKPS(qyr9Ukk`@Go>T-?$lQjkh!~CaQdMaFl!E(3wv9Q}d(8fLE;pR9v+y4n}tj(Mv
zm73Qo+nr7-6eA9V-X`v+S60@SL#<N(12?7D=)RNL3)im=|8zB4*_^$3qCIg)`mN4v
zyj*R%w;w4VmuB9Oo;kC6{kuEuz8}_}=0|SC3Wv^r+v$vs{`%|-PpscMeX%leWT>)y
zspZ9#*B=ar&#i5=JEN`7Q2p!MKTd29T)KN}JvCW)x3=86aKor-e|-G@=JtJON6%il
z{QJSjvh1m))BWxKqN=D@Kd*f7=~rd_mrhCzk5qmhoZIT$$$p5oR*wz**@+MClUMFC
zkG|A*?!7aI_Z8p#KC`<2sE|Fj6@7K&@_cCa)YKKSMTCg`Ctg%y?RUNmek{36LHS62
H?v=j)GF+RR
index d2b933652f6a280a9719fedfcd16ecce048a0ca9..ab83fcd6393d2f95243d75178b829b7877dee6ab
GIT binary patch
literal 1192
zc$}S7O>Epm6n2^_MMW#6<p80m9eMdLYkTaqcWq@!V|(2$Wz%%CkQ70PV^6YH)*fR|
zvYV9v6`@wWpmOMmLQBQZ33B2>Q6r>sC`hTeAXJbl6cmIwP$Ak12!wIiO%bYcU}Sq{
z-hAJCZ{Ckj3=i#3ZNGOr!!W7R0kcBqoymJg5B)y9^x7z$`bcq%jNmEKup`6_x_A<S
zl5bC=3bNh#7cQZGhUu<()iE+weo}L=&)ErvYx*IRjQ)XUXgf2AfJrp%1qJr!^NTF-
z+yXl)mxXd@pqh7}6`_&VP}OP8II7DIJP!Js8dcyUVuPk%4`QuZVAu6(be)KK7OX?a
zOo9E!sj>1fFmQx`%t;wXfDkAO2eY!Gz{h|nK#>>dqhw%KlNC+Of%agjwaA^)DyG%8
zMRx_ZMo6gfe529e8WM-2X&$Pon&=S43`Jz(`GDBXOc19#8cY;BkrxsV2O!zolX#XC
zShjNoKP;Cw6bErTP&8zG(++va3B2#~9dt}8XliqGT%8XQUqLaRjU1Yfsr0{0ZB9*q
z)En(k<k6(qbrU<YJ_<<5EU@&1b3IqH@;M8_Tvo`5f|7?YFXSal7u7-4D2k#4J34O1
zRb{AWWl1hd286H(byXFMYEdy{U9`-6zQZjAF|h*&b-3OwZgx|yW<<y)II3b??^M8W
z4HF#Ka0rYM1w34~9WO`(k0c3d`-&oO4!Kr@eXt&3&AW{UId#y=DUuH1t(zAuMKyKZ
zG*s1O+g$hmM2)A;@c${7j)>M^vfL<sy4h$S6wscDXmeb9VChBLSYMUQ!D{o$<m%em
zK)1}?)qRS&lRNS8drJ&>s_SBF`0a!HzWuT~dZFu$mQ^3$%Ppk7Us*YFbLINpWA7i@
zEv;_T`})+L9f#quh36Ny{yL}N`#+yKefrr`;P*?*$K#jQe#_kW;qsoty}KSAHOM_Q
z6+f>2`N#3^E?-@I_Zwy5<<v#IuYU5UqtTUjwki)v(ihv#cI}zi0+e)m8K1oGQ(;Tb
zwIcwTuK8wn&nJ+(yYKbhWh-0SpZ@GDzItKj2Rok2JTZQL?)ook<=mNx@m;%*rg|rs
ZrLUiP>%qTX{V4f&l!`;<hx)`Te*^s4hPMC!
index 664d7bc76296c5c944159a81f5a59e4ff71ad476..b286cb8b62265c42022341946cdd1c2954dd5776
GIT binary patch
literal 1432
zc%17D@N?(olHy`uVBq!ia0vp^av;pX1|+Qw)-3{3k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z{UBn>d-88oRofI+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`cB^jf&MnVI3$Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf1
z3L3tN$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM
z=oCvAC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCML^N^=VX1LHAI7srr_
zTS>qE|F=Kvkf7Ga$h26DzrH*2gJ;;)tuHoh*l>=;NZj=5)bk3*4%|9cX7A><?2di?
zzbV^HL*o^09%oezRq+1KG;^AR&DwP<jr%#gn;WOCV>614h=}+mGA&GcQqITO*Vn5V
z82k}$Es|`kV6r>CaGD;o(M<)V|E=-+t1Ks`bl=}wZT<P*-re<$Yz6|GWV)B~DC~7G
zUN$-B<F>P}!}r$yR+~5B=?)#%SH4WMHp)!@*|XpgxBQ1sygg!KVv#FWEIGroQ9R4a
zK$79BU200ok<^z;HP3{$%xHL8-!Nlph<E3?;||T!9&way(otQ>z!>@O{r&wF2^@cq
z3Ki5h-fYkC_SD-sWlCrrgYc#JoM$IaX>wdza^lFes*6o~<!9XbyfVvholdjrxz25K
zI%B*YIXT^%lus3@73s37s@SZYyWpvX?m113&j-^r1tZtWM_gP2bob@s{YiCye|d&<
zvTU{CyIHg#?pQnjJJyLgAJ50zpU#il|Lwuy-{m~t-`!J;uwZyPtx;!x_49A{`Q`5!
z-`P|6_Tu^Z_Qof*j2c~++N=m-c=U9ESM!W3TvvpdmLxUq5LoeC&NcOGMsog@M~bP2
b4h@V9mwGmsao$pA2bGncu6{1-oD!M<AMgbY
index cd83299baf23e7ee73a700d38bf318a8091c2df9..8b1dd29697871f78903a8b65a22959e60e8e0220
GIT binary patch
literal 1274
zc$}S7TWs4@7|s$@rjSZVL842!crMafL~I`?abhcJN#cZsE?r3@5gw50*vF06`hx8)
zX#sT?QLR%eP1?juCDy)7q8f;s1cRcYj)#IKwx<E(0U?k!HpH|t!RYA1aY;Iarao|F
zpUdz6`~UC!7f<!~J=5w9cwH`6Yi>7RK<h)!yS)X?GgFVYqGgAjDcJ+MY*z&nx{{J!
zhFDG&hF}2-(%4I1z_`ohsVK#gUCQs_L|r8WM~A4XhRYf8o|++u!_daca7fV-`1Mbg
za7>XB`16rGl{eC`qU;_w;lOxbQ5+u@Sqbmy#^N;&8Bn1uU^R6_v$$FU->}P}y(1=Z
zY(vE!PT>ELD&_mJv~EHyLWF`M1pvk{1PDhM20Vq)6rf28JxmaUxd_A2QLHg=<js_1
zuE1v-zR)RwS8UthNU~b364el)n?odES=O;Z(?O&Ww8k`Bs0B5vqiKPMmS`%5t>_x&
zoQ1MJYA0~Kc?H$T=Qj;&RwGa-WMoY+NI+1es*+7@%Pv59Yi+AIW<at4Eq&A!Q9k63
zf4SNk>L?;M++I^bNfAbPT^v=RX6N_>j=m6*B5~PRGz&m9Ohsvmi2)F!Vxeq`W|M3>
zL(?J9v~e$Nl!@{T4I+Fb83rH&l3_m0W|<7b(hM8UrkmKDX4!%!!X{R^iw$py<<ce;
zY~3vC`be_^`YXDvTNT~F(gO_EnHNMwa|B&Zf*M?*sqBYR*3?yOBf^|=PX@_slnJE(
zxO?+VmSOo+3Q=Ksyn&VePt-_6hWt;tG)1Teo$Y4vqr+zVKn?YbiJIfX4}z#mw{_<D
zWU+Rs{8zo+<B4qZgQNQbmtt?qgPHvCkl+8?wU1AI#Vxemy7I%}Gxd7?#}>MM3Y?fb
z_;~l?`A=WI{5v@}@B6&%*$bbkvtR2ifk5i?JfHEdTp&;OycYjx;`+m$vlEMxG`?&0
z>Ka4Hvb;Yo-*(@KWAfzcwb`p*&b|}4(*EGGT#?qiD?jZ5KhL*$|5#m`sK+MicQOlt
zZ|})&?dEE0@z9MI27PnAOD`@Ozjht#n(2N2zya*=dq<!2baeR7QInU?zj4uh_SRz;
zsVDB+*Z$r5!O6GW^tZ=+!#mm6ry|o851PJNeB|lV0>5MXo^$^C`t9BmLg%~F54^H=
z6a2Y+Ce(gsz5ac2g({glk0f4o$BsOA|MIk_P(JQ<xqU8v;g^9izc}OkjdGbj{_WJ@
Gp}zsXcC+>X
index 0729383f53abc342ea7d77494048ca3f2c443f6e..880f12b8de70444643132606e4f44405f8b16ed3
GIT binary patch
literal 1500
zc%17D@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G}
zXKrG8YEWuoN@d~6R2v2c=8Vjch>{3jAFJg2T)jk)8oi3#0tOJUv9BmdOwLX%QAkQn
z&&;z`dcS+Wl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$oq|n;70`g()RIJn
zirk#MVyg;UC9t_xKsHENUr7P1q$Jx`3F4>--v9;Y{GwC^Q$1tdWCKG(1v4`}LlaXo
zGeaE(BLhPteFGpe(={})GBvX@GFN~CC7^9ZDQQ+gE^bh}fIM5JjFOT9D}DX)@^Za$
zW4-*MbbUihOG}U$Mn<|o6}rWhc_oPzx_QOQFcVx-i<65o3raHc^Ate*#H9Sv5?duD
zm=|&je0|{t=M_T(3K(Si6^RA<hI$72xw-l<)x{-2scHCC7l%|9r0NHy7U!21B?IFl
zO&Q55{8~W@fv&OgFUkZ)N@9*nesXDUYF>$_i>(q+MlU5Z#mddX+|AI?+{D1#$iU3P
z(9pub!r0Bp$kNf$+11F%*brt0HofL%<}PMNhK4StjwXhNu7-{#F3y&2X0B$IMrM{K
zZq6{ho_WP3iFwJXFuj=wy#{#oS~(Y`CYIzEh2-bwz*0a!Mt(_taYlZDf^)E$f`)Hm
za%LV#Kob-}P`9QQWtOF;xE1B+Du6@SDif;<9No;#jGYV(5k7ZyGqZGYasoQV(nSfX
zH-(%~(+4_6A1%4Sgn(%f#Dph)AP1g(QuBa$rU;lhVmq_;GB7Z4dAc};RNPAX^Z&m+
zvniu6^Hj#GyeS9OB0{e#9XfO<iXo-y|L^bNU7ejjO(*PSKk+U*b469lc?Y*I25Z*k
zZ%s-|i~RrWtM<m{=jR#y`SbO&wz0AC_KpsX<}E#U#NFK5Zan*Sir1ymQh9j*SH_KL
z;rj6%wiN~Wd>0IU=FYzU`On|q;SZjk7H|Fj{%&GgN=nqc_?S$GDbrb5TUR&eiPe1j
z@=;}h<4=P^h2P2(W<7W+{o}>$?d!9D{`hgbp+>(+FC{gV_utRY&)?hE|2Inr<}s<b
z+b?ggXJllwi>1}A=&`9lhV}LR_5W2OA|vG(O!pmss%mDoO<H01|9?NVd#^hzP`qzf
z|L=>eM4M9JMo){$!u<UGclzb;OV<7W`L}Vw^mv>4G6s<;TwPxKZiq||H-E(_-1hVL
z_xJ0VWj}N+Xmk)Sv#<X4#NL4S+`8;n2JX{V=jMc`razBhzoe|FxO3i%5)PizY>J8x
zs}g4YK7Q`pK4Fa#-VV{a|Nq|peR?{b&(TqF!lwBD|NnC{EIa;|g||gYifzd)OG}HX
z5jP_w|NZ%Q_`~1d+r=HGx~HZ*X;M{LS|D|*WBnFJsWqHS9CkTIzSlCi^N;DMRYTjf
z$3{~o&UwUrGho5#`nx;ou4a60GYu~k<7;8KuvFB+S+Zg0vOkxX_nS9He&&o3dg4^H
oak;;Pg#fp5w;|szA!&sJ44hT!4ZK46OF`wWr>mdKI;Vst0Ah?O6#xJL
index af80eb36cf8e4f0b21b60c49411794e840a89b3d..70ed68b23b600c3fd84a94163c2471d9f549c3e0
GIT binary patch
literal 1253
zc%17D@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G}
zXKrG8YEWuoN@d~6R2v2c=8Vjch>{3jAFJg2T)jk)8oi3#0tOJUv9BmdOwLX%QAkQn
z&&;z`dcS+Wl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$oq|n;70`g()RIJn
zirk#MVyg;UC9t_xKsHENUr7P1q$Jx`3F4>--v9;Y{GwC^Q$1tdWCKG(1v4`}LlaXo
zGeaE(BLhPteFGpe(={})GBvX@GFN~CC7^9ZDQQ+gE^bh}fIM5JjFOT9D}DX)@^Za$
zW4-*MbbUihOG}U$Mn<|o6}rWhc_oPzx_QOQFcVx-i<65o3raHc^Ate*#H9Sv5?duD
zm=|&je0|{t=M_T(3K(Si6^RA<hI$72xw-l<)x{-2scHCC7l%|9r0NHy7U!21B?IFl
zO&Q55{8~W@fv&OgFUkZ)N@9*nesXDUYF>$_i>(q+MlU5Z#mddX+|AI?+{D1#$iU3P
z(9pub!r0Bp$kNf$+11F%*brt0HofL%76#5nZYD0KjwXhNu7-{#F3y&2X0B$IMrM{K
zZq6{ho_WP3iFwJXFuj=wy~cR;S~(Y`CYIzEh2-bwz*0a!Mt(_taYlZDf^)E$f`)Hm
za%LV#Kob-}P`9QQWtOF;xE1B+Du6@SDif;<9No;#jGYV(5k7ZyGqZGYasoQV(nSfX
zH-(%~(+4_6A1%4Sgn(%f#Dph)AP1g(QuBa$rU;lh64sd6GB7X-d%8G=RNPAX^Z&m+
zvniu6^VEY6%qOtU48DHl=ch9-h1YmEt@-nZ>AtAQROx?ze}8}du(|r`e7jl^#;*Tu
zng)hjf7}fT*Xz6LpdfI2TcxdX&*P`kCw_c<%)b42zuX!2qIw2iZ}v;O8?*i?TRyV)
z6JNx<;@Dh==FbcN#Hv(Eo=pATFoj{tZ<da)C%K$erfUYO22F^mkoWlLyz_j6*o%Ny
zPDdX;J`}&d?va_mj1`i9n4JG_-n`Lx!={af48q0%U;cYnvOZ-?Q2g}w;^AuE`S!Jw
ze)rEhEcdWj@$!88`j*CszK6HNB^CZ#3;bt&HsR)iJ0D+OUY?>*%kZMPen-q151)^$
qJi+1_0dEwSOe@@CvqXY{MS_9xeS^{WjOI2_!Q<)b=d#Wzp$Pzb6R{`&
index fb36c4cad1db96b44db6626d9f01b4b785f63782..a5efeb3c9b753301f78d91982ced88384975c3ce
GIT binary patch
literal 1152
zc$}S7OK8+U7>+1fON)viS`|VnV$t1XvfX48yDi-$s|#)|+oe_%HJePkp_@mOSvT!T
zJ&0avJry5__Ns^v@Zf_A7NvMm6csP(Nj%i5R8$bxN!_g?(t|^infd4Y{{Nr<k>i~m
z+v;l@Y6*g<Pi>boc&-cHn#K6rUEKQ?Piv6UgSzZqR8n0?wCi>bk||T|gBhsmg9DSW
zg&-E@jcgC<N$(If+YGA#ChVII5sa2L-%+)Gh{zo5Gpsl@eQTT|4Lwfnil&*gBf-3}
zeaMAfLmgRds9zIws;!l5@kOk_gh(ZQvtW6mAE##Zig+D}X^NbMp#C`Z%c-7pCn?!3
zB%|R-NMisXIW7#EqZ|jekSqgOn!yhj0?lHS6Iq_D3<_Iw^<FU}Co8t_E>7hUazvUg
zl}h1KBy78VG!O(K(801Hj0kyy7E=9?<uz6{$k5YV!$F2^k-=Wg*+mqmsOl9=C!L;C
zY<ZPH;gHe3>d+v}(56XO(H_dc-ucm9cF=)z26}eU)o?y~8~-phKQ#biZ^WIhfs>*Z
zWLqnm&_XFWPT`ZVZs=k%#wP*bn;D*ExEKI2CKgF1SfO2z6qb#Es*ZngrGz9f5nfRu
z63&DI5`w@gg2GAB1e=s&u_`xZc}TT1SmheOx$?YRQF5V*Y&UD$g=z(K=51tqdD|hS
zE{@!kRyD&41WiGLD!xM3I0*HmYn$Y3ghk^Y9`HhYlIJ1`0Dj+GNpgamNXU{P$W(=^
z|4-Ct><s-^xl~2C27~2X@#D>0`#=l#jEkFN^ThpkxUnv$<o2xpGWWe)Zd=%NXvJ>n
z^Wsvgwcv)q@4Q`0xNR5r94mGUg>#249bS5>al>Tv+x?HDH(#~>V3*`Z*FM;{F*-Ff
zEO*~KGIr)<)7?kApN%~#Ocj@pm$OdI$m#lthv4kf66LQQ`84rnW=dJrf2XtX^~>nv
zl_&Pc!P%MVWdj!$J^xUq2O3^qn0fz=KYxAomE6d>qxJmo_>18OPqwZeyDG1n1nD}W
Zh9T<KcU&vqDIN^|2`QyRzMMF4<R_qre_sFq
index f257b0ba333e3c86777b5d3df5aacd39db73829c..332b48b7acf7de5af1c5b0b7c62490469ecdaa1e
GIT binary patch
literal 1133
zc$}S7Pe>F|7$1|Qq&;{lJ56JOLA&#3-PxUCH{G4t&5hP%U2G3UjWbVoT<1?SZ{6`<
zl!u^O(4~kvL{OLNnkER5W+5E{DKvvlf}uu1L|XR7b}d3Y^q86V-uHgL@B7~OXRfri
z9P?D~uf{OUlWZ2#Xx`(#yQ<K)y>NN~O|>wdg>6PBEJ_x@qKeT0@T4Ynfi#emzVk0Y
z7{e-aY9<S_sS~_xXg<ls_#Dl|+!1bcOi9iIh<AW4RgVxWPsRycRU*WxK#EG40?4V&
z{T68JZ^_90d6`p)#-n)H;gJFjKnZuW9^K}h2(h7;M{8G168HuL<|D*!r?RP5Trezv
z2Yi07OwlyXvOc;Yz_RoaoS|rjq|n29=>|T)@=Opf4FXxSlukY^CQ7!@E<)rWG<lLN
z7K^^3-)C4|B+YT0tAk;@2;sH+bSODq-L5NZ5P>aQstHv?$KAcuVH9A5Aj((J%v5Sq
zv2K?Fg+fL;l1b7&iqtf+jJ9DKbZ(EfGkqo?)4(<gmW=YzS@)Nz?WryhdBdNyRFo8{
zM>OPu26UJdBLq6}DXPLJLcs)02OFp$L$M*64pAY0BF1o0PKYy%pDydziYvqfj`9bi
zale2v5vOAu$HcifD+FRpLJWn<+@x+pNtZ#HtN!6~+j4oq0unT=jA8VYE1)%JK*P=%
zCN8wGczsHeRoxXFb`w<c6<BI7P!g7*;TsX=)h#>-a?wPP^~Y%X&&}frmJ?$!QQ$a{
zC~=kli5iKVA^$0tvIy0nyWA{(wApMQprf9#P;)GOz?M;C-Asznj5FJ@w!Yq2dHCYa
z8`o}~effN1BCzy+ey*Zvx$6*^dA0m?a`#mC^{d>D9mCgF=0_f^{#Y&Ac<;!-LVH?L
z3kO>~)6>%xv!mZ@=GaH$)ld1+ssm$VgSAuL`=kr^^Na7Q?uO5Yh6dWsjO-ot+;-L$
zugoN$VV?toYu_sF-8tE8eR3WTeVptK|9pF?=6J)G%BG7I*uB@G%fW2@8}|p0jJJpn
IW9No{0SK*n#sB~S
index ecbdca8527b2174f736635f2c251b11fd93ea71e..8c7bcc64aedf00a5722591e8947bf72e4d956746
GIT binary patch
literal 1283
zc%17D@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=WQl7;NpOBzNqJ&XDuZK6ep0G}
zXKrG8YEWuoN@d~6R2v2c=8Vjch>{3jAFJg2T)jk)8oi3#0tOJUv9BmdOwLX%QAkQn
z&&;z`dcS+Wl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$oq|n;70`g()RIJn
zirk#MVyg;UC9t_xKsHENUr7P1q$Jx`3F4>--v9;Y{GwC^Q$1tdWCKG(1v4`}LlaXo
zGeaE(BLhPteFGpe(={})GBvX@GFN~CC7^9ZDQQ+gE^bh}fIM5JjFOT9D}DX)@^Za$
zW4-*MbbUihOG}U$Mn<|o6}rWhc_oPzx_QOQFcVx-i<65o3raHc^Ate*#H9Sv5?duD
zm=|&je0|{t=M_T(3K(Si6^RA<hI$72xw-l<)x{-2scHCC7l%|9r0NHy7U!21B?IFl
zO&Q55{8~W@fv&OgFUkZ)N@9*nesXDUYF>$_i>(q+MlU5Z#mddX+|AI?+{D1#$iU3P
z(9pub!r0Bp$kNf$+11F%*brt0HofL%<}PMNhL$d-jwXhNu7-{#F3y&2X0B$IMrM{K
zZq6{ho_WP3iFwJXFuj=wy%u=&S~(Y`CYIzEh2-bwz*0a!Mt(_taYlZDf^)E$f`)Hm
za%LV#Kob-}P`9QQWtOF;xE1B+Du6@SDif;<9No;#jGYV(5k7ZyGqZGYasoQV(nSfX
zH-(%~(+4_6A1%4Sgn(%f#Dph)AP1g(QuBa$rU;lhf|?$$V_;x3^mK6yskoK&=l_3u
zW>ZFC=BWoCm``AhU9e$G)RgJd^F=4@T(WXqjh>lrsqfs64q7iBALlO=uD)&msPy4+
z{`c1zG}#sA@m`tHb#z0Df~kDR-+TM3clRuq9>1qz-^Y`W-4)c71<t#eiDcc#nQ-SY
z`}cqQD?eB1?y7UkIeF}~`37KEtcrFE<2%Bt>B0V}{zTi}y1!bvx1W72?l2N)U&zzK
zb6EPc1FvoU|9_gTk}O9RnhT}e3~rv#*4XP_B<s^NaZO2w9ODk9E)C|3yv(gPyT#9Y
zbsCBsKG5{&l#9vXAjd>DuHX{q&s?V`b4pdbzc+V-|9m?myB+o7X*Xh?bTCQ&`f-t&
zEkQ4FPyPRO{0CE*ee@1FWLa`B^Umm3_7r8%6j$hDTJ_T<#7ah&zmtuDk&QuLY2Su-
S2X1Zz6-%D3elF{r5}E)20<c#A
index f7033848e77854bab4c4abf7af48112417adcf01..6f089287af5424ac3814236f5d2baaadf608f917
GIT binary patch
literal 1471
zc%17D@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z{UBo4A=cIy<?TI+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^g80zYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCE>%`0CEU!1&hF#WAGf)|(sW
zy$>Zwuz%P&$M{m-Bu!4YrQgi2Ec9-7(BRlrvM#vYD#VGyv!%4Vukz)T?F$z0IhOUj
z5Oaw=vg~K}tCKyFJLWZdOnG$Y_nupc`g``gzxVdT&3n1;%Z*QLI`ijw(uGE=4RO!@
zaQhzr9WhOE_J>bluOH-W)w;WXpH259mA{tnUVVxYo}g-J&1(McV<ba4^K5Z7;r}l_
z`t7Qm=f1ni#o_mc%Sjs})-SY<l`mra#3$^@(xQ2{CGFL91FcCM8eNr&vpvmkx3;Bl
z`WsC0;!K?7A@<OWbA{tKp%q*^_X-z%7xLik<XqBpgl&~;-#4Kf4rxa3*G@3p>Txx@
z(4b@i>#p?)(QkwwxY`Tf<347}$SBg9)>#yh*_~r`^xw~;jd~BHF7Ms8@98@Zj_|8D
zj-Gh_YfT8BHPf}Mt?QFEE(lopnk#9Z=kj2G+561`0sadk)haJp_9Z9GOg{7M-?SYr
zN^*_wxLBfQdM(OpmS&3KF{_O#xN@&K!a~czN5*PH-{$0p0gd(r+aoMY6m(^{CaCpE
zoREC^=*0eRS-#m)GAAdwu>8@O&TLY6<Ur8M9}`4`jCAJ&c?5f#Oh0`~Ax6e>j&fVj
z$^$B`+l3|Kk9tW-Y<v|V@;P+H?hE$KyBZ~%zsS$93Si%+d7p`g;lcS}`{J@fVNj9k
M>FVdQ&MBb@03}2dmH+?%
index 52d1d9696f38374bd9dd7de68309489c29a1e373..8bf5222b536c9d2f018405b3347eaab7d0573e66
GIT binary patch
literal 2133
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
index 0412fedd868c1f53040eadac7451a558a6c3fa4e..9a9e5ec83d0398d3b64b2648c6925147df5ef95c
GIT binary patch
literal 1717
zc%17D@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`IYx*0i|xH`L-I+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^g7|yYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCIN?^X?1-1Jh$q7srr_TW=z~
zGlU%_=GCS&uU(tD_Uz*6x7?zuf_XAFcFA!+di?5S^MixVtQVUvBsnhZc;M(?CD<w_
zvX<lCDkTvXZ*8rh)w!QvDf`a4k~3@4+qCQXPE{B0zBzU*@8I8u$!Y0E|7$*<x8Hof
zEiiOyPHJ*albPe}1-=)Qn)d!>cGmEl^<g5b9aH(?g)<!^r+Ip>{%;WTeZgCS2TMOo
z{HVBizxwNxF!uPQfQfUwiYz^=OJ`hrD6mSR?d6f=<+mRfuUs|B;k?2;%UwUVns&a(
zopf1qP4RVJmVA+UHF1G<^-}z=dY@aKyT0M{+26Bfy=a+!QBBip-t5_PRXZzurhWct
zx#eV3^Y^#>CdD$xr_GvgzOnVu>gngBcl*z|_J)P=`k_O2Dh>Z`&d;xQH|G8M{bc7<
zAGbYyziJa^{^PUzCsDojz1rK`8v~o%+|+k&ofIqC*V4TH<-Eoi^HUSOWP~oWWM^e{
z)cem)i?`Y5v1sCl8<&C>Ex%zBv@$rxkENf%*{YVmLEA#4U%U3~3^k1|B}sW{(_b@l
zBpq*9FR0tB|LW9}2TDZ-QvcLhA}_C(X?yv|!fqw&v}AUj{sgPJVs7?(%3to;wn|r>
zLt0P$(X=NC(ber~49VP|RfISrXE!TcV?Dw8^@H?;`P+5-7icWAe6rwPlT5TC`~AF=
zGA%M%Q`ni<x5mo~tXRD|@=mMaBp*G|TUpuJp2>^bLqhZ0<sNgM-lSUlf9)c(-?|Qw
zwT$mtn=bo{xGL_B{&W0ejUWeubz`oZ-+~o0H!02VQuU0Doy)m3PN87Rp~qii4^$bi
zus1R;h~2n6XyvEv6|asz2^LB3`E*Xx!n4+yxp4R1fGd8hR*2?U3wNKLoTB7d6m+g*
zA(PGR58-p?EouuCtql`s@!p}HdE#omaQt*t&t1({Q{x?NU1MJcuSuVBfLEZ(!r1m}
zTb;+kI-cB%XZNM`=y0v9UpJ%rqL<~?|B)LwZ?WVy{kJ|C&&0#<%E;i1(N^gtpo+xP
L)z4*}Q$iB}E**`o
index 98f8ac5988594246df9568b2a566b52b9350ec59..8276c14431a388f18376989d65b7b04bcd556c69
GIT binary patch
literal 1442
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z{VO8akPn8XLMAI~y7rx*9rJS{k`px|%tgIvKgS
zSXjXHdgc|EB<3Zj!t`b$^cvvRYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|Ft>DcGdDAKGBiZ^+||v@(#6Ti#o5x*
zMG2}mg`7~+2RcR{ExEvifN2oKgeQI=2cCUW^MHA#2$(sfBs#A!Ffd;5ba4!+xRvzh
z|9^XCT}I`*x*ThbTs(}73|7qQFzV3!(8jRyrb7<v5&MQ8G6Md!Uq76lb$fZdVM9;E
z-7>k=tUeM-{{<uBqB|me=9Sw`*elf`+c1N-<L81mSCfitx*fA5KCm!x>v8hQg|TUt
zHi|8{$0G3mYV&y>{`Gs<PoI3v(Nx2lbd2GuP36xI#j1M61-~4EI{jNe+B<6=wr6Ye
zUtec%$L?>{!}a;~OB^MRuyr;*amZ2;{b|y<jX`9d!WsQjGg+6+bbNE%+)n1t|9(Zu
z6LoCI9Lyqk7EPP!-(uWcA@9IwZNA$0%qIQ!b!CjL|CBuc|NZgHUEN1+#kGk)EE?P-
zgq0U_X>k1e|NH!h-^cG?esSvG-+$##?$7_v<Kxq#u=SKnw1U?0(+cZVSxja$a?gsW
zk7m=@du-8nV}buntCE>7#kjCfoU|`PNZb0faohg`J`4xfIQ)@kPitQJ+E(h*n%@Nl
zMvmMPl9J0A4~Ghg?NdqcTyRg5rJ3VJY8jUo8()&n0<8lxyE4)a*3XLmkiR1O1Ahji
zM)@S>e}8}bTP(KS`}5!N_yoZZ|K*uIC6+wD`Idh_$FB!3-+s?^h+$6IH1P%FgokgL
h<JI{sxfz&v7|t0A{<-tpZUv~+^mO%eS?83{1OV~s{Z{}0
index e75af3c277fa26cfe06826c5feb426e5312b539a..9a3f25f2eac079548e8b8b27e6d730a1d2866c03
GIT binary patch
literal 1379
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z{VO8akPn8o9U{I~y7rx*9rJS{k`px|%tgIvKgS
zSXjXHdgc|EB<3Zj!t`b$^g83!Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|Ft>DcGdDAKGBiZ^+||v@(#6Ti#o5x*
zMG2}mg`7~+2RcR{ExEvifN2oKgeQI=2cCUW^MHA#2$(r6q#w^_U|^i+>EaktaVzQ1
z|Nr*Px{S(qbw7OKb@5=@*tE!~c|%7A$Ap=@N5UNbFn641{CH)1{{1zT1@HNoPqgID
zzMj0bfph-bOGZU!91cHcp1Hd524ly~h8g^);&gR%Hc2dDn=h%eL&f5TrG$!#YIMUH
z7J>h7XJ6;>pKsF^rNjM6v_q0P<THy#c;{)EId%e~;^B;JL7E+Ze|}bPWB>kM@6XrY
z(@i*<ZzvdMI85v6>dc;$!zeFbFE)Xx`v1|->FkXU=kTQ1F((R0tFVQhI&=E?bjMAs
zZ{En9Gx)ZBef;i*EAc8X_s84Szj6tB?Xii~$HzxYL2AmWy8l0GrDFfR-(T<k@Be@H
z;MG1QD%}jq{4<OkeDn%9jE(-88E&oUb$y?%@Q>9uGREb%L!6^w=hUfRB_|1JpHQ|i
zkoF0T4Sv4)*0FCXO=1Q{M!w8JlTuQmJQv*4JaUB5npKsV-P3ZWRKk@e#|%cD@=44a
zULM`>;O6G#_9r&7EP4L(bNYS`G12q$ZF89)Nj-`2Qelw1XZNA>(}c|o3I`ZE_fE44
TX1ul)RP1@W`njxgN@xNAvy$B1
index eb3251c91526d966d318969fa49bdb0cbcd216ed..db6269d513e325f046f23181d2fbb949724bab72
GIT binary patch
literal 1600
zc%17D@N?(olHy`uVBq!ia0vp^8X(NU1|)m_?Z^dEk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`IYx*0i|xLUZFI+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^qS+<Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`Q0BPgsL#N_l;`Q<7*cU7>CgZF
z_J<SLe0Z8=daMerG%n_odBvBa=oaYcDJm{6|KCXAGHXY%+@1ZqADo?i{YX2LvU2mJ
zE~(iK4G(e@uD|^Mzuxlf*QwH-7f*YvSa42T=edx8$Ssai8IA^%B@D8b{Sxj<mU*HR
zUh|9oV=YM$xiB$XvoA?5?w+bgA9FQV$8!x0E%nZ>u8EH=1QL={Qlh5Kn3U<fky+ku
zM}D*Fl!JX!!UMdHJ@v5ZV{X=ux7)n8^6#lBN$mUT|LZ-zclUOEfkly-nY++Ki?-X_
z^JISiet$owOLj-@=U=4`?ruV_Jr>D+|Gr-R!W(^&bRmfkpLlr$MMR?3Em?Ew(1{Zr
zdb~y|UoRg1UHtP0Ye(rF^;M$A0UOvPCh;7YaO9asfyb$n+M5_N%d;%|<}_9DHolnW
z=6if%^yCM{D$J&`?w+CSWhxss{A>2V*e`FdQ6%G9YG|;1ouG(N-|^*b&CQROO_;Dj
zeZtSqoaz%LGHWzAl^2BYMzFLBttwpc%E9TW%(|jUdVDHRcD%p8-}r&nnb)(dCTG5K
zNXqJvzP>)@aQNd1kAcqjNco!TxgtvC>O>bygY_$#R=nb#6@5M6@<bNd8B?Qux*m6|
zE$k>$abz$0{J}@{Vxfz*k)7t<nOwZrs?+}e`>T4jkVW?A!@t(Yw&%xb2fjI=AHOf<
z&aTSG#up5iSn(}aws(kfmHzkl|NaSDZygh&FU*?UTr9nz{?PY#Z>0mgXUut}-7<T2
zx~00h`sv%-^UWCE^0Hq$zkkKegsTie*BtgRb?l!MHIGr2+32v$36`0gc~1QIotpRj
p#fd{JnB8S9UL8n$=g`2w%pmyxx`24pCtXmP?&<31vd$@?2>^HwO(p;U
index 3d88a5fb0648eeb8085b52b07ea31c5bd299ee9e..63ab707141c24840d2bc707d766ec79c838b55b0
GIT binary patch
literal 1486
zc%17D@N?(olHy`uVBq!ia0vp^S|H591|*LjJ{b+9BuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFlS_jM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L;Oh%FIIkEQP{1J5uShJ=H`FuG&&}0`sV*)FN=?JBx;Uh=AXPsowK%`DC>a<Z
zY05}e;nxaM2y~5=e^DkdQWA4q@{>z*Q}aqZU2K(rGI}YQDOPS4=5B_D<|YQ_Mh0dU
zhK3df7RGK)MwX72&aOsA#)dF6u<12%GBPo6F*9>9bu=|JbTxD|adEbEGjlbwG%~X^
zadU?0^~@_SNz6-5h3U;i=rzTw*UGslHL)bWC?r2W2bKZ?GV)9Ei!<^I6r6+26f}Gj
zlQZ)`0-B%*g1R-eD6=dz#jPkmR{<QtR+(5_U~cB<W^QKeWN3)+xvQI*rHhjj&?%NK
zN>IHi<b;|&&@uXG$pt0^OoJdMJn;iL@a&VC2h1}?z|1i#hdYgdf$@*0i(^Q|tv5G!
z`yX<UVgIl#kd0kHymYI;KR)GI9!^sZu4vvI$Y$Wjmv!Z!h4ka>i;j!+et7(mzLPTP
z#}m^Gc`a_&4MFw3r<|sU{oc*xslPL39q)C2uJZ4>3q@TQ&RS>?GFe2rD>mv3p8!Xj
zM%yyYYp=6QciwUrSvsepX2<?>Pw(;8{`;hqc2@T41U`p(PTw1r&D6g3Shi@lwbbj?
z@87&yr@(wmkv+k`D&o9>+BK7qX-_3H*jDqczLD&+CUb?t2g}CibylriM`wJsepyn~
zZ6e0JDlhl)l8q6sGgx<fa&_-~u=<99rp~u>E<D~z+^S8gTdzwWGjq}~Y?&J$#VaY<
zV<tUEeA@Mr^^B#=ude7n_ZCPw7AE#QslJKnfxxW5?nMjqwuvR(IkachKb}6d!x!(h
z@t+gOlTkX){<^J8X??`k2kaiN-hF$v^+Vu|wbl=pPx7x0P(NeGYQW=MxySC*%aW@u
zUXz}*Z<()P_WG*3plph?!ubWSuR9+5pDKIQMW{JRxzpjbqmy}F#ho;VMNXbdfpHEY
zisu*JZtp!($(YEaIm<C=Z-YV88}nwD#=4WAbTU=AraZSiaa7-BV#MY;>&c#Li|=f1
z`{UxCbhgS=$7R#ZlApdJ%146&8?3DwI$fgYndF%0KmES&>?%#c>f?*w+DqrG;618&
bpNWUTWNzUi#%EsPpc2;8)z4*}Q$iB}8fq1;
index 5d948d8119793cb90be6aec622bdaa34d6e3feae..e49d6f9d72c9a436cc74be11a24fe357443cab38
GIT binary patch
literal 2156
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
C0&)2O
index 63168d897da9066d7d0081590700225a651adb70..b1eea14d96096f21006d7665e8e95c0c4535441a
GIT binary patch
literal 1855
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
index ca4e2f4a378ca8bde620eb116c9d0d7ba86002c0..3e0e3f5da1e74f87e25c339e0639a946ac42d066
GIT binary patch
literal 1410
zc%17D@N?(olHy`uVBq!ia0vp^(jd&i1|)m0d<g|ok|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z_70n!7oh7#X@6I~y4qx*9rJS{k`px|%tgIvKgS
zSXjXHdgc|EB<3Zj!t`b$^cvvRYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|Ft>DcGdDAKGBiZ^+||v@(#6Ti#o5x*
zMG2}mg`7~+2RcR{ExEvifN2oKgeQI=2cCUW^MHA#2$(tUK7VtNfq`*@r;B4q#jT`2
z|Nq-F?`05XmSv39O;&U*{Qi-l%#1HBT_ITb)rHyhb${>1=IncDZTL&Fvv+gn^Co9U
z5drT-o_iS|HPtNM>b){4^8U*ODr#xREET>g{Oey|FY)jH@AC&vp5_Yv^#A_;|CO$4
zua^a+M7}H%XU#PIm+hdYZg4^(Z(hyO4-cPyuXgwsZzsqXTFPC>mT;kI%D<|*=ZpQ)
zf6Tj`qAtJ~c<#>s{}L9BGamkHEziGi|Nq^tU4Qo&39PQI`Fi->!K2&t9g7^!98*6u
z(>X9J<#}2uYo%OEy#3FpUCTcIk((hiq4vkw%lS(UD$Df3(z}9`g@qRzF<;qGzyJSQ
z$LZ`{xd}h`!&kdR+WkI$fc40M6RAJ8FMItby(DwP4f_pN0?$;m8@IgqV$QZ~+tCX)
zu3S4lK7RfFMb`D+=N)`*e0kSY4|rTxSiImu!t<0^&LyFp+j@Mu6C7HXuzZ@oF7@&L
zhgp)kuR>}#Q)c{n^ZWUIo;fx-DU!ebp4PwAwc7f5{M{eleu^`%nV>3G|NoQpn&~R@
zYyW;Q{&uPH_<~1WSI*Q5cO+|OiS?L0W$R64U}R$udvz`A)rSYCK&7ImtDnm{r-UW|
DgfI<Y
index 462d78935ed43d437b4145add82094fda0031507..b5e53ce84f20ae3c12e0887d437f290ba59b6df3
GIT binary patch
literal 1345
zc%17D@N?(olHy`uVBq!ia0vp^(jd&i1|)m0d<g|ok|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z_70n!7oh7`nI`I~y4qx*9rJS{k`px|%tgIvKgS
zSXjXHdgc|EB<3Zj!t`b$^g83!Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|Ft>DcGdDAKGBiZ^+||v@(#6Ti#o5x*
zMG2}mg`7~+2RcR{ExEvifN2oKgeQI=2cCUW^MHA#2$(rs*NClVU|`Jmba4!+xRvzh
z|9^Yty$r(4vW&61$%?Lpskz+N+S;p)C#>WweR0;l{@<It>{b8#dg|Pg9<N!q(pbd9
zmnF&5WTm-7%!QEfeN(g!MqIuyk7Y^NA)Q}8KdT?^m$y&2q~x$?$F_~O?Md^Ori*HH
zczeV#8(B6w9xHhNF1O8pzTG|MPyauC`m{<*bG0Euv)Ga^*H=&1FG=%xyWe-)`5!-i
z7CVYH-td>Rui@TuqV)E&ucsW=eEa!1-Fm?d?-fC2ad!V?x|$}=oqJgHSl$13xtbRy
z*&5hQsQq#HcllC|t#8hWL>@bGWC>5=-}E29-`|%isa$Y_O=YXs6g2_8j4%I~e?2kY
zr7}xGJ(6?DnpFp9G&dI;n)pv-%KP)@r}D1NTmQ*iv}2Ci(!$g2;J_?#UfYw`jhD+y
zZR*5Of&M779-ZGGA6wsSdvvM$@}}S4-`!C-?i66le#tv%^Mlvd*KZ8hi;wYfd$y1B
m$VL%UZnxma3pVm79AG%cHpzFp-K_*rq2}r8=d#Wzp$P!I<ll1u
index f452c48b4273b072fd6e5fc77fe0e96fda21771a..096f08559f9ddf1432f984f2a605f15d35bc3c63
GIT binary patch
literal 1654
zc%17D@N?(olHy`uVBq!ia0vp^S|H591|*LjJ{b+9BuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFlS_jM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L;Oh%FIIkEQP{1J5uShJ=H`FuG&&}0`sV*)FN=?JBx;Uh=AXPsowK%`DC>a<Z
zY05}e;nxaM2y~5=e^DkdQWA4q@{>z*Q}aqZU2K(rGI}YQDOPS4=5B_D<|YQ_Mh0dU
zhK3df7RGK)MwX72&aOsA#)dF6u<123urzhDG%<BCbu=|JbTxD|adEbEGjlbwG%~X^
zadU?0^~@_SNz6-5h3U;i=rzHs*UGslHL)bWC?r2W2bKZ?GV)9Ei!<^I6r6+26f}Gj
zlQZ)`0-B%*g1R-eD6=dz#jPkmR{<QtR+(5_U~cB<W^QKeWN3)+xvQI*rHhjj&?%NK
zN>IHi<b;|&&@uXG$pt0^OoJdMJn;iL@a&VC2h1}?z|0}LOi`PGfoX}Si(^Q|tv5G(
zGlU&Q7#_ULSg_l3+x96^d#4<cuzBgLla;wrBH+Wbz=ciiPDg{hE;#TVlv@%YU{iHL
zu0?K<s7TAAgz8TVIu>0rQCqt;$t-u%N>0v`>+-$00#Bu-eePl@Pq?xF=FR?-=Votz
zX~5IG#d+Zp-!9&*3(daNH@_3ll<7NCCChhw!@AcWBTW9Z&E=lEU*n5|>q{lO`UetA
zzl5v|sVYb}+SO^bsDX#6XyV&L&T)6U{P;Thyksp|zUv=&xJAWt{qe(r{O9+|+Gt<C
z;iB@QWLMmwyz;{@m3rQ^9=Y_q()Y5<ghGoc(t5Qa#`eG8-<^AEi_M~`ML++=dxWJ_
zyqI&oKE)wWWVJ_F-!$!~w>9i*U%mcx>RMRhc5mN}z7tetho0<zpRKKNVb(f+{o0>f
zG`gNTE}PUTS@E;L?aR%}6^t96yKG=Oar#0%Z>rH-5f0aPwNvcAvp1>7>V41i-KKuy
z*RNYO{{7;-nlc|M-LJj2EfL<<KU?u;^wxB3VSceJo>eWaTlTaRC2*>3TDo-~<L&^R
ze@3~hGk;E-psTLR^SWfG^W3?YtT&e#e2m*MRqwRNlsBAC7dU5FFkWsCxW)eVSLBIb
z>H!`;ZLc;*XI+}&+N|CnyQOPsb>o__)h{BtdQ&$4KKy(8D$hAvTbADNm~oeX_10PQ
zU73A!j=DK<>|$!S<cL+2)3FknkZw8AT5-jJ=GHp)iwmwFKa~E8lTCk8M}oWCasR~*
z=4P9O#U{i=9KMkH;<*-ANT~7V`(c;ECM=6^nDnG*(WLXw(=L1pJmH#OVRJW_eGmIh
zj>%U`y2O7T&pP$#X59UUc9CV1O0*(RJ~h)n7$kGtZ;pF{aHAD>=@iwyi|&8r;r=Rk
y<#E7zNBQE6`KQ0dTbW&HyA>dP>)(a@Ogs#+u@|D&<onuyY64GJKbLh*2~7Y6JatL{
index ff81c3b352be031ebe6303a265df979a5a5b6624..ad7d29e5474b44660e2ac58c86db8ba13c585e73
GIT binary patch
literal 1451
zc%17D@N?(olHy`uVBq!ia0vp^G9b*s1|*Ak?@s|zk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z_8hySbSeI$F4xI+_|9x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^qS+<Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCML=ml2pt8E<;JIEGZ*O8WEv
zzdf@p<KqRJFPt_PIQQ()lca#l7p|lvCiedN^tAZ=+h}vUe}8|Aum6`j`}*P!Gd&9D
zHci?jcVSbrLmDqX|NF8~Q{K9?w6sYz9+O(v$M2oPzr<x>jCYZa>e)lr*QeQ4RmfZN
zd2E}~dBkG=*H>3h+j!}uDk(4YU3er&%_!LX<}{<g2}=v2RxMlCc{xap>$72)_s*S_
zWe+w@X`RriwoHsgxAoFw2UgB0xs01aVx3PjpZMpoVadwuS2k=#nxbBtHkaq!-x9m6
z;$FFvW0vRAMVBRBD26u`a_Fe9OuD_hJYUkT_RojO2{QL~)P2>Muu1J$KtSWVbt}&{
z%yV#<c6WbuwWYzKZxdpp7ciHVm9drb=Ej<tZ9D9sXD@a-sd4Mk_*E&~VPauy375i|
zqPFo)Pjz?~KWQ`TwKJ!W99ghvnck^$=QawTnA#Zq?Hljmzt!ahQEt=tXG%y)hJ;+*
z+3+*Rc*5$Yw3|jX(<Y`aY+7U_EiZ3>!l+nh+R=xbds4VtTUsPrTU?(p&h&c{;kKzY
zet%u(kH5dmO=hKfcWwnLsQ>q;^3%26Z2d-)!?VrTCrmpkoGod&^2@#N^7m!+<E{3y
qo?tUw7Ua1xr(m0R`<_+?MmB~$g`bl?EYfoa6`!82elF{r5}E+WRS<jt
index 2aa8bc614ca0b9d2cd67af8a03e4d02a1f0ae63e..a2845afdfcb567c543ff32c740de3135ac6f1a64
GIT binary patch
literal 1821
zc$}S8c~BE)6pxBWg;)>@N)gt8O4Veu2`pqKm7Gn`a74t2iX_=3te9-rED-RZAmRlm
zpdwoA$YFsBUZ@2J6>YUt$0`mUh;<wkFBllDV-bXIENG|W_(#9l-S55kz2AH9d&lgS
z@X&9V6Wu2=7!0OTAyw16hwYs(j{cI&`#b4vDkalUi-<TXMN47~5lZMVKxxz(Fg2z{
zQxlu9AO>ShJRYf`G^&M&o-lH>HXV-DXlB?}(0r>|t53ivK!+J{laSSO`Ya2;Q6X!I
zzly6eOR#uckw#*R(n2HkX$g7(%9{T*5M)JY14fL}0#@T{lLfH~S?}y3G;I@uEa06A
zl^|sO6O=|34oC<R1N=FBww?<?01R^=KYtj8<^nt}!~?nX1G6DN#2-d@0l@HL(cVZj
z4pB?x!@g)v$cm>ZGXjDsDJh&3K8GL;AS4h7Y&Lj2Hm$+7q?#zLm2I+kk64gm7CniZ
zDV#6?HeRbEk|-gIHF5=`S*3b!*kl<_6rD2Asx^ZUhYK2w;E1+`Qe$zS*0w~ZnlVs~
zS%@T3PuC;P`(Lg;4YeuK(I8<YP8UVHT1x1XjF^d1N`)-?goENJA`c9ZLr{PpH-N{5
z10g7o8_1W7c><9@BIEJ+(1?wXVYvZvISh&Xr2Zm*2$I<-i9im^U;z&n_{k+BSf$BA
zX-#@;1dD&b@;`}1BqXM#2r`l&R*!T*csxN7mUzMpNEX3>uS%=OO*X+-wgL^uijjCS
zhRR982)xTMf`24}09Ygsfcatw`fziZ92Q8$VmcIolr@Y+|4-IHIvDUj?J^>wd(cL{
zZ+@D2KR%d=o*9xJj*JE{nVz`?N~tK)+SV1NT<9DzWxer-jVJ4FxHdRN-C?<hT6;5D
z<CnB6a<Vtf^z@sazZois&1pIgWt;h&S>X=ST=$OMPh|B|au-}K&8i6wcoMQ{_ZuN^
z2GbRB-dG6s@rL#lr=RH?8d@{7rob8$3X_WFaod@*(3VDXRn3aM`S}q{3qN+;=yS93
zI^Ikx?0||a*@qVIG=#m$a)M9Qg=k97IHBEpTo13U4fnlhzYSi|`sJ~nNuM)+=Gw`8
zl{5BQ*fq0DLhmz=@4sp=G@>`3Pq(+XmvV}ncegq<HU-~%+Hvda`|a18M(qPzPqoOc
z&;DGh6loLPW^9v}q1InLU-!S=4yD^I9PL_kxqhW^S8I556ld4vFOs6!cMV51Df2uE
zBd(Vo?d&XRdIX5D-dmg<-RB0l=JD21?PK!BZpi4~kbD;nI-|Iky!24LTe-R_aF-_$
z)C^!tD!UU;>;LjqJ?&q-wqNq#T1?T6sRx{kb8uPp;?fDN&knh}Kb(Bv(!Jb)bVbL|
zFVA1KcN$AVYX0!v>X=^7)`I5c+Z|gI^A$bE0CeFA-}9Qe)yrlY&@%A^%z<BUq)a)O
zIpHzACZCjFaL;lSAIL6`H^`iHLMEHTsmj}PrLzPtD{SuFUy;{FF?EfDF2yak7t~dA
zSN?wRrQ6*chr))b%}4A)LM|_@Y$(3k=$Yb@`=H8KTuGXAx~?dnW93w%ylkDOzT&r7
zzrCBqwVJd|$$P)^@UCi)t`H$!y>EBL*LAJK4z^5hIMMy%{PS^faqDLvuAD1BTYl;y
zqb=<FG0t^27?FcT83jJKaH(cqZ2zElkXOu!6BS(*09)ciym)E<(&5gXE&KZ}_4coG
zEQ0%Px`eG-uwx?Yp%SmI^=@;%?NlC8vGrP-I%1<(6n)$p=&|0wD^9q!X2u+4_elb-
zj0x0EP8{1^GO#}0F7uq>TR8i0u(M)b)DFa|UPFWx{luJdVbbzt9jTA6T=C0S_)O~?
zEBj16C**}IQu*lZP@hwoB`vKwbv5N9SP_Nxv}Q<{)vu5nluseKJS#ZJW0j}dKK0S^
zmSDg<CabJcKTYZ!6DCGXI<L2zpMwqX*b;ouD{Cljz%`a}dg-dyEu}86Z9gofEL2)6
Hj?MfV8ezPu
index 46471fb5a7336515b929163743e223200f1a6108..88f5f6a7c4e473730ec72e10127355d8454c714b
GIT binary patch
literal 1552
zc%17D@N?(olHy`uVBq!ia0vp^G9b*s1|*Ak?@s|zk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z_7$7#JIxIk~x*I+_|9x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^t$5JYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCLBLK;SzA1CyPni(^Q|t)xHy
z|JyU$G72-#J-DJZgk9&voL$S#y>&RntoUjE!}s_12bd`{8ykOCS9tsd$m5!4S6Sog
z7--3KLZ3A$Rw3<Z;_*w%c72jqBi5wD99i)1PNsx>%58Ox*)w~m_WDPKor{c!NNMj`
zQ*(E|ef=}Lx-Sh6|L)$-^MAvVGT~ru0a4x~7P>5r{kP55i#HVRsbPL7w7>5Eq+Rvz
z{j3lF|6j<|<P>YZF23^n-{0Sv7F@|v_}6%J&HsvK5$T3qLTvLGn~nZmT+IG|f8Adp
zjxA@nG|HyFv2bByJv#OF&mXKd8$3dpn{D4;T|Ird$5x*8t=seN9$3yVvi`D$-_jEd
z68-ZoOzBqQ;|Xeeetv$CdbC3Gou*B>HGlrhd-3T1zrSmlg5HK~|M2ea?fH#Ys&#_y
zubB4nVw1_7b&j+6eU|=-2!8oLOW~qhDR=(;T_5?|uh>Vit~BrX#?8^#{rB(pe#Yq5
zvqw&xIB?{M%e>YDOtS<f@|z6yHBQvr^kq6QEdJGf`(k+bIRAUel&2yRKUi5LBO)Sh
zG!)%YiRRE*C$VE^<&TCl<vUC^Y~Fl7JS1q{?+*_ThcPl9v|BKNU!eOz5Py+`ANTtB
z-Ar2R&J<*(rKYAbL@nZ2qbbJ0!I8r#^^9L9Msi>M|F*5$8pQ5JPhgecG+i_yn_EGE
zJ*hrV@10&Dr>9)P*^Rs_b~9>}v4+fi;K9A*s#wMYRe|%re!YEtll}X9F(%z^Wz(yZ
tZXdDW<~gKNw29+!#_p06(HsH^3=4NXd@9xX(F9aRd%F6$taD0e0ss}eKs^8e
index 07f74a1a3a82592db0ed9ddd37be2695945a4bce..094022b421eeddf71e54bee8c104dfc43cf45e26
GIT binary patch
literal 1251
zc%17D@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%o&*>5hW46K32*3xq68pHF_1f1q>iyV_#8_n4FzjqL7rD
zo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6<f`ms%M>MhI|Z8xE1&_nsU?XD
z6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{h9;(F
zW`;TnMh1pP`UXH`rfX<oWol++WUc@ON<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo<>h+i
z#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7{riAnjTCALaR
zFfZg5`1-;P&MSrn6fns2D-sLz4fPE4b941!s*6j4Qq%COE)J<INYxKYEzU13N(RP9
znlh4A__cx*0$pR}Uz7=ql*AmD{N&Qy)VvZ;7h5Huj9yA+ij|v%xtpP(xru?fk%5_o
zp`nF=g|VBHk)@-hv#XJju_4S1Y<dk0&E1?$3@u%aosA3)T@9TqEsb0)UCo?Los8UE
zEG%GpJ@bl767!N%VR|zWdM)tkwQ?>>O)SYT3dzsUfu(?ejQo=P;*9(P1?ONh1r6WC
z<jg#ffF>w{pl(eq$}CGwaVyHtRRD*uRVFqUm{}O0``ppR(bdGj(b3Jx*h~qkH-(%~
z(+4_6A1%4Sgn(%f#Dph)AP1g(QuBa$rU;lhZgI>KXJB9y^mK6yskoK&=l_3uW>W@X
z=BW(adY!L$-<?VNWOLLZjZNS*!^c{MxE~Lne&1KspKISyHgSf``KJH>C9LFQE7w<4
z{x`lRUT(kA@K1V%sKDbpbIgy=o2k((wY|EPfw!}=<m+F1g?0abylTHY*Em1TZr{H~
zMvZq$TE}PmO}W0~=grLxQW9}@{@&TL>v4^6$d7`QxhLH-LmQ3s;<i;N)Jr*v8yXtV
zY*e~@#5>Py(~gzfYxF(lOzaF4kL6dc`tn_l+m3IEPDjUz;G<#LXA7&|{<nAIR!Y9Z
zlP~f2xBJ?XFVnr){{A;Vz?SIp|M~a*694|Et90yVxcad4;#6mUKPJs$C7Hrmiah>S
iQXi69ve+0|Bp3u%mDkQqo+Sq=c067ET-G@yGywn}TBy?i
index feb3ddc32a1e82cf09e7a9f5d92ac487a14fcc3c..fdb9a78a75e86d9d695a74410d14bdacbef05d59
GIT binary patch
literal 1219
zc%17D@N?(olHy`uVBq!ia0vp^LLkh+1|-AI^@Rf|$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%o&*>5hW46K32*3xq68pHF_1f1q>iyV_#8_n4FzjqL7rD
zo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6<f`ms%M>MhI|Z8xE1&_nsU?XD
z6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{h9;(F
zW`;TnMh1pP`UXH`rfX<oWol++WUc@ON<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo<>h+i
z#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7{riAnjTCALaR
zFfZg5`1-;P&MSrn6fns2D-sLz4fPE4b941!s*6j4Qq%COE)J<INYxKYEzU13N(RP9
znlh4A__cx*0$pR}Uz7=ql*AmD{N&Qy)VvZ;7h5Huj9yA+ij|v%xtpP(xru?fk%5_o
zp`nF=g|VBHk)@-hv#XJju_4S1Y<gXtUCn_Cja-eL4Gj%l4V^53Y)e-&XHzF5Hx~;F
zm|oAk;*!L?<W!j6OoU!Tyn3yii&7Iy@{2<9^K)P+ARr^ZB)>Q#zd*q`*i1pgH!(Rg
z4<w)oiXf<4Q;RaoQd8WD@^clyA#9b2#RWj`8ld~!(Z$i##K6(f&B@qI392`RoKVvT
zIz}HYxxj>gX%NJOCw?FYo_$jDfO)0}m^tpuaGVd!SRXxI978H@CH?vT-=5i&LHR82
zsdM_NVq#*NY(~Zn5o{grnLi%#pKtfg_eJLK#&z>Jr}H{Eiy0XFd0+GGOXs7r(&3Tu
z`|DP+iR3+f{P_Ny33CqmOmS>odR5Uu>)FlA%m2@_tq%JC^K<&{cK&zgYd-#w^tk03
z;bI~i%g=4rykqCi%?@8?Utd3KTW;Ka7E!x5@)F+yoq|^NOrESQcVfQV1y>)RGieG@
z=MQ9<ZQ8MKVWGauJkRL~3D-?a<=BJ7TwJcKT(+yIxJGZ2g3+<F9bKkD2R)2lyuPmQ
zlIarOK2c$P{O%$lkD0=W*D`-S`^RX^p>Tkqu`Ndb-_phBK*frutDnm{r-UW|uiT!x
index 35c7554f9d322fcce4509ca578cdac1af25151f2..25833214a29497a6631021b40103ae5619fe25c8
GIT binary patch
literal 1490
zc%17D@N?(olHy`uVBq!ia0vp^G9b*s1|*Ak?@s|zk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z_8hySbSeIy$?UI+_|9x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^g7|yYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCLv<UiY7Yfr-J>#WAGfR??sU
z|LvJ=86U4`T`U%K_0X<m=eQJ}{(XJ@{EXSx*W3R2`C8p?>nE<Ro<)lu$vP}M^Zfk$
zp#1xL{^g!tRx0soMuB9&?Hh6IOKvsZXzT6$+pufdG#hJaYrE5F3^P+5WR9Lby?tu?
z^nT{qQESAiezF<a*A(oZ)yVj+nl)ycmWIYb9q;DOy|urOJ^Z}9f16A6j@-|`_UGT*
z<5yqs|6Y8}v?d*4LDAWrX_AMVtINfhOW!J6@-^D|3J40$UA$n$5uOk(;W~z%;P&(L
z?d^rc#26!|bsgR0qVQe+!owxYgJPyJeH2vaJD4hIvc%v_vZ9izJ_DP6hugLg#;(Gs
zHf{sKnY9knmN7I79^UZ(|9?Z9`d=x6hSMe{DQYz8u&8}MEKzvq#205@=gpimCj1jh
z<`bSctug4aj>2WeZWDHcukRR_#j(cxoT9=#QODb{bMx<V$qSp#)FtU0%}xx<Gb}s(
z?rtPY&*c=IpHmhrwa`6tMw2PhOnP>zgZ89`JC#3lQd1LE&pOpHHflO(Nw%kMVA&)v
zeQC~{oFtXVitpca-`m&!d$75Oar)AJxqH+9|N6RG#;mw7?a%uA``GU7DJ(VT=U@K;
z7)b?@Z8@5U-{0T=+=%J($#(wtn;VnTPiT5?b+{@la9&j{n7PqfpgHJ_T8!)MjM-^d
foF*|kG%zx-JT~P@k9z41DrG%g{an^LB{Ts5x>Xw~
index 327eaa3b28542b2295272cc41f6f9e56442ca51b..6cf6b4bd1cec4d518c93ed895301395806b1bb2a
GIT binary patch
literal 1639
zc%17D@N?(olHy`uVBq!ia0vp^79h;Q1|(OsS<3+_$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%o&*>5hW46K32*3xq68pHF_1f1q>iyV_#8_n4FzjqL7rD
zo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6<f`ms%M>MhI|Z8xE1&_nsU?XD
z6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{h9;(F
zW`;TnMh1pP`UXH`rfX<oWol++WUc@ON<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo<>h+i
z#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7{riAnjTCALaR
zFfZg5`1-;P&MSrn6fns2D-sLz4fPE4b941!s*6j4Qq%COE)J<INYxKYEzU13N(RP9
znlh4A__cx*0$pR}Uz7=ql*AmD{N&Qy)VvZ;7h5Huj9yA+ij|v%xtpP(xru?fk%5_o
zp`nF=g|VBHk)@-hv#XJju_4S1Y<dkW3{1@pEgW4;9Zd}lT@4*gT%0Z4%v{YZjm#`f
z+?-*0J@bl767!N%VR|zWdM)wlwQ?>>O)SYT3dzsUfu(?ejQo=P;*9(P1?ONh1r6WC
z<jg#ffF>w{pl(eq$}CGwaVyHtRRD*uRVEe}n43GgnVT6q85$yd?&@Y{>Eh%Bbc&^m
z5>#&rIiaQxbc{Y)a)Ai}(;$cmPy9d*Jo}{P0rN}|FmwEQ;Hb*Lz%<p<#WAGf)|*@Y
z-qMaD3?J@>I`KxBXYor_Z@SfVf8jsNERk1B)%9(;bvatM1uR@UMb7KvgR^p6N);Dm
zoJ4K5#4oydR_fxEc}Yn=EZ1Wv``+Ky`DB60<TusEoYn>ghxrogXHK74>HH*VqsG>v
zz$Ie(au=An;%*t*l@$Ft`9I%3aLK}l?)%Q2+g*HN@0oe2W_*vU?ycLjA=mxTqw@)z
z&)M(jm4q)`SGuzC!-M9;`AVnH$}SS!A^V~)%!Z4xXtGcz)0?+@!;jhSduXUBr0p{Q
zZj-Y6B8Fh~lZSp*uDfL*q{1Z-c5*%Yu5ZCCDq$T_+j84o9Fp?Bh@UyJuzj8KMt`H6
z6MChm9nEeB_Oe<&RhX~8=aZ@M1no(mHq`c>dAcdZ<5kWhd80ak-;S+MChA$9$kb9<
zUo(N{r13*l$5Rs9v-0oPCP}_)muj>MJbdH*%{MpSe0ttLE&G6Zw|8-F?%VhUH<eH5
zvIuX=>R`%?REV*RIs92a?$@1PylgCcyl1_6_wJ|KFQv;Fl~S{2?!COp;jlr<3G26Q
zjjc{`7IRW(2E|;j1BOJ{;RE+OANP28u#4ZmZ*8V)9CG@{D)Id<OS0r%ahZg!na;=d
z-n;g%qu3pZGjUC~-QxG%Ogm6puq|eL;T>_woETrlQ_|_PmMzKt`f$ft1?6`u;$*}V
zWOsb5DtzLQC8Ifky^rSvxBI3pHg<;V$JyKYbRJGy@N-v~Oo?#bzUE7(EKC-xVrx0D
zur<TIy}pgn{F#bw#Kab(=H)N1c-Yk+m2GEh5s&ZBtX4Ny)GVCQ?Q_VWr_e!7d*T&~
zH@$XTCpbNdC(S&wa<YZDp{`fg;u|j(A6sfzC2{?}^Y2AlZvJ0r^Z(R6`6Sx~>|Yvy
gY2#kpKQ04?S7!wGR7A|#4=VaSUHx3vIVCg!0DX6600000
index 308d4b0ff13543f90987d083214b7218c0f8ad6b..2c69c449d9ad015aae9c3ee539cd42e863ed680f
GIT binary patch
literal 2595
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
index 776b95611417c8160b93ce1067d877e098987286..c0f270201d177204a384a0415c401d82fd9fdc8a
GIT binary patch
literal 2082
zc$}S8dsGu=7EeWyV*y`OP*KK^tw14RLf$;{lpp~K0eOdz3^0UbLNZ8TMFd|5P*w%O
z1NMlKl}HteVg;lMs3^6dTZCG4w_tsMpy;Z=;Zb*DLHF$G@sIt^%-rwZ@BZ$+-+i3P
z-x9RRYRQ@<I2_JO=+6^llwo=;%(1U=ujhJ<tVa0}Xeg41X2`S<j;%lvAV8>+B|&0H
zrpQd|guHM#vt(Ejfkub|S#m^0l$mshdX)xeT3)_-jZChDP#^(Hg4N#mu}fF*0IcxF
zZ>5UdMH()Y4Etwkq0p=#i9AawXDaZ%K7f~=g&9yms0`4nQq?+^-W&hkE(_b6#3VfM
zUIkTp<NpXMLbL_oB3cNb5<T4H?jQ)zXhe`grO`lFfb0&EN$%J~a|0<XDvd>^19J<H
zdDAKqSz?}G&KJgc<C9TT!y=I~GBSu69z;Z&L;{&irpX4G?1pK$=`z)*Oz)=FInG<)
zK{~k>)}Sz=228vx0ZB)_@%Z^Gs5Bzc2g7RJT%xd)k@PYR2_(9cR4UTEwhk3TiJ#Wi
zNisDMNet<bbgdk#N223@x%xEJq=-es3f96{QDmt+M4qmK)Tof>jmJ)i3RuAsFz5mh
zq*L7KWOo_^1R3rO4*`eFWHY&ZGT8&1xAA9K3J2tKXiO@P%BF%KA7oQ_T&94=r!mPi
zCPl!V#|qUtRHl|g^H}&Jmhwp~i>rlXD58}hNa}nCY)M8?M3;<c0B$G^a1zPnu-YVW
zHWg?tR!9qPgA@WSq5|G$m<9hy1avxEK&N?dK=9+u`2re~$Khb1FnRbntm6O48VL)A
z^grz~FT#4zwEfWh81rF#AT>5KT5LGBSA%LCZs8Uok1f&nk4D9&-j~>14l1V%_f-kY
z8+`*ei_b<cPu_X-+FE}b@Vl`7rQg1Q`@_GGw3!9^&y+3rsbQlZ$KUdfzM_LbgGU-1
z#@h*m-A;eK*KpPs?!R;7n(krMt*MosPcFqS`HLjKxMTpG@RyD%r4G}#nkF9Tin>nM
z1caZnySc<xaB#U|;cE6rGIOOW<@Bzxx9grgW?Zefcfsa#hIQkj7;*2LjVE&tDgR+)
z<QSSVt>Dy@et(Of4?GFoX=`-$o1mcM*>|V=1`Tc&TBOXcsDSx;U~#3g^(iuZrndG=
zuU}iKG-}R%Ps@Rrr7z=i9~mP~yxw)#^=M}6;}st3hm7~T-i_8|WK_;}lZP5g0$!3r
zZ1&91UKT#_)Y)$`Ua+^e9bCIc7}h)E=4xF%0u^^QWSo%Vmv7_{0#BV<!7F`yjCDZZ
znE9q&bc??DJi+=d9A>PkffExue3{Jp&}Hp))6sps_fxk8Of5S01kAZP8FA2p^Jqo?
zakH||(&~%OR|o&jO}a7u^!YvitXBr-fiE={rSRJIEor$?pFce5n|o-Gd2pm%?Wu98
zh>2`TCces=t@_vVPGr21x7Qqb5cEyTrg(+%-HCk;uq~f`;JV>!Mz;9kNM+AsR-UN5
zs3Ydv`y<_UR<EBujqmJ^Ub!Jn`*7m+55iifypWIw+-%|H9r=w7VZ!RIN#zNI6+5<u
zm-xiGzG))ZS=ukQP9Dly-+10Q3w1O%FYRq6uljLc*Duzk*9}>A1|R9?Y~JCE4zX*@
zk+`~+)b>GiN5$=3;`p?88-C+|RS2BRi;bFU%L~3**cbj_nN^W_5N?`+evb<bOK86&
zJ!zX=3cbm)H!SKf97$qdGf0*D`O{zZ6c#*GyVX0nHbNn;QS3O19m5=jfnSb)Q5e3z
zc(^;J>~^6#IxViGPhPWMkTAe7*mipI;I^l)M8V0uNehNrHoFv%%UV46O47o}nP1;I
z*#~<kMDFY1pXn>#V~_+ne>YH-ZrxufOn-TUkUHLcd}rOl4KuS5nv$bki9a=8?n<eT
zfPI=)-t%9l8^17?qo2HTVPJH0bo+1}uO8C2cd6+)1fr0XIk|VS-wS+^%86g^S{>kM
zw`OTk?c1qrbMBxn-<n-C{qx-y<NC=STE+9;zu$B&I1}kRt8u3Ita8q;BwUXxuAK?k
zY<XSMcveFxjjH&%(c9|;HN@o`rBa%^Hbn~9<nI=`x*Q%JhNtd`KkM09K317{<Ko@w
zm}u6v5|-Dx)?&ZE^$cfq6cSdKiVWWugr75W<ceL6Of7i6vNeqLY?bs_?4;WWr!FMn
zQC!G`&A)HhLXkfG%{#8vD9FO!dK`L&DF^oceg`6i?%uxd5q(?qvhF=si_L%u`=WpL
zs*K@PF_wEeF1Phh!pzPi#X$Dvx8_X~`06w5^<(_`xow+1I&ge}CGODSgRIF@!9%9M
NwvZphtL4P!{Rh<OPQ?HK
index aeb46215b166e0eb2dadbcbcc602e5e9f0010f2a..b9fc07f91bac176df59a07f0bcf95830aa3e8bc8
GIT binary patch
literal 1558
zc%17D@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFlS_jM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L;Oh%FIIkEQP{1J5uShJ=H`FuG&&}0`sV*)FN=?JBx;Uh=AXPsowK%`DC>a<Z
zY05}e;nxaM2y~5=e^DkdQWA4q@{>z*Q}aqZU2K(rGI}YQDOPS4=5B_D<|YQ_Mh0dU
zhK3df7RGK)MwX72&aOsA#)dF6u<13jaB(!TaC3Dvb~Z9JbTxFcv@~+HbTxA}buw~u
zv9N&Y^~@_SNz6-5h3U;i=yk!X*UGslHL)bWC?r2W2bKZ?GV)9Ei!<^I6r6+26f}Gj
zlQZ)`0-B%*g1R-eD6=dz#jPkmR{<QtR+(5_U~cK?W^QKeWN3)+xvQI*rHhl3i?gMr
zixO0C3OS*s4|I$^T5^F20n;Fe2~Ye$4m|s$<^l6e5ioP;A9}6Kz`*3<>EaktaVzQ1
z|Nr)f6PS7y^GTHo*vg7TrJgu&;=}=k<+>*n7V9lIdE&?nCXsK9NvbO*RXgl?`hWlb
z;(2%e6#RWS^}EKe@a=QeGuVYa&#~`{z3S2v8Rop9bK=C0N)zH)j$}EUVLGZ%Cg{Pp
z#O-Rt6u~9zeVq&{mL5)>{f<8K(ita2avxb!F{SBA)=|;Q^iJ&$lb)oD1&N$~&9RI*
z*@7+d&D+cCdEU>jXWq=Jx>KTM>CTBugGIiy^zEzsRC@5f{r?rS+lta|eOw{YZO35L
znwYfRZ+}w7-w&s&0(LcW{p>jPnPt_?F2(HH^5<`|e@_2yUmtnb@u<lW{bQnxCA$qy
z{8jk#>f!YN>*Z=X**7&eRLF_2Gah{uXZPce{4&0d)&*57XSY?f-nctK_(k{b`O_F8
zyEkaW{&{rox$B9nO4i0I$rW!D!phRTpYVKs`gr}!9arl9{>T>F6eU)c7Q9M5D<MqG
z{oJnqb^muac<TndQ`!`zrWUgI%E{FK0h@P*F1QqKvueN5f;26^<Z{bbPd434KDf^z
z%ShvTaD=uE%cDC<tGCWRSr%~n9YcJX-n3qY(vVfF{{8>;@A&>psfW`x37JZ(pB7nA
zEje+M!O|HMr#7cb-OPOP-=58q?G>}+Cs`AQv;1Ohj?a|Dm?CQnEMNTpe^Eo4SJBJ4
zW8yo$q$G(HhJ23N|DR?zHqV~AO6=c{U$g%R?5h5EbuKWx4HuN8Y8+75+>mxp)w*Th
zp8ta7FAqH4>99;~D$@%q0rmcGZ{1~07Rj&(Brwb>GE13|_ec*^QhU1kxvX<aXaWFE
CHA)}=
index 84fbc7d8ebf3468a2984acb478da18e92e4270c2..978ebc8ec8a59435fa31c6404fc43d3758356ed3
GIT binary patch
literal 1466
zc%17D@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{(
zJaZG%Q-e|yQz{EjrrIztFlS_jM3hAM`dB6B=jtVb)aX^@7BGN-jeSKyVsdtBi9%9p
zdS;%j()-=}l@u~lY?Z=IeGPmIoKrJ0J*tXQgRA^PlB=?lEmM^2?G$V(tbhjOrj{fs
zROII56<bx<DuK<l0<uBE`br95B_-LmN)Sgy_y#CA=NF|anCcnpCL0(UDwvt+8Jd`y
znHlOR7#SEE=^Fr%nXaLUm8qGPk+}jCC;@FNN=dT{a&d#&1?1T(Wt5Z@Sn2DRmzV36
z8|&p4rRy77T3Uk4Ff!5ws?aU2%qvN((9J7WhMC}!TAW;zSx}OhpQixgCnn{Wme?vO
z!Mu=L;Oh%FIIkEQP{1J5uShJ=H`FuG&&}0`sV*)FN=?JBx;Uh=AXPsowK%`DC>a<Z
zY05}e;nxaM2y~5=e^DkdQWA4q@{>z*Q}aqZU2K(rGI}YQDOPS4=5B_D<|YQ_Mh0dU
zhK3df7RGK)MwX72&aOsA#)dF6u<13jaB(!TaC3Aub~Z9JbTxFcv@~+HbTxA}buw~u
zv9N&Y^~@_SNz6-5h3U;i=(WVF*UGslHL)bWC?r2W2bKZ?GV)9Ei!<^I6r6+26f}Gj
zlQZ)`0-B%*g1R-eD6=dz#jPkmR{<QtR+(5_U~cK?W^QKeWN3)+xvQI*rHhl3i?gMr
zixO0C3OS*s4|I$^T5^F20n;Fe2~Ye$4m|s$<^l6e5ioPSe69=3rHn5;T^vIyZYBNs
z|KI*_0+SC<Gf$6I#tF-gR*|D|`x<$A9HP9Ura3wVc}<=;(UA4TSH>jO6_ctR_OQ+f
ze72|J-<w~Tm-h#L$-lj4-Y>-^3zi(x(Nw+5QgX&sVLM01)dh0Njhnh1iWE$_xV(By
zdW`}D4cQVCC$c)E=?ZLq6v#DcwWy%zY*i&CFKc$s(<hcPuarpH$p8Mnq0NqZ@gBz<
zlL<=7+Vc;bIpR{wepG$w=M5V+Y*FgIyT82s;kmidukY`voXc}a!OVk4b>gNCU${8C
zKLp%$tf~1U=-?%Btp4}6v-Jvn>_*KE6>=i%j7J~c+gI5e^M~8<YtVJaJ2rdrPW-vP
zK2DD@sC$D(?4Ms>PrI(Ds=Tw}okCbxn0Ly*@A>iRkAi;xy}dnh#l>S;UZw1en>Se)
z{eQo|Uc6u>>#10mjV+y?bHrGcz0AxFxBlpI*WD$veBM6ALOJy-e^z9_`obDCxiMni
zp{R$70?*B^PR&=dKBbj4%c1Y42kUVIhqE^#0x!Su-qw8M#*O6-P7}LI)s>~CZ<}}t
zZI$8GDw%ol+l3X)Zn7q?76h^fo_4ga|F>XQYs;A<uN4x0|2Wq#e}CmOi3yPo#_uQH
zmHYMSsrQ|!r^TN$&72idbh%W)Z`lf4lUXa=WlgTgum~hD2=AKKw>aiTIjA)CboFyt
I=akR{05oV6AOHXW
index 5d10b6a4eebad69c618f2a81609f2eb26a41116e..89f481177dd54c05511d19c1dd8f06328d072c96
GIT binary patch
literal 1812
zc%17D@N?(olHy`uVBq!ia0vp^79h;Q1|(OsS<3+_$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%o&*>5hW46K32*3xq68pHF_1f1q>iyV_#8_n4FzjqL7rD
zo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6<f`ms%M>MhI|Z8xE1&_nsU?XD
z6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{h9;(F
zW`;TnMh1pP`UXH`rfX<oWol++WUc@ON<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo<>h+i
z#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7{riAnjTCALaR
zFfZg5`1-;P&MSrn6fns2D-sLz4fPE4b941!s*6j4Qq%COE)J<INYxKYEzU13N(RP9
znlh4A__cx*0$pR}Uz7=ql*AmD{N&Qy)VvZ;7h5Huj9yA+ij|v%xtpP(xru?fk%5_o
zp`nF=g|VBHk)@-hv#XJju_4S1Y<f+c3|*bfEDc>u9Zd}lT@4*gT%0Z4%v{YZjm#`f
z+?-*0J@bl767!N%VR|zWdJXXEwQ?>>O)SYT3dzsUfu(?ejQo=P;*9(P1?ONh1r6WC
z<jg#ffF>w{pl(eq$}CGwaVyHtRRD*uRVEe}n43GgnVT6q85$yd?&@Y{>Eh%Bbc&^m
z5>#&rIiaQxbc{Y)a)Ai}(;$cmPy9d*Jo}{P0rN}|Fmp_sRdyVh=bSuU978H@y}9X~
zA?zr@@Zjtu79qi)SwW&AhK6Aq<wR__y7aj=is{H{ZN0HtESoi2apE>F-L7W|Ri6q4
zSmYHX0$N_3oUG6^W0t9|r}h;UF14v|o;hy%r@ed9wXC%A^lge~_?@>^o;fp}^S}LO
z)6PXFt`u+Znaj=^qyR<N3TJGs`|xMM{)2h(rhL=&0(Igg_nLf(s$6^a_QLF-^UnS=
zyZ@b*+kDfAqkdVXopsUQR~}K`@oKu&fs*E&)2*K_=W4KFJ24?{!P&IrZCi3~^I5#)
z&Ym>Cj{U^ns0li3b40=>ch)|VmizoFa%cU6B{x)iEej4lSJ>4Qdv~wd^xL1)IM*4~
zt$%W+#AJ%!{{yY7d$wN=%sb!wyZp0D*oFz`<$v+NJMXpY&g{K>?#y{IEjy&270kHd
zZ*n?4egB!Gt95ra*)%n|95+03Cuh$Q?wTG6flar6rx+PBc(5`4+#wYttEaXs=;UUD
zc7B)1JUj)$6P|xjdTX{jDn`Di_Vfg&_2QZjZFHlfJs+D~KiJiD@BW=V&yM}#m0tZ!
z{lvPt6JqB(P6{Yk@A0^Vd8>l=(xNjtW{V%4W6)cXUZ*Bge)WpN!oMxoGFbSe15_s&
za<zXoQB<E-*K#CTg70@Br<&M>u8@KP$s?BPZ=O4{&h$8=T>tF%b`e3Djm-L2b~aqT
zS;G7EZ?E6;+!d1@g^CrKro4{fFIr~2Q9aT4!n(BPeMt@$oywvgQ_F1nJrp9(?2wfz
zs8`Gu(s-<9`bbQ%_HgoBQ&yLwo=X`DoBMcAN_9^5VoaKQq%EcQ$jMT_n>-zE3X#o)
zUMx>Os}!p2X0mXexT?{4U!duZ%c0xivnINCGFkV}kI3B^5x?SquR_Ucwx1hT@4oKK
zqrtJqU7)2@qHxs&gKeghJ+})nPjmg4Jmt5@xu-=Ig&rqj{1WVngC7>{{4+^HpwH>2
z)5d}c-7Pzpda$y;pP8`b_$Cj|<F3n;jwXF%_;Oy@*T~?24bPTvr$gskCocGSgNN^q
z(vmCb3n!$Di5YR_$$$BObwjmL?!CUP9}3uSsbxGi__4R^`WLxbOYQs)E|r&JU+d1z
s_u6-P6z?zlDy}6CFmzy6Z#)wZgZ|6xuc!D*3_<mjr>mdKI;Vst0O2I3H2?qr
index 542c3fc514a5dc56268e78ab2abfc89f75bf57e1..76d1b56ba9ff091f15330ebc03b12a623b9ff73b
GIT binary patch
literal 1560
zc%17D@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%o&*>5hW46K32*3xq68pHF_1f1q>iyV_#8_n4FzjqL7rD
zo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6<f`ms%M>MhI|Z8xE1&_nsU?XD
z6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{h9;(F
zW`;TnMh1pP`UXH`rfX<oWol++WUc@ON<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo<>h+i
z#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7{riAnjTCALaR
zFfZg5`1-;P&MSrn6fns2D-sLz4fPE4b941!s*6j4Qq%COE)J<INYxKYEzU13N(RP9
znlh4A__cx*0$pR}Uz7=ql*AmD{N&Qy)VvZ;7h5Huj9yA+ij|v%xtpP(xru?fk%5_o
zp`nF=g|VBHk)@-hv#XJju_4S1ta=UHj4ce@3|vedO$-fP4INEfoGsnVT+J+v%q&gZ
zoMC!B^NLFn^O93xdNbjAUET2NwQ?>>O)SYT3dzsUfu(?ejQo=P;*9(P1?ONh1r6WC
z<jg#ffF>w{pl(eq$}CGwaVyHtRRD*uRVEe}n43AenVT6q85$yd?&@Y{>Eh%Bbc&^m
z5>#&rIiaQxbc{Y)a)Ai}(;$cmPy9d*Jo}{P0rN}|Fmr6??UZ0(U~=<xaSW-r_2%Yj
zufq-^Y!6Oe3E7pgRdCJPMJu+xV15yHv{hlp2PRi@tsTNF;qPL8aP4a_7jX;-s9`&}
zG{VJ~`<`R=-3rgH&gD_AN3wj+&(ugsII)HI;eVr<FMYIUE<5?Jc%n=La{)s<^R8Xh
zI<Xt}*c@1uofW-6(ram+nb50;lM^4R<>sz=S}J#ZkMzwC$rtXl?RxfITYKwQ-aI|e
z6x#;2fGL}{e=wdo@9e(2>>a9JEK&#7PjR(xO;-}gXn689)IK?FU5kE)6%&ipgKuW0
z(>qrCH=HQ-ieDKYdCV<=@6p+mPgPIYUG&YGl<g;RFA|)SkR;HxfMJhfo2$YKhMAi*
zm>f9;nijB4P<CPP5Om#X_n~U<nss)EQX<`)Q~Eat#NJmtH1QZ?#%tEE4hjM}tskDh
z`8qA}YHR+X{mM1_CawM0dGb*cgV6KG1su1w_`htJ7s1rBdxBxWnK!!n{lO&#9>2Jo
zZv+|oE)KuGHO!mgu)!O?^N(IlT$g!k<I>0%pB}wA`1oVOIj8l>+{--9#a6bq+m?!a
zJ65=Q_OCRHGwEt7Teez1*OBQH`RV1gx3VpM`yX3|RQ4?4q6+?&^MCGK=oE~*q3|!a
zqGIQ~?_2*DR}?XnRs=P4d`MvkeCWxbba*kdOS?Pk4M90kfmLgS<m5yZPQS~%_%M+1
zdAhpju65kJ{ag*H@2?!Jd-FxP$;#%N&XkHPa<>@@i|Xr-UwUa0+|TEE`2QBEtwA9U
zTaJG#3*Y?vW#Ee0Q%;LM&ktjNz#!AG_i1DUBZI)aUGFzaS6hS1YEM@`mvv4FO#p9f
BKoS4|
index 8fd572d91ff26fc459fcec164267a04464dd166c..d0cd83eed2ee204016eb61fed6276183cb24aeee
GIT binary patch
literal 2368
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
C{oVfn
index c1db6cccd0ec87754ec6078c11c8313a2a8e91d6..b64be5495d06854ec9bb72f8f26f344dee816544
GIT binary patch
literal 1816
zc$}S8c~BE)6c4u?QWUU)h|2;Bl^h$whC~oTHbII(gn-adYmNm1CL5Eb2^1`c2cdu{
zii!n6D^@BfQm{h3rXo@VQAAYKQo)KRmoth->BfR~I*xzzo85iid*A!L_r7<`>cYc<
zr&~B$kVvHIAxn@5g3|QwG*jZc!f<>uK^$;i3?7Na;Tn+&C2^#f7zIM)qIfg{6-iUp
zwW59`l2L+87=y<Mma-+7oFdZeP_%L-Nx%F8v`UdA3B>_18ZT4$gF{WHK|m(;2UqwA
zXaXe{O^_`~RiTloVM0l2l7uA%0~P~*S~g)oj^ZLfD_^Tnv$g)<Tf1yxuNPB6;H?Ut
z<PZK6RE!`T;9@Ei@S%8<B{T>EV3-0id|(*z0_Ze|PNfkKOokY2ADB&N0+S0Qys4yd
z><ENE>5Jg}!2}#vvZ+*!MnlnfQ!rIL6=JbidK+{)nb07sQxv#JOID~|rz{|-TB4FE
zaT%rn^t?!nCFA}eICTZNQXqI|SfQRw6p=EjR-~jt6dF}7r%q|B@dz~T<JxLriV~$p
zplU2xB_Zk&=lU;KABXA{iD=l%R5GF{qO}MnNtUAuJOuFvi4%%cCS~(|nS2OhGH6UX
z4fcf~Uz)EsKZwrau(&)r-5Z*+@j)z&@9WK@c_Tg?1_bdS4g=w`_%IJ<(P0*Y&z-`C
zDAc$}Awj3GviDf}N3m?K3Kij)N{C@=r#c`!0mCtM0;UAGkucyP5J_YTy}(mnpvhQK
zmFz22%2#1>;BAK4vJXVSggJaB>>UI_?{CiI!z?5yhzNy+fRkA1|H&Ga2!{Hfc9{|p
zJ*eNlYkq=xH$JF>m>Cr@9FmgPXNZ~OhaeoG_U7YQ!BSg}-TGHuWLd=llX1_x9K^#h
z+d}8OG*9>G{^eoFNMEe0t}M??>^q}>W5V6`qF~#JnN(-L!gAee;W_b)ji#AbA`&Xv
z6wh0j?Zw#@Pbi&@Zr-gur5#@{8au@tYR4<{Y91ZkW63oSH{4Eg57d*4x#m_@*3<XD
zU`MA|zNvOy@3Q*0W3K_m;#n(v?5!J2OpZ5=e%A0DEC3$b9By4~PkJ-bcc%2O_6;U^
z5=Ea`{ACyW93T^zmM&<26_!}ln0x+obHh_IdpFZbwj%@WpCGq8Z_(t4c3p+@sEOY`
z7=H0=gv(*I(fVwRhf{y7sDMaWea4%AT?aFN_6ns1JU5GuE_QKkE4ObwS@YDk^0Byj
zAk?LtW53O<9@%fnY&o^QOxGeAC{0Dkhl*g(m5m&a`6e!3tWk0bZ6b4mODgLp%1Y8o
z5Ntuw!oY{$=U=dzD?4a<FZ8EI-E5!--1@-(#t!R8FNC2`A!_*KEH^whHYz+m*~g?}
z=y&0AJ8X_1QRh^Dz{Zg?$fJn|3+8yl*7_L@#@3mCS$u4VlP`L3@62Lz<3-j+PY=hb
z%Ds%e?g!2<N;y)MyV@p~p4jWK%W4@ivejeXtU9&z%3Iy6HKKV(<E>+EnLTD2;q#7i
zrWv>o2Lufc*4DINN_9FuW3;L&%dMI#_O!ON9LtE$$loyBb2aV{)rpMzDQjk5(*}Ef
zVo=b(b2R6d6T1<5$j-L8e7~{rq)iKg`oX@-wFm0+o5w~_;fbt4x3oM<(iLo<n=!ts
zcX-?KwD~W`fC5`UcPFsxPM5Exh2w-pZ^uAN3v#+K*>Fs)j*tL-x6bEYe=s&aw6!bN
zp#N;%NNqE(ot}B)#)b5AtLl0dI<;jH2i=PUu68q}{VQ!YlzsQgj+g22XR}J|xo1ID
z<!&_4ZtuWt<>>8;rA?iZ?kELfd3Rg3=Gjm{=NFMt_gbCZBM-STeH;qV?H9SPUmA|s
z)<*wO$2_ukXS##CX*$PhU&YzsEuBqxYQAkVBlzL<YaHpOj*{D$`z$EsQgB>laGi!9
z(-MD^65xKZn6as&dgV!BcISkdhr#C=Gs}$|qW-d=k&?p-)1GAUdiDRR5MCHk6SOAl
EZ{&oySO5S3
index 811bbcb7b596a734186f8e76fa7e210599852de4..eeca80eb3d67df83794f4eb0933625337ebfc18b
GIT binary patch
literal 1470
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%o&*>5hW46K32*3xq68pHF_1f1q>iyV_#8_n4FzjqL7rD
zo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6<f`ms%M>MhI|Z8xE1&_nsU?XD
z6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{h9;(F
zW`;TnMh1pP`UXH`rfX<oWol++WUc@ON<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo<>h+i
z#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7{riAnjTCALaR
zFfZg5`1-;P&MSrn6fns2D-sLz4fPE4b941!s*6j4Qq%COE)J<INYxKYEzU13N(RP9
znlh4A__cx*0$pR}Uz7=ql*AmD{N&Qy)VvZ;7h5Huj9yA+ij|v%xtpP(xru?fk%5_o
zp`nF=g|VBHk)@-hv#XJju_4S1Y<gXtUCk{WEnHoVoed2QT@9TqEsb0)UCo?Los8UE
zEG%GpJ@bl767!N%VR|zWdR_49wQ?>>O)SYT3dzsUfu(?ejQo=P;*9(P1?ONh1r6WC
z<jg#ffF>w{pl(eq$}CGwaVyHtRRD*uRVEe}0Ihd3H#2rJG(`B^)y>S(#mULV+0xQQ
z392`RoKVvTIz}HYxxj>gX%NJOCw?FYo_$jDfO)0}m^t)C<L5CjFuw70aSW-rmGtNT
zfBVA@Olob6Y>W9M3fMPHShetThrK$xxi{kkNv<PV4rlm|gf~_k?O$K7HtlxKAHS~3
zo+VG3<~?S-wdT#4*^NG~GG6cg{`+}-`H`Z-rK{W>AM@!~ij_V4>+oEwY0jVT_v_of
z>+f$i?BEq*PEuVktC{!q-X|;MSpO`VQ`~6Q(R5?}{l6(Y3g0|EA8-FphVA1`i^v>P
zoufA^TOBqYRM1jj3pst@f!9_6jrf;YtUa3P0XctveVqRA)<bdiy1M_1_w4$+N1NmS
zpKtE08f8K%>_N;&^c-xbg%mTG+gF<$wpU>8h`;mq3zx|GY^!tjttXjp`a2{kSkACo
zFi&EYWy93wn-WsTdE)Q=pS5+_=ReUUrVbm;9d_O{C{?fx@n$~b(<78Hzmezv@BcD-
zr4Bnc8<aZOP68Uvt!=E&Y_dHo%InXerF=Ty<=3^hKPp;Kx_!SayZLJ&h2Uvtn%;fv
zU%!9xs#tS5MQxTFmXYFr{=08`s-VDal5962O!YLQ!)ei#0e4nUn9KI!V#vYy9RGVu
z*m){M{>XpO_+fuR@x%PW1X+eP4<#aQ%+TEQ;QRXhPp-G|uisbu{rPo!wus{P5S~lF
zU%a|~J*EA?Z1wrvjTKB2G(FN7_OL$^T4n0xZmqVMZviU<hXI5Cw|g1quP7CRN>oo*
KKbLh*2~7Yk*%aRZ
index d51d36df010d062f1af9cac2ac73ca1c4b998683..cee0b162fbe7b227bc5feee646e79fefbf2610bd
GIT binary patch
literal 1407
zc%17D@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%o&*>5hW46K32*3xq68pHF_1f1q>iyV_#8_n4FzjqL7rD
zo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6<f`ms%M>MhI|Z8xE1&_nsU?XD
z6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{h9;(F
zW`;TnMh1pP`UXH`rfX<oWol++WUc@ON<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo<>h+i
z#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7{riAnjTCALaR
zFfZg5`1-;P&MSrn6fns2D-sLz4fPE4b941!s*6j4Qq%COE)J<INYxKYEzU13N(RP9
znlh4A__cx*0$pR}Uz7=ql*AmD{N&Qy)VvZ;7h5Huj9yA+ij|v%xtpP(xru?fk%5_o
zp`nF=g|VBHk)@-hv#XJju_4S1Y<gXtUCk{WEgW5qoed2QT@9TqEsb0)UCo?Los8UE
zEG%GpJ@bl767!N%VR|!xdR;7xO`Kg_obl?laxO|uEXgkl$<NP$rGS8p{F40QjQj!x
z=U_7h4d2A%%sh~QCMbfSZcQ!9EK5ysE6UGR0Ee(uCKeX}o$h9CX6$5Wi14|qo0+AH
zlaq_HrKO7!RBsA7p{5UXj6Pa&fe8WAAczT1{6G#o`=sUp^Gp#ib4)*~1<Y5BYdu{Y
zLn>}1{rUgj{;&hnu|W17tA-HvDdFaYn>KG2XPCLrVGY}nHx4zT9pQie{47pN&%Rqe
z%W}c0b*{5pTT6{6tn6?;x!1nF?)Mhct1-)WF>`sXdh+wf4}a#FixmF-|NmdYuKpj-
zw8u}MrY5AMG-=lUeR<h^GN)~Be~01p)`;m$y7Rd=|9O2~pQrr&onJp+UtfP%!A@Fw
z_S#KdQr70?{2kg{p|8DqcKRIAICVyI6I0MRg>Ucg@0ZNGzpIcbW9O-DXJ5xUN*vi&
z{Q8;Z1R0SX3|}LH&N9Z_xpUFr+wAM><Np2pd|W)^qwoxgj=$0p-xVxXYz;$-8ML)m
z8}|Htd;9uL2k!d|Rx@_(WjmR8*?A-Lj2Saj6W-MS|2OyWQocyO74DO=_!1HmAGU4`
zy=qeTFsNOJ{mNnILNgXItFi-5>6{ZZz0(}O|9F00K5*{ZukI(f7#BR{*4QA!l5+E=
z<+ETR)~*nZccB`7%v)F%^GTE*Si$_kiXq~4U=HJkR+oLua`sgp-o20iB+Gc|_m7K*
zucvJ9xVNu1nB$0WgO8)p-4Ajd-fq8HfjY17F>n|#DC!?)nsRBbF{nuNboFyt=akR{
E08dW)H~;_u
index 50985ec947f2be789e950df8ab6515e05dbde75a..c52f1f03b51a736b5ee877de2060bfe5d53a6fa7
GIT binary patch
literal 1699
zc%17D@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O`
z&)mfH)S%SFl*+=BsWuD@%o&*>5hW46K32*3xq68pHF_1f1q>iyV_#8_n4FzjqL7rD
zo|$K>^nUk#C56lsTcvPQUjyF)=hTc$kE){7;3~h6<f`ms%M>MhI|Z8xE1&_nsU?XD
z6}dTi#a0!zN?>!XfNYSkzLEl1NlCV?62wsvz5xo(`9-M;rh3M@$p(go3T9?{h9;(F
zW`;TnMh1pP`UXH`rfX<oWol++WUc@ON<iC+Qqrt~T-=~`0eQAc86_nJR{Hwo<>h+i
z#(Mch>H3D2mX;thjEr=FDs+o0^GXscbn}XpVJ5hw7AF^F7L;V>=P7{riAnjTCALaR
zFfZg5`1-;P&MSrn6fns2D-sLz4fPE4b941!s*6j4Qq%COE)J<INYxKYEzU13N(RP9
znlh4A__cx*0$pR}Uz7=ql*AmD{N&Qy)VvZ;7h5Huj9yA+ij|v%xtpP(xru?fk%5_o
zp`nF=g|VBHk)@-hv#XJju_4S1ta=UHj4ce@Ok7MIO$-fP4INEfoGsnVT+J+v%q&gZ
zoMC!B^NLFn^O93xdNUDvjq&QWaxO|uEXgkl$<NP$rGS8p{F40QjQj!x=U_7h4d2A%
z%sh~QCMbfSZcQ!9EK5ysE6UGR0Ee(uCKeZ%n>o6fn;AP98X|n|>Sku?;^YK$ilvJZ
zRBsA7p{5UXj6Pa&fe8WAAczT1{6G#o`=sUp^Gp#ibJ+iQ;ljYcbkWnrF{I+wn;G^Q
z!hsS8;^UH*KIi<VC%AFj&*Y638m`Ox_(}teL{^G8zgFN|r*x@{cgDh3Pp%wvyt1%q
za`T0yM;(tGT*|l2^#8iRRUFSY-T0IH>Sye&1dhGW_U`_k)cXD4MDI_Z?!7PH`Mvi2
z+|vd;U+mkxIXD;<6<AsvqFM8NT~s}-47w(K)D)ZhBjM^hr-~UX?B~BX_{83{obl-L
z*Eh{2bwibBRsZdJ@qLESKY;`LTQ92{JougQ#_`C>tGAo@W83$MJ$&1=s%k!~Q*EBO
ztNalr^Zfg!55*sRdGpOZPvXbU*v|bQUKBDPxA3re%gb`thgGjP=BD~-_UBR$CJJ||
z{dmT0w`|ou$z@DWi&m}=IKdxP<Ewg+X`h&-t@W{x2ip^u2!EXFI>EtDh2!DH={;tr
zLl}&lmPW0e$KKgrrt0x9eCrkN6HewkmIQkA#`PaJu3z;334>3@>a^JtlGd-wdKu}_
zUH0JkSv!x*8l|!erXG+8KCIkjm9Sdqvc~}dAzhntMyt+SHjA5<3m!O;c7P#r#trAS
z>Sne!zBj}cOnAWdK4L-Sq9D!fIs5nh>z1?;ZrtS(KHccb#f|otSFP1K{a)niX_k32
z8zd)ao&CCbzCu0^oAYt^#EWg;dK^r?6<oL3AAFRplY^V{PFlq?p&9BmddnAwWvee2
znjyVsrq<<?(^a?~)PbBoVXJy3h+6*^nxR}{8=6+>m2mFE*9DUTM5gXNaAoiB>mCmm
zZg?BAq(il;>hJWKTroWS<%b>^^F3Ip;<faW@-ildFi+J-Ry^-m=6NiN&{5Kz>a*#d
zaQ-vyp9MzyCS_0Az_@>P3+MbFd-iMzyesi=tGb<Xsn=)szB28jNsNDg{5vZ&@59BU
z+~6y<Ytj#}mOsCB>$<9dHT(SkPj;%?vFevUh-gc`_3G4QJLy(~;B#NT-8IPkXPtX9
o=-pHSCMO4IdOEPb$DWCY!I&*j-GA+=G*GqS>FVdQ&MBb@02;!EJOBUy
index 610db35087e47457f6cae42081dae40746bd8d1c..1146c963cd125ab236df98ae8bb22a376750aefa
GIT binary patch
literal 1308
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aTDZEHI+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`bW^*S25nHw4y8{pMz<y@4SSdw29lAoUgO925H`6c<q8TkbY
z&cS918or6inRy@qO;7|u-I`jIS(cjOR+OKs01jcROe`)iH*<6|H#2rJG(`B^)y>S(
z#mNci6iXK+sNNKELQNm&7=5(l0uutJK@bz3_<<aF_DRhH=9wa3=Fk#5HG_eH(aY1t
zF{I*F(x3nT?U{8Mg_(O9xedFrq;B1vF=K|>-~a#DFW9-Sh&{AcKuR$C)QJ-t7*B+x
zr=;8pxP9ZDV<`8&y1$1io`2I#TkzU3rYuNTG2`I2v#<SY|NKxC$T+EAq@$=csc~A)
z;lxh$t3iT%-q(aTwJb^T>QhyD&OAYNRhCqvLvy`j>xZaA9H&q2V^mzz=C+K#(Z|#1
z^Of`W_t*d2ZhrmUkyp+2|Nj;K{q@y*(jS}O^Z%ZF>|R{>EM<ZJzSvzA?+hnsdY{mc
zlapf$HT7jnOG}%P*Y^ASyMML6zxk@3Q&3_JxxPJ;k@r4d$|pt1c`QBiT}9lDG}|WU
zFs^KyoWf|?CY<Y7TB{w|CY;(hJzwGU?(+QYlaehiuH?u#$>XW{@{9ca{r_wK|C7Dg
zCLFt%(ec^mbpQEGFS8vEU!OF|K%%{7sedsy0}~HJ+{6#F1^qHIK;@OEtDnm{r-UW|
DoX5wk
index ba907977b61599c6426c3b5b9eb4fd3bd3b4e9a2..66d14738dd375b71fc2fc11ff1079b4a9c657421
GIT binary patch
literal 1608
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`IYx|tgq7`eEZI+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^g83!Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCFdecJ(#}2BtDk7srr_TS<TZ
z|F>t>WfW%aWjw2!a8Nby@&&b%M~=+lP5H&NkxSq|>mzB0JrB>%zd!lbtgL+k$&AX|
zELLQ{>R}2p{{Q#)@z3w>O1I_5?>90qGBWz`;gcZ;2S?M5_5c3=7rz}7zq31qJ4@<T
z@QfKV(rW+zoBQ$HTIu`s|9<V1(Wqg26>XiT_l`l-v{WoCY+L;P`u|0F`Ri<*wy?g8
zWHovuG|3!j!RgYcpN_8HU-$RZy=|3$ol|(@_BFcM*x1ZAH7Q-vaA$eH+`a1&2Ia@Z
z7b(q*ci14{QMkAA^DpiT1^y+69T_yr-kqMVzi_@?Ez3?HsTJydFG7x-JNJ%v(f+!h
zn;0@KB*)BZC_3Jd^-bZmVg}=d*F8Ku|EDgvGucH&V1rZwhqln$=K1#ZP0B6p)2C0I
z@Y29^f8D<y?o(JD^8f$;@b7P|Ky*aJm01&5_w1=LQ}}hb{rmUMZwF6LKX1+)EWm6q
z^Vqad(-jXcg@j(u;`iEgV9x=dp513%qCfop{(j%@@9&x>$%wPFKYw=XSXrsg%nQ?6
zTT^*8I*pBt{sskw#d-(1F}sy@ELd<si`7-tEiG+Yyu-q;4mDC8HyzfoC6y;!VLB`?
z=Ud(Ac`e_`|F-#}ZmtEYj5=q|e0Dv0g!RV{RtXCW3kio;b$@;w{P6K`b-<4Q!J(HE
zn0`%KpxU$J74rgBCI>C%BP>a(8Hwf69p;Q5)55~8t$igGHLFD@QDyrfMk@!VjFWaH
z-uL!ZzBMlmI&a?fnmJ)p9ixwkpLu@F?thPum(SSn`TF|!Wr1rCIc{T-u;Dq-)c^46
z>gnn$g<M`7WL+|?K}&hT(%=<&2S2R)!pOwKu&7D-SbyfzQ=qcl)78&qol`;+06NlS
AVE_OC
index d6ae017a97a0d17c241f371cc2d246e5225213ec..8fc9457f4f280bcbd05af7add0ccc26a18678eb6
GIT binary patch
literal 1306
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aTAI0-I+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^qS(;Yvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCMKcM@)!;fziX$#WAGfR??sU
z|LvJ|8HJg953XQkVdOSizHa4b!wHiPE_%l=5dZt@>u^El!~gYja^C!P*k>nDoEZ3f
z$;x#xVyjsV4xgW6*Z9g;O-+oE(a|>2vh^nqPfz{(yL;DuczC$Ft^WVNg)58=w<b80
zD{!0T=ic5kPjKe@r_v|BzPlSOzkpwjvG%}+r>CbEEchU{U{`*I;s^PBfrm^1&0&nX
zRcuTCGyOb%vWwXy+@2+<$iu0>f$em#$jOX#)0S6hNqs%o@S|a$>(PFBdkG5*iw&s~
z0n_$={rvoVNrKz&qvy^UN}jmRoMcwQT>tl1=j|r#>H2qAf?mCtHKQ?=b$`QxwmnUc
zm@)zveiDob`Qxgswcr7xQTxOhQoIrm_b7DDk54%E|Nnmp``TYq_`1{*Y--h(OrJPK
vOE_bq^@Lx%CKd7<t0dfCKVjU?pm2a;*6VI1^Q*JOK&6$ZtDnm{r-UW|l={Vb
index ee3230852c58c55de3146ac1d2f6cd05f549c63e..f42249ba426173615a88d2db330f746ce8ceca9e
GIT binary patch
literal 1189
zc$}S7U2NM_6n0kx)0&BGeLyg@UR+IL8nJVo#)++DRct411j(W_((*8*IreR1HTHGw
zTjEv%_Vd7skV+qUq+&t{G=!K0V}l_vG*Cf9o2E@ez<A?@Kf%;W%Lvyc=@6Rwz?JQL
z&$-`s&bjBF<Ari*Z2PvywlNH|y)dp-=)5C*w?0U}Lw|I1Iz38qH8O!GNlW(-lQnT2
zfr711p$gK?xtT9fnqm4IR<%ZI#b;y#+ngR^xWIOqaHK~AS2v~+0d+KGIT`lXa~D`(
znHly_q8KZ>Dr#8c^B$U*FIA2CX+tvE(E}hI$kc$1hz<g~>G*PxVb|@-bRDXB7OX?a
zbcX#Ws9LcMRO}&;;Nnpu1|bkd4vr*55k3Wk7!>#zeZ(jnkrSdUBtdtu)SG8c$`vi&
z^+lx&+aSc1dA`+ZajiIqy(u0_k`&qygeXNs{W*u|LDcbwdloe08=mD73p*f`^*Wv<
z8J6uG!FG$q4a1J#O%zQTALuR*xfpNTd=KrD3Yy#;?N{eq#8;4yXFY@7$K>$8Ty0Jb
zfixQVpl8ub(VH4JW^Lq<f|g<F4rf}XoKGe55GF@rNg*btAWX$l@w_5PSxL<aLLByN
z+>e`8q^zQhq;hc;LYRY!BndewC#nfW$ZM%ok6UnjqB{oaajkpY<fdF%^^i`mSH-y5
ztAKI?6YMvz3)Be_JXzEY%Lx_x!VBugiahH%Wad3=gY^u{)_o#KO4)o;j4Ke{J9#cI
zN}8f*sw8P_muvo?tnoA${y*i?Q_&g>mm9@Tg^l(>4(%C_HpiPUpBti$b+w>ntHI5B
zyVDu%-+Of7nDXiIr<Xg;SN9JN8rLu57th={TRVOC&gzACz6ri_mJgRd`26ZCOG`5=
z9}nQ$2l3pWkB{#@x&~&JBe!-QdH1i*;<2Bv-Q`cc{q5!b=g)V}K5+4&g+as&?0#P=
z_n&xcvAt!-4_}Sxdrm&QYwXa<$vp$lUplecw{I-{qxjwzp50e^q<v@Qr>z$wfqUTl
z+S=;kl}1~Az3+{WnBmALFRXq2TW4sv)V}>0-{w9fw|?IXPQ7&L%0T3aV0r16*B0vi
a%$5j~O*aqkde+?;{x}M`l6G1-a{O;3tdpGp
index fbb14f611dc0f16ea055947287b05fed4c22b568..973e01542e3aed49aa576f52d4bf7498b98eff33
GIT binary patch
literal 1158
zc%17D@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`I&Svop7nV7g5I~y7rx*9rJS{k`px|%tgIvKgS
zSXjXHdgc|EB<3Zj!t`b$^cv&UYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|Ft>DcGdDAKGBiZ^+||v@(#6Ti#o5x*
zMG2}mg`7~+2RcR{ExEvifN2oKgeQI=2cCUW^MHA#2$(sp^iC}WW~?oqE{-7;x03$+
z|8LK%+R)kPbfC$5(YB3uXHJ~B^7-}k^P_Td-dz9p|9|+UnE0L3HN>BYhR$F#&9DCS
zW8uH0-OuMUXEF=OtN2Y}ymQCqszcY?v$L-+y=}HWyyEk(P|gm1QS}@KZSB>T9cBh5
zkqpaveV!|JD>J)&iCB^S>JIx7nU5{Ek1X5uiK#}fKt<rg&ye0@ju{8OzrX(>>&LgZ
w+W)3hd_A?)+rf*!UsC*o+v5w|E)5LK3=i4tgYHhY0+lojp00i_>zopr08>JS1ONa4
index 351b795831c669ae346c22b1f03c5f470e5d3f0f..b089892e41aab5612bba4fc5fe286c6b5b8f2d38
GIT binary patch
literal 1410
zc%17D@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk?
zp1FzXsX?iUDV2pMQ*9U+m@_g%B1$5BeXNr6bM+EIYV;~{3m8Da#=fE;F*!T6L?J0P
zJu}Z%>HY5gN(z}Nwo2iqz6QPp&Z!xh9#uuD!Bu`C$yM3OmMKd1b_zBXRzL%CQ%e#R
zDspr3imfVamB8j&0ofp7eI*63l9Fs&C5WRUd;=7m^NUgyO!bU)lMM_F70k@^3{6bU
z%nWrDj0_Bo^bLT>OxMuF%GAut$Xo#mlz_GsrKDK}xwt{?0`hE?GD=Dctn~HE%ggo3
zjrH=2()A53EiFN27#ZmTRp=I1=9MH?=;jqG!%T2VElw`VEGWs$&r<;L6O-~wOKg>t
zU|z^A@b!fooL3ADC}5E3S0onb8|oS8=jQ6eR2P>7rKaImT^v$bkg6Y)TAW{6lnjiI
zG-V{K@M{Gr1iHq`zbF$JDTz5Q`N^fZsd*)yF1AWQ8NHOu6e~9ib2mdna}xt|BLg!F
zLqiJ#3u8AYBTGk1XICR5V?&r3*z`KN7#X@aS{k{SI+_?7x*9r~xHwz7nYo%-8kt#|
zxH-f0dgc|EB<3Zj!t`b$^cv#TYvo*&npl!w6q28x14{t`8Tlpo#Toep3eLf13L3tN
z$(eZ|0ZmW@LEV~Klv$RV;#QQOs{jsRt4u5|FgJ5_GdDAKGBiZ^+||v@(#6RM=oCvA
zC8*vMazafX=oo#p<N^}{ra=%Bp7?<rc=k!n1Lm0`VCE2C7`U5(fpLSUi(^Q|t)xHy
z|JyU`G72;I9$dl7!pLoQaLt{hG{L})kq*mFZO@NquCkhS@3GN>bt{dfJyiev`l`KX
z@zQU4fp!T=Y4aGDOlr8%*WF!R?&&&Lf$#9=#w#fbW{F8jcizj3sQFA`<$rhg;m<E0
znR~K(&I+w~_}AggkLTy}+oH|a761A7cXq1=_rJgY=T|)cc2;(W&cUP~uk-Kk-<flJ
z&p*{&kv%(%W=+pmU>8<?TqPP>%5PW4IO9X4LLB=M-3XrjEoWuiYAhw&RTCU~9<of<
z40z0+P{3OE>q{p4E*XQXd;WcWz1-ODaOWv@1@DxUr{5NKGe3SZb5`3m;Vxq-6DRA$
zgP(qWR-ZA&?!qM79g_?K#S*-Ax97*%H%!^p!x4GNrR(7Vj#9Q`o$OIU$Fe!YxIcAi
z8Eus0>*+u3@JBeqlVO*tjLe*BrlvzXJI|hc7r(#mpn;6$qleRKSfW0?zaQUby*)qU
z&#%AU4J&FGeEv5b__DuyVyEZ3_xJbfooHLUGC7^)nQ&TK+HU*$e?J(nzExIL-^{GZ
zw_sWS4<V)i*%f~T8CF$07x~Gpz4#)D(V>BnLFJe7)k)=@ZJ<)o)78&qol`;+0EG$r
A=Kufz
--- a/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml
+++ b/mobile/android/base/resources/layout-land-v14/browser_toolbar.xml
@@ -51,72 +51,81 @@
 
         <TextSwitcher android:id="@+id/tabs_count"
                      style="@style/AddressBar.ImageButton"
                      android:layout_width="39dip"
                      android:layout_height="wrap_content"
                      android:layout_marginTop="4.5dp"
                      android:layout_alignRight="@id/tabs"
                      android:gravity="center_horizontal"/>
-        
-        <Button android:id="@+id/awesome_bar"
-                style="@style/AddressBar.Button"
-                android:layout_width="fill_parent"
-                android:layout_marginTop="3dp"
-                android:layout_marginBottom="3dp"
-                android:layout_marginLeft="4dp"
-                android:layout_marginRight="45dp"
-                android:layout_alignParentLeft="true"
-                android:layout_alignParentBottom="true"
-                android:layout_centerVertical="true"
-                android:background="@drawable/address_bar_url"
-                android:singleLine="true"
-                android:gravity="center_vertical|left"
-                android:hint="@string/awesomebar_default_text"
-                android:textColor="#222222"
-                android:paddingLeft="35dip"
-                android:paddingRight="7dip"/>
+
+        <FrameLayout style="@style/AddressBar.Button"
+                     android:layout_marginTop="3dp"
+                     android:layout_marginBottom="3dp"
+                     android:layout_marginLeft="4dp"
+                     android:layout_marginRight="45dp"
+                     android:layout_alignParentLeft="true"
+                     android:layout_alignParentBottom="true"
+                     android:layout_centerVertical="true">
 
-        <ImageButton android:id="@+id/favicon"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="21.33dip"
-                     android:layout_height="21.33dip"
-                     android:layout_marginLeft="7dip"
-                     android:layout_centerVertical="true"
-                     android:src="@drawable/favicon"
-                     android:layout_alignLeft="@id/awesome_bar"/>
+            <Button android:id="@+id/awesome_bar"
+                    style="@style/AddressBar.Button"
+                    android:background="@drawable/address_bar_url"/>
+
+            <LinearLayout style="@style/AddressBar.Button"
+                          android:orientation="horizontal">
+
+                <ImageButton android:id="@+id/favicon"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="29.33dip"
+                             android:layout_height="fill_parent"
+                             android:scaleType="fitCenter"
+                             android:paddingLeft="8dip"
+                             android:layout_marginRight="4dip"
+                             android:layout_gravity="center_vertical"
+                             android:src="@drawable/favicon"/>
 
-        <LinearLayout android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:layout_centerVertical="true"
-                      android:layout_alignRight="@id/awesome_bar"
-                      android:orientation="horizontal">
-
-            <ImageButton android:id="@+id/reader"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="10dip"
-                         android:src="@drawable/reader"
-                         android:contentDescription="@string/reader_mode"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/site_security"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="@dimen/browser_toolbar_lock_width"
+                             android:scaleType="fitCenter"
+                             android:layout_marginLeft="-4dip"
+                             android:paddingLeft="1dp"
+                             android:paddingRight="1dp"
+                             android:src="@drawable/site_security_level"
+                             android:contentDescription="@string/site_security"
+                             android:visibility="gone"/>
 
-            <ImageButton android:id="@+id/site_security"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="10dip"
-                         android:src="@drawable/site_security_level"
-                         android:contentDescription="@string/site_security"
-                         android:visibility="gone"/>
+                <TextView android:id="@+id/awesome_bar_title"
+                          style="@style/AddressBar.Button"
+                          android:layout_width="fill_parent"
+                          android:layout_height="fill_parent"
+                          android:layout_weight="1.0"
+                          android:singleLine="true"
+                          android:paddingRight="8dp"
+                          android:textColor="#222222"
+                          android:gravity="center_vertical|left"
+                          android:hint="@string/awesomebar_default_text"
+                          android:layout_gravity="center_vertical"/>
 
-            <ImageButton android:id="@+id/stop"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="10dip"
-                         android:src="@drawable/urlbar_stop"
-                         android:contentDescription="@string/stop"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/reader"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/reader"
+                             android:contentDescription="@string/reader_mode"
+                             android:visibility="gone"/>
 
-        </LinearLayout>
+                <ImageButton android:id="@+id/stop"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/urlbar_stop"
+                             android:contentDescription="@string/stop"
+                             android:visibility="gone"/>
+
+            </LinearLayout>
+
+        </FrameLayout>
 
          <ImageView android:id="@+id/shadow"
                     android:layout_width="fill_parent"
                     android:layout_height="2dp"
                     android:layout_alignParentBottom="true"
                     android:background="@drawable/address_bar_bg_shadow_repeat"
                     android:visibility="gone"/>
 
--- a/mobile/android/base/resources/layout-land-v14/browser_toolbar_menu.xml
+++ b/mobile/android/base/resources/layout-land-v14/browser_toolbar_menu.xml
@@ -62,71 +62,80 @@
         <TextSwitcher android:id="@+id/tabs_count"
                      style="@style/AddressBar.ImageButton"
                      android:layout_width="80dip"
                      android:layout_height="wrap_content"
                      android:layout_marginTop="4.5dp"
                      android:layout_alignRight="@id/tabs"
                      android:gravity="center_horizontal"/>
         
-        <Button android:id="@+id/awesome_bar"
-                style="@style/AddressBar.Button"
-                android:layout_width="fill_parent"
-                android:layout_marginTop="3dp"
-                android:layout_marginBottom="3dp"
-                android:layout_marginLeft="4dp"
-                android:layout_marginRight="80dp"
-                android:layout_alignParentLeft="true"
-                android:layout_alignParentBottom="true"
-                android:layout_centerVertical="true"
-                android:background="@drawable/address_bar_url"
-                android:singleLine="true"
-                android:gravity="center_vertical|left"
-                android:hint="@string/awesomebar_default_text"
-                android:textColor="#222222"
-                android:paddingLeft="35dip"
-                android:paddingRight="7dip"/>
+        <FrameLayout style="@style/AddressBar.Button"
+                     android:layout_marginTop="3dp"
+                     android:layout_marginBottom="3dp"
+                     android:layout_marginLeft="4dp"
+                     android:layout_marginRight="80dp"
+                     android:layout_alignParentLeft="true"
+                     android:layout_alignParentBottom="true"
+                     android:layout_centerVertical="true">
+
+            <Button android:id="@+id/awesome_bar"
+                    style="@style/AddressBar.Button"
+                    android:background="@drawable/address_bar_url"/>
 
-        <ImageButton android:id="@+id/favicon"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="21.33dip"
-                     android:layout_height="21.33dip"
-                     android:layout_marginLeft="7dip"
-                     android:layout_centerVertical="true"
-                     android:src="@drawable/favicon"
-                     android:layout_alignLeft="@id/awesome_bar"/>
+            <LinearLayout style="@style/AddressBar.Button"
+                          android:orientation="horizontal">
+
+                <ImageButton android:id="@+id/favicon"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="29.33dip"
+                             android:layout_height="fill_parent"
+                             android:scaleType="fitCenter"
+                             android:paddingLeft="8dip"
+                             android:layout_marginRight="4dip"
+                             android:layout_gravity="center_vertical"
+                             android:src="@drawable/favicon"/>
 
-        <LinearLayout android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:layout_centerVertical="true"
-                      android:layout_alignRight="@id/awesome_bar"
-                      android:orientation="horizontal">
-
-            <ImageButton android:id="@+id/reader"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="10dip"
-                         android:src="@drawable/reader"
-                         android:contentDescription="@string/reader_mode"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/site_security"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="@dimen/browser_toolbar_lock_width"
+                             android:scaleType="fitCenter"
+                             android:layout_marginLeft="-4dip"
+                             android:paddingLeft="1dp"
+                             android:paddingRight="1dp"
+                             android:src="@drawable/site_security_level"
+                             android:contentDescription="@string/site_security"
+                             android:visibility="gone"/>
 
-            <ImageButton android:id="@+id/site_security"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="10dip"
-                         android:src="@drawable/site_security_level"
-                         android:contentDescription="@string/site_security"
-                         android:visibility="gone"/>
+                <TextView android:id="@+id/awesome_bar_title"
+                          style="@style/AddressBar.ImageButton"
+                          android:layout_width="fill_parent"
+                          android:layout_height="fill_parent"
+                          android:layout_weight="1.0"
+                          android:singleLine="true"
+                          android:paddingRight="8dp"
+                          android:textColor="#222222"
+                          android:gravity="center_vertical|left"
+                          android:hint="@string/awesomebar_default_text"
+                          android:layout_gravity="center_vertical"/>
 
-            <ImageButton android:id="@+id/stop"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="10dip"
-                         android:src="@drawable/urlbar_stop"
-                         android:contentDescription="@string/stop"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/reader"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/reader"
+                             android:contentDescription="@string/reader_mode"
+                             android:visibility="gone"/>
 
-        </LinearLayout>
+                <ImageButton android:id="@+id/stop"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/urlbar_stop"
+                             android:contentDescription="@string/stop"
+                             android:visibility="gone"/>
+
+            </LinearLayout>
+
+        </FrameLayout>
 
          <ImageView android:id="@+id/shadow"
                     android:layout_width="fill_parent"
                     android:layout_height="2dp"
                     android:layout_alignParentBottom="true"
                     android:background="@drawable/address_bar_bg_shadow_repeat"
                     android:visibility="gone"/>
 
--- a/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml
+++ b/mobile/android/base/resources/layout-large-v11/browser_toolbar_menu.xml
@@ -56,99 +56,105 @@
                      android:gravity="center_horizontal"/>
 
         <LinearLayout android:id="@+id/menu_items"
                       android:layout_width="wrap_content"
                       android:layout_height="fill_parent"
                       android:orientation="horizontal"
                       android:layout_marginRight="110dip"
                       android:layout_alignParentRight="true"/>
-        
-        <Button android:id="@+id/awesome_bar"
-                style="@style/AddressBar.Button"
-                android:layout_width="fill_parent"
-                android:layout_marginLeft="26dp"
-                android:layout_marginTop="6dp"
-                android:layout_marginBottom="6dp"
-                android:layout_marginRight="0dp"
-                android:layout_toLeftOf="@id/menu_items"
-                android:layout_alignParentLeft="true"
-                android:layout_alignParentBottom="true"
-                android:layout_centerVertical="true"
-                android:background="@drawable/address_bar_url"
-                android:singleLine="true"
-                android:gravity="center_vertical|left"
-                android:hint="@string/awesomebar_default_text"
-                android:textColor="#222222"
-                android:paddingLeft="105dip"
-                android:paddingRight="10dip"/>
+
+        <FrameLayout style="@style/AddressBar.Button"
+                     android:layout_toLeftOf="@id/menu_items"
+                     android:layout_alignParentLeft="true"
+                     android:layout_alignParentBottom="true"
+                     android:layout_centerVertical="true">
+
+            <Button android:id="@+id/awesome_bar"
+                    style="@style/AddressBar.Button"
+                    android:layout_marginLeft="20dp"
+                    android:layout_marginTop="6dp"
+                    android:layout_marginBottom="6dp"
+                    android:layout_marginRight="0dp"
+                    android:background="@drawable/address_bar_url"/>
 
-        <ImageButton android:id="@+id/forward"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="64dip"
-                     android:layout_height="40dip"
-                     android:layout_centerVertical="true"
-                     android:layout_alignLeft="@id/awesome_bar"
-                     android:paddingLeft="26dp"
-                     android:src="@drawable/ic_menu_forward"
-                     android:contentDescription="@string/forward"
-                     android:background="@drawable/address_bar_forward_button"/>
+            <ImageButton android:id="@+id/forward"
+                         style="@style/AddressBar.ImageButton"
+                         android:layout_width="64dip"
+                         android:layout_height="40dip"
+                         android:layout_marginLeft="26dp"
+                         android:paddingLeft="26dp"
+                         android:layout_gravity="center_vertical"
+                         android:src="@drawable/ic_menu_forward"
+                         android:contentDescription="@string/forward"
+                         android:background="@drawable/address_bar_forward_button"/>
 
-        <ImageButton android:id="@+id/back"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="50dip"
-                     android:layout_height="50dip"
-                     android:layout_marginLeft="6dp"
-                     android:layout_centerVertical="true"
-                     android:layout_alignParentLeft="true"
-                     android:src="@drawable/ic_menu_back"
-                     android:contentDescription="@string/back"
-                     android:background="@drawable/address_bar_back_button"/>
+            <ImageButton android:id="@+id/back"
+                         style="@style/AddressBar.ImageButton"
+                         android:layout_width="50dip"
+                         android:layout_height="50dip"
+                         android:layout_marginLeft="6dp"
+                         android:layout_gravity="center_vertical"
+                         android:src="@drawable/ic_menu_back"
+                         android:contentDescription="@string/back"
+                         android:background="@drawable/address_bar_back_button"/>
+
+            <LinearLayout style="@style/AddressBar.Button"
+                          android:layout_marginLeft="90dp"
+                          android:layout_marginTop="6dp"
+                          android:layout_marginBottom="6dp"
+                          android:layout_marginRight="0dp"
+                          android:orientation="horizontal">
 
-        <ImageButton android:id="@+id/favicon"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="21.33dip"
-                     android:layout_height="21.33dip"
-                     android:layout_marginLeft="10dip"
-                     android:layout_centerVertical="true"
-                     android:src="@drawable/favicon"
-                     android:layout_toRightOf="@id/forward"/>
+                <ImageButton android:id="@+id/favicon"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="29.33dip"
+                             android:layout_height="fill_parent"
+                             android:scaleType="fitCenter"
+                             android:paddingLeft="8dip"
+                             android:layout_marginRight="4dip"
+                             android:layout_gravity="center_vertical"
+                             android:src="@drawable/favicon"/>
 
-        <LinearLayout android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:layout_marginRight="10dip"
-                      android:layout_centerVertical="true"
-                      android:layout_alignRight="@id/awesome_bar"
-                      android:orientation="horizontal">
+                <ImageButton android:id="@+id/site_security"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="@dimen/browser_toolbar_lock_width"
+                             android:scaleType="fitCenter"
+                             android:layout_marginLeft="-4dip"
+                             android:src="@drawable/site_security_level"
+                             android:contentDescription="@string/site_security"
+                             android:visibility="gone"/>
 
-            <ImageButton android:id="@+id/reader"
-                         style="@style/AddressBar.ImageButton"
-                         android:layout_width="24dip"
-                         android:layout_height="24dip"
-                         android:src="@drawable/reader"
-                         android:contentDescription="@string/reader_mode"
-                         android:visibility="gone"/>
+                <TextView android:id="@+id/awesome_bar_title"
+                          style="@style/AddressBar.Button"
+                          android:layout_width="fill_parent"
+                          android:layout_height="fill_parent"
+                          android:layout_weight="1.0"
+                          android:singleLine="true"
+                          android:paddingRight="8dp"
+                          android:textColor="#222222"
+                          android:gravity="center_vertical|left"
+                          android:hint="@string/awesomebar_default_text"
+                          android:layout_gravity="center_vertical"/>
 
-            <ImageButton android:id="@+id/site_security"
-                         style="@style/AddressBar.ImageButton"
-                         android:layout_width="24dip"
-                         android:layout_height="24dip"
-                         android:src="@drawable/site_security_level"
-                         android:contentDescription="@string/site_security"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/reader"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/reader"
+                             android:contentDescription="@string/reader_mode"
+                             android:visibility="gone"/>
 
-            <ImageButton android:id="@+id/stop"
-                         style="@style/AddressBar.ImageButton"
-                         android:layout_width="24dip"
-                         android:layout_height="24dip"
-                         android:src="@drawable/urlbar_stop"
-                         android:contentDescription="@string/stop"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/stop"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/urlbar_stop"
+                             android:contentDescription="@string/stop"
+                             android:visibility="gone"/>
 
-        </LinearLayout>
+            </LinearLayout>
+
+        </FrameLayout>
 
          <ImageView android:id="@+id/shadow"
                     android:layout_width="fill_parent"
                     android:layout_height="2dp"
                     android:layout_alignParentBottom="true"
                     android:background="@drawable/address_bar_bg_shadow_repeat"
                     android:visibility="gone"/>
 
--- a/mobile/android/base/resources/layout-large-v11/site_identity_popup.xml
+++ b/mobile/android/base/resources/layout-large-v11/site_identity_popup.xml
@@ -4,17 +4,17 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content">
 
     <RelativeLayout android:layout_width="@dimen/site_identity_popup_width"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="24dip"
+                    android:layout_marginTop="15dip"
                     android:layout_alignParentTop="true"
                     android:background="@drawable/doorhanger_popup_bg">
 
       <LinearLayout android:id="@+id/identity_info"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
                     android:padding="12dip"
                     android:background="@drawable/doorhanger_bg"
@@ -72,14 +72,13 @@
                 android:textAppearance="?android:attr/textAppearanceSmall"
                 android:textColor="?android:attr/textColorPrimary"/>
 
     </RelativeLayout>
 
     <ImageView android:id="@+id/arrow"
                android:layout_width="@dimen/doorhanger_arrow_width"
                android:layout_height="16dip"
-               android:layout_marginTop="9dip"
                android:layout_alignParentTop="true"
                android:src="@drawable/doorhanger_arrow"
                android:scaleType="fitXY"/>
 
 </RelativeLayout>
--- a/mobile/android/base/resources/layout-xlarge-v11/browser_toolbar_menu.xml
+++ b/mobile/android/base/resources/layout-xlarge-v11/browser_toolbar_menu.xml
@@ -41,99 +41,105 @@
                      android:paddingRight="14dip"
                      android:visibility="gone"/>
 
         <LinearLayout android:id="@+id/menu_items"
                       android:layout_width="wrap_content"
                       android:layout_height="fill_parent"
                       android:orientation="horizontal"
                       android:layout_toLeftOf="@id/menu"/>
-        
-        <Button android:id="@+id/awesome_bar"
-                style="@style/AddressBar.Button"
-                android:layout_width="fill_parent"
-                android:layout_marginLeft="0dp"
-                android:layout_marginTop="6dp"
-                android:layout_marginBottom="6dp"
-                android:layout_marginRight="6dp"
-                android:layout_toRightOf="@id/tabs"
-                android:layout_toLeftOf="@id/menu_items"
-                android:layout_alignParentBottom="true"
-                android:layout_centerVertical="true"
-                android:background="@drawable/address_bar_url"
-                android:singleLine="true"
-                android:gravity="center_vertical|left"
-                android:hint="@string/awesomebar_default_text"
-                android:textColor="#222222"
-                android:paddingLeft="105dip"
-                android:paddingRight="10dip"/>
+
+        <FrameLayout style="@style/AddressBar.Button"
+                     android:layout_toRightOf="@id/tabs"
+                     android:layout_toLeftOf="@id/menu_items"
+                     android:layout_marginLeft="-28dp"
+                     android:layout_alignParentBottom="true"
+                     android:layout_centerVertical="true">
+
+            <Button android:id="@+id/awesome_bar"
+                    style="@style/AddressBar.Button"
+                    android:layout_marginLeft="26dp"
+                    android:layout_marginTop="6dp"
+                    android:layout_marginBottom="6dp"
+                    android:layout_marginRight="0dp"
+                    android:background="@drawable/address_bar_url"/>
 
-        <ImageButton android:id="@+id/forward"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="64dip"
-                     android:layout_height="40dip"
-                     android:layout_centerVertical="true"
-                     android:layout_alignLeft="@id/awesome_bar"
-                     android:paddingLeft="22dp"
-                     android:src="@drawable/ic_menu_forward"
-                     android:contentDescription="@string/forward"
-                     android:background="@drawable/address_bar_forward_button"/>
+            <ImageButton android:id="@+id/forward"
+                         style="@style/AddressBar.ImageButton"
+                         android:layout_width="64dip"
+                         android:layout_height="40dip"
+                         android:layout_marginLeft="22dp"
+                         android:paddingLeft="22dp"
+                         android:layout_gravity="center_vertical"
+                         android:src="@drawable/ic_menu_forward"
+                         android:contentDescription="@string/forward"
+                         android:background="@drawable/address_bar_forward_button"/>
 
-        <ImageButton android:id="@+id/back"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="50dip"
-                     android:layout_height="50dip"
-                     android:layout_centerVertical="true"
-                     android:layout_marginLeft="-28dp"
-                     android:layout_alignLeft="@id/awesome_bar"
-                     android:src="@drawable/ic_menu_back"
-                     android:contentDescription="@string/back"
-                     android:background="@drawable/address_bar_back_button"/>
+            <ImageButton android:id="@+id/back"
+                         style="@style/AddressBar.ImageButton"
+                         android:layout_width="50dip"
+                         android:layout_height="50dip"
+                         android:layout_gravity="center_vertical"
+                         android:src="@drawable/ic_menu_back"
+                         android:contentDescription="@string/back"
+                         android:background="@drawable/address_bar_back_button"/>
+
+            <LinearLayout style="@style/AddressBar.Button"
+                          android:layout_marginLeft="84dp"
+                          android:layout_marginTop="6dp"
+                          android:layout_marginBottom="6dp"
+                          android:layout_marginRight="0dp"
+                          android:orientation="horizontal">
 
-        <ImageButton android:id="@+id/favicon"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="21.33dip"
-                     android:layout_height="21.33dip"
-                     android:layout_marginLeft="10dip"
-                     android:layout_centerVertical="true"
-                     android:src="@drawable/favicon"
-                     android:layout_toRightOf="@id/forward"/>
+                <ImageButton android:id="@+id/favicon"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="29.33dip"
+                             android:layout_height="fill_parent"
+                             android:scaleType="fitCenter"
+                             android:paddingLeft="8dip"
+                             android:layout_marginRight="4dip"
+                             android:layout_gravity="center_vertical"
+                             android:src="@drawable/favicon"/>
 
-        <LinearLayout android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:layout_marginRight="10dip"
-                      android:layout_centerVertical="true"
-                      android:layout_alignRight="@id/awesome_bar"
-                      android:orientation="horizontal">
+                <ImageButton android:id="@+id/site_security"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="@dimen/browser_toolbar_lock_width"
+                             android:scaleType="fitCenter"
+                             android:layout_marginLeft="-4dip"
+                             android:src="@drawable/site_security_level"
+                             android:contentDescription="@string/site_security"
+                             android:visibility="gone"/>
 
-            <ImageButton android:id="@+id/reader"
-                         style="@style/AddressBar.ImageButton"
-                         android:layout_width="24dip"
-                         android:layout_height="24dip"
-                         android:src="@drawable/reader"
-                         android:contentDescription="@string/reader_mode"
-                         android:visibility="gone"/>
+                <TextView android:id="@+id/awesome_bar_title"
+                          style="@style/AddressBar.Button"
+                          android:layout_width="fill_parent"
+                          android:layout_height="fill_parent"
+                          android:layout_weight="1.0"
+                          android:singleLine="true"
+                          android:paddingRight="8dp"
+                          android:textColor="#222222"
+                          android:gravity="center_vertical|left"
+                          android:hint="@string/awesomebar_default_text"
+                          android:layout_gravity="center_vertical"/>
 
-            <ImageButton android:id="@+id/site_security"
-                         style="@style/AddressBar.ImageButton"
-                         android:layout_width="24dip"
-                         android:layout_height="24dip"
-                         android:src="@drawable/site_security_level"
-                         android:contentDescription="@string/site_security"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/reader"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/reader"
+                             android:contentDescription="@string/reader_mode"
+                             android:visibility="gone"/>
 
-            <ImageButton android:id="@+id/stop"
-                         style="@style/AddressBar.ImageButton"
-                         android:layout_width="24dip"
-                         android:layout_height="24dip"
-                         android:src="@drawable/urlbar_stop"
-                         android:contentDescription="@string/stop"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/stop"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/urlbar_stop"
+                             android:contentDescription="@string/stop"
+                             android:visibility="gone"/>
 
-        </LinearLayout>
+            </LinearLayout>
+
+        </FrameLayout>
 
          <ImageView android:id="@+id/shadow"
                     android:layout_width="fill_parent"
                     android:layout_height="2dp"
                     android:layout_alignParentBottom="true"
                     android:background="@drawable/address_bar_bg_shadow_repeat"
                     android:visibility="gone"/>
 
--- a/mobile/android/base/resources/layout/browser_toolbar.xml
+++ b/mobile/android/base/resources/layout/browser_toolbar.xml
@@ -51,72 +51,79 @@
 
         <TextSwitcher android:id="@+id/tabs_count"
                      style="@style/AddressBar.ImageButton"
                      android:layout_width="44.5dip"
                      android:layout_height="wrap_content"
                      android:layout_marginTop="5dp"
                      android:layout_alignRight="@id/tabs"
                      android:gravity="center_horizontal"/>
-        
-        <Button android:id="@+id/awesome_bar"
-                style="@style/AddressBar.Button"
-                android:layout_width="fill_parent"
-                android:layout_marginTop="4dp"
-                android:layout_marginBottom="4dp"
-                android:layout_marginLeft="4dp"
-                android:layout_marginRight="52dp"
-                android:layout_alignParentLeft="true"
-                android:layout_alignParentBottom="true"
-                android:layout_centerVertical="true"
-                android:background="@drawable/address_bar_url"
-                android:singleLine="true"
-                android:gravity="center_vertical|left"
-                android:hint="@string/awesomebar_default_text"
-                android:textColor="#222222"
-                android:paddingLeft="41dip"
-                android:paddingRight="10dip"/>
+
+        <FrameLayout style="@style/AddressBar.Button"
+                     android:layout_marginTop="4dp"
+                     android:layout_marginBottom="4dp"
+                     android:layout_marginLeft="4dp"
+                     android:layout_marginRight="52dp"
+                     android:layout_alignParentLeft="true"
+                     android:layout_alignParentBottom="true"
+                     android:layout_centerVertical="true">
 
-        <ImageButton android:id="@+id/favicon"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="21.33dip"
-                     android:layout_height="21.33dip"
-                     android:layout_marginLeft="10dip"
-                     android:layout_centerVertical="true"
-                     android:src="@drawable/favicon"
-                     android:layout_alignLeft="@id/awesome_bar"/>
+            <Button android:id="@+id/awesome_bar"
+                    style="@style/AddressBar.Button"
+                    android:background="@drawable/address_bar_url"/>
+
+            <LinearLayout style="@style/AddressBar.Button"
+                          android:orientation="horizontal">
+
+                <ImageButton android:id="@+id/favicon"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="29.33dip"
+                             android:layout_height="fill_parent"
+                             android:scaleType="fitCenter"
+                             android:paddingLeft="8dip"
+                             android:layout_marginRight="4dip"
+                             android:layout_gravity="center_vertical"
+                             android:src="@drawable/favicon"/>
 
-        <LinearLayout android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:layout_centerVertical="true"
-                      android:layout_alignRight="@id/awesome_bar"
-                      android:orientation="horizontal">
-
-            <ImageButton android:id="@+id/reader"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="12dip"
-                         android:src="@drawable/reader"
-                         android:contentDescription="@string/reader_mode"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/site_security"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="@dimen/browser_toolbar_lock_width"
+                             android:scaleType="fitCenter"
+                             android:layout_marginLeft="-4dip"
+                             android:src="@drawable/site_security_level"
+                             android:contentDescription="@string/site_security"
+                             android:visibility="gone"/>
 
-            <ImageButton android:id="@+id/site_security"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="12dip"
-                         android:src="@drawable/site_security_level"
-                         android:contentDescription="@string/site_security"
-                         android:visibility="gone"/>
+                <TextView android:id="@+id/awesome_bar_title"
+                          style="@style/AddressBar.Button"
+                          android:layout_width="fill_parent"
+                          android:layout_height="fill_parent"
+                          android:layout_weight="1.0"
+                          android:singleLine="true"
+                          android:paddingRight="8dp"
+                          android:textColor="#222222"
+                          android:gravity="center_vertical|left"
+                          android:hint="@string/awesomebar_default_text"
+                          android:layout_gravity="center_vertical"/>
 
-            <ImageButton android:id="@+id/stop"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="12dip"
-                         android:src="@drawable/urlbar_stop"
-                         android:contentDescription="@string/stop"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/reader"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/reader"
+                             android:contentDescription="@string/reader_mode"
+                             android:visibility="gone"/>
 
-        </LinearLayout>
+                <ImageButton android:id="@+id/stop"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/urlbar_stop"
+                             android:contentDescription="@string/stop"
+                             android:visibility="gone"/>
+
+            </LinearLayout>
+
+        </FrameLayout>
 
          <ImageView android:id="@+id/shadow"
                     android:layout_width="fill_parent"
                     android:layout_height="2dp"
                     android:layout_alignParentBottom="true"
                     android:background="@drawable/address_bar_bg_shadow_repeat"
                     android:visibility="gone"/>
 
--- a/mobile/android/base/resources/layout/browser_toolbar_menu.xml
+++ b/mobile/android/base/resources/layout/browser_toolbar_menu.xml
@@ -62,72 +62,79 @@
 
         <TextSwitcher android:id="@+id/tabs_count"
                      style="@style/AddressBar.ImageButton"
                      android:layout_width="98dip"
                      android:layout_height="wrap_content"
                      android:layout_marginTop="5dp"
                      android:layout_alignRight="@id/tabs"
                      android:gravity="center_horizontal"/>
-        
-        <Button android:id="@+id/awesome_bar"
-                style="@style/AddressBar.Button"
-                android:layout_width="fill_parent"
-                android:layout_marginTop="4dp"
-                android:layout_marginBottom="4dp"
-                android:layout_marginLeft="4dp"
-                android:layout_marginRight="100dp"
-                android:layout_alignParentLeft="true"
-                android:layout_alignParentBottom="true"
-                android:layout_centerVertical="true"
-                android:background="@drawable/address_bar_url"
-                android:singleLine="true"
-                android:gravity="center_vertical|left"
-                android:hint="@string/awesomebar_default_text"
-                android:textColor="#222222"
-                android:paddingLeft="41dip"
-                android:paddingRight="10dip"/>
+
+        <FrameLayout style="@style/AddressBar.Button"
+                     android:layout_marginTop="4dp"
+                     android:layout_marginBottom="4dp"
+                     android:layout_marginLeft="4dp"
+                     android:layout_marginRight="100dp"
+                     android:layout_alignParentLeft="true"
+                     android:layout_alignParentBottom="true"
+                     android:layout_centerVertical="true">
 
-        <ImageButton android:id="@+id/favicon"
-                     style="@style/AddressBar.ImageButton"
-                     android:layout_width="21.33dip"
-                     android:layout_height="21.33dip"
-                     android:layout_marginLeft="10dip"
-                     android:layout_centerVertical="true"
-                     android:src="@drawable/favicon"
-                     android:layout_alignLeft="@id/awesome_bar"/>
+            <Button android:id="@+id/awesome_bar"
+                    style="@style/AddressBar.Button"
+                    android:background="@drawable/address_bar_url"/>
+
+            <LinearLayout style="@style/AddressBar.Button"
+                          android:orientation="horizontal">
+
+                <ImageButton android:id="@+id/favicon"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="29.33dip"
+                             android:layout_height="fill_parent"
+                             android:scaleType="fitCenter"
+                             android:paddingLeft="8dip"
+                             android:layout_marginRight="4dip"
+                             android:layout_gravity="center_vertical"
+                             android:src="@drawable/favicon"/>
 
-        <LinearLayout android:layout_width="wrap_content"
-                      android:layout_height="wrap_content"
-                      android:layout_centerVertical="true"
-                      android:layout_alignRight="@id/awesome_bar"
-                      android:orientation="horizontal">
-
-            <ImageButton android:id="@+id/reader"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="12dip"
-                         android:src="@drawable/reader"
-                         android:contentDescription="@string/reader_mode"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/site_security"
+                             style="@style/AddressBar.ImageButton"
+                             android:layout_width="@dimen/browser_toolbar_lock_width"
+                             android:scaleType="fitCenter"
+                             android:layout_marginLeft="-4dip"
+                             android:src="@drawable/site_security_level"
+                             android:contentDescription="@string/site_security"
+                             android:visibility="gone"/>
 
-            <ImageButton android:id="@+id/site_security"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="12dip"
-                         android:src="@drawable/site_security_level"
-                         android:contentDescription="@string/site_security"
-                         android:visibility="gone"/>
+                <TextView android:id="@+id/awesome_bar_title"
+                          style="@style/AddressBar.Button"
+                          android:layout_width="fill_parent"
+                          android:layout_height="fill_parent"
+                          android:layout_weight="1.0"
+                          android:singleLine="true"
+                          android:paddingRight="8dp"
+                          android:textColor="#222222"
+                          android:gravity="center_vertical|left"
+                          android:hint="@string/awesomebar_default_text"
+                          android:layout_gravity="center_vertical"/>
 
-            <ImageButton android:id="@+id/stop"
-                         style="@style/AddressBar.ImageButton.Icon"
-                         android:padding="12dip"
-                         android:src="@drawable/urlbar_stop"
-                         android:contentDescription="@string/stop"
-                         android:visibility="gone"/>
+                <ImageButton android:id="@+id/reader"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/reader"
+                             android:contentDescription="@string/reader_mode"
+                             android:visibility="gone"/>
 
-        </LinearLayout>
+                <ImageButton android:id="@+id/stop"
+                             style="@style/AddressBar.ImageButton.Icon"
+                             android:src="@drawable/urlbar_stop"
+                             android:contentDescription="@string/stop"
+                             android:visibility="gone"/>
+
+            </LinearLayout>
+
+        </FrameLayout>
 
          <ImageView android:id="@+id/shadow"
                     android:layout_width="fill_parent"
                     android:layout_height="2dp"
                     android:layout_alignParentBottom="true"
                     android:background="@drawable/address_bar_bg_shadow_repeat"
                     android:visibility="gone"/>
 
--- a/mobile/android/base/resources/layout/site_identity_popup.xml
+++ b/mobile/android/base/resources/layout/site_identity_popup.xml
@@ -4,17 +4,17 @@
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="fill_parent"
                 android:layout_height="wrap_content">
 
     <RelativeLayout android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="24dip"
+                    android:layout_marginTop="15dip"
                     android:layout_alignParentTop="true"
                     android:background="@drawable/doorhanger_popup_bg">
 
       <LinearLayout android:id="@+id/identity_info"
                     android:layout_width="fill_parent"
                     android:layout_height="wrap_content"
                     android:padding="12dip"
                     android:background="@drawable/doorhanger_bg"
@@ -72,14 +72,13 @@
                 android:textAppearance="?android:attr/textAppearanceSmall"
                 android:textColor="?android:attr/textColorPrimary"/>
 
     </RelativeLayout>
 
     <ImageView android:id="@+id/arrow"
                android:layout_width="@dimen/doorhanger_arrow_width"
                android:layout_height="16dip"
-               android:layout_marginTop="9dip"
                android:layout_alignParentTop="true"
                android:src="@drawable/doorhanger_arrow"
                android:scaleType="fitXY"/>
 
 </RelativeLayout>
--- a/mobile/android/base/resources/values-land-v14/dimens.xml
+++ b/mobile/android/base/resources/values-land-v14/dimens.xml
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <resources>
 
     <dimen name="browser_toolbar_height">40dp</dimen>
+    <dimen name="browser_toolbar_icon_width">46dp</dimen>
     <dimen name="tabs_counter_size">18sp</dimen>
 
 </resources>
--- a/mobile/android/base/resources/values-large-v11/dimens.xml
+++ b/mobile/android/base/resources/values-large-v11/dimens.xml
@@ -1,11 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- 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/. -->
 
 <resources>
 
     <dimen name="browser_toolbar_height">56dp</dimen>
+    <dimen name="browser_toolbar_icon_width">45dp</dimen>
     <dimen name="tabs_counter_size">26sp</dimen>
 
 </resources>
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -10,16 +10,18 @@
     <dimen name="abouthome_gutter_large">0dp</dimen>
     <dimen name="abouthome_icon_crop">-14dp</dimen>
     <dimen name="autocomplete_min_width">200dp</dimen>
     <dimen name="autocomplete_row_height">32dp</dimen>
     <dimen name="awesomebar_header_row_height">20dp</dimen>
     <dimen name="awesomebar_row_height">48dp</dimen>
     <dimen name="awesomebar_tab_transparency_height">38dp</dimen>
     <dimen name="browser_toolbar_height">48dp</dimen>
+    <dimen name="browser_toolbar_icon_width">36dp</dimen>
+    <dimen name="browser_toolbar_lock_width">21.33dp</dimen>
     <dimen name="doorhanger_arrow_width">44dp</dimen>
     <dimen name="flow_layout_spacing">6dp</dimen>
     <dimen name="local_tab_row_height">108dp</dimen>
     <dimen name="menu_item_row_height">44dp</dimen>
     <dimen name="menu_item_row_width">240dp</dimen>
     <dimen name="prompt_service_group_padding_size">32dp</dimen>
     <dimen name="prompt_service_icon_size">72dp</dimen>
     <dimen name="prompt_service_icon_text_padding">10dp</dimen>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -49,31 +49,33 @@
     <style name="AddressBar.Button">
         <item name="android:layout_height">fill_parent</item>
         <item name="android:textSize">16sp</item>
         <item name="android:background">@android:color/transparent</item>
     </style>
 
     <!-- Address bar - Image Button -->
     <style name="AddressBar.ImageButton" parent="AddressBar.Button">
-        <item name="android:scaleType">fitCenter</item>
+        <item name="android:scaleType">center</item>
+        <item name="android:layout_gravity">center_vertical</item>
         <item name="android:background">@android:color/transparent</item>
     </style>
 
     <!-- Address bar - Image Button - Unused -->
     <style name="AddressBar.ImageButton.Unused">
         <item name="android:layout_width">0dip</item>
         <item name="android:layout_height">0dip</item>
         <item name="android:visibility">gone</item>
     </style>
 
     <!-- Address bar - Image Button - Icon -->
     <style name="AddressBar.ImageButton.Icon">
-         <item name="android:layout_width">@dimen/browser_toolbar_height</item>
+         <item name="android:layout_width">@dimen/browser_toolbar_icon_width</item>
          <item name="android:layout_height">@dimen/browser_toolbar_height</item>
+         <item name="android:layout_weight">0.0</item>
     </style>
 
     <!-- AwesomeBar -->
     <style name="AwesomeBar">
         <item name="android:layout_width">fill_parent</item>
         <item name="android:layout_height">48dip</item>
         <item name="android:orientation">horizontal</item>
     </style>
--- a/mobile/android/base/tests/testAboutPage.java.in
+++ b/mobile/android/base/tests/testAboutPage.java.in
@@ -13,17 +13,17 @@ public class testAboutPage extends Pixel
 
     public void testAboutPage() {
         mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
 
         // Load the about: page
         String url = "about:";
         loadAndPaint(url);
 
-        Element awesomebar = mDriver.findElement(getActivity(), "awesome_bar");
+        Element awesomebar = mDriver.findElement(getActivity(), "awesome_bar_title");
         mAsserter.isnot(awesomebar, null, "Got the awesomebar");
         assertMatches(awesomebar.getText(), "About (Fennec|Nightly|Aurora|Firefox|Firefox Beta)", "page title match");
 
         // Open a new page to remove the about: page from the current tab
         url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
         loadUrl(url);
 
         // Use the menu to open the Settings
@@ -45,13 +45,13 @@ public class testAboutPage extends Pixel
         mSolo.waitForText("About (Fennec|Nightly|Aurora|Firefox|Firefox Beta)");
         mSolo.clickOnText("About (Fennec|Nightly|Aurora|Firefox|Firefox Beta)");
 
         // Wait for the new tab and page to load
         tabEventExpecter.blockForEvent();
         contentEventExpecter.blockForEvent();
 
         // Grab the title to make sure the about: page was loaded
-        awesomebar = mDriver.findElement(getActivity(), "awesome_bar");
+        awesomebar = mDriver.findElement(getActivity(), "awesome_bar_title");
         mAsserter.isnot(awesomebar, null, "Got the awesomebar");
         assertMatches(awesomebar.getText(), "About (Fennec|Nightly|Aurora|Firefox|Firefox Beta)", "page title match");
     }
 }
--- a/mobile/android/build.mk
+++ b/mobile/android/build.mk
@@ -18,20 +18,16 @@ endif
 include  $(topsrcdir)/toolkit/mozapps/installer/package-name.mk
 
 TIERS += app
 
 ifdef MOZ_EXTENSIONS
 tier_app_dirs += extensions
 endif
 
-ifdef MOZ_SERVICES_SYNC
-tier_app_dirs += services
-endif
-
 tier_app_dirs += \
   $(MOZ_BRANDING_DIRECTORY) \
   mobile/android \
   $(NULL)
 
 
 installer: 
 	@$(MAKE) -C mobile/android/installer installer
--- a/mobile/android/chrome/content/JSDOMParser.js
+++ b/mobile/android/chrome/content/JSDOMParser.js
@@ -318,16 +318,19 @@
     },
 
     replaceChild: function (newNode, oldNode) {
       let childNodes = this.childNodes;
       let childIndex = childNodes.indexOf(oldNode);
       if (childIndex == -1) {
         throw "replaceChild: node not found";
       } else {
+        if (newNode.parentNode)
+          newNode.parentNode.removeChild(newNode);
+
         childNodes[childIndex] = newNode;
         newNode.parentNode = this;
         oldNode.parentNode = null;
         return oldNode;
       }
     }
   };
 
--- a/mobile/android/chrome/content/Readability.js
+++ b/mobile/android/chrome/content/Readability.js
@@ -70,17 +70,17 @@ Readability.prototype = {
   // Defined up here so we don't instantiate them repeatedly in loops.
   REGEXPS: {
     unlikelyCandidates: /combx|comment|community|disqus|extra|foot|header|menu|remark|rss|shoutbox|sidebar|sponsor|ad-break|agegate|pagination|pager|popup|tweet|twitter/i,
     okMaybeItsACandidate: /and|article|body|column|main|shadow/i,
     positive: /article|body|content|entry|hentry|main|page|pagination|post|text|blog|story/i,
     negative: /hidden|combx|comment|com-|contact|foot|footer|footnote|masthead|media|meta|outbrain|promo|related|scroll|shoutbox|sidebar|sponsor|shopping|tags|tool|widget/i,
     extraneous: /print|archive|comment|discuss|e[\-]?mail|share|reply|all|login|sign|single|utility/i,
     byline: /byline|author|dateline|writtenby/i,
-    divToPElements: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul)/i,
+    divToPElements: /<(a|blockquote|dl|div|img|ol|p|pre|table|ul|select)/i,
     replaceFonts: /<(\/?)font[^>]*>/gi,
     trim: /^\s+|\s+$/g,
     normalize: /\s{2,}/g,
     killBreaks: /(<br\s*\/?>(\s|&nbsp;?)*){1,}/g,
     videos: /http:\/\/(www\.)?(youtube|vimeo)\.com/i,
     nextLink: /(next|weiter|continue|>([^\|]|$)|»([^\|]|$))/i,
     prevLink: /(prev|earl|old|new|<|«)/i
   },
@@ -293,17 +293,17 @@ Readability.prototype = {
   /**
    * Prepare the article node for display. Clean out any inline styles,
    * iframes, forms, strip extraneous <p> tags, etc.
    *
    * @param Element
    * @return void
    **/
   _prepArticle: function(articleContent) {
-    this._cleanStyles(this._doc, articleContent);
+    this._cleanStyles(articleContent);
     this._killBreaks(articleContent);
 
     // Clean out junk from the article content
     this._cleanConditionally(articleContent, "form");
     this._clean(articleContent, "object");
     this._clean(articleContent, "h1");
 
     // If there is only one h2, they are probably using it as a header
@@ -453,28 +453,39 @@ Readability.prototype = {
           }
         }
 
         if (node.tagName === "P" || node.tagName === "TD" || node.tagName === "PRE")
           nodesToScore[nodesToScore.length] = node;
 
         // Turn all divs that don't have children block level elements into p's
         if (node.tagName === "DIV") {
-          if (node.innerHTML.search(this.REGEXPS.divToPElements) === -1) {
-            let newNode = doc.createElement('p');
-            newNode.innerHTML = node.innerHTML;
-            node.parentNode.replaceChild(newNode, node);
+          // Sites like http://mobile.slate.com encloses each paragraph with a DIV
+          // element. DIVs with only a P element inside and no text content can be
+          // safely converted into plain P elements to avoid confusing the scoring
+          // algorithm with DIVs with are, in practice, paragraphs.
+          let pIndex = this._getSinglePIndexInsideDiv(node);
 
-            // Manually update allElements since it is not a live NodeList
-            newNode._index = nodeIndex;
-            allElements[nodeIndex] = newNode;
+          if (node.innerHTML.search(this.REGEXPS.divToPElements) === -1 || pIndex >= 0) {
+            let newNode;
+            if (pIndex >= 0) {
+              newNode = node.childNodes[pIndex];
+            } else {
+              newNode = doc.createElement('p');
+              newNode.innerHTML = node.innerHTML;
+
+              // Manually update allElements since it is not a live NodeList
+              newNode._index = nodeIndex;
+              allElements[nodeIndex] = newNode;
+
+              nodesToScore[nodesToScore.length] = newNode;
+            }
+
+            node.parentNode.replaceChild(newNode, node);
             purgeNode(node);
-
-            nodeIndex -= 1;
-            nodesToScore[nodesToScore.length] = node;
           } else {
             // EXPERIMENTAL
             for (let i = 0, il = node.childNodes.length; i < il; i += 1) {
               let childNode = node.childNodes[i];
               if (!childNode)
                 continue;
 
               if (childNode.nodeType === 3) { // Node.TEXT_NODE
@@ -705,16 +716,46 @@ Readability.prototype = {
       scripts[i].removeAttribute('src');
 
       if (scripts[i].parentNode)
           scripts[i].parentNode.removeChild(scripts[i]);
     }
   },
 
   /**
+   * Get child index of the only P element inside a DIV with no
+   * text content. Returns -1 if the DIV node contains non-empty
+   * text nodes or if it contains other element nodes.
+   *
+   * @param Element
+  **/
+  _getSinglePIndexInsideDiv: function(e) {
+    let childNodes = e.childNodes;
+    let pIndex = -1;
+
+    for (let i = childNodes.length; --i >= 0;) {
+      let node = childNodes[i];
+
+      if (node.nodeType === Node.ELEMENT_NODE) {
+        if (node.tagName !== "P")
+          return -1;
+
+        if (pIndex >= 0)
+          return -1;
+
+        pIndex = i;
+      } else if (node.nodeType == Node.TEXT_NODE && this._getInnerText(node, false)) {
+        return -1;
+      }
+    }
+
+    return pIndex;
+  },
+
+  /**
    * Get the inner text of a node - cross browser compatibly.
    * This also strips out any excess whitespace to be found.
    *
    * @param Element
    * @return string
   **/
   _getInnerText: function(e, normalizeSpaces) {
     let textContent = e.textContent.replace(this.REGEXPS.trim, "");
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2182,16 +2182,17 @@ Tab.prototype = {
     this.browser.addEventListener("DOMContentLoaded", this, true);
     this.browser.addEventListener("DOMLinkAdded", this, true);
     this.browser.addEventListener("DOMTitleChanged", this, true);
     this.browser.addEventListener("DOMWindowClose", this, true);
     this.browser.addEventListener("DOMWillOpenModalDialog", this, true);
     this.browser.addEventListener("scroll", this, true);
     this.browser.addEventListener("MozScrolledAreaChanged", this, true);
     this.browser.addEventListener("PluginClickToPlay", this, true);
+    this.browser.addEventListener("PluginPlayPreview", this, true);
     this.browser.addEventListener("PluginNotFound", this, true);
     this.browser.addEventListener("pageshow", this, true);
 
     Services.obs.addObserver(this, "before-first-paint", false);
     Services.prefs.addObserver("browser.ui.zoom.force-user-scalable", this, false);
 
     if (!aParams.delayLoad) {
       let flags = "flags" in aParams ? aParams.flags : Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
@@ -2275,16 +2276,17 @@ Tab.prototype = {
     this.browser.removeProgressListener(this);
     this.browser.removeEventListener("DOMContentLoaded", this, true);
     this.browser.removeEventListener("DOMLinkAdded", this, true);
     this.browser.removeEventListener("DOMTitleChanged", this, true);
     this.browser.removeEventListener("DOMWindowClose", this, true);
     this.browser.removeEventListener("DOMWillOpenModalDialog", this, true);
     this.browser.removeEventListener("scroll", this, true);
     this.browser.removeEventListener("PluginClickToPlay", this, true);
+    this.browser.removeEventListener("PluginPlayPreview", this, true);
     this.browser.removeEventListener("PluginNotFound", this, true);
     this.browser.removeEventListener("MozScrolledAreaChanged", this, true);
 
     Services.obs.removeObserver(this, "before-first-paint");
     Services.prefs.removeObserver("browser.ui.zoom.force-user-scalable", this);
 
     // Make sure the previously selected panel remains selected. The selected panel of a deck is
     // not stable when panels are removed.
@@ -2837,16 +2839,62 @@ Tab.prototype = {
           tab.clickToPlayPluginsActivated = true;
           PluginHelper.playAllPlugins(win);
 
           NativeWindow.doorhanger.hide("ask-to-play-plugins", tab.id);
         }, true);
         break;
       }
 
+      case "PluginPlayPreview": {
+        let plugin = aEvent.target;
+
+        // Force a style flush, so that we ensure our binding is attached.
+        plugin.clientTop;
+
+        let doc = plugin.ownerDocument;
+        let previewContent = doc.getAnonymousElementByAttribute(plugin, "class", "previewPluginContent");
+        if (!previewContent) {
+          // If the plugin is hidden, fallback to click-to-play logic
+          PluginHelper.stopPlayPreview(plugin, false);
+          break;
+        }
+        let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
+        if (!iframe) {
+          // lazy initialization of the iframe
+          iframe = doc.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
+          iframe.className = "previewPluginContentFrame";
+          previewContent.appendChild(iframe);
+
+          // Force a style flush, so that we ensure our binding is attached.
+          plugin.clientTop;
+        }
+        let mimeType = PluginHelper.getPluginMimeType(plugin);
+        let playPreviewUri = "data:application/x-moz-playpreview;," + mimeType;
+        iframe.src = playPreviewUri;
+
+        // MozPlayPlugin event can be dispatched from the extension chrome
+        // code to replace the preview content with the native plugin
+        previewContent.addEventListener("MozPlayPlugin", function playPluginHandler(e) {
+          if (!e.isTrusted)
+            return;
+
+          previewContent.removeEventListener("MozPlayPlugin", playPluginHandler, true);
+
+          let playPlugin = !aEvent.detail;
+          PluginHelper.stopPlayPreview(plugin, playPlugin);
+
+          // cleaning up: removes overlay iframe from the DOM
+          let iframe = previewContent.getElementsByClassName("previewPluginContentFrame")[0];
+          if (iframe)
+            previewContent.removeChild(iframe);
+        }, true);
+        break;
+      }
+
       case "PluginNotFound": {
         let plugin = aEvent.target;
         plugin.clientTop; // force style flush
 
         // On devices where we don't support Flash, there will be a "Learn More..." link in
         // the missing plugin error message.
         let learnMoreLink = plugin.ownerDocument.getAnonymousElementByAttribute(plugin, "class", "unsupportedLearnMoreLink");
         if (learnMoreLink) {
@@ -5232,20 +5280,32 @@ var PluginHelper = {
     if (!plugins || !plugins.length)
       return;
 
     plugins.forEach(this.playPlugin);
   },
 
   playPlugin: function(plugin) {
     let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
-    if (!objLoadingContent.activated)
+    if (!objLoadingContent.activated &&
+        objLoadingContent.pluginFallbackType !== Ci.nsIObjectLoadingContent.PLUGIN_PLAY_PREVIEW)
       objLoadingContent.playPlugin();
   },
 
+  stopPlayPreview: function(plugin, playPlugin) {
+    let objLoadingContent = plugin.QueryInterface(Ci.nsIObjectLoadingContent);
+    if (objLoadingContent.activated)
+      return;
+
+    if (playPlugin)
+      objLoadingContent.playPlugin();
+    else
+      objLoadingContent.cancelPlayPreview();
+  },
+
   getPluginPreference: function getPluginPreference() {
     let pluginDisable = Services.prefs.getBoolPref("plugin.disable");
     if (pluginDisable)
       return "0";
 
     let clickToPlay = Services.prefs.getBoolPref("plugins.click_to_play");
     return clickToPlay ? "2" : "1";
   },
@@ -5272,16 +5332,32 @@ var PluginHelper = {
     // Is the <object>'s size too small to hold what we want to show?
     let pluginRect = plugin.getBoundingClientRect();
     // XXX bug 446693. The text-shadow on the submitted-report text at
     //     the bottom causes scrollHeight to be larger than it should be.
     let overflows = (overlay.scrollWidth > pluginRect.width) ||
                     (overlay.scrollHeight - 5 > pluginRect.height);
 
     return overflows;
+  },
+
+  getPluginMimeType: function (plugin) {
+    var tagMimetype;
+    if (plugin instanceof HTMLAppletElement) {
+      tagMimetype = "application/x-java-vm";
+    } else {
+      tagMimetype = plugin.QueryInterface(Components.interfaces.nsIObjectLoadingContent)
+                          .actualType;
+
+      if (tagMimetype == "") {
+        tagMimetype = plugin.type;
+      }
+    }
+
+    return tagMimetype;
   }
 };
 
 var PermissionsHelper = {
 
   _permissonTypes: ["password", "geolocation", "popup", "indexedDB",
                     "offline-app", "desktop-notification", "plugins"],
   _permissionStrings: {
--- a/mobile/android/confvars.sh
+++ b/mobile/android/confvars.sh
@@ -8,17 +8,16 @@ MOZ_APP_VENDOR=Mozilla
 MOZ_APP_VERSION=17.0a1
 MOZ_APP_UA_NAME=Firefox
 
 MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial
 MOZ_OFFICIAL_BRANDING_DIRECTORY=mobile/android/branding/official
 # MOZ_APP_DISPLAYNAME is set by branding/configure.sh
 
 MOZ_SAFE_BROWSING=
-MOZ_SERVICES_SYNC=
 
 MOZ_DISABLE_DOMCRYPTO=1
 
 # Enable getUserMedia
 MOZ_MEDIA_NAVIGATOR=1
 
 if test "$LIBXUL_SDK"; then
 MOZ_XULRUNNER=1
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -190,19 +190,16 @@
 #ifdef MOZ_ENABLE_PROFILER_SPS
 @BINPATH@/components/profiler.xpt
 #endif
 @BINPATH@/components/proxyObject.xpt
 @BINPATH@/components/rdf.xpt
 @BINPATH@/components/satchel.xpt
 @BINPATH@/components/saxparser.xpt
 @BINPATH@/components/sessionstore.xpt
-#ifdef MOZ_SERVICES_SYNC
-@BINPATH@/components/services-crypto.xpt
-#endif
 @BINPATH@/components/services-crypto-component.xpt
 @BINPATH@/components/shellservice.xpt
 @BINPATH@/components/shistory.xpt
 @BINPATH@/components/spellchecker.xpt
 @BINPATH@/components/storage.xpt
 @BINPATH@/components/telemetry.xpt
 @BINPATH@/components/toolkitprofile.xpt
 #ifdef MOZ_ENABLE_XREMOTE
@@ -334,22 +331,16 @@
 @BINPATH@/components/nsFilePicker.manifest
 #ifdef MOZ_ENABLE_DBUS
 @BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
 #endif
 @BINPATH@/components/nsINIProcessor.manifest
 @BINPATH@/components/nsINIProcessor.js
 @BINPATH@/components/nsPrompter.manifest
 @BINPATH@/components/nsPrompter.js
-#ifdef MOZ_SERVICES_SYNC
-@BINPATH@/components/SyncComponents.manifest
-@BINPATH@/components/Weave.js
-@BINPATH@/components/WeaveCrypto.manifest
-@BINPATH@/components/WeaveCrypto.js
-#endif
 @BINPATH@/components/TelemetryPing.js
 @BINPATH@/components/TelemetryPing.manifest
 @BINPATH@/components/Webapps.js
 @BINPATH@/components/Webapps.manifest
 @BINPATH@/components/AppsService.js
 @BINPATH@/components/AppsService.manifest
 
 @BINPATH@/components/TCPSocket.js
@@ -394,19 +385,16 @@
 @BINPATH@/icons/*.png
 #endif
 
 ; [Default Preferences]
 ; All the pref files must be part of base to prevent migration bugs
 @BINPATH@/@PREF_DIR@/mobile.js
 @BINPATH@/@PREF_DIR@/mobile-branding.js
 @BINPATH@/@PREF_DIR@/channel-prefs.js
-#ifdef MOZ_SERVICES_SYNC
-@BINPATH@/@PREF_DIR@/services-sync.js
-#endif
 @BINPATH@/greprefs.js
 @BINPATH@/defaults/autoconfig/platform.js
 @BINPATH@/defaults/autoconfig/prefcalls.js
 @BINPATH@/defaults/profile/prefs.js
 
 ; [Layout Engine Resources]
 ; Style Sheets, Graphics and other Resources used by the layout engine. 
 @BINPATH@/res/EditorOverride.css
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -165,16 +165,20 @@ pref("media.wave.enabled", true);
 #ifdef MOZ_WEBM
 pref("media.webm.enabled", true);
 #endif
 #ifdef MOZ_GSTREAMER
 pref("media.h264.enabled", true);
 #endif
 #ifdef MOZ_WEBRTC
 pref("media.navigator.enabled", false);
+#else
+#ifdef ANDROID
+pref("media.navigator.enabled", true);
+#endif
 #endif
 
 // Whether to autostart a media element with an |autoplay| attribute
 pref("media.autoplay.enabled", true);
 
 // 0 = Off, 1 = Full, 2 = Tagged Images Only. 
 // See eCMSMode in gfx/thebes/gfxPlatform.h
 pref("gfx.color_management.mode", 2);
@@ -693,17 +697,17 @@ pref("javascript.options.strict",       
 pref("javascript.options.strict.debug",     true);
 #endif
 pref("javascript.options.relimit",          true);
 pref("javascript.options.methodjit.content", true);
 pref("javascript.options.methodjit.chrome",  true);
 pref("javascript.options.pccounts.content", false);
 pref("javascript.options.pccounts.chrome",  false);
 pref("javascript.options.methodjit_always", false);
-pref("javascript.options.xml.content", true);
+pref("javascript.options.xml.content", false);
 pref("javascript.options.xml.chrome", true);
 pref("javascript.options.jit_hardening", true);
 pref("javascript.options.typeinference", true);
 // This preference limits the memory usage of javascript.
 // If you want to change these values for your device,
 // please find Bug 417052 comment 17 and Bug 456721
 // Comment 32 and Bug 613551.
 pref("javascript.options.mem.high_water_mark", 128);
new file mode 100644
--- /dev/null
+++ b/security/manager/boot/src/nsSTSPreloadList.inc
@@ -0,0 +1,135 @@
+/* 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 is an automatically generated file. If you're not                    */
+/* nsStrictTransportSecurityService.cpp, you shouldn't be #including it.     */
+/*****************************************************************************/
+
+#include <prtypes.h>
+
+class nsSTSPreload
+{
+  public:
+    const char *mHost;
+    const bool mIncludeSubdomains;
+};
+
+static const nsSTSPreload kSTSPreloadList[] = {
+  { "accounts.google.com", true },
+  { "aladdinschools.appspot.com", false },
+  { "alpha.irccloud.com", false },
+  { "api.recurly.com", true },
+  { "apis.google.com", true },
+  { "app.recurly.com", true },
+  { "appengine.google.com", false },
+  { "arivo.com.br", true },
+  { "betnet.fr", true },
+  { "bigshinylock.minazo.net", true },
+  { "blog.torproject.org", true },
+  { "braintreegateway.com", true },
+  { "braintreepayments.com", false },
+  { "browserid.org", true },
+  { "business.medbank.com.mt", true },
+  { "cert.se", true },
+  { "check.torproject.org", true },
+  { "checkout.google.com", true },
+  { "chrome.google.com", true },
+  { "chromiumcodereview.appspot.com", true },
+  { "cloudsecurityalliance.org", true },
+  { "codereview.appspot.com", true },
+  { "crate.io", true },
+  { "crypto.cat", true },
+  { "crypto.is", true },
+  { "developer.mydigipass.com", false },
+  { "docs.google.com", true },
+  { "download.jitsi.org", false },
+  { "drive.google.com", true },
+  { "dropcam.com", false },
+  { "ebanking.indovinabank.com.vn", true },
+  { "emailprivacytester.com", false },
+  { "encrypted.google.com", true },
+  { "entropia.de", false },
+  { "epoxate.com", false },
+  { "factor.cc", false },
+  { "gmail.com", false },
+  { "googlemail.com", false },
+  { "googleplex.com", true },
+  { "greplin.com", false },
+  { "grepular.com", true },
+  { "groups.google.com", true },
+  { "health.google.com", true },
+  { "hostedtalkgadget.google.com", true },
+  { "howrandom.org", true },
+  { "id.mayfirst.org", false },
+  { "irccloud.com", false },
+  { "jitsi.org", false },
+  { "jottit.com", true },
+  { "keyerror.com", true },
+  { "kyps.net", false },
+  { "lastpass.com", false },
+  { "ledgerscope.net", false },
+  { "linx.net", true },
+  { "lists.mayfirst.org", false },
+  { "logentries.com", false },
+  { "login.persona.org", true },
+  { "login.sapo.pt", true },
+  { "luneta.nearbuysystems.com", true },
+  { "mail.google.com", true },
+  { "market.android.com", true },
+  { "mattmccutchen.net", true },
+  { "members.mayfirst.org", false },
+  { "mydigipass.com", false },
+  { "neg9.org", false },
+  { "neonisi.com", false },
+  { "ottospora.nl", true },
+  { "passwd.io", true },
+  { "piratenlogin.de", true },
+  { "pixi.me", true },
+  { "plus.google.com", true },
+  { "profiles.google.com", true },
+  { "riseup.net", true },
+  { "romab.com", true },
+  { "sandbox.mydigipass.com", false },
+  { "script.google.com", true },
+  { "shops.neonisi.com", true },
+  { "simon.butcher.name", true },
+  { "sites.google.com", true },
+  { "sol.io", true },
+  { "spreadsheets.google.com", true },
+  { "squareup.com", false },
+  { "ssl.google-analytics.com", true },
+  { "stripe.com", true },
+  { "sunshinepress.org", true },
+  { "support.mayfirst.org", false },
+  { "talk.google.com", true },
+  { "talkgadget.google.com", true },
+  { "torproject.org", false },
+  { "ubertt.org", true },
+  { "uprotect.it", true },
+  { "www.apollo-auto.com", true },
+  { "www.braintreepayments.com", false },
+  { "www.cueup.com", true },
+  { "www.developer.mydigipass.com", false },
+  { "www.dropcam.com", false },
+  { "www.elanex.biz", false },
+  { "www.entropia.de", false },
+  { "www.gmail.com", false },
+  { "www.googlemail.com", false },
+  { "www.greplin.com", false },
+  { "www.irccloud.com", false },
+  { "www.jitsi.org", false },
+  { "www.kyps.net", false },
+  { "www.lastpass.com", false },
+  { "www.ledgerscope.net", false },
+  { "www.logentries.com", false },
+  { "www.moneybookers.com", true },
+  { "www.mydigipass.com", false },
+  { "www.neonisi.com", true },
+  { "www.noisebridge.net", false },
+  { "www.paycheckrecords.com", false },
+  { "www.paypal.com", false },
+  { "www.sandbox.mydigipass.com", false },
+  { "www.torproject.org", true },
+};
--- a/security/manager/boot/src/nsStrictTransportSecurityService.cpp
+++ b/security/manager/boot/src/nsStrictTransportSecurityService.cpp
@@ -12,64 +12,58 @@
 #include "nsISSLStatusProvider.h"
 #include "nsStrictTransportSecurityService.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsThreadUtils.h"
 #include "nsStringGlue.h"
 #include "nsIScriptSecurityManager.h"
 
+// A note about the preload list:
+// When a site specifically disables sts by sending a header with
+// 'max-age: 0', we keep a "knockout" value that means "we have no information
+// regarding the sts state of this host" (any ancestor of "this host" can still
+// influence its sts status via include subdomains, however).
+// This prevents the preload list from overriding the site's current
+// desired sts status. Knockout values are indicated by permission values of
+// STS_KNOCKOUT.
+#include "nsSTSPreloadList.inc"
+
+#define STS_SET (nsIPermissionManager::ALLOW_ACTION)
+#define STS_UNSET (nsIPermissionManager::UNKNOWN_ACTION)
+#define STS_KNOCKOUT (nsIPermissionManager::DENY_ACTION)
+
 #if defined(PR_LOGGING)
 PRLogModuleInfo *gSTSLog = PR_NewLogModule("nsSTSService");
 #endif
 
 #define STSLOG(args) PR_LOG(gSTSLog, 4, args)
 
 #define STS_PARSER_FAIL_IF(test,args) \
   if (test) { \
     STSLOG(args); \
     return NS_ERROR_FAILURE; \
   }
 
-namespace {
-
-/**
- * Returns a principal (aPrincipal) corresponding to aURI.
- * This is used to interact with the permission manager.
- */
-nsresult
-GetPrincipalForURI(nsIURI* aURI, nsIPrincipal** aPrincipal)
-{
-   // The permission manager wants a principal but don't actually check a
-   // permission but a data we saved in the permission manager so we are good by
-   // creating a no-app codebase principal and send it to the permission manager.
-   nsresult rv;
-   nsCOMPtr<nsIScriptSecurityManager> securityManager =
-      do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
-   NS_ENSURE_SUCCESS(rv, rv);
-
-   return securityManager->GetNoAppCodebasePrincipal(aURI, aPrincipal);
-}
-
-} // anonymous namespace
-
 ////////////////////////////////////////////////////////////////////////////////
 
 nsSTSHostEntry::nsSTSHostEntry(const char* aHost)
   : mHost(aHost)
   , mExpireTime(0)
-  , mDeleted(false)
+  , mExpired(false)
+  , mStsPermission(STS_UNSET)
   , mIncludeSubdomains(false)
 {
 }
 
 nsSTSHostEntry::nsSTSHostEntry(const nsSTSHostEntry& toCopy)
   : mHost(toCopy.mHost)
   , mExpireTime(toCopy.mExpireTime)
-  , mDeleted(toCopy.mDeleted)
+  , mExpired(toCopy.mExpired)
+  , mStsPermission(toCopy.mStsPermission)
   , mIncludeSubdomains(toCopy.mIncludeSubdomains)
 {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 
 nsStrictTransportSecurityService::nsStrictTransportSecurityService()
@@ -119,44 +113,68 @@ nsStrictTransportSecurityService::GetHos
 
   if (NS_FAILED(rv) || aResult.IsEmpty())
     return NS_ERROR_UNEXPECTED;
 
   return NS_OK;
 }
 
 nsresult
+nsStrictTransportSecurityService::GetPrincipalForURI(nsIURI* aURI,
+                                                     nsIPrincipal** aPrincipal)
+{
+  nsresult rv;
+  nsCOMPtr<nsIScriptSecurityManager> securityManager =
+     do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // We have to normalize the scheme of the URIs we're using, so just use https.
+  // HSTS information is shared across all ports for a given host.
+  nsCAutoString host;
+  rv = GetHost(aURI, host);
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIURI> uri;
+  rv = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("https://") + host);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // We want all apps to share HSTS state, so this is one of the few places
+  // where we do not silo persistent state by extended origin.
+  return securityManager->GetNoAppCodebasePrincipal(uri, aPrincipal);
+}
+
+nsresult
 nsStrictTransportSecurityService::SetStsState(nsIURI* aSourceURI,
                                               int64_t maxage,
                                               bool includeSubdomains)
 {
   // If max-age is zero, that's an indication to immediately remove the
   // permissions, so here's a shortcut.
   if (!maxage)
     return RemoveStsState(aSourceURI);
 
   // Expire time is millis from now.  Since STS max-age is in seconds, and
   // PR_Now() is in micros, must equalize the units at milliseconds.
-  int64_t expiretime = (PR_Now() / 1000) + (maxage * 1000);
+  int64_t expiretime = (PR_Now() / PR_USEC_PER_MSEC) +
+                       (maxage * PR_MSEC_PER_SEC);
 
   // record entry for this host with max-age in the permissions manager
   STSLOG(("STS: maxage permission SET, adding permission\n"));
   nsresult rv = AddPermission(aSourceURI,
                               STS_PERMISSION,
-                              (uint32_t) nsIPermissionManager::ALLOW_ACTION,
+                              (uint32_t) STS_SET,
                               (uint32_t) nsIPermissionManager::EXPIRE_TIME,
                               expiretime);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (includeSubdomains) {
     // record entry for this host with include subdomains in the permissions manager
     STSLOG(("STS: subdomains permission SET, adding permission\n"));
     rv = AddPermission(aSourceURI,
                        STS_SUBDOMAIN_PERMISSION,
-                       (uint32_t) nsIPermissionManager::ALLOW_ACTION,
+                       (uint32_t) STS_SET,
                        (uint32_t) nsIPermissionManager::EXPIRE_TIME,
                        expiretime);
     NS_ENSURE_SUCCESS(rv, rv);
   } else { // !includeSubdomains
     nsCAutoString hostname;
     rv = GetHost(aSourceURI, hostname);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -314,36 +332,171 @@ nsStrictTransportSecurityService::IsStsH
   nsCOMPtr<nsIURI> uri;
   nsDependentCString hostString(aHost);
   nsresult rv = NS_NewURI(getter_AddRefs(uri),
                           NS_LITERAL_CSTRING("https://") + hostString);
   NS_ENSURE_SUCCESS(rv, rv);
   return IsStsURI(uri, aResult);
 }
 
+int STSPreloadCompare(const void *key, const void *entry)
+{
+  const char *keyStr = (const char *)key;
+  const nsSTSPreload *preloadEntry = (const nsSTSPreload *)entry;
+  return strcmp(keyStr, preloadEntry->mHost);
+}
+
+// Returns the preload list entry for the given host, if it exists.
+// Only does exact host matching - the user must decide how to use the returned
+// data. May return null.
+const nsSTSPreload *
+nsStrictTransportSecurityService::GetPreloadListEntry(const char *aHost)
+{
+  return (const nsSTSPreload *) bsearch(aHost,
+                                        kSTSPreloadList,
+                                        PR_ARRAY_SIZE(kSTSPreloadList),
+                                        sizeof(nsSTSPreload),
+                                        STSPreloadCompare);
+}
+
 NS_IMETHODIMP
 nsStrictTransportSecurityService::IsStsURI(nsIURI* aURI, bool* aResult)
 {
   // Should be called on the main thread (or via proxy) since the permission
   // manager is used and it's not threadsafe.
   NS_ENSURE_TRUE(NS_IsMainThread(), NS_ERROR_UNEXPECTED);
 
-  nsresult rv;
-  uint32_t permExact, permGeneral;
-  // If this domain has the forcehttps permission, this is an STS host.
-  rv = TestPermission(aURI, STS_PERMISSION, &permExact, true);
+  // set default in case if we can't find any STS information
+  *aResult = false;
+
+  nsCAutoString host;
+  nsresult rv = GetHost(aURI, host);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  const nsSTSPreload *preload = nullptr;
+  nsSTSHostEntry *pbEntry = nullptr;
+
+  if (mInPrivateMode) {
+    pbEntry = mPrivateModeHostTable.GetEntry(host.get());
+  }
+
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = GetPrincipalForURI(aURI, getter_AddRefs(principal));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRUint32 permMgrPermission;
+  rv = mPermMgr->TestExactPermissionFromPrincipal(principal, STS_PERMISSION,
+                                                  &permMgrPermission);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // If any super-domain has the includeSubdomains permission, this is an
-  // STS host.
-  rv = TestPermission(aURI, STS_SUBDOMAIN_PERMISSION, &permGeneral, false);
-  NS_ENSURE_SUCCESS(rv, rv);
+  // First check the exact host. This involves first checking for an entry in
+  // the private browsing table. If that entry exists, we don't want to check
+  // in either the permission manager or the preload list. We only want to use
+  // the stored permission if it is not a knockout entry, however.
+  // Additionally, if it is a knockout entry, we want to stop looking for data
+  // on th