diff --git a/.gitignore b/.gitignore
index efe5213..530c4b29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -367,6 +367,7 @@
 /third_party/nss
 /third_party/omaha/src/omaha
 /third_party/openmax_dl/
+/third_party/openh264/src
 /third_party/opus/src
 /third_party/pdfsqueeze
 /third_party/pdfium
@@ -404,6 +405,7 @@
 /third_party/v8-i18n
 /third_party/valgrind
 /third_party/v4l2capture
+/third_party/wayland/src
 /third_party/webdriver/pylib
 /third_party/webdriver/python/selenium
 /third_party/webgl
diff --git a/AUTHORS b/AUTHORS
index 2ac0c60..4cd6e8b 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -28,6 +28,7 @@
 Alex Gartrell <agartrell@cmu.edu>
 Alex Henrie <alexhenrie24@gmail.com>
 Alex Scheele <alexscheele@gmail.com>
+Alexander Shalamov <alexander.shalamov@intel.com>
 Alexander Sulfrian <alexander@sulfrian.net>
 Alexandre Abreu <wiss1976@gmail.com>
 Alexandru Chiculita <achicu@adobe.com>
@@ -650,6 +651,7 @@
 Siddharth Bagai <b.siddharth@samsung.com>
 Andrei Borza <andrei.borza@gmail.com>
 anatoly techtonik <techtonik@gmail.com>
+Aleksandar Stojiljkovic <aleksandar.stojiljkovic@intel.com>
 
 BlackBerry Limited <*@blackberry.com>
 Code Aurora Forum <*@codeaurora.org>
diff --git a/BUILD.gn b/BUILD.gn
index 9eec119a..2beb6626 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -72,7 +72,6 @@
     "//skia:skia_unittests",
     "//sql:sql_unittests",
     "//sync:sync_unit_tests",
-    "//third_party/openh264/tests:openh264_unittests",
     "//ui/base:ui_base_unittests",
     "//ui/gfx:gfx_unittests",
     "//url:url_unittests",
diff --git a/DEPS b/DEPS
index 80add81..b16b9c6 100644
--- a/DEPS
+++ b/DEPS
@@ -43,7 +43,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '9a06cc82532a5cf9df8aad51d85b692687ff1e94',
+  'v8_revision': '10449d46aa20f10f39598627bf07f70def597029',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -148,7 +148,7 @@
     Var('chromium_git') + '/external/snappy.git' + '@' + '762bb32f0c9d2f31ba4958c7c0933d22e80c20bf',
 
   'src/tools/gyp':
-    Var('chromium_git') + '/external/gyp.git' + '@' + '2c1e6cced23554ce84806e570acea637f6473afc',
+    Var('chromium_git') + '/external/gyp.git' + '@' + '33b351b2eda8facc464c89213fc8cd9919666c05',
 
   'src/tools/swarming_client':
    Var('chromium_git') + '/external/swarming.client.git' + '@' +  Var('swarming_revision'),
@@ -187,7 +187,7 @@
    Var('chromium_git') + '/webm/libvpx.git' + '@' +  '0941ff72a00732cea6750477edfe649348e699de',
 
   'src/third_party/ffmpeg':
-   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'b1b22ffc6a5c809c41cc27910e3e8b479c15d3a2',
+   Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + '3540f6b0097b03aae1f29e41d8d8433044ee8cdb',
 
   'src/third_party/libjingle/source/talk':
     Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '54a2705b0cb5978dc4c6054bea2f02130a21d328', # commit position 10622
@@ -275,6 +275,9 @@
   'src/third_party/catapult':
     Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' +
     '704c40202baaeb9484af0622aedf41c4a48e0df2',
+
+  'src/third_party/openh264/src':
+    Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
 }
 
 
@@ -412,6 +415,10 @@
     # Graphics buffer allocator for Chrome OS.
     'src/third_party/minigbm/src':
      Var('chromium_git') + '/chromiumos/platform/minigbm.git' + '@' + 'f9d2ab79a15a1bb6a1307f3b608964c81c27791b',
+
+    # Display server protocol for Linux.
+    'src/third_party/wayland/src':
+     Var('chromium_git') + '/external/wayland/wayland.git' + '@' + 'b05668f0ad64ad9ba82e124965163daed4172ead',
   },
   'android': {
     'src/third_party/android_protobuf/src':
diff --git a/PRESUBMIT.py b/PRESUBMIT.py
index 23594dd..b8ec42b 100644
--- a/PRESUBMIT.py
+++ b/PRESUBMIT.py
@@ -1962,9 +1962,6 @@
 def CheckChangeOnCommit(input_api, output_api):
   results = []
   results.extend(_CommonChecks(input_api, output_api))
-  # TODO(thestig) temporarily disabled, doesn't work in third_party/
-  #results.extend(input_api.canned_checks.CheckSvnModifiedDirectories(
-  #    input_api, output_api, sources))
   # Make sure the tree is 'open'.
   results.extend(input_api.canned_checks.CheckTreeIsOpen(
       input_api,
diff --git a/android_webview/browser/aw_render_thread_context_provider.cc b/android_webview/browser/aw_render_thread_context_provider.cc
index 34531a5..748de1f3 100644
--- a/android_webview/browser/aw_render_thread_context_provider.cc
+++ b/android_webview/browser/aw_render_thread_context_provider.cc
@@ -130,8 +130,8 @@
   g_gles2_initializer.Get();
   gles2::SetGLContext(ContextGL());
 
-  skia::RefPtr<GrGLInterface> interface =
-      skia::AdoptRef(skia_bindings::CreateCommandBufferSkiaGLBinding());
+  skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(new GrGLInterface);
+  skia_bindings::InitCommandBufferSkiaGLBinding(interface.get());
   interface->fCallback = BindGrContextCallback;
   interface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
 
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 75a8dcfc..bec617c 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -108,7 +108,7 @@
     private static final float ZOOM_CONTROLS_EPSILON = 0.007f;
 
     private static final boolean FORCE_AUXILIARY_BITMAP_RENDERING =
-            "goldfish".equals(Build.HARDWARE);
+            "goldfish".equals(Build.HARDWARE) || "ranchu".equals(Build.HARDWARE);
 
     /**
      * WebKit hit test related data structure. These are used to implement
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
index 53715c6..1a04af4 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
@@ -26,6 +26,9 @@
     // Whether this webcontents has ever committed any navigation.
     private boolean mCommittedNavigation;
 
+    // Temporarily stores the URL passed the last time to didFinishLoad callback.
+    private String mLastDidFinishLoadUrl;
+
     public AwWebContentsObserver(
             WebContents webContents, AwContents awContents, AwContentsClient awContentsClient) {
         super(webContents);
@@ -33,15 +36,31 @@
         mAwContentsClient = new WeakReference<>(awContentsClient);
     }
 
+    private AwContentsClient getClientIfNeedToFireCallback(String validatedUrl) {
+        AwContentsClient client = mAwContentsClient.get();
+        if (client != null) {
+            String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
+            if (unreachableWebDataUrl == null || !unreachableWebDataUrl.equals(validatedUrl)) {
+                return client;
+            }
+        }
+        return null;
+    }
+
     @Override
     public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
-        AwContentsClient client = mAwContentsClient.get();
-        if (client == null) return;
-        String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
-        boolean isErrorUrl =
-                unreachableWebDataUrl != null && unreachableWebDataUrl.equals(validatedUrl);
-        if (isMainFrame && !isErrorUrl) {
+        if (isMainFrame && getClientIfNeedToFireCallback(validatedUrl) != null) {
+            mLastDidFinishLoadUrl = validatedUrl;
+        }
+    }
+
+    @Override
+    public void didStopLoading(String validatedUrl) {
+        if (validatedUrl.length() == 0) validatedUrl = "about:blank";
+        AwContentsClient client = getClientIfNeedToFireCallback(validatedUrl);
+        if (client != null && validatedUrl.equals(mLastDidFinishLoadUrl)) {
             client.getCallbackHelper().postOnPageFinished(validatedUrl);
+            mLastDidFinishLoadUrl = null;
         }
     }
 
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java
index c68be40..45e2239 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java
@@ -52,6 +52,7 @@
 
         int callCount = onPageFinishedHelper.getCallCount();
         mWebContentsObserver.didFinishLoad(frameId, EXAMPLE_URL, mainFrame);
+        mWebContentsObserver.didStopLoading(EXAMPLE_URL);
         onPageFinishedHelper.waitForCallback(callCount);
         assertEquals("onPageFinished should be called for main frame navigations.", callCount + 1,
                 onPageFinishedHelper.getCallCount());
@@ -65,6 +66,7 @@
         callCount = onPageFinishedHelper.getCallCount();
         mWebContentsObserver.didFinishLoad(frameId, EXAMPLE_URL, subFrame);
         mWebContentsObserver.didFinishLoad(frameId, SYNC_URL, mainFrame);
+        mWebContentsObserver.didStopLoading(SYNC_URL);
         onPageFinishedHelper.waitForCallback(callCount);
         assertEquals("onPageFinished should only be called for the main frame.", callCount + 1,
                 onPageFinishedHelper.getCallCount());
@@ -74,6 +76,7 @@
         callCount = onPageFinishedHelper.getCallCount();
         mWebContentsObserver.didFinishLoad(frameId, mUnreachableWebDataUrl, mainFrame);
         mWebContentsObserver.didFinishLoad(frameId, SYNC_URL, mainFrame);
+        mWebContentsObserver.didStopLoading(SYNC_URL);
         onPageFinishedHelper.waitForCallback(callCount);
         assertEquals("onPageFinished should not be called for the error url.", callCount + 1,
                 onPageFinishedHelper.getCallCount());
@@ -97,6 +100,7 @@
         mWebContentsObserver.didNavigateMainFrame(EXAMPLE_URL, baseUrl,
                 !navigationToDifferentPage, !fragmentNavigation, httpStatusCode);
         mWebContentsObserver.didFinishLoad(frameId, SYNC_URL, mainFrame);
+        mWebContentsObserver.didStopLoading(SYNC_URL);
         onPageFinishedHelper.waitForCallback(callCount);
         onPageFinishedHelper.waitForCallback(callCount);
         assertEquals("onPageFinished should be called only for main frame fragment navigations.",
diff --git a/android_webview/native/state_serializer.cc b/android_webview/native/state_serializer.cc
index e6577bd1..22139a2 100644
--- a/android_webview/native/state_serializer.cc
+++ b/android_webview/native/state_serializer.cc
@@ -6,7 +6,6 @@
 
 #include <string>
 
-#include "base/memory/scoped_vector.h"
 #include "base/pickle.h"
 #include "base/time/time.h"
 #include "content/public/browser/child_process_security_policy.h"
@@ -95,14 +94,14 @@
   if (selected_entry >= entry_count)
     return false;
 
-  ScopedVector<content::NavigationEntry> restored_entries;
+  std::vector<scoped_ptr<content::NavigationEntry>> entries;
+  entries.reserve(entry_count);
   for (int i = 0; i < entry_count; ++i) {
-    restored_entries.push_back(content::NavigationEntry::Create());
-    if (!internal::RestoreNavigationEntryFromPickle(iterator,
-                                                    restored_entries[i]))
+    entries.push_back(content::NavigationEntry::Create());
+    if (!internal::RestoreNavigationEntryFromPickle(iterator, entries[i].get()))
       return false;
 
-    restored_entries[i]->SetPageID(i);
+    entries[i]->SetPageID(i);
   }
 
   // |web_contents| takes ownership of these entries after this call.
@@ -110,8 +109,8 @@
   controller.Restore(
       selected_entry,
       content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
-      &restored_entries);
-  DCHECK_EQ(0u, restored_entries.size());
+      &entries);
+  DCHECK_EQ(0u, entries.size());
 
   if (controller.GetLastCommittedEntry()) {
     // Set up the file access rights for the selected navigation entry.
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 5e1aab0..57683ff 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -196,6 +196,7 @@
       gesture_drag_amount_(0.f),
       gesture_drag_auto_hide_state_(SHELF_AUTO_HIDE_SHOWN),
       update_shelf_observer_(NULL),
+      chromevox_panel_height_(0),
       duration_override_in_ms_(0) {
   Shell::GetInstance()->AddShellObserver(this);
   Shell::GetInstance()->lock_state_controller()->AddObserver(this);
@@ -541,6 +542,11 @@
          GetAlignment() == SHELF_ALIGNMENT_TOP;
 }
 
+void ShelfLayoutManager::SetChromeVoxPanelHeight(int height) {
+  chromevox_panel_height_ = height;
+  LayoutShelf();
+}
+
 // static
 ShelfLayoutManager* ShelfLayoutManager::ForShelf(aura::Window* window) {
   ShelfWidget* shelf = RootWindowController::ForShelf(window)->shelf();
@@ -834,6 +840,12 @@
     target_bounds->work_area_insets += dock_insets;
   }
 
+  // Also push in the work area insets for the ChromeVox panel if it's visible.
+  if (chromevox_panel_height_) {
+    gfx::Insets chromevox_insets(chromevox_panel_height_, 0, 0, 0);
+    target_bounds->work_area_insets += chromevox_insets;
+  }
+
   target_bounds->opacity =
       (gesture_drag_status_ == GESTURE_DRAG_IN_PROGRESS ||
        state.visibility_state == SHELF_VISIBLE ||
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 8b5d166..478850c5 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -215,6 +215,10 @@
   // Is the shelf's alignment horizontal?
   bool IsHorizontalAlignment() const;
 
+  // Set the height of the ChromeVox panel, which takes away space from the
+  // available work area from the top of the screen.
+  void SetChromeVoxPanelHeight(int height);
+
   // Returns a ShelfLayoutManager on the display which has a shelf for
   // given |window|. See RootWindowController::ForShelf for more info.
   static ShelfLayoutManager* ForShelf(aura::Window* window);
@@ -412,6 +416,10 @@
   // keyboard.
   gfx::Rect user_work_area_bounds_;
 
+  // The height of the ChromeVox panel at the top of the screen, which
+  // needs to be removed from the available work area.
+  int chromevox_panel_height_;
+
   // The show hide animation duration override or 0 for default.
   int duration_override_in_ms_;
 
diff --git a/base/memory/raw_scoped_refptr_mismatch_checker.h b/base/memory/raw_scoped_refptr_mismatch_checker.h
index 0190558..09f982b 100644
--- a/base/memory/raw_scoped_refptr_mismatch_checker.h
+++ b/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -51,75 +51,10 @@
   enum { value = 1 };
 };
 
-template <typename A>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A>> {
-  enum { value = !NeedsScopedRefptrButGetsRawPtr<A>::value };
-};
-
-template <typename A, typename B>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B>> {
-  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<B>::value) };
-};
-
-template <typename A, typename B, typename C>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C>> {
-  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<C>::value) };
-};
-
-template <typename A, typename B, typename C, typename D>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D>> {
-  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<D>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E>> {
-  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<E>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
-          typename F>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F>> {
-  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<F>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
-          typename F, typename G>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G>> {
-  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<F>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<G>::value) };
-};
-
-template <typename A, typename B, typename C, typename D, typename E,
-          typename F, typename G, typename H>
-struct ParamsUseScopedRefptrCorrectly<Tuple<A, B, C, D, E, F, G, H>> {
-  enum { value = !(NeedsScopedRefptrButGetsRawPtr<A>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<B>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<C>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<D>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<E>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<F>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<G>::value ||
-                   NeedsScopedRefptrButGetsRawPtr<H>::value) };
+template <typename Head, typename... Tail>
+struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
+  enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
+                 ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
 };
 
 }  // namespace internal
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
index c8314c7a..4eccbd7 100644
--- a/base/sys_info_win.cc
+++ b/base/sys_info_win.cc
@@ -48,7 +48,7 @@
 
 // static
 int64 SysInfo::AmountOfVirtualMemory() {
-  return 0;
+  return AmountOfMemory(&MEMORYSTATUSEX::ullTotalVirtual);
 }
 
 // static
diff --git a/base/trace_event/OWNERS b/base/trace_event/OWNERS
index 5136401..9160267 100644
--- a/base/trace_event/OWNERS
+++ b/base/trace_event/OWNERS
@@ -1,5 +1,6 @@
-nduca@chromium.org
 dsinclair@chromium.org
+nduca@chromium.org
+oysteine@chromium.org
 primiano@chromium.org
 simonhatch@chromium.org
 per-file trace_event_android.cc=wangxianzhu@chromium.org
diff --git a/blimp/client/compositor/blimp_context_provider.cc b/blimp/client/compositor/blimp_context_provider.cc
index 24be455..35c8444 100644
--- a/blimp/client/compositor/blimp_context_provider.cc
+++ b/blimp/client/compositor/blimp_context_provider.cc
@@ -113,8 +113,8 @@
   g_gles2_initializer.Get();
   gles2::SetGLContext(ContextGL());
 
-  skia::RefPtr<GrGLInterface> interface =
-      skia::AdoptRef(skia_bindings::CreateCommandBufferSkiaGLBinding());
+  skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(new GrGLInterface);
+  skia_bindings::InitCommandBufferSkiaGLBinding(interface.get());
   interface->fCallback = BindGrContextCallback;
   interface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
 
diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn
index 8c7edb4..4635fe7 100644
--- a/blimp/net/BUILD.gn
+++ b/blimp/net/BUILD.gn
@@ -9,6 +9,8 @@
     "blimp_message_checkpoint_observer.h",
     "blimp_message_demultiplexer.cc",
     "blimp_message_demultiplexer.h",
+    "blimp_message_multiplexer.cc",
+    "blimp_message_multiplexer.h",
     "blimp_message_output_buffer.cc",
     "blimp_message_output_buffer.h",
     "blimp_message_processor.h",
@@ -48,6 +50,7 @@
 
   sources = [
     "blimp_message_demultiplexer_unittest.cc",
+    "blimp_message_multiplexer_unittest.cc",
     "stream_packet_reader_unittest.cc",
     "stream_packet_writer_unittest.cc",
     "tcp_transport_unittest.cc",
diff --git a/blimp/net/blimp_message_multiplexer.cc b/blimp/net/blimp_message_multiplexer.cc
new file mode 100644
index 0000000..644d747
--- /dev/null
+++ b/blimp/net/blimp_message_multiplexer.cc
@@ -0,0 +1,63 @@
+// Copyright 2015 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 "blimp/net/blimp_message_multiplexer.h"
+
+#include "base/logging.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/net/blimp_message_processor.h"
+
+namespace blimp {
+namespace {
+
+class MultiplexedSender : public BlimpMessageProcessor {
+ public:
+  MultiplexedSender(base::WeakPtr<BlimpMessageProcessor> output_processor,
+                    BlimpMessage::Type type);
+  ~MultiplexedSender() override;
+
+  // BlimpMessageProcessor implementation.
+  // |message.type|, if set, must match the sender's type.
+  void ProcessMessage(scoped_ptr<BlimpMessage> message,
+                      const net::CompletionCallback& callback) override;
+
+ private:
+  base::WeakPtr<BlimpMessageProcessor> output_processor_;
+  BlimpMessage::Type type_;
+
+  DISALLOW_COPY_AND_ASSIGN(MultiplexedSender);
+};
+
+MultiplexedSender::MultiplexedSender(
+    base::WeakPtr<BlimpMessageProcessor> output_processor,
+    BlimpMessage::Type type)
+    : output_processor_(output_processor), type_(type) {}
+
+MultiplexedSender::~MultiplexedSender() {}
+
+void MultiplexedSender::ProcessMessage(
+    scoped_ptr<BlimpMessage> message,
+    const net::CompletionCallback& callback) {
+  if (message->has_type()) {
+    DCHECK_EQ(type_, message->type());
+  } else {
+    message->set_type(type_);
+  }
+  output_processor_->ProcessMessage(message.Pass(), callback);
+}
+
+}  // namespace
+
+BlimpMessageMultiplexer::BlimpMessageMultiplexer(
+    BlimpMessageProcessor* output_processor)
+    : output_weak_factory_(output_processor) {}
+
+BlimpMessageMultiplexer::~BlimpMessageMultiplexer() {}
+
+scoped_ptr<BlimpMessageProcessor> BlimpMessageMultiplexer::CreateSenderForType(
+    BlimpMessage::Type type) {
+  return make_scoped_ptr(
+      new MultiplexedSender(output_weak_factory_.GetWeakPtr(), type));
+}
+}  // namespace blimp
diff --git a/blimp/net/blimp_message_multiplexer.h b/blimp/net/blimp_message_multiplexer.h
new file mode 100644
index 0000000..27713af0
--- /dev/null
+++ b/blimp/net/blimp_message_multiplexer.h
@@ -0,0 +1,41 @@
+// Copyright 2015 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.
+
+#ifndef BLIMP_NET_BLIMP_MESSAGE_MULTIPLEXER_H_
+#define BLIMP_NET_BLIMP_MESSAGE_MULTIPLEXER_H_
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/net/blimp_net_export.h"
+
+namespace blimp {
+
+class BlimpConnection;
+class BlimpMessageProcessor;
+
+// Creates MessageProcessors that receive outgoing messages and put them
+// onto a multiplexed message stream.
+class BLIMP_NET_EXPORT BlimpMessageMultiplexer {
+ public:
+  // |output_processor|: A pointer to the MessageProcessor that will receive the
+  // multiplexed message stream.
+  explicit BlimpMessageMultiplexer(BlimpMessageProcessor* output_processor);
+
+  ~BlimpMessageMultiplexer();
+
+  // Creates a BlimpMessageProcessor object for sending messages of type |type|.
+  // Any number of senders can be created at a time for a given type.
+  scoped_ptr<BlimpMessageProcessor> CreateSenderForType(
+      BlimpMessage::Type type);
+
+ private:
+  base::WeakPtrFactory<BlimpMessageProcessor> output_weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(BlimpMessageMultiplexer);
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_NET_BLIMP_MESSAGE_MULTIPLEXER_H_
diff --git a/blimp/net/blimp_message_multiplexer_unittest.cc b/blimp/net/blimp_message_multiplexer_unittest.cc
new file mode 100644
index 0000000..4c757b2
--- /dev/null
+++ b/blimp/net/blimp_message_multiplexer_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright 2015 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 "blimp/common/proto/blimp_message.pb.h"
+#include "blimp/common/proto/input.pb.h"
+#include "blimp/common/proto/navigation.pb.h"
+#include "blimp/net/blimp_message_multiplexer.h"
+#include "blimp/net/test_common.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::DoAll;
+using testing::Ref;
+using testing::SaveArg;
+
+namespace blimp {
+namespace {
+
+class BlimpMessageMultiplexerTest : public testing::Test {
+ public:
+  BlimpMessageMultiplexerTest()
+      : multiplexer_(&mock_output_processor_),
+        input_message_(new BlimpMessage),
+        navigation_message_(new BlimpMessage),
+        input_processor_(multiplexer_.CreateSenderForType(BlimpMessage::INPUT)),
+        navigation_processor_(
+            multiplexer_.CreateSenderForType(BlimpMessage::NAVIGATION)) {}
+
+  void SetUp() override {
+    EXPECT_CALL(mock_output_processor_, MockableProcessMessage(_, _))
+        .WillRepeatedly(
+            DoAll(SaveArg<0>(&captured_message_), SaveArg<1>(&captured_cb_)));
+
+    input_message_->mutable_input()->set_type(InputMessage::DRAG);
+    navigation_message_->mutable_navigation()->set_type(
+        NavigationMessage::LOAD_URL);
+  }
+
+ protected:
+  MockBlimpMessageProcessor mock_output_processor_;
+  BlimpMessageMultiplexer multiplexer_;
+  scoped_ptr<BlimpMessage> input_message_;
+  scoped_ptr<BlimpMessage> navigation_message_;
+  BlimpMessage captured_message_;
+  net::CompletionCallback captured_cb_;
+  scoped_ptr<BlimpMessageProcessor> input_processor_;
+  scoped_ptr<BlimpMessageProcessor> navigation_processor_;
+};
+
+// Verify that each sender propagates its types and copies the message payload
+// correctly.
+TEST_F(BlimpMessageMultiplexerTest, TypeSetByMux) {
+  net::TestCompletionCallback cb_1;
+  input_processor_->ProcessMessage(input_message_.Pass(), cb_1.callback());
+  EXPECT_EQ(BlimpMessage::INPUT, captured_message_.type());
+  EXPECT_EQ(InputMessage::DRAG, captured_message_.input().type());
+  captured_cb_.Run(net::OK);
+  EXPECT_EQ(net::OK, cb_1.WaitForResult());
+
+  net::TestCompletionCallback cb_2;
+  navigation_processor_->ProcessMessage(navigation_message_.Pass(),
+                                        cb_2.callback());
+  EXPECT_EQ(BlimpMessage::NAVIGATION, captured_message_.type());
+  EXPECT_EQ(NavigationMessage::LOAD_URL, captured_message_.navigation().type());
+  captured_cb_.Run(net::ERR_FAILED);
+  EXPECT_EQ(net::ERR_FAILED, cb_2.WaitForResult());
+}
+
+// Verify that the multiplexer allows the caller to supply a message type.
+TEST_F(BlimpMessageMultiplexerTest, TypeSetByCaller) {
+  input_message_->set_type(BlimpMessage::INPUT);
+
+  net::TestCompletionCallback cb_1;
+  input_processor_->ProcessMessage(input_message_.Pass(), cb_1.callback());
+  EXPECT_EQ(BlimpMessage::INPUT, captured_message_.type());
+  EXPECT_EQ(InputMessage::DRAG, captured_message_.input().type());
+  captured_cb_.Run(net::OK);
+  EXPECT_EQ(net::OK, cb_1.WaitForResult());
+}
+
+// Verify that senders for a given type can be torn down and recreated.
+TEST_F(BlimpMessageMultiplexerTest, SenderTransience) {
+  net::TestCompletionCallback cb_3;
+  input_processor_ = multiplexer_.CreateSenderForType(BlimpMessage::INPUT);
+  input_processor_->ProcessMessage(input_message_.Pass(), cb_3.callback());
+  EXPECT_EQ(BlimpMessage::INPUT, captured_message_.type());
+  EXPECT_EQ(InputMessage::DRAG, captured_message_.input().type());
+  captured_cb_.Run(net::OK);
+  EXPECT_EQ(net::OK, cb_3.WaitForResult());
+}
+
+// Verify that there is no limit on the number of senders for a given type.
+TEST_F(BlimpMessageMultiplexerTest, SenderMultiplicity) {
+  net::TestCompletionCallback cb_4;
+  scoped_ptr<BlimpMessageProcessor> input_processor_2 =
+      multiplexer_.CreateSenderForType(BlimpMessage::INPUT);
+  input_processor_2->ProcessMessage(input_message_.Pass(), cb_4.callback());
+  EXPECT_EQ(BlimpMessage::INPUT, captured_message_.type());
+  EXPECT_EQ(InputMessage::DRAG, captured_message_.input().type());
+  captured_cb_.Run(net::ERR_INVALID_ARGUMENT);
+  EXPECT_EQ(net::ERR_INVALID_ARGUMENT, cb_4.WaitForResult());
+}
+
+}  // namespace
+}  // namespace blimp
diff --git a/build/all.gyp b/build/all.gyp
index 196529d4..ecbe935 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -30,7 +30,6 @@
         '../testing/gtest.gyp:*',
         '../third_party/icu/icu.gyp:*',
         '../third_party/libxml/libxml.gyp:*',
-        '../third_party/openh264/tests/openh264_unittests.gyp:*',
         '../third_party/sqlite/sqlite.gyp:*',
         '../third_party/zlib/zlib.gyp:*',
         '../ui/accessibility/accessibility.gyp:*',
diff --git a/build/config/chromecast_build.gni b/build/config/chromecast_build.gni
index 3fac609..b3d1bc2 100644
--- a/build/config/chromecast_build.gni
+++ b/build/config/chromecast_build.gni
@@ -8,8 +8,14 @@
   # Set this true for a Chromecast build. Chromecast builds are supported on
   # Linux and Android.
   is_chromecast = false
+
+  # Set this true for an audio-only Chromecast build.
+  disable_display = false
 }
 
 # Assert that Chromecast is being built for a supported platform.
 assert(is_linux || is_android || !is_chromecast,
        "Chromecast builds are not supported on $target_os")
+
+# Assert that disable_display is not true on a non-Chromecast build.
+assert(!disable_display || is_chromecast)
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 34a7f74..a19b8f1b 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -60,6 +60,10 @@
   packages = [ "dbus-1" ]
 }
 
+pkg_config("libffi") {
+  packages = [ "libffi" ]
+}
+
 config("x11") {
   libs = [
     "X11",
diff --git a/build/config/nacl/rules.gni b/build/config/nacl/rules.gni
new file mode 100644
index 0000000..adecc30
--- /dev/null
+++ b/build/config/nacl/rules.gni
@@ -0,0 +1,147 @@
+# Copyright 2015 The Native Client Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+import("//build/config/nacl/config.gni")
+
+# Generate a nmf file
+#
+# Native Client Manifest (nmf) is a JSON file that tells the browser where to
+# download and load Native Client application files and libraries.
+#
+# Variables:
+#   executables: .nexe/.pexe/.bc executables to generate nmf for
+#   lib_prefix: path to prepend to shared libraries in the nmf
+#   nmf: the name and the path of the output file
+#   nmfflags: additional flags for the nmf generator
+#   stage_dependencies: directory for staging libraries
+template("generate_nmf") {
+  assert(defined(invoker.executables), "Must define executables")
+  assert(defined(invoker.nmf), "Must define nmf")
+
+  action(target_name) {
+    nmfflags = []
+
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "data_deps",
+                             "executables",
+                             "lib_prefix",
+                             "nmf",
+                             "nmfflags",
+                             "public_deps",
+                             "stage_dependencies",
+                             "testonly",
+                           ])
+
+    objdump = rebase_path("${nacl_toolprefix}objdump")
+    if (host_os == "win") {
+      objdump += ".exe"
+    }
+
+    script = "//native_client_sdk/src/tools/create_nmf.py"
+    inputs = [
+      objdump,
+    ]
+    sources = executables
+    outputs = [
+      nmf,
+    ]
+    if (is_nacl_glibc) {
+      if (defined(stage_dependencies)) {
+        nmfflags += [ "--stage-dependencies=" +
+                      rebase_path(stage_dependencies, root_build_dir) ]
+        lib_path = stage_dependencies
+      } else {
+        lib_path = root_build_dir
+      }
+      if (defined(lib_prefix)) {
+        nmfflags += [ "--lib-prefix=" + lib_prefix ]
+        lib_path += "/${lib_prefix}"
+      }
+
+      # NOTE: There is no explicit dependency for the lib32
+      # and lib64 directories created in the product directory.
+      # They are created as a side-effect of nmf creation.
+      nmfflags += [ "--library-path=" + rebase_path(root_out_dir) ]
+      if (current_cpu == "x86") {
+        nmfflags += [ "--library-path=" +
+                      rebase_path("${nacl_toolchain_tooldir}/lib32") ]
+        data = [
+          "${lib_path}/lib32/",
+        ]
+      } else if (current_cpu == "x64") {
+        nmfflags +=
+            [ "--library-path=" + rebase_path("${nacl_toolchain_tooldir}/lib") ]
+        data = [
+          "${lib_path}/lib64/",
+        ]
+      } else {
+        nmfflags +=
+            [ "--library-path=" + rebase_path("${nacl_toolchain_tooldir}/lib") ]
+        data = [
+          "${lib_path}/lib/",
+        ]
+      }
+    }
+    args = [
+             "--no-default-libpath",
+             "--objdump=" + objdump,
+             "--output=" + rebase_path(nmf, root_build_dir),
+           ] + nmfflags + rebase_path(sources, root_build_dir)
+    if (is_nacl_glibc && current_cpu == "arm") {
+      deps += [ "//native_client/src/untrusted/elf_loader:elf_loader" ]
+    }
+  }
+}
+
+# Generate a nmf file for Non-SFI tests
+#
+# Non-SFI tests use a different manifest format from regular Native Client and
+# as such requires a different generator.
+#
+# Variables:
+#   executable: Non-SFI .nexe executable to generate nmf for
+#   nmf: the name and the path of the output file
+template("generate_nonsfi_test_nmf") {
+  assert(defined(invoker.executable), "Must define executable")
+  assert(defined(invoker.nmf), "Must define nmf")
+
+  action(target_name) {
+    forward_variables_from(invoker,
+                           [
+                             "deps",
+                             "data_deps",
+                             "executable",
+                             "nmf",
+                             "testonly",
+                             "public_deps",
+                           ])
+
+    script = "//ppapi/tests/create_nonsfi_test_nmf.py"
+    sources = [
+      executable,
+    ]
+    outputs = [
+      nmf,
+    ]
+
+    # NOTE: We use target_cpu rather than current_cpu on purpose because
+    # current_cpu is always going to be pnacl for Non-SFI, but the Non-SFI
+    # .nexe executable is always translated to run on the target machine.
+    if (target_cpu == "x86") {
+      arch = "x86-32"
+    } else if (target_cpu == "x64") {
+      arch = "x86-64"
+    } else {
+      arch = target_cpu
+    }
+    args = [
+      "--program=" + rebase_path(executable, root_build_dir),
+      "--arch=${arch}",
+      "--output=" + rebase_path(nmf, root_build_dir),
+    ]
+  }
+}
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index c0f55d24..a9555ab 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -82,7 +82,6 @@
         '../third_party/WebKit/Source/wtf/wtf_tests.gyp:wtf_unittests',
         '../third_party/leveldatabase/leveldatabase.gyp:env_chromium_unittests',
         '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
-        '../third_party/openh264/tests/openh264_unittests.gyp:*',
         '../third_party/smhasher/smhasher.gyp:pmurhash',
         '../tools/battor_agent/battor_agent.gyp:battor_agent',
         '../tools/telemetry/telemetry.gyp:bitmaptools#host',
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index 6b0023e..658c99fb 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -1119,7 +1119,7 @@
           ],
           'variables': {
             'dex_additional_options': [
-              '--main-dex-list-path', '<(main_dex_list_path)'
+              '--main-dex-list-path', '<(main_dex_list_path)',
               '--multidex-configuration-path', '<(multidex_configuration_path)',
             ],
           },
diff --git a/build/linux/system.gyp b/build/linux/system.gyp
index 56b56925..2c34629 100644
--- a/build/linux/system.gyp
+++ b/build/linux/system.gyp
@@ -1268,5 +1268,26 @@
         }],
       ],
     },
+    {
+      'target_name': 'libffi',
+      'type': 'none',
+      'conditions': [
+        ['_toolset=="target"', {
+          'direct_dependent_settings': {
+            'cflags': [
+              '<!@(<(pkg-config) --cflags libffi)',
+            ],
+          },
+          'link_settings': {
+            'ldflags': [
+              '<!@(<(pkg-config) --libs-only-L --libs-only-other libffi)',
+            ],
+            'libraries': [
+              '<!@(<(pkg-config) --libs-only-l libffi)',
+            ],
+          },
+        }],
+      ],
+    },
   ],
 }
diff --git a/build/toolchain/nacl/BUILD.gn b/build/toolchain/nacl/BUILD.gn
index 23f1027f..f36fba98a 100644
--- a/build/toolchain/nacl/BUILD.gn
+++ b/build/toolchain/nacl/BUILD.gn
@@ -22,24 +22,42 @@
                         "trim list lines")
 nacl_x86_glibc_rev = revisions[0]
 nacl_arm_glibc_rev = revisions[1]
-pnacl_newlib_rev = revisions[2]
 
-nacl_toolchain("newlib_pnacl") {
-  toolchain_package = "pnacl_newlib"
-  toolchain_revision = pnacl_newlib_rev
-  toolchain_cpu = "pnacl"
-  toolprefix =
-      rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/pnacl-",
-                  root_build_dir)
+# TODO(mcgrathr): Uncomment this when
+# https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+#pnacl_newlib_rev = revisions[2]
 
+template("pnacl_toolchain") {
+  assert(defined(invoker.strip), "Must define strip")
+  assert(defined(invoker.executable_extension),
+         "Must define executable_extension")
+
+  # TODO(mcgrathr): See above.
+  pnacl_newlib_rev = revisions[2]
+
+  nacl_toolchain(target_name) {
+    toolchain_package = "pnacl_newlib"
+    toolchain_revision = pnacl_newlib_rev
+    toolchain_cpu = "pnacl"
+    toolprefix =
+        rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/pnacl-",
+                    root_build_dir)
+
+    is_clang = true
+    cc = toolprefix + "clang"
+    cxx = toolprefix + "clang++"
+    ar = toolprefix + "ar"
+    ld = cxx
+    readelf = toolprefix + "readelf"
+    nm = toolprefix + "nm"
+    strip = toolprefix + invoker.strip
+    executable_extension = invoker.executable_extension
+  }
+}
+
+pnacl_toolchain("newlib_pnacl") {
   executable_extension = ".pexe"
 
-  is_clang = true
-  cc = toolprefix + "clang"
-  cxx = toolprefix + "clang++"
-  ar = toolprefix + "ar"
-  ld = cxx
-
   # The pnacl-finalize tool turns a .pexe.debug file into a .pexe file.
   # It's very similar in purpose to the traditional "strip" utility: it
   # turns what comes out of the linker into what you actually want to
@@ -47,23 +65,13 @@
   # you ever actually want to use other than pnacl-finalize, so just
   # make pnacl-finalize the strip tool rather than adding an additional
   # step like "postlink" to run pnacl-finalize.
-  strip = toolprefix + "finalize"
+  strip = "finalize"
 }
 
-nacl_toolchain("newlib_pnacl_nonsfi") {
-  toolchain_package = "pnacl_newlib"
-  toolchain_revision = pnacl_newlib_rev
-  toolchain_cpu = "pnacl"
-  toolprefix =
-      rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/pnacl-",
-                  root_build_dir)
-
-  is_clang = true
-  cc = toolprefix + "clang"
-  cxx = toolprefix + "clang++"
-  ar = toolprefix + "ar"
-  ld = cxx
+pnacl_toolchain("newlib_pnacl_nonsfi") {
   executable_extension = ""
+
+  strip = "strip"
 }
 
 template("nacl_glibc_toolchain") {
@@ -81,14 +89,25 @@
                                invoker.toolchain_tuple + "-",
                            root_build_dir)
 
+  # TODO(mcgrathr): Hoist this to top level when
+  # https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+  if (host_os == "win") {
+    toolsuffix = ".exe"
+  } else {
+    toolsuffix = ""
+  }
+
   nacl_toolchain("glibc_" + toolchain_cpu) {
     is_clang = false
     is_nacl_glibc = true
 
-    cc = toolprefix + "gcc"
-    cxx = toolprefix + "g++"
-    ar = toolprefix + "ar"
+    cc = toolprefix + "gcc" + toolsuffix
+    cxx = toolprefix + "g++" + toolsuffix
+    ar = toolprefix + "ar" + toolsuffix
     ld = cxx
+    readelf = toolprefix + "readelf" + toolsuffix
+    nm = toolprefix + "nm" + toolsuffix
+    strip = toolprefix + "strip" + toolsuffix
   }
 }
 
@@ -114,18 +133,32 @@
   toolchain_cpu = target_name
   assert(defined(invoker.toolchain_tuple), "Must define toolchain_tuple")
 
+  # TODO(mcgrathr): See above.
+  pnacl_newlib_rev = revisions[2]
+
   toolchain_package = "pnacl_newlib"
   toolchain_revision = pnacl_newlib_rev
   toolprefix = rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/" +
                                invoker.toolchain_tuple + "-",
                            root_build_dir)
 
+  # TODO(mcgrathr): Hoist this to top level when
+  # https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+  if (host_os == "win") {
+    toolsuffix = ".exe"
+  } else {
+    toolsuffix = ""
+  }
+
   nacl_toolchain("clang_newlib_" + toolchain_cpu) {
     is_clang = true
-    cc = toolprefix + "clang"
-    cxx = toolprefix + "clang++"
-    ar = toolprefix + "ar"
+    cc = toolprefix + "clang" + toolsuffix
+    cxx = toolprefix + "clang++" + toolsuffix
+    ar = toolprefix + "ar" + toolsuffix
     ld = cxx
+    readelf = toolprefix + "readelf" + toolsuffix
+    nm = toolprefix + "nm" + toolsuffix
+    strip = toolprefix + "strip" + toolsuffix
   }
 }
 
@@ -133,12 +166,23 @@
   toolchain_cpu = target_name
   assert(defined(invoker.toolchain_tuple), "Must define toolchain_tuple")
 
+  # TODO(mcgrathr): See above.
+  pnacl_newlib_rev = revisions[2]
+
   toolchain_package = "pnacl_newlib"
   toolchain_revision = pnacl_newlib_rev
   toolprefix = rebase_path("${nacl_toolchain_dir}/${toolchain_package}/bin/" +
                                invoker.toolchain_tuple + "-",
                            root_build_dir)
 
+  # TODO(mcgrathr): Hoist this to top level when
+  # https://code.google.com/p/chromium/issues/detail?id=395883 is fixed.
+  if (host_os == "win") {
+    toolsuffix = ".exe"
+  } else {
+    toolsuffix = ""
+  }
+
   link_irt = rebase_path("//native_client/build/link_irt.py", root_build_dir)
 
   tls_edit_label =
@@ -150,11 +194,12 @@
 
   nacl_toolchain("irt_" + toolchain_cpu) {
     is_clang = true
-    cc = toolprefix + "clang"
-    cxx = toolprefix + "clang++"
-    ar = toolprefix + "ar"
-    readelf = toolprefix + "readelf"
-    strip = toolprefix + "strip"
+    cc = toolprefix + "clang" + toolsuffix
+    cxx = toolprefix + "clang++" + toolsuffix
+    ar = toolprefix + "ar" + toolsuffix
+    readelf = toolprefix + "readelf" + toolsuffix
+    nm = toolprefix + "nm" + toolsuffix
+    strip = toolprefix + "strip" + toolsuffix
 
     # Always build the IRT with full debugging symbols, regardless of
     # how Chromium itself is being built (or other NaCl executables).
diff --git a/build/toolchain/nacl_toolchain.gni b/build/toolchain/nacl_toolchain.gni
index fa790386..c1db32d 100644
--- a/build/toolchain/nacl_toolchain.gni
+++ b/build/toolchain/nacl_toolchain.gni
@@ -42,8 +42,10 @@
                              "is_nacl_glibc",
                              "ld",
                              "link_outputs",
-                             "symbol_level",
+                             "nm",
+                             "readelf",
                              "strip",
+                             "symbol_level",
                              "toolchain_cpu",
                            ])
 
@@ -51,7 +53,6 @@
     is_component_build = false
     clear_sanitizers = true
     use_ccache = false
-    use_goma = false
 
     rebuild_define = "NACL_TC_REV=" + invoker.toolchain_revision
   }
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index 97dca966..e3100399 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -67,7 +67,7 @@
     tool("cc") {
       rspfile = "{{output}}.rsp"
       precompiled_header_type = "msvc"
-      pdbname = "{{target_out_dir}}/{{target_output_name}}_c.pdb"
+      pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb"
       command = "ninja -t msvc -e $env -- $cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname"
       depsformat = "msvc"
       description = "CC {{output}}"
@@ -82,7 +82,7 @@
       precompiled_header_type = "msvc"
 
       # The PDB name needs to be different between C and C++ compiled files.
-      pdbname = "{{target_out_dir}}/{{target_output_name}}_cc.pdb"
+      pdbname = "{{target_out_dir}}/{{label_name}}_cc.pdb"
       command = "ninja -t msvc -e $env -- $cl /nologo /showIncludes /FC @$rspfile /c {{source}} /Fo{{output}} /Fd$pdbname"
       depsformat = "msvc"
       description = "CXX {{output}}"
diff --git a/cc/base/BUILD.gn b/cc/base/BUILD.gn
index c6dc603..6898aa1f 100644
--- a/cc/base/BUILD.gn
+++ b/cc/base/BUILD.gn
@@ -7,6 +7,7 @@
 
   sources = [
     "completion_event.h",
+    "container_util.h",
     "delayed_unique_notifier.cc",
     "delayed_unique_notifier.h",
     "histograms.cc",
@@ -27,7 +28,6 @@
     "rtree.cc",
     "rtree.h",
     "scoped_ptr_algorithm.h",
-    "scoped_ptr_deque.h",
     "scoped_ptr_vector.h",
     "simple_enclosed_region.cc",
     "simple_enclosed_region.h",
diff --git a/cc/base/container_util.h b/cc/base/container_util.h
new file mode 100644
index 0000000..2f0da6c
--- /dev/null
+++ b/cc/base/container_util.h
@@ -0,0 +1,34 @@
+// Copyright 2015 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.
+
+#ifndef CC_BASE_CONTAINER_UTIL_H_
+#define CC_BASE_CONTAINER_UTIL_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace cc {
+
+// Removes the front element from the container and returns it. Note that this
+// currently only works with types that implement Pass().
+// TODO(vmpstr): Use std::move instead of Pass when allowed.
+template <typename Container>
+typename Container::value_type PopFront(Container* container) {
+  typename Container::value_type element = container->front().Pass();
+  container->pop_front();
+  return element;
+}
+
+// Removes the back element from the container and returns it. Note that this
+// currently only works with types that implement Pass().
+// TODO(vmpstr): Use std::move instead of Pass when allowed.
+template <typename Container>
+typename Container::value_type PopBack(Container* container) {
+  typename Container::value_type element = container->back().Pass();
+  container->pop_back();
+  return element;
+}
+
+}  // namespace cc
+
+#endif  // CC_BASE_CONTAINER_UTIL_H_
diff --git a/cc/base/scoped_ptr_deque.h b/cc/base/scoped_ptr_deque.h
deleted file mode 100644
index cb4adfc..0000000
--- a/cc/base/scoped_ptr_deque.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// Copyright 2012 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.
-
-#ifndef CC_BASE_SCOPED_PTR_DEQUE_H_
-#define CC_BASE_SCOPED_PTR_DEQUE_H_
-
-#include <algorithm>
-#include <deque>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/stl_util.h"
-
-namespace cc {
-
-// This type acts like a deque<scoped_ptr> based on top of std::deque. The
-// ScopedPtrDeque has ownership of all elements in the deque.
-template <typename T>
-class ScopedPtrDeque {
- public:
-  typedef typename std::deque<T*>::const_iterator const_iterator;
-  typedef typename std::deque<T*>::reverse_iterator reverse_iterator;
-  typedef typename std::deque<T*>::const_reverse_iterator
-      const_reverse_iterator;
-
-#if defined(OS_ANDROID)
-  // On Android the iterator is not a class, so we can't block assignment.
-  typedef typename std::deque<T*>::iterator iterator;
-#else
-  // Ban setting values on the iterator directly. New pointers must be passed
-  // to methods on the ScopedPtrDeque class to appear in the deque.
-  class iterator : public std::deque<T*>::iterator {
-   public:
-    explicit iterator(const typename std::deque<T*>::iterator& other)
-        : std::deque<T*>::iterator(other) {}
-    T* const& operator*() { return std::deque<T*>::iterator::operator*(); }
-  };
-#endif
-
-  ScopedPtrDeque() {}
-
-  ~ScopedPtrDeque() { clear(); }
-
-  size_t size() const {
-    return data_.size();
-  }
-
-  T* at(size_t index) const {
-    DCHECK(index < size());
-    return data_[index];
-  }
-
-  T* operator[](size_t index) const {
-    return at(index);
-  }
-
-  T* front() const {
-    DCHECK(!empty());
-    return at(0);
-  }
-
-  T* back() const {
-    DCHECK(!empty());
-    return at(size() - 1);
-  }
-
-  bool empty() const {
-    return data_.empty();
-  }
-
-  scoped_ptr<T> take_front() {
-    scoped_ptr<T> ret(front());
-    data_.pop_front();
-    return ret.Pass();
-  }
-
-  scoped_ptr<T> take_back() {
-    scoped_ptr<T> ret(back());
-    data_.pop_back();
-    return ret.Pass();
-  }
-
-  void clear() {
-    STLDeleteElements(&data_);
-  }
-
-  void push_front(scoped_ptr<T> item) {
-    data_.push_front(item.release());
-  }
-
-  void push_back(scoped_ptr<T> item) {
-    data_.push_back(item.release());
-  }
-
-  void insert(iterator position, scoped_ptr<T> item) {
-    DCHECK(position <= end());
-    data_.insert(position, item.release());
-  }
-
-  scoped_ptr<T> take(iterator position) {
-    DCHECK(position < end());
-    scoped_ptr<T> ret(*position);
-    data_.erase(position);
-    return ret.Pass();
-  }
-
-  void swap(iterator a, iterator b) {
-    DCHECK(a < end());
-    DCHECK(b < end());
-    if (a == end() || b == end() || a == b)
-      return;
-    typename std::deque<T*>::iterator writable_a = a;
-    typename std::deque<T*>::iterator writable_b = b;
-    std::swap(*writable_a, *writable_b);
-  }
-
-  iterator begin() { return static_cast<iterator>(data_.begin()); }
-  const_iterator begin() const { return data_.begin(); }
-  iterator end() { return static_cast<iterator>(data_.end()); }
-  const_iterator end() const { return data_.end(); }
-
-  reverse_iterator rbegin() { return data_.rbegin(); }
-  const_reverse_iterator rbegin() const { return data_.rbegin(); }
-  reverse_iterator rend() { return data_.rend(); }
-  const_reverse_iterator rend() const { return data_.rend(); }
-
- private:
-  std::deque<T*> data_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedPtrDeque);
-};
-
-}  // namespace cc
-
-#endif  // CC_BASE_SCOPED_PTR_DEQUE_H_
diff --git a/cc/cc.gyp b/cc/cc.gyp
index b8d6c40f..5a8143f 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -76,6 +76,7 @@
         'animation/transform_operations.cc',
         'animation/transform_operations.h',
         'base/completion_event.h',
+        'base/container_util.h',
         'base/delayed_unique_notifier.cc',
         'base/delayed_unique_notifier.h',
         'base/histograms.cc',
@@ -96,7 +97,6 @@
         'base/rtree.cc',
         'base/rtree.h',
         'base/scoped_ptr_algorithm.h',
-        'base/scoped_ptr_deque.h',
         'base/scoped_ptr_vector.h',
         'base/simple_enclosed_region.cc',
         'base/simple_enclosed_region.h',
diff --git a/cc/output/bsp_tree.cc b/cc/output/bsp_tree.cc
index 4eb87cb..a32c3f49 100644
--- a/cc/output/bsp_tree.cc
+++ b/cc/output/bsp_tree.cc
@@ -7,7 +7,7 @@
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
-#include "cc/base/scoped_ptr_deque.h"
+#include "cc/base/container_util.h"
 #include "cc/base/scoped_ptr_vector.h"
 #include "cc/output/bsp_compare_result.h"
 #include "cc/quads/draw_polygon.h"
@@ -20,11 +20,11 @@
 BspNode::~BspNode() {
 }
 
-BspTree::BspTree(ScopedPtrDeque<DrawPolygon>* list) {
+BspTree::BspTree(std::deque<scoped_ptr<DrawPolygon>>* list) {
   if (list->size() == 0)
     return;
 
-  root_ = make_scoped_ptr(new BspNode(list->take_front()));
+  root_ = make_scoped_ptr(new BspNode(PopFront(list)));
   BuildTree(root_.get(), list);
 }
 
@@ -35,14 +35,14 @@
 // can always simply just take from the front of the deque for our node's
 // data.
 void BspTree::BuildTree(BspNode* node,
-                        ScopedPtrDeque<DrawPolygon>* polygon_list) {
-  ScopedPtrDeque<DrawPolygon> front_list;
-  ScopedPtrDeque<DrawPolygon> back_list;
+                        std::deque<scoped_ptr<DrawPolygon>>* polygon_list) {
+  std::deque<scoped_ptr<DrawPolygon>> front_list;
+  std::deque<scoped_ptr<DrawPolygon>> back_list;
 
   // We take in a list of polygons at this level of the tree, and have to
   // find a splitting plane, then classify polygons as either in front of
   // or behind that splitting plane.
-  while (polygon_list->size() > 0) {
+  while (!polygon_list->empty()) {
     // Is this particular polygon in front of or behind our splitting polygon.
     BspCompareResult comparer_result =
         GetNodePositionRelative(*polygon_list->front(), *(node->node_data));
@@ -52,10 +52,10 @@
     // or front of the list.
     switch (comparer_result) {
       case BSP_FRONT:
-        front_list.push_back(polygon_list->take_front().Pass());
+        front_list.push_back(PopFront(polygon_list));
         break;
       case BSP_BACK:
-        back_list.push_back(polygon_list->take_front().Pass());
+        back_list.push_back(PopFront(polygon_list));
         break;
       case BSP_SPLIT:
       {
@@ -63,7 +63,7 @@
         scoped_ptr<DrawPolygon> new_front;
         scoped_ptr<DrawPolygon> new_back;
         // Time to split this geometry, *it needs to be split by node_data.
-        polygon = polygon_list->take_front();
+        polygon = PopFront(polygon_list);
         bool split_result =
             polygon->Split(*(node->node_data), &new_front, &new_back);
         DCHECK(split_result);
@@ -75,10 +75,10 @@
         break;
       }
       case BSP_COPLANAR_FRONT:
-        node->coplanars_front.push_back(polygon_list->take_front());
+        node->coplanars_front.push_back(PopFront(polygon_list));
         break;
       case BSP_COPLANAR_BACK:
-        node->coplanars_back.push_back(polygon_list->take_front());
+        node->coplanars_back.push_back(PopFront(polygon_list));
         break;
       default:
         NOTREACHED();
@@ -88,14 +88,13 @@
 
   // Build the back subtree using the front of the back_list as our splitter.
   if (back_list.size() > 0) {
-    node->back_child = make_scoped_ptr(new BspNode(back_list.take_front()));
+    node->back_child = make_scoped_ptr(new BspNode(PopFront(&back_list)));
     BuildTree(node->back_child.get(), &back_list);
   }
 
   // Build the front subtree using the front of the front_list as our splitter.
   if (front_list.size() > 0) {
-    node->front_child =
-        scoped_ptr<BspNode>(new BspNode(front_list.take_front()));
+    node->front_child = make_scoped_ptr(new BspNode(PopFront(&front_list)));
     BuildTree(node->front_child.get(), &front_list);
   }
 }
diff --git a/cc/output/bsp_tree.h b/cc/output/bsp_tree.h
index 29c8605..0a0b948 100644
--- a/cc/output/bsp_tree.h
+++ b/cc/output/bsp_tree.h
@@ -5,10 +5,10 @@
 #ifndef CC_OUTPUT_BSP_TREE_H_
 #define CC_OUTPUT_BSP_TREE_H_
 
+#include <deque>
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
-#include "cc/base/scoped_ptr_deque.h"
 #include "cc/base/scoped_ptr_vector.h"
 #include "cc/output/bsp_compare_result.h"
 #include "cc/quads/draw_polygon.h"
@@ -31,7 +31,7 @@
 
 class CC_EXPORT BspTree {
  public:
-  explicit BspTree(ScopedPtrDeque<DrawPolygon>* list);
+  explicit BspTree(std::deque<scoped_ptr<DrawPolygon>>* list);
   scoped_ptr<BspNode>& root() { return root_; }
 
   template <typename ActionHandlerType>
@@ -47,7 +47,7 @@
   scoped_ptr<BspNode> root_;
 
   void FromList(ScopedPtrVector<DrawPolygon>* list);
-  void BuildTree(BspNode* node, ScopedPtrDeque<DrawPolygon>* data);
+  void BuildTree(BspNode* node, std::deque<scoped_ptr<DrawPolygon>>* data);
 
   template <typename ActionHandlerType>
   void WalkInOrderAction(ActionHandlerType* action_handler,
diff --git a/cc/output/bsp_tree_unittest.cc b/cc/output/bsp_tree_unittest.cc
index 100bc91..18e65a54 100644
--- a/cc/output/bsp_tree_unittest.cc
+++ b/cc/output/bsp_tree_unittest.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <deque>
+
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "cc/base/scoped_ptr_deque.h"
 #include "cc/base/scoped_ptr_vector.h"
 #include "cc/output/bsp_tree.h"
 #include "cc/output/bsp_walk_action.h"
@@ -30,7 +31,7 @@
 
 class BspTreeTest {
  public:
-  static void RunTest(ScopedPtrDeque<DrawPolygon>* test_polygons,
+  static void RunTest(std::deque<scoped_ptr<DrawPolygon>>* test_polygons,
                       const std::vector<int>& compare_list) {
     BspTree bsp_tree(test_polygons);
 
@@ -113,7 +114,7 @@
   scoped_ptr<DrawPolygon> polygon_c(
       CREATE_DRAW_POLYGON(vertices_c, gfx::Vector3dF(0.0f, 0.0f, 1.0f), 2));
 
-  ScopedPtrDeque<DrawPolygon> polygon_list;
+  std::deque<scoped_ptr<DrawPolygon>> polygon_list;
   polygon_list.push_back(polygon_a.Pass());
   polygon_list.push_back(polygon_b.Pass());
   polygon_list.push_back(polygon_c.Pass());
@@ -141,7 +142,7 @@
   scoped_ptr<DrawPolygon> polygon_b(
       CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1));
 
-  ScopedPtrDeque<DrawPolygon> polygon_list;
+  std::deque<scoped_ptr<DrawPolygon>> polygon_list;
   polygon_list.push_back(polygon_a.Pass());
   polygon_list.push_back(polygon_b.Pass());
 
@@ -170,7 +171,7 @@
   scoped_ptr<DrawPolygon> polygon_b(
       CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1));
 
-  ScopedPtrDeque<DrawPolygon> polygon_list;
+  std::deque<scoped_ptr<DrawPolygon>> polygon_list;
   polygon_list.push_back(polygon_a.Pass());
   polygon_list.push_back(polygon_b.Pass());
 
@@ -199,7 +200,7 @@
   scoped_ptr<DrawPolygon> polygon_b(
       CREATE_DRAW_POLYGON(vertices_b, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 1));
 
-  ScopedPtrDeque<DrawPolygon> polygon_list;
+  std::deque<scoped_ptr<DrawPolygon>> polygon_list;
   polygon_list.push_back(polygon_b.Pass());
   polygon_list.push_back(polygon_a.Pass());
 
@@ -235,7 +236,7 @@
   scoped_ptr<DrawPolygon> polygon_c(
       CREATE_DRAW_POLYGON(vertices_c, gfx::Vector3dF(0.0f, 1.0f, 0.0f), 2));
 
-  ScopedPtrDeque<DrawPolygon> polygon_list;
+  std::deque<scoped_ptr<DrawPolygon>> polygon_list;
   polygon_list.push_back(polygon_a.Pass());
   polygon_list.push_back(polygon_b.Pass());
   polygon_list.push_back(polygon_c.Pass());
@@ -276,7 +277,7 @@
   scoped_ptr<DrawPolygon> polygon_f = polygon_c->CreateCopy();
 
   {
-    ScopedPtrDeque<DrawPolygon> polygon_list;
+    std::deque<scoped_ptr<DrawPolygon>> polygon_list;
     polygon_list.push_back(polygon_a.Pass());
     polygon_list.push_back(polygon_b.Pass());
     polygon_list.push_back(polygon_c.Pass());
@@ -288,7 +289,7 @@
 
   // Now check a different order and ensure we get that back as well
   {
-    ScopedPtrDeque<DrawPolygon> polygon_list;
+    std::deque<scoped_ptr<DrawPolygon>> polygon_list;
     polygon_list.push_back(polygon_f.Pass());
     polygon_list.push_back(polygon_d.Pass());
     polygon_list.push_back(polygon_e.Pass());
@@ -333,7 +334,7 @@
   scoped_ptr<DrawPolygon> polygon_d(
       CREATE_DRAW_POLYGON(vertices_d, gfx::Vector3dF(-1.0f, 0.0f, 0.0f), 3));
 
-  ScopedPtrDeque<DrawPolygon> polygon_list;
+  std::deque<scoped_ptr<DrawPolygon>> polygon_list;
   polygon_list.push_back(polygon_a.Pass());
   polygon_list.push_back(polygon_b.Pass());
   polygon_list.push_back(polygon_c.Pass());
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 43e19c3..16dcd5a3 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -404,10 +404,11 @@
   }
 }
 
-void DirectRenderer::FlushPolygons(ScopedPtrDeque<DrawPolygon>* poly_list,
-                                   DrawingFrame* frame,
-                                   const gfx::Rect& render_pass_scissor,
-                                   bool use_render_pass_scissor) {
+void DirectRenderer::FlushPolygons(
+    std::deque<scoped_ptr<DrawPolygon>>* poly_list,
+    DrawingFrame* frame,
+    const gfx::Rect& render_pass_scissor,
+    bool use_render_pass_scissor) {
   if (poly_list->empty()) {
     return;
   }
@@ -473,7 +474,7 @@
       MoveFromDrawToWindowSpace(frame, render_pass_scissor_in_draw_space));
 
   const QuadList& quad_list = render_pass->quad_list;
-  ScopedPtrDeque<DrawPolygon> poly_list;
+  std::deque<scoped_ptr<DrawPolygon>> poly_list;
 
   int next_polygon_id = 0;
   int last_sorting_context_id = 0;
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index 87e64d6..be72632 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -9,7 +9,6 @@
 #include "base/callback.h"
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "cc/base/cc_export.h"
-#include "cc/base/scoped_ptr_deque.h"
 #include "cc/output/overlay_processor.h"
 #include "cc/output/renderer.h"
 #include "cc/raster/task_graph_runner.h"
@@ -104,7 +103,7 @@
 
   static gfx::Size RenderPassTextureSize(const RenderPass* render_pass);
 
-  void FlushPolygons(ScopedPtrDeque<DrawPolygon>* poly_list,
+  void FlushPolygons(std::deque<scoped_ptr<DrawPolygon>>* poly_list,
                      DrawingFrame* frame,
                      const gfx::Rect& render_pass_scissor,
                      bool use_render_pass_scissor);
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 22fea9e5..22e2cb81 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -17,6 +17,7 @@
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
 #include "base/trace_event/trace_event.h"
+#include "cc/base/container_util.h"
 #include "cc/base/math_util.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/output/compositor_frame_metadata.h"
@@ -474,12 +475,12 @@
       if (pending_sync_queries_.front()->IsPending())
         break;
 
-      available_sync_queries_.push_back(pending_sync_queries_.take_front());
+      available_sync_queries_.push_back(PopFront(&pending_sync_queries_));
     }
 
     current_sync_query_ = available_sync_queries_.empty()
                               ? make_scoped_ptr(new SyncQuery(gl_))
-                              : available_sync_queries_.take_front();
+                              : PopFront(&available_sync_queries_);
 
     read_lock_fence = current_sync_query_->Begin();
   } else {
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index a090324b..0aa4e8f 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -5,9 +5,10 @@
 #ifndef CC_OUTPUT_GL_RENDERER_H_
 #define CC_OUTPUT_GL_RENDERER_H_
 
+#include <deque>
+
 #include "base/cancelable_callback.h"
 #include "cc/base/cc_export.h"
-#include "cc/base/scoped_ptr_deque.h"
 #include "cc/base/scoped_ptr_vector.h"
 #include "cc/output/direct_renderer.h"
 #include "cc/output/gl_renderer_draw_cache.h"
@@ -504,8 +505,8 @@
   scoped_ptr<ResourceProvider::ScopedWriteLockGL> current_framebuffer_lock_;
 
   class SyncQuery;
-  ScopedPtrDeque<SyncQuery> pending_sync_queries_;
-  ScopedPtrDeque<SyncQuery> available_sync_queries_;
+  std::deque<scoped_ptr<SyncQuery>> pending_sync_queries_;
+  std::deque<scoped_ptr<SyncQuery>> available_sync_queries_;
   scoped_ptr<SyncQuery> current_sync_query_;
   bool use_sync_query_;
   bool use_blend_equation_advanced_;
diff --git a/cc/raster/one_copy_tile_task_worker_pool.cc b/cc/raster/one_copy_tile_task_worker_pool.cc
index 5e31746..5aa1aaa 100644
--- a/cc/raster/one_copy_tile_task_worker_pool.cc
+++ b/cc/raster/one_copy_tile_task_worker_pool.cc
@@ -12,6 +12,7 @@
 #include "base/trace_event/memory_dump_manager.h"
 #include "base/trace_event/trace_event.h"
 #include "base/trace_event/trace_event_argument.h"
+#include "cc/base/container_util.h"
 #include "cc/base/math_util.h"
 #include "cc/debug/traced_value.h"
 #include "cc/raster/raster_buffer.h"
@@ -613,8 +614,8 @@
       if (!CheckForQueryResult(gl, busy_buffers_.front()->query_id))
         break;
 
-      MarkStagingBufferAsFree(busy_buffers_.front());
-      free_buffers_.push_back(busy_buffers_.take_front());
+      MarkStagingBufferAsFree(busy_buffers_.front().get());
+      free_buffers_.push_back(PopFront(&busy_buffers_));
     }
   }
 
@@ -628,14 +629,14 @@
 
     if (resource_provider_->use_sync_query()) {
       WaitForQueryResult(gl, busy_buffers_.front()->query_id);
-      MarkStagingBufferAsFree(busy_buffers_.front());
-      free_buffers_.push_back(busy_buffers_.take_front());
+      MarkStagingBufferAsFree(busy_buffers_.front().get());
+      free_buffers_.push_back(PopFront(&busy_buffers_));
     } else {
       // Fall-back to glFinish if CHROMIUM_sync_query is not available.
       gl->Finish();
       while (!busy_buffers_.empty()) {
-        MarkStagingBufferAsFree(busy_buffers_.front());
-        free_buffers_.push_back(busy_buffers_.take_front());
+        MarkStagingBufferAsFree(busy_buffers_.front().get());
+        free_buffers_.push_back(PopFront(&busy_buffers_));
       }
     }
   }
@@ -643,13 +644,14 @@
   // Find a staging buffer that allows us to perform partial raster when
   // using persistent GpuMemoryBuffers.
   if (use_partial_raster_ && previous_content_id) {
-    StagingBufferDeque::iterator it =
-        std::find_if(free_buffers_.begin(), free_buffers_.end(),
-                     [previous_content_id](const StagingBuffer* buffer) {
-                       return buffer->content_id == previous_content_id;
-                     });
+    StagingBufferDeque::iterator it = std::find_if(
+        free_buffers_.begin(), free_buffers_.end(),
+        [previous_content_id](const scoped_ptr<StagingBuffer>& buffer) {
+          return buffer->content_id == previous_content_id;
+        });
     if (it != free_buffers_.end()) {
-      staging_buffer = free_buffers_.take(it);
+      staging_buffer = it->Pass();
+      free_buffers_.erase(it);
       MarkStagingBufferAsBusy(staging_buffer.get());
     }
   }
@@ -658,12 +660,13 @@
   if (!staging_buffer) {
     StagingBufferDeque::iterator it =
         std::find_if(free_buffers_.begin(), free_buffers_.end(),
-                     [resource](const StagingBuffer* buffer) {
+                     [resource](const scoped_ptr<StagingBuffer>& buffer) {
                        return buffer->size == resource->size() &&
                               buffer->format == resource->format();
                      });
     if (it != free_buffers_.end()) {
-      staging_buffer = free_buffers_.take(it);
+      staging_buffer = it->Pass();
+      free_buffers_.erase(it);
       MarkStagingBufferAsBusy(staging_buffer.get());
     }
   }
@@ -681,9 +684,9 @@
       break;
 
     free_buffers_.front()->DestroyGLResources(gl);
-    MarkStagingBufferAsBusy(free_buffers_.front());
-    RemoveStagingBuffer(free_buffers_.front());
-    free_buffers_.take_front();
+    MarkStagingBufferAsBusy(free_buffers_.front().get());
+    RemoveStagingBuffer(free_buffers_.front().get());
+    free_buffers_.pop_front();
   }
 
   return staging_buffer.Pass();
@@ -763,9 +766,9 @@
         return;
 
       free_buffers_.front()->DestroyGLResources(gl);
-      MarkStagingBufferAsBusy(free_buffers_.front());
-      RemoveStagingBuffer(free_buffers_.front());
-      free_buffers_.take_front();
+      MarkStagingBufferAsBusy(free_buffers_.front().get());
+      RemoveStagingBuffer(free_buffers_.front().get());
+      free_buffers_.pop_front();
     }
 
     while (!busy_buffers_.empty()) {
@@ -773,8 +776,8 @@
         return;
 
       busy_buffers_.front()->DestroyGLResources(gl);
-      RemoveStagingBuffer(busy_buffers_.front());
-      busy_buffers_.take_front();
+      RemoveStagingBuffer(busy_buffers_.front().get());
+      busy_buffers_.pop_front();
     }
   }
 }
diff --git a/cc/raster/one_copy_tile_task_worker_pool.h b/cc/raster/one_copy_tile_task_worker_pool.h
index a582c4e..08445b0 100644
--- a/cc/raster/one_copy_tile_task_worker_pool.h
+++ b/cc/raster/one_copy_tile_task_worker_pool.h
@@ -5,6 +5,7 @@
 #ifndef CC_RASTER_ONE_COPY_TILE_TASK_WORKER_POOL_H_
 #define CC_RASTER_ONE_COPY_TILE_TASK_WORKER_POOL_H_
 
+#include <deque>
 #include <set>
 
 #include "base/memory/weak_ptr.h"
@@ -12,7 +13,6 @@
 #include "base/time/time.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "base/values.h"
-#include "cc/base/scoped_ptr_deque.h"
 #include "cc/output/context_provider.h"
 #include "cc/raster/tile_task_runner.h"
 #include "cc/raster/tile_task_worker_pool.h"
@@ -152,7 +152,7 @@
   // |lock_| must be acquired when accessing the following members.
   using StagingBufferSet = std::set<const StagingBuffer*>;
   StagingBufferSet buffers_;
-  using StagingBufferDeque = ScopedPtrDeque<StagingBuffer>;
+  using StagingBufferDeque = std::deque<scoped_ptr<StagingBuffer>>;
   StagingBufferDeque free_buffers_;
   StagingBufferDeque busy_buffers_;
   int bytes_scheduled_since_last_flush_;
diff --git a/cc/raster/task_graph_runner_unittest.cc b/cc/raster/task_graph_runner_unittest.cc
index eb9b6d9..31144e72 100644
--- a/cc/raster/task_graph_runner_unittest.cc
+++ b/cc/raster/task_graph_runner_unittest.cc
@@ -4,12 +4,13 @@
 
 #include "cc/raster/task_graph_runner.h"
 
+#include <deque>
 #include <vector>
 
 #include "base/bind.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/simple_thread.h"
-#include "cc/base/scoped_ptr_deque.h"
+#include "cc/base/container_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
@@ -181,8 +182,8 @@
   }
   void TearDown() override {
     task_graph_runner_->Shutdown();
-    while (workers_.size()) {
-      scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front();
+    while (!workers_.empty()) {
+      scoped_ptr<base::DelegateSimpleThread> worker = PopFront(&workers_);
       worker->Join();
     }
   }
@@ -191,7 +192,7 @@
   // Overridden from base::DelegateSimpleThread::Delegate:
   void Run() override { task_graph_runner_->Run(); }
 
-  ScopedPtrDeque<base::DelegateSimpleThread> workers_;
+  std::deque<scoped_ptr<base::DelegateSimpleThread>> workers_;
 };
 
 TEST_P(TaskGraphRunnerTest, Basic) {
diff --git a/cc/resources/resource_pool.cc b/cc/resources/resource_pool.cc
index 28ab249..c6f9cbb 100644
--- a/cc/resources/resource_pool.cc
+++ b/cc/resources/resource_pool.cc
@@ -10,6 +10,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/trace_event/memory_dump_manager.h"
+#include "cc/base/container_util.h"
 #include "cc/resources/resource_provider.h"
 #include "cc/resources/resource_util.h"
 #include "cc/resources/scoped_resource.h"
@@ -79,7 +80,7 @@
   DCHECK_EQ(0u, in_use_resources_.size());
 
   while (!busy_resources_.empty()) {
-    DidFinishUsingResource(busy_resources_.take_back());
+    DidFinishUsingResource(PopBack(&busy_resources_));
   }
 
   SetResourceUsageLimits(0, 0);
@@ -96,7 +97,7 @@
   // LRU resources within kResourceExpirationDelayMs.
   for (ResourceDeque::iterator it = unused_resources_.begin();
        it != unused_resources_.end(); ++it) {
-    ScopedResource* resource = *it;
+    ScopedResource* resource = it->get();
     DCHECK(resource_provider_->CanLockForWrite(resource->id()));
 
     if (resource->format() != format)
@@ -105,7 +106,8 @@
       continue;
 
     // Transfer resource to |in_use_resources_|.
-    in_use_resources_.set(resource->id(), unused_resources_.take(it));
+    in_use_resources_.set(resource->id(), it->Pass());
+    unused_resources_.erase(it);
     in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
         resource->size(), resource->format());
     return resource;
@@ -137,18 +139,20 @@
 Resource* ResourcePool::TryAcquireResourceWithContentId(uint64_t content_id) {
   DCHECK(content_id);
 
-  auto it = std::find_if(unused_resources_.begin(), unused_resources_.end(),
-                         [content_id](const PoolResource* pool_resource) {
-                           return pool_resource->content_id() == content_id;
-                         });
+  auto it =
+      std::find_if(unused_resources_.begin(), unused_resources_.end(),
+                   [content_id](const scoped_ptr<PoolResource>& pool_resource) {
+                     return pool_resource->content_id() == content_id;
+                   });
   if (it == unused_resources_.end())
     return nullptr;
 
-  Resource* resource = *it;
+  Resource* resource = it->get();
   DCHECK(resource_provider_->CanLockForWrite(resource->id()));
 
   // Transfer resource to |in_use_resources_|.
-  in_use_resources_.set(resource->id(), unused_resources_.take(it));
+  in_use_resources_.set(resource->id(), it->Pass());
+  unused_resources_.erase(it);
   in_use_memory_usage_bytes_ += ResourceUtil::UncheckedSizeInBytes<size_t>(
       resource->size(), resource->format());
   return resource;
@@ -192,7 +196,7 @@
     // can't be locked for write might also not be truly free-able.
     // We can free the resource here but it doesn't mean that the
     // memory is necessarily returned to the OS.
-    DeleteResource(unused_resources_.take_back());
+    DeleteResource(PopBack(&unused_resources_));
   }
 }
 
@@ -214,13 +218,15 @@
 void ResourcePool::CheckBusyResources() {
   for (size_t i = 0; i < busy_resources_.size();) {
     ResourceDeque::iterator it(busy_resources_.begin() + i);
-    PoolResource* resource = *it;
+    PoolResource* resource = it->get();
 
     if (resource_provider_->CanLockForWrite(resource->id())) {
-      DidFinishUsingResource(busy_resources_.take(it));
+      DidFinishUsingResource(it->Pass());
+      busy_resources_.erase(it);
     } else if (resource_provider_->IsLost(resource->id())) {
       // Remove lost resources from pool.
-      DeleteResource(busy_resources_.take(it));
+      DeleteResource(it->Pass());
+      busy_resources_.erase(it);
     } else {
       ++i;
     }
@@ -270,7 +276,7 @@
     if (unused_resources_.back()->last_usage() > time_limit)
       return;
 
-    DeleteResource(unused_resources_.take_back());
+    DeleteResource(PopBack(&unused_resources_));
   }
 
   // Also free busy resources older than the delay. With a sufficiently large
@@ -281,7 +287,7 @@
     if (busy_resources_.back()->last_usage() > time_limit)
       return;
 
-    DeleteResource(busy_resources_.take_back());
+    DeleteResource(PopBack(&busy_resources_));
   }
 }
 
diff --git a/cc/resources/resource_pool.h b/cc/resources/resource_pool.h
index ef99d26..31653c4d 100644
--- a/cc/resources/resource_pool.h
+++ b/cc/resources/resource_pool.h
@@ -11,7 +11,6 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/trace_event/memory_dump_provider.h"
 #include "cc/base/cc_export.h"
-#include "cc/base/scoped_ptr_deque.h"
 #include "cc/output/renderer.h"
 #include "cc/resources/resource.h"
 #include "cc/resources/resource_format.h"
@@ -117,7 +116,7 @@
   size_t total_resource_count_;
 
   // Holds most recently used resources at the front of the queue.
-  using ResourceDeque = ScopedPtrDeque<PoolResource>;
+  using ResourceDeque = std::deque<scoped_ptr<PoolResource>>;
   ResourceDeque unused_resources_;
   ResourceDeque busy_resources_;
 
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 2c567f71..86b6025 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -5,6 +5,7 @@
 #include "cc/resources/resource_provider.h"
 
 #include <algorithm>
+#include <deque>
 #include <map>
 #include <set>
 #include <vector>
@@ -13,7 +14,6 @@
 #include "base/containers/hash_tables.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "cc/base/scoped_ptr_deque.h"
 #include "cc/output/output_surface.h"
 #include "cc/resources/returned_resource.h"
 #include "cc/resources/shared_bitmap_manager.h"
@@ -182,12 +182,11 @@
     uint32 sync_point = shared_data_->InsertSyncPoint();
     // Commit the produceTextureCHROMIUM calls at this point, so that
     // they're associated with the sync point.
-    for (PendingProduceTextureList::iterator it =
-             pending_produce_textures_.begin();
-         it != pending_produce_textures_.end();
-         ++it) {
-      shared_data_->ProduceTexture((*it)->mailbox, gpu::SyncToken(sync_point),
-                                   (*it)->texture);
+    for (const scoped_ptr<PendingProduceTexture>& pending_texture :
+         pending_produce_textures_) {
+      shared_data_->ProduceTexture(pending_texture->mailbox,
+                                   gpu::SyncToken(sync_point),
+                                   pending_texture->texture);
     }
     pending_produce_textures_.clear();
     return sync_point;
@@ -357,10 +356,9 @@
     GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
     scoped_refptr<TestTexture> texture;
   };
-  typedef ScopedPtrDeque<PendingProduceTexture> PendingProduceTextureList;
   ContextSharedData* shared_data_;
   gpu::SyncToken last_waited_sync_token_;
-  PendingProduceTextureList pending_produce_textures_;
+  std::deque<scoped_ptr<PendingProduceTexture>> pending_produce_textures_;
 };
 
 void GetResourcePixels(ResourceProvider* resource_provider,
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc
index 02c23af..a56560f 100644
--- a/cc/test/test_in_process_context_provider.cc
+++ b/cc/test/test_in_process_context_provider.cc
@@ -114,8 +114,8 @@
   g_gles2_initializer.Get();
   gles2::SetGLContext(ContextGL());
 
-  skia::RefPtr<GrGLInterface> interface =
-      skia::AdoptRef(skia_bindings::CreateCommandBufferSkiaGLBinding());
+  skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(new GrGLInterface);
+  skia_bindings::InitCommandBufferSkiaGLBinding(interface.get());
   interface->fCallback = BindGrContextCallback;
   interface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
 
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc
index 357db7c6..968224f 100644
--- a/cc/trees/layer_tree_host_common_perftest.cc
+++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -4,6 +4,7 @@
 
 #include "cc/trees/layer_tree_host_common.h"
 
+#include <deque>
 #include <sstream>
 
 #include "base/files/file_path.h"
@@ -13,7 +14,6 @@
 #include "base/strings/string_piece.h"
 #include "base/threading/thread.h"
 #include "base/time/time.h"
-#include "cc/base/scoped_ptr_deque.h"
 #include "cc/base/scoped_ptr_vector.h"
 #include "cc/debug/lap_timer.h"
 #include "cc/layers/layer.h"
@@ -165,7 +165,7 @@
 
     timer_.Reset();
     do {
-      ScopedPtrDeque<DrawPolygon> test_list;
+      std::deque<scoped_ptr<DrawPolygon>> test_list;
       for (int i = 0; i < num_duplicates_; i++) {
         for (size_t i = 0; i < polygon_list.size(); i++) {
           test_list.push_back(polygon_list[i]->CreateCopy());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 9c04c7e..3ceb3e1 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -4776,8 +4776,11 @@
   int will_begin_impl_frame_count_;
 };
 
-SINGLE_AND_MULTI_THREAD_TEST_F(
-    LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime);
+// TODO(mithro): Re-enable the multi-threaded version of this test
+// http://crbug.com/537621
+// SINGLE_AND_MULTI_THREAD_TEST_F(
+//    LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime);
+SINGLE_THREAD_TEST_F(LayerTreeHostTestBeginMainFrameTimeIsAlsoImplTime);
 
 class LayerTreeHostTestSendBeginFramesToChildren : public LayerTreeHostTest {
  public:
diff --git a/chrome/VERSION b/chrome/VERSION
index fc86763..50c1ed06 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
-MAJOR=48
+MAJOR=49
 MINOR=0
-BUILD=2563
+BUILD=2565
 PATCH=0
diff --git a/chrome/android/chrome_apk.gyp b/chrome/android/chrome_apk.gyp
index 5f11ad8..b7b31a80 100644
--- a/chrome/android/chrome_apk.gyp
+++ b/chrome/android/chrome_apk.gyp
@@ -240,6 +240,8 @@
         'apk_name': 'ChromeSyncShell',
         'native_lib_target': 'libchrome_sync_shell',
         'java_in_dir': 'java',
+        'enable_multidex': 1,
+        'enable_multidex_configurations': ['Debug'],
         'conditions': [
           # Only attempt loading the library from the APK for 64 bit devices
           # until the number of 32 bit devices which don't support this
diff --git a/chrome/android/java/res/layout/new_tab_page.xml b/chrome/android/java/res/layout/new_tab_page.xml
index 7ffd3227..e59ca3e 100644
--- a/chrome/android/java/res/layout/new_tab_page.xml
+++ b/chrome/android/java/res/layout/new_tab_page.xml
@@ -126,6 +126,13 @@
                 android:inflatedId="@+id/most_visited_placeholder"
                 android:layout="@layout/most_visited_placeholder" />
 
+            <android.support.v7.widget.RecyclerView
+                android:id="@+id/snippets_card_list"
+                android:scrollbars="none"
+                android:visibility="gone"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
             <!-- Spacer -->
             <View
                 android:id="@+id/ntp_bottom_spacer"
diff --git a/chrome/android/java/res/layout/new_tab_page_snippets_card.xml b/chrome/android/java/res/layout/new_tab_page_snippets_card.xml
new file mode 100644
index 0000000..b8f28931
--- /dev/null
+++ b/chrome/android/java/res/layout/new_tab_page_snippets_card.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 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. -->
+
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/snippets_card_view"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:background="@drawable/bg_find_toolbar_popup">
+    
+    <ImageView
+        android:id="@+id/article_thumbnail"
+        android:layout_width="@dimen/snippets_thumbnail_size"
+        android:layout_height="@dimen/snippets_thumbnail_size"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentStart="true"           
+        android:contentDescription="@null"
+        android:padding="8dp"            
+        android:src="@null"/>
+    
+    <TextView
+        android:id="@+id/article_headline"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_toEndOf="@+id/article_thumbnail"
+        android:maxLines="2"
+        android:paddingTop="8dp"
+        android:paddingStart="8dp"
+        android:paddingEnd="8dp"                
+        android:textSize="18sp"
+        android:textColor="@color/snippets_headline_text_color" />
+    
+    <TextView
+        android:id="@+id/article_publisher"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@+id/article_headline"
+        android:layout_toEndOf="@+id/article_thumbnail"                
+        android:ellipsize="end"
+        android:maxLines="1"                
+        android:padding="8dp"
+        android:textSize="14sp"
+        android:textColor="@color/snippets_publisher_name_color" />
+    
+    <TextView
+        android:id="@+id/article_snippet"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_below="@+id/article_thumbnail"
+        android:padding="8dp"
+        android:textSize="14sp"
+        android:textColor="@color/snippets_text_color"
+        android:visibility="gone" />
+            
+     <TextView
+        android:id="@+id/read_more_link"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_below="@+id/article_snippet"
+        android:padding="16dp"
+        android:text="@string/snippets_ntp_read_more_link_text"
+        android:textAllCaps="true"
+        android:textSize="14sp"
+        android:textColor="@color/snippets_read_more_link_color"
+        android:visibility="gone" />
+     
+</RelativeLayout>
diff --git a/chrome/android/java/res/layout/new_tab_page_snippets_header.xml b/chrome/android/java/res/layout/new_tab_page_snippets_header.xml
new file mode 100644
index 0000000..df57123
--- /dev/null
+++ b/chrome/android/java/res/layout/new_tab_page_snippets_header.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2015 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. -->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/snippets_list_header"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_margin="8dp"
+    android:text="@string/snippets_header"
+    android:textColor="@color/snippets_list_header_text_color"
+    android:textSize="18sp" />
diff --git a/chrome/android/java/res/layout/reader_mode_control.xml b/chrome/android/java/res/layout/reader_mode_control.xml
deleted file mode 100644
index 64a44088..0000000
--- a/chrome/android/java/res/layout/reader_mode_control.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 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. -->
-
-<!-- Reader Mode view. -->
-<org.chromium.chrome.browser.widget.ReaderModeControl
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/reader_mode_view"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center_vertical"
-    android:background="#FFF"
-    android:gravity="center_vertical|start"
-    android:orientation="vertical"
-    >
-
-    <!-- Lint flags this as a false positive overlap. -->
-    <!--suppress RelativeOverlap -->
-    <RelativeLayout
-        android:layout_width="match_parent"
-        android:layout_height="56dp">
-        <ImageView
-            android:id="@+id/main_icon"
-            android:src="@drawable/infobar_mobile_friendly"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="16dp"
-            android:layout_alignParentStart="true"
-            android:layout_centerVertical="true"
-            android:contentDescription="@null"
-            />
-        <TextView
-            android:id="@+id/main_text"
-            android:text="@string/reader_view_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="8dp"
-            android:layout_marginEnd="8dp"
-            android:layout_toEndOf="@id/main_icon"
-            android:layout_toStartOf="@+id/main_close"
-            android:layout_centerVertical="true"
-            android:ellipsize="end"
-            android:singleLine="true"
-            android:fontFamily="sans-serif"
-            android:textColor="#333333"
-            android:textSize="@dimen/reader_mode_text_size"
-            />
-        <ImageView
-            android:id="@+id/main_close"
-            android:src="@drawable/btn_close"
-            android:layout_width="48dp"
-            android:layout_height="48dp"
-            android:scaleType="centerInside"
-            android:layout_marginEnd="16dp"
-            android:layout_alignParentEnd="true"
-            android:layout_centerVertical="true"
-            android:contentDescription="@string/close"
-            />
-    </RelativeLayout>
-</org.chromium.chrome.browser.widget.ReaderModeControl>
diff --git a/chrome/android/java/res/values-sw600dp/dimens.xml b/chrome/android/java/res/values-sw600dp/dimens.xml
index 346f1f69..19e81540 100644
--- a/chrome/android/java/res/values-sw600dp/dimens.xml
+++ b/chrome/android/java/res/values-sw600dp/dimens.xml
@@ -7,7 +7,7 @@
     <!-- Menu Dimensions -->
     <!-- Necessary to align the menu icon with the actual button. -->
     <dimen name="menu_negative_software_vertical_offset">6dp</dimen>
-    
+
     <!-- Tab title -->
     <dimen name="tab_title_favicon_start_padding">0dp</dimen>
     <dimen name="tab_title_favicon_end_padding">5dp</dimen>
@@ -45,6 +45,7 @@
     <!-- NTP dimensions -->
     <dimen name="most_visited_spacing">16dp</dimen>
     <dimen name="ntp_logo_height">180dp</dimen>
+    <dimen name="snippets_thumbnail_size">120dp</dimen>
 
     <!-- Recent tabs page -->
     <dimen name="recent_tabs_visible_separator_padding">28dp</dimen>
diff --git a/chrome/android/java/res/values/colors.xml b/chrome/android/java/res/values/colors.xml
index bd5080b..c1ecf5f 100644
--- a/chrome/android/java/res/values/colors.xml
+++ b/chrome/android/java/res/values/colors.xml
@@ -97,6 +97,11 @@
     <color name="ntp_list_header_text">#333</color>
     <color name="ntp_list_header_subtext">#969696</color>
     <color name="ntp_list_header_subtext_active">#7cadff</color>
+    <color name="snippets_publisher_name_color">#7f7f7f</color>
+    <color name="snippets_text_color">#7f7f7f</color>
+    <color name="snippets_list_header_text_color">#7f7f7f</color>
+    <color name="snippets_headline_text_color">#000000</color>
+    <color name="snippets_read_more_link_color">@color/light_active_color</color>
 
     <!-- Signin promo screen colors -->
     <color name="illustration_background_color">#4FC3F7</color>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index 930f9de5..dd1ad804 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -262,6 +262,7 @@
     <dimen name="ntp_list_item_text_size">16sp</dimen>
     <dimen name="ntp_list_item_favicon_container_size">24dp</dimen>
     <dimen name="ntp_shadow_height">9dp</dimen>
+    <dimen name="snippets_thumbnail_size">90dp</dimen>
 
     <!-- Bookmarks page -->
     <dimen name="bookmark_folder_min_height">48dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 1b4cc4b..b8ba464 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -40,6 +40,9 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.BaseSwitches;
@@ -72,7 +75,6 @@
 import org.chromium.chrome.browser.datausage.DataUseTabUIManager;
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.dom_distiller.DistilledPagePrefsView;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeActivityDelegate;
 import org.chromium.chrome.browser.dom_distiller.ReaderModeManager;
 import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils;
 import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarksModel;
@@ -134,6 +136,8 @@
 import org.chromium.ui.base.PageTransition;
 import org.chromium.ui.base.WindowAndroid;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 
@@ -203,7 +207,7 @@
     private ChromeFullscreenManager mFullscreenManager;
     private CompositorViewHolder mCompositorViewHolder;
     private ContextualSearchManager mContextualSearchManager;
-    private ReaderModeActivityDelegate mReaderModeActivityDelegate;
+    private ReaderModeManager mReaderModeManager;
     private SnackbarManager mSnackbarManager;
     private LoFiBarPopupController mLoFiBarPopupController;
     private DataUseSnackbarController mDataUseSnackbarController;
@@ -442,7 +446,7 @@
         }
 
         if (ReaderModeManager.isEnabled(this)) {
-            mReaderModeActivityDelegate = new ReaderModeActivityDelegate(this);
+            mReaderModeManager = new ReaderModeManager(getTabModelSelector(), this);
         }
 
         TraceEvent.end("ChromeActivity:CompositorInitialization");
@@ -678,6 +682,7 @@
                     mInflateInitialLayoutDurationMs, TimeUnit.MILLISECONDS);
             mToolbarManager.onDeferredStartup(getOnCreateTimestampMs(), simpleName);
         }
+        recordKeyboardLocaleUma();
     }
 
     @Override
@@ -747,9 +752,9 @@
     @SuppressLint("NewApi")
     @Override
     protected final void onDestroy() {
-        if (mReaderModeActivityDelegate != null) {
-            mReaderModeActivityDelegate.destroy();
-            mReaderModeActivityDelegate = null;
+        if (mReaderModeManager != null) {
+            mReaderModeManager.destroy();
+            mReaderModeManager = null;
         }
 
         if (mContextualSearchManager != null) {
@@ -1194,14 +1199,6 @@
     }
 
     /**
-     * @return A {@link ReaderModeActivityDelegate} instance or {@code null} if reader mode is
-     *         not enabled.
-     */
-    public ReaderModeActivityDelegate getReaderModeActivityDelegate() {
-        return mReaderModeActivityDelegate;
-    }
-
-    /**
      * Create a full-screen manager to be used by this activity.
      * @param controlContainer The control container that will be controlled by the full-screen
      *                         manager.
@@ -1253,12 +1250,6 @@
             mContextualSearchManager.setSearchContentViewDelegate(layoutManager);
         }
 
-        if (mReaderModeActivityDelegate != null) {
-            mReaderModeActivityDelegate.initialize(contentContainer);
-            mReaderModeActivityDelegate.setDynamicResourceLoader(
-                    mCompositorViewHolder.getDynamicResourceLoader());
-        }
-
         layoutManager.addSceneChangeObserver(this);
         mCompositorViewHolder.setLayoutManager(layoutManager);
         mCompositorViewHolder.setFocusable(false);
@@ -1266,7 +1257,8 @@
         mCompositorViewHolder.setFullscreenHandler(mFullscreenManager);
         mCompositorViewHolder.setUrlBar(urlBar);
         mCompositorViewHolder.onFinishNativeInitialization(getTabModelSelector(), this,
-                getTabContentManager(), contentContainer, mContextualSearchManager);
+                getTabContentManager(), contentContainer, mContextualSearchManager,
+                mReaderModeManager);
 
         if (controlContainer != null
                 && DeviceClassManager.enableToolbarSwipe(FeatureUtilities.isDocumentMode(this))) {
@@ -1283,7 +1275,10 @@
 
     @Override
     public void onOrientationChange(int orientation) {
+        // TODO(mdjones): Orientation change for panels should not be handled here. The event
+        // should probably be passed to the OverlayPanelManager.
         if (mContextualSearchManager != null) mContextualSearchManager.onOrientationChange();
+        if (mReaderModeManager != null) mReaderModeManager.onOrientationChange();
         if (mToolbarManager != null) mToolbarManager.onOrientationChange();
     }
 
@@ -1537,6 +1532,34 @@
         }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
+    private void recordKeyboardLocaleUma() {
+        InputMethodManager imm =
+                (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+        List<InputMethodInfo> ims = imm.getEnabledInputMethodList();
+        ArrayList<String> uniqueLanguages = new ArrayList<String>();
+        for (InputMethodInfo method : ims) {
+            List<InputMethodSubtype> submethods =
+                    imm.getEnabledInputMethodSubtypeList(method, true);
+            for (InputMethodSubtype submethod : submethods) {
+                if (submethod.getMode().equals("keyboard")) {
+                    String language = submethod.getLocale().split("_")[0];
+                    if (!uniqueLanguages.contains(language)) {
+                        uniqueLanguages.add(language);
+                    }
+                }
+            }
+        }
+        RecordHistogram.recordCountHistogram("InputMethod.ActiveCount", uniqueLanguages.size());
+
+        InputMethodSubtype current = imm.getCurrentInputMethodSubtype();
+        Locale currentSystemLocale = Locale.getDefault();
+        if (current.getLocale() != null && Locale.getDefault() != null) {
+            boolean match = currentSystemLocale.getLanguage().equalsIgnoreCase(
+                    current.getLocale().split("_")[0]);
+            RecordHistogram.recordBooleanHistogram("InputMethod.MatchesSystemLanguage", match);
+        }
+    }
+
     @Override
     public void terminateIncognitoSession() {}
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
index a408622..f41d9b04 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -94,6 +94,11 @@
      */
     public static final String DISABLE_LOFI_SNACKBAR = "disable-lo-fi-snackbar";
 
+    /**
+     * Enable content snippets on the NTP
+     */
+    public static final String ENABLE_NTP_SNIPPETS = "enable-ntp-snippets";
+
     ///////////////////////////////////////////////////////////////////////////////////////////////
     // Native Switches
     ///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index 2c7a455..6344a84 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -39,6 +39,7 @@
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
 import org.chromium.chrome.browser.device.DeviceClassManager;
+import org.chromium.chrome.browser.dom_distiller.ReaderModeManagerDelegate;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager.FullscreenListener;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
@@ -776,14 +777,16 @@
      * @param androidContentContainer The {@link ViewGroup} the {@link LayoutManager} should bind
      *                                Android content to.
      * @param contextualSearchManager A {@link ContextualSearchManagementDelegate} instance.
+     * @param readerModeManager       A {@link ReaderModeManagerDelegate} instance.
      */
     public void onFinishNativeInitialization(TabModelSelector tabModelSelector,
             TabCreatorManager tabCreatorManager, TabContentManager tabContentManager,
             ViewGroup androidContentContainer,
-            ContextualSearchManagementDelegate contextualSearchManager) {
+            ContextualSearchManagementDelegate contextualSearchManager,
+            ReaderModeManagerDelegate readerModeManager) {
         assert mLayoutManager != null;
         mLayoutManager.init(tabModelSelector, tabCreatorManager, tabContentManager,
-                androidContentContainer, contextualSearchManager,
+                androidContentContainer, contextualSearchManager, readerModeManager,
                 mCompositorView.getResourceManager().getDynamicResourceLoader());
         mTabModelSelector = tabModelSelector;
         tabModelSelector.addObserver(new EmptyTabModelSelectorObserver() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
index befa592f..1038d34 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanel.java
@@ -64,7 +64,12 @@
         OPTOUT,
         CLOSE_BUTTON,
         SUPPRESS,
-        UNSUPPRESS;
+        UNSUPPRESS,
+        FULLSCREEN_ENTERED,
+        FULLSCREEN_EXITED,
+        INFOBAR_SHOWN,
+        INFOBAR_HIDDEN,
+        CONTENT_CHANGED;
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
index 4dbf65ad..8a3b0cca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelContent.java
@@ -354,7 +354,7 @@
         if (isVisible) {
             // If the last call to loadUrl was sepcified to be delayed, load it now.
             if (!TextUtils.isEmpty(mPendingUrl)) {
-                loadUrl(mPendingUrl, false);
+                loadUrl(mPendingUrl, true);
             }
 
             // The CVC is created with the search request, but if none was made we'll need
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchIconSpriteControl.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchIconSpriteControl.java
index 3e9c3e7..353f4e4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchIconSpriteControl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchIconSpriteControl.java
@@ -32,6 +32,11 @@
     private boolean mShouldAnimateAppearance;
 
     /**
+     * Whether the appearance of the search provider icon sprite is disabled by a field trial.
+     */
+    private boolean mIsAnimationDisabledByTrial;
+
+    /**
      * The completion percentage for the animation; used to calculate which sprite frame to display.
      */
     private float mCompletionPercentage;
@@ -41,7 +46,6 @@
      */
     private ContextualSearchPanel mPanel;
 
-
     /**
      * @param panel The panel.
      * @param context The Android Context used to retrieve resources.
@@ -82,10 +86,13 @@
 
     /**
      * @param shouldAnimateAppearance Whether the appearance of the search provider icon sprite
-     * should be animated.
+     *                                should be animated.
+     * @param isAnimationDisabledByTrial Whether animating the search provider icon is disabled by a
+     *                                   field trial.
      */
-    public void setShouldAnimateAppearance(boolean shouldAnimateAppearance) {
-        if (shouldAnimateAppearance) {
+    public void setShouldAnimateAppearance(boolean shouldAnimateAppearance,
+            boolean isAnimationDisabledByTrial) {
+        if (shouldAnimateAppearance && !isAnimationDisabledByTrial) {
             // The search provider icon sprite should be hidden until the animation starts.
             mIsVisible = false;
             mCompletionPercentage = 0.f;
@@ -94,6 +101,7 @@
             mCompletionPercentage = 1.f;
         }
         mShouldAnimateAppearance = shouldAnimateAppearance;
+        mIsAnimationDisabledByTrial = isAnimationDisabledByTrial;
     }
 
      // ============================================================================================
@@ -107,8 +115,12 @@
     public void animateApperance() {
         // The search provider icon sprite should be visible once the animation starts.
         mIsVisible = true;
-        mPanel.addToAnimation(this, AnimationType.APPEARANCE, 0.f, 1.f,
-                ContextualSearchPanelAnimation.MAXIMUM_ANIMATION_DURATION_MS, 0);
+        if (!mIsAnimationDisabledByTrial) {
+            mPanel.addToAnimation(this, AnimationType.APPEARANCE, 0.f, 1.f,
+                    ContextualSearchPanelAnimation.MAXIMUM_ANIMATION_DURATION_MS, 0);
+        } else {
+            mCompletionPercentage = 1.f;
+        }
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
index adb8741..bc8550d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanel.java
@@ -221,7 +221,10 @@
                 getPeekPromoControl().animateAppearance();
             }
             if (getIconSpriteControl().shouldAnimateAppearance()) {
+                mPanelMetrics.setWasIconSpriteAnimated(true);
                 getIconSpriteControl().animateApperance();
+            } else {
+                mPanelMetrics.setWasIconSpriteAnimated(false);
             }
         }
 
@@ -677,9 +680,13 @@
 
     /**
      * @param shouldAnimateIconSprite Whether the search provider icon sprite should be animated.
+     * @param isAnimationDisabledByTrial Whether animating the search provider icon is disabled by a
+     *                                   field trial.
      */
-    public void setShouldAnimateIconSprite(boolean shouldAnimateIconSprite) {
-        getIconSpriteControl().setShouldAnimateAppearance(shouldAnimateIconSprite);
+    public void setShouldAnimateIconSprite(boolean shouldAnimateIconSprite,
+            boolean isAnimationDisabledByTrial) {
+        getIconSpriteControl().setShouldAnimateAppearance(shouldAnimateIconSprite,
+                isAnimationDisabledByTrial);
     }
 
     // ============================================================================================
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
index 4e5e7a2c..7eb80bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/contextualsearch/ContextualSearchPanelMetrics.java
@@ -25,6 +25,7 @@
     private boolean mIsSerpNavigation;
     private boolean mWasActivatedByTap;
     private boolean mIsSearchPanelFullyPreloaded;
+    private boolean mWasIconSpriteAnimated;
     private long mSearchStartTimeNs;
     private long mSearchViewStartTimeNs;
 
@@ -65,6 +66,9 @@
             } else {
                 ContextualSearchUma.logResultsSeen(mWasSearchContentViewSeen, mWasActivatedByTap);
             }
+
+            ContextualSearchUma.logIconSpriteAnimated(mWasIconSpriteAnimated,
+                    mWasSearchContentViewSeen, mWasActivatedByTap);
         }
         if (isStartingSearch) {
             mSearchStartTimeNs = System.nanoTime();
@@ -154,6 +158,13 @@
     }
 
     /**
+     * @param wasIconSpriteAnimated Whether the search provider icon sprite was animated.
+     */
+    public void setWasIconSpriteAnimated(boolean wasIconSpriteAnimated) {
+        mWasIconSpriteAnimated = wasIconSpriteAnimated;
+    }
+
+    /**
      * Gets whether the promo is active.
      */
     private boolean getIsPromoActive() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
index 6cb14d19..f0fa3933 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/readermode/ReaderModePanel.java
@@ -140,6 +140,8 @@
             if (mManagerDelegate != null) {
                 setChromeActivity(mManagerDelegate.getChromeActivity());
                 initializeUiState();
+                // TODO(mdjones): Improve the base page movement API so that the default behavior
+                // is to hide the toolbar; this function call should not be necessary here.
                 updateBasePageTargetY();
             }
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
index 523c424d..c37a9d9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManager.java
@@ -27,6 +27,7 @@
 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilterHost;
 import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
+import org.chromium.chrome.browser.dom_distiller.ReaderModeManagerDelegate;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -232,11 +233,13 @@
      * @param content                  A {@link TabContentManager} instance.
      * @param androidContentContainer  A {@link ViewGroup} for Android views to be bound to.
      * @param contextualSearchDelegate A {@link ContextualSearchDelegate} instance.
+     * @param readerModeDelegate       A {@link ReaderModeManagerDelegate} instance.
      * @param dynamicResourceLoader    A {@link DynamicResourceLoader} instance.
      */
     public void init(TabModelSelector selector, TabCreatorManager creator,
             TabContentManager content, ViewGroup androidContentContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
+            ReaderModeManagerDelegate readerModeDelegate,
             DynamicResourceLoader dynamicResourceLoader) {
         mTabModelSelector = selector;
         mContentContainer = androidContentContainer;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
index 6c31db92..dbe8b3d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChrome.java
@@ -26,6 +26,7 @@
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
 import org.chromium.chrome.browser.device.DeviceClassManager;
+import org.chromium.chrome.browser.dom_distiller.ReaderModeManagerDelegate;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.EmptyTabModelObserver;
@@ -228,6 +229,7 @@
     public void init(TabModelSelector selector, TabCreatorManager creator,
             TabContentManager content, ViewGroup androidContentContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
+            ReaderModeManagerDelegate readerModeDelegate,
             DynamicResourceLoader dynamicResourceLoader) {
         // TODO: TitleCache should be a part of the ResourceManager.
         mTitleCache = mHost.getTitleCache();
@@ -238,7 +240,7 @@
         if (mOverviewLayout != null) mOverviewLayout.setTabModelSelector(selector, content);
 
         super.init(selector, creator, content, androidContentContainer, contextualSearchDelegate,
-                dynamicResourceLoader);
+                readerModeDelegate, dynamicResourceLoader);
 
         mTabModelSelectorObserver = new EmptyTabModelSelectorObserver() {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
index 9265acbf..b089f8f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromePhone.java
@@ -11,6 +11,7 @@
 import org.chromium.chrome.browser.compositor.layouts.phone.SimpleAnimationLayout;
 import org.chromium.chrome.browser.compositor.overlays.SceneOverlay;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
+import org.chromium.chrome.browser.dom_distiller.ReaderModeManagerDelegate;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
 import org.chromium.chrome.browser.tabmodel.TabModel.TabLaunchType;
@@ -50,12 +51,13 @@
     public void init(TabModelSelector selector, TabCreatorManager creator,
             TabContentManager content, ViewGroup androidContentContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
+            ReaderModeManagerDelegate readerModeDelegate,
             DynamicResourceLoader dynamicResourceLoader) {
         // Initialize Layouts
         mSimpleAnimationLayout.setTabModelSelector(selector, content);
 
         super.init(selector, creator, content, androidContentContainer, contextualSearchDelegate,
-                dynamicResourceLoader);
+                readerModeDelegate, dynamicResourceLoader);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
index 7c91fb0..ba8bf36a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerChromeTablet.java
@@ -21,6 +21,7 @@
 import org.chromium.chrome.browser.compositor.overlays.strip.StripLayoutHelperManager;
 import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchManagementDelegate;
+import org.chromium.chrome.browser.dom_distiller.ReaderModeManagerDelegate;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -137,13 +138,14 @@
     public void init(TabModelSelector selector, TabCreatorManager creator,
             TabContentManager content, ViewGroup androidContentContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
+            ReaderModeManagerDelegate readerModeDelegate,
             DynamicResourceLoader dynamicResourceLoader) {
         if (mTabStripLayoutHelperManager != null) {
             mTabStripLayoutHelperManager.setTabModelSelector(selector, creator, content);
         }
 
         super.init(selector, creator, content, androidContentContainer, contextualSearchDelegate,
-                dynamicResourceLoader);
+                readerModeDelegate, dynamicResourceLoader);
 
         mTabObserver = new TabModelSelectorTabObserver(selector) {
             @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerDocument.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerDocument.java
index b3ed7ec..9056924 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerDocument.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerDocument.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelContentViewDelegate;
 import org.chromium.chrome.browser.compositor.bottombar.OverlayPanelManager;
 import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel;
+import org.chromium.chrome.browser.compositor.bottombar.readermode.ReaderModePanel;
 import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
 import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
 import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
@@ -35,11 +36,7 @@
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchStaticEventFilter;
 import org.chromium.chrome.browser.contextualsearch.ContextualSearchStaticEventFilter.ContextualSearchTapHandler;
 import org.chromium.chrome.browser.device.DeviceClassManager;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeEdgeSwipeHandler;
-import org.chromium.chrome.browser.dom_distiller.ReaderModePanel;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeStaticEventFilter;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeStaticEventFilter.ReaderModePanelSelector;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeStaticEventFilter.ReaderModeTapHandler;
+import org.chromium.chrome.browser.dom_distiller.ReaderModeManagerDelegate;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
@@ -60,8 +57,7 @@
  * driving all {@link Layout}s that get shown via the {@link LayoutManager}.
  */
 public class LayoutManagerDocument extends LayoutManager
-        implements ContextualSearchTapHandler, OverlayPanelContentViewDelegate,
-                ReaderModeTapHandler {
+        implements ContextualSearchTapHandler, OverlayPanelContentViewDelegate {
     // Layouts
     /** A {@link Layout} used for showing a normal web page. */
     protected final StaticLayout mStaticLayout;
@@ -77,17 +73,16 @@
     /** A {@link GestureHandler} that will delegate all events to {@link #getActiveLayout()}. */
     protected final GestureHandler mGestureHandler;
     private final EdgeSwipeHandler mOverlayPanelEdgeSwipeHandler;
-    private final EdgeSwipeHandler mReaderModeEdgeSwipeHandler;
 
     // Internal State
     private final SparseArray<LayoutTab> mTabCache = new SparseArray<LayoutTab>();
     private final ContextualSearchPanel mContextualSearchPanel;
+    private final ReaderModePanel mReaderModePanel;
     private final OverlayPanelManager mOverlayPanelManager;
     /** A delegate for interacting with the Contextual Search manager. */
     protected ContextualSearchManagementDelegate mContextualSearchDelegate;
 
     @SuppressWarnings("unused") private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
-    private final ReaderModePanelSelector mReaderModePanelSelector;
 
     /**
      * Creates a {@link LayoutManagerDocument} instance.
@@ -100,22 +95,10 @@
 
         mOverlayPanelManager = new OverlayPanelManager();
         mContextualSearchPanel = new ContextualSearchPanel(context, this, mOverlayPanelManager);
-
-        mReaderModePanelSelector = new ReaderModePanelSelector() {
-            @Override
-            public ReaderModePanel getActiveReaderModePanel() {
-                if (mStaticLayout == null || !mStaticLayout.isActive()) return null;
-                ReaderModePanel panel = mStaticLayout.getReaderModePanel();
-                if (panel == null) return null;
-                if (!panel.isShowing() || !panel.isReaderModeCurrentlyAllowed()) return null;
-                return panel;
-            }
-        };
+        mReaderModePanel = new ReaderModePanel(context, this, mOverlayPanelManager, this);
 
         // Build Event Filter Handlers
         mOverlayPanelEdgeSwipeHandler = new OverlayPanelEdgeSwipeHandler(this);
-        mReaderModeEdgeSwipeHandler = new ReaderModeEdgeSwipeHandler(
-                mReaderModePanelSelector, this);
         mGestureHandler = new GestureHandlerLayoutDelegate(this);
         mToolbarSwipeHandler = new ToolbarSwipeHandler(this);
 
@@ -126,11 +109,8 @@
                 context, this, mGestureHandler, mOverlayPanelManager);
         EventFilter contextualSearchStaticEventFilter = new ContextualSearchStaticEventFilter(
                 context, this, mOverlayPanelManager, mOverlayPanelEdgeSwipeHandler, this);
-        EventFilter readerModeStaticEventFilter = new ReaderModeStaticEventFilter(
-                context, this, mReaderModePanelSelector, mReaderModeEdgeSwipeHandler, this);
         EventFilter staticCascadeEventFilter = new CascadeEventFilter(context, this,
-                new EventFilter[] {readerModeStaticEventFilter, contextualSearchStaticEventFilter,
-                        mStaticEdgeEventFilter});
+                new EventFilter[] {contextualSearchStaticEventFilter, mStaticEdgeEventFilter});
 
         // Build Layouts
         mStaticLayout = new StaticLayout(
@@ -148,6 +128,7 @@
     public void init(TabModelSelector selector, TabCreatorManager creator,
             TabContentManager content, ViewGroup androidContentContainer,
             ContextualSearchManagementDelegate contextualSearchDelegate,
+            ReaderModeManagerDelegate readerModeDelegate,
             DynamicResourceLoader dynamicResourceLoader) {
         // Save state
         mContextualSearchDelegate = contextualSearchDelegate;
@@ -168,6 +149,14 @@
             contextualSearchDelegate.setContextualSearchPanel(mContextualSearchPanel);
         }
 
+        mReaderModePanel.setManagerDelegate(readerModeDelegate);
+        // TODO(mdjones): The manager should be responsible for passing the resource loader to all
+        // panels.
+        mReaderModePanel.setDynamicResourceLoader(dynamicResourceLoader);
+        if (readerModeDelegate != null) {
+            readerModeDelegate.setReaderModePanel(mReaderModePanel);
+        }
+
         mTabModelSelectorTabObserver = new TabModelSelectorTabObserver(selector) {
             @Override
             public void onContentChanged(Tab tab) {
@@ -186,7 +175,7 @@
         };
 
         super.init(selector, creator, content, androidContentContainer, contextualSearchDelegate,
-                dynamicResourceLoader);
+                readerModeDelegate, dynamicResourceLoader);
     }
 
     @Override
@@ -320,6 +309,7 @@
         if (getActiveLayout() == mContextualSearchLayout) return;
 
         OverlayPanel panel = mOverlayPanelManager.getActivePanel();
+        if (panel == null) return;
 
         // When not in compatibility mode, tapping on the Search Bar will expand the Panel,
         // therefore we must start showing the ContextualSearchLayout.
@@ -328,11 +318,11 @@
         // ContextualSearchLayout. Coordinate with dtrainor@ to solve this. It might be
         // necessary for the ContextualSearchPanel to be able to trigger the display of the
         // ContextualSearchLayout.
-        if (panel != null && panel.supportsContextualSearchLayout()) {
+        if (panel.supportsContextualSearchLayout()) {
             showContextualSearchLayout(true);
         }
 
-        mOverlayPanelManager.getActivePanel().handleClick(time, x, y);
+        panel.handleClick(time, x, y);
     }
 
     @Override
@@ -453,10 +443,4 @@
             return direction == ScrollDirection.LEFT || direction == ScrollDirection.RIGHT;
         }
     }
-
-    @Override
-    public void handleTapReaderModeBar(long time, float x, float y) {
-        ReaderModePanel activePanel = mReaderModePanelSelector.getActiveReaderModePanel();
-        if (activePanel != null) activePanel.handleClick(time, x, y);
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
index 91ba105..1cba75a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/StaticLayout.java
@@ -17,8 +17,6 @@
 import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
 import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer;
 import org.chromium.chrome.browser.compositor.scene_layer.StaticTabSceneLayer;
-import org.chromium.chrome.browser.dom_distiller.ReaderModePanel;
-import org.chromium.chrome.browser.dom_distiller.ReaderModePanel.ReaderModePanelLayoutDelegate;
 import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tabmodel.TabModel;
@@ -59,9 +57,6 @@
     private boolean mUnstalling;
     private StaticTabSceneLayer mSceneLayer;
 
-    // TODO(aruslan): look into moving this to an overlay/it's own layout.
-    private ReaderModePanel mReaderModePanel;
-
     /**
      * Creates an instance of the {@link StaticLayout}.
      * @param context             The current Android's context.
@@ -93,12 +88,6 @@
         return SizingFlags.HELPER_SUPPORTS_FULLSCREEN;
     }
 
-    @Override
-    public float getTopControlsOffset(float currentOffsetDp) {
-        if (mReaderModePanel == null) return super.getTopControlsOffset(currentOffsetDp);
-        return mReaderModePanel.getTopControlsOffset(currentOffsetDp);
-    }
-
     /**
      * Initialize the layout to be shown.
      * @param time   The current time of the app in ms.
@@ -181,44 +170,9 @@
         } else {
             setPostHideState();
         }
-        mReaderModePanel = ReaderModePanel.getReaderModePanel(mTabModelSelector.getTabById(id));
-        if (mReaderModePanel != null) {
-            mReaderModePanel.setLayoutDelegate(new ReaderModePanelLayoutDelegate() {
-                @Override
-                public void requestUpdate() {
-                    StaticLayout.this.requestUpdate();
-                }
-
-                @Override
-                public void setLayoutTabBrightness(float v) {
-                    if (mLayoutTabs != null && mLayoutTabs.length > 0
-                            && mLayoutTabs[0].getId() == id) {
-                        mLayoutTabs[0].setBrightness(v);
-                    }
-                }
-
-                @Override
-                public void setLayoutTabY(float v) {
-                    if (mLayoutTabs != null && mLayoutTabs.length > 0
-                            && mLayoutTabs[0].getId() == id) {
-                        mLayoutTabs[0].setY(v);
-                    }
-                }
-            });
-            final boolean isToolbarVisible = getHeight() == getHeightMinusTopControls();
-            final float dpToPx = getContext().getResources().getDisplayMetrics().density;
-            mReaderModePanel.onSizeChanged(getWidth(), getHeight(), isToolbarVisible, dpToPx);
-        }
         requestRender();
     }
 
-    /**
-     * @return Currently active reader mode panel, or null.
-     */
-    public ReaderModePanel getReaderModePanel() {
-        return mReaderModePanel;
-    }
-
     @Override
     public void unstallImmediately(int tabId) {
         if (mLayoutTabs != null && mLayoutTabs.length > 0 && mLayoutTabs[0].getId() == tabId) {
@@ -266,25 +220,6 @@
     }
 
     @Override
-    protected void notifySizeChanged(float width, float height, int orientation) {
-        super.notifySizeChanged(width, height, orientation);
-        if (mReaderModePanel == null) return;
-
-        final boolean isToolbarVisible = getHeight() == getHeightMinusTopControls();
-        final float dpToPx = getContext().getResources().getDisplayMetrics().density;
-        mReaderModePanel.onSizeChanged(width, height, isToolbarVisible, dpToPx);
-    }
-
-    @Override
-    protected boolean onUpdateAnimation(long time, boolean jumpToEnd) {
-        boolean parentAnimating = super.onUpdateAnimation(time, jumpToEnd);
-        boolean panelAnimating = mReaderModePanel != null
-                ? mReaderModePanel.onUpdateAnimation(time, jumpToEnd)
-                : false;
-        return panelAnimating || parentAnimating;
-    }
-
-    @Override
     protected void updateSceneLayer(Rect viewport, Rect contentViewport,
             LayerTitleCache layerTitleCache, TabContentManager tabContentManager,
             ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) {
@@ -307,9 +242,6 @@
         OverlayPanel panel = mPanelManager.getActivePanel();
         if (panel != null && panel.isShowing()) {
             overlayLayer = super.getSceneLayer();
-        } else if (mReaderModePanel != null && mReaderModePanel.isShowing()) {
-            mReaderModePanel.updateSceneLayer(resourceManager);
-            overlayLayer = mReaderModePanel.getSceneLayer();
         }
         mSceneLayer.setContentSceneLayer(overlayLayer);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ReaderModeSceneLayer.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ReaderModeSceneLayer.java
deleted file mode 100644
index a4a3009..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ReaderModeSceneLayer.java
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2015 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.
-
-package org.chromium.chrome.browser.compositor.scene_layer;
-
-import org.chromium.base.annotations.JNINamespace;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.dom_distiller.ReaderModePanel;
-import org.chromium.content.browser.ContentViewCore;
-import org.chromium.ui.resources.ResourceManager;
-
-/**
- * A SceneLayer to render layers for ReaderModeLayout.
- */
-@JNINamespace("chrome::android")
-public class ReaderModeSceneLayer extends SceneLayer {
-
-    // NOTE: If you use SceneLayer's native pointer here, the JNI generator will try to
-    // downcast using reinterpret_cast<>. We keep a separate pointer to avoid it.
-    private long mNativePtr;
-
-    private final float mDpToPx;
-
-    public ReaderModeSceneLayer(float dpToPx) {
-        mDpToPx = dpToPx;
-    }
-
-    /**
-     * Update reader mode's layer tree using the parameters.
-     *
-     * @param panel
-     * @param resourceManager
-     */
-    public void update(ReaderModePanel panel, ResourceManager resourceManager) {
-        if (panel == null) return;
-        if (!panel.isShowing()) return;
-
-        nativeUpdateReaderModeLayer(mNativePtr,
-                R.drawable.reader_mode_bar_background, R.id.reader_mode_view,
-                panel.didFirstNonEmptyDistilledPaint() ? panel.getDistilledContentViewCore() : null,
-                panel.getPanelY() * mDpToPx,
-                panel.getWidth() * mDpToPx,
-                panel.getMarginTop() * mDpToPx,
-                panel.getPanelHeight() * mDpToPx,
-                panel.getDistilledContentY() * mDpToPx,
-                panel.getDistilledHeight() * mDpToPx,
-                panel.getX() * mDpToPx,
-                panel.getTextOpacity(),
-                panel.getReaderModeHeaderBackgroundColor(),
-                resourceManager);
-    }
-
-    @Override
-    protected void initializeNative() {
-        if (mNativePtr == 0) {
-            mNativePtr = nativeInit();
-        }
-        assert mNativePtr != 0;
-    }
-
-    /**
-     * Destroys this object and the corresponding native component.
-     */
-    @Override
-    public void destroy() {
-        super.destroy();
-        mNativePtr = 0;
-    }
-
-    private native long nativeInit();
-    private native void nativeUpdateReaderModeLayer(long nativeReaderModeSceneLayer,
-            int panelBackgroundResourceId, int panelTextResourceId,
-            ContentViewCore readerModeContentViewCore,
-            float panelY, float panelWidth, float panelMarginTop, float panelHeight,
-            float distilledY, float distilledHeight,
-            float x,
-            float panelTextOpacity, int headerBackgroundColor,
-            ResourceManager resourceManager);
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
index fc158b5e..1ba524a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -32,13 +32,13 @@
 
     // Translation.
     @VisibleForTesting
-    static final String TRANSLATION_ONEBOX_ENABLED = "translation_onebox_enabled";
+    static final String DISABLE_FORCE_TRANSLATION_ONEBOX = "disable_force_translation_onebox";
 
     // Cached values to avoid repeated and redundant JNI operations.
     private static Boolean sEnabled;
     private static Boolean sIsPeekPromoEnabled;
     private static Integer sPeekPromoMaxCount;
-    private static Boolean sIsTranslationOneboxEnabled;
+    private static Boolean sDisableForceTranslationOnebox;
 
     /**
      * Don't instantiate.
@@ -130,13 +130,13 @@
     }
 
     /**
-     * @return Whether triggering a translation Onebox in the SERP is enabled.
+     * @return Whether forcing a translation Onebox is disabled.
      */
-    static boolean isTranslationOneboxEnabled() {
-        if (sIsTranslationOneboxEnabled == null) {
-            sIsTranslationOneboxEnabled = getBooleanParam(TRANSLATION_ONEBOX_ENABLED);
+    static boolean disableForceTranslationOnebox() {
+        if (sDisableForceTranslationOnebox == null) {
+            sDisableForceTranslationOnebox = getBooleanParam(DISABLE_FORCE_TRANSLATION_ONEBOX);
         }
-        return sIsTranslationOneboxEnabled.booleanValue();
+        return sDisableForceTranslationOnebox.booleanValue();
     }
 
     // --------------------------------------------------------------------------------------------
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
index 5f40198..6788787 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -119,6 +119,8 @@
      */
     private boolean mShouldLoadDelayedSearch;
 
+    private boolean mIsShowingPeekPromo;
+    private boolean mWouldShowPeekPromo;
     private boolean mIsShowingPromo;
     private boolean mDidLogPromoOutcome;
 
@@ -384,6 +386,10 @@
 
         mSearchRequest = null;
 
+        if (mIsShowingPeekPromo || mWouldShowPeekPromo) {
+            mPolicy.logPeekPromoMetrics(mIsShowingPeekPromo, mWouldShowPeekPromo);
+        }
+
         if (mIsShowingPromo && !mDidLogPromoOutcome) {
             logPromoOutcome();
         }
@@ -403,7 +409,8 @@
                 && (reason == StateChangeReason.BACK_PRESS
                 || reason == StateChangeReason.BASE_PAGE_SCROLL
                 || reason == StateChangeReason.SWIPE
-                || reason == StateChangeReason.FLING);
+                || reason == StateChangeReason.FLING
+                || reason == StateChangeReason.CLOSE_BUTTON);
     }
 
     /**
@@ -473,14 +480,13 @@
             // If the user action was not a long-press, immediately start loading content.
             mShouldLoadDelayedSearch = false;
         }
-
         if (isTap && mPolicy.shouldPreviousTapResolve(
                 mNetworkCommunicator.getBasePageUrl())) {
             mNetworkCommunicator.startSearchTermResolutionRequest(
                     mSelectionController.getSelectedText());
             didRequestSurroundings = true;
             // Cache the target languages in case they are needed for translation.
-            if (mPolicy.isTranslationEnabled()) getTargetLanguages();
+            if (!mPolicy.disableForceTranslationOnebox()) getReadableLanguages();
         } else {
             boolean shouldPrefetch = mPolicy.shouldPrefetchSearchResult(isTap);
             mSearchRequest = new ContextualSearchRequest(mSelectionController.getSelectedText(),
@@ -507,8 +513,9 @@
         // Show the Peek Promo only when the Panel wasn't previously visible, provided
         // the policy allows it.
         if (!mSearchPanel.isShowing()) {
-            boolean isPeekPromoAvailable = mPolicy.isPeekPromoAvailable(mSelectionController);
-            if (isPeekPromoAvailable) {
+            mWouldShowPeekPromo = mPolicy.isPeekPromoConditionSatisfied(mSelectionController);
+            mIsShowingPeekPromo = mPolicy.isPeekPromoAvailable(mSelectionController);
+            if (mIsShowingPeekPromo) {
                 mSearchPanel.showPeekPromo();
                 mPolicy.registerPeekPromoSeen();
             }
@@ -518,7 +525,8 @@
         // peekPanel(). If the sprite should be animated, the animation will begin after the panel
         // finishes peeking. If it should not be animated, the icon will be drawn right away.
         mSearchPanel.setShouldAnimateIconSprite(mPolicy.shouldAnimateSearchProviderIcon(
-                mSelectionController.getSelectionType(), mSearchPanel.isShowing()));
+                mSelectionController.getSelectionType(), mSearchPanel.isShowing()),
+                ContextualSearchFieldTrial.areExtraSearchBarAnimationsDisabled());
 
         // Note: now that the contextual search has properly started, set the promo involvement.
         if (mPolicy.isPromoAvailable()) {
@@ -697,7 +705,6 @@
     public void handleSearchTermResolutionResponse(boolean isNetworkUnavailable, int responseCode,
             String searchTerm, String displayText, String alternateTerm, boolean doPreventPreload,
             int selectionStartAdjust, int selectionEndAdjust, String contextLanguage) {
-        if (!mSearchPanel.isShowing()) return;
 
         // Show an appropriate message for what to search for.
         String message;
@@ -730,11 +737,14 @@
             boolean shouldPreload = !doPreventPreload && mPolicy.shouldPrefetchSearchResult(true);
             mSearchRequest = new ContextualSearchRequest(searchTerm, alternateTerm, shouldPreload);
             // Trigger translation, if enabled.
-            if (!contextLanguage.isEmpty() && mPolicy.isTranslationEnabled()) {
-                List<String> targetLanguages = getTargetLanguages();
-                if (mPolicy.needsTranslation(contextLanguage, targetLanguages)) {
-                    mSearchRequest.forceTranslation(
-                            contextLanguage, mPolicy.bestTargetLanguage(targetLanguages));
+            if (!contextLanguage.isEmpty()) {
+                if (mPolicy.needsTranslation(contextLanguage, getReadableLanguages())) {
+                    boolean doForceTranslate = !mPolicy.disableForceTranslationOnebox();
+                    if (doForceTranslate) {
+                        mSearchRequest.forceTranslation(contextLanguage,
+                                mPolicy.bestTargetLanguage(getWritableLanguages()));
+                    }
+                    ContextualSearchUma.logTranslateOnebox(doForceTranslate);
                 }
             }
             mDidStartLoadingResolvedSearchRequest = false;
@@ -789,11 +799,12 @@
     // ============================================================================================
 
     /**
-     * Gets the list of target languages for the current user, with the first
+     * Gets the list of readable languages for the current user, with the first
      * item in the list being the user's primary language.
+     * We assume that the user can read all languages that they can write.
      * @return The {@link List} of languages the user understands with their primary language first.
      */
-    private List<String> getTargetLanguages() {
+    private List<String> getReadableLanguages() {
         // May be cached.
         if (mTargetLanguages != null) return mTargetLanguages;
 
@@ -804,13 +815,10 @@
         uniqueLanguages.add(
                 trimLocaleToLanguage(nativeGetTargetLanguage(mNativeContextualSearchManagerPtr)));
 
-        // Next add languages the user knows how to type.
-        Context context = mActivity.getApplicationContext();
-        List<String> locales = context != null
-                ? new ArrayList<String>(UiUtils.getIMELocales(context))
-                : new ArrayList<String>();
-        for (int i = 0; i < locales.size(); i++) {
-            uniqueLanguages.add(trimLocaleToLanguage(locales.get(i)));
+        // Next add languages the user knows how to write.
+        List<String> writable = getWritableLanguages();
+        for (int i = 0; i < writable.size(); i++) {
+            uniqueLanguages.add(trimLocaleToLanguage(writable.get(i)));
         }
 
         // Add the accept languages last, since they are a weaker hint than presence of a keyboard.
@@ -823,6 +831,22 @@
     }
 
     /**
+     * Gets the list of writable languages for the current user, based on their IME keyboards.
+     * @return An ordered {@link List} of languages the user reads.
+     */
+    private List<String> getWritableLanguages() {
+        List<String> result = new ArrayList<String>();
+        Context context = mActivity.getApplicationContext();
+        List<String> locales = context != null
+                ? new ArrayList<String>(UiUtils.getIMELocales(context))
+                : new ArrayList<String>();
+        for (int i = 0; i < locales.size(); i++) {
+            result.add(trimLocaleToLanguage(locales.get(i)));
+        }
+        return result;
+    }
+
+    /**
      * Gets the list of accept languages for this user.
      * @return The {@link List} of languages the user understands or does not want translated.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
index 5625c2c..ae8956c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -167,32 +167,41 @@
     }
 
     /**
+     * @param controller The {@link ContextualSearchSelectionController} instance.
      * @return Whether the Peek promo is available to be shown above the Search Bar.
      */
     public boolean isPeekPromoAvailable(ContextualSearchSelectionController controller) {
         // Allow Promo to be forcefully enabled for testing.
         if (ContextualSearchFieldTrial.isPeekPromoForced()) return true;
 
-        // Check for several conditions to determine whether the Peek Promo is available.
-
-        // 1) Enabled by Finch.
+        // Enabled by Finch.
         if (!ContextualSearchFieldTrial.isPeekPromoEnabled()) return false;
 
-        // 2) If the Panel was never opened.
+        return isPeekPromoConditionSatisfied(controller);
+    }
+
+    /**
+     * @param controller The {@link ContextualSearchSelectionController} instance.
+     * @return Whether the condition to show the Peek promo is satisfied.
+     */
+    public boolean isPeekPromoConditionSatisfied(ContextualSearchSelectionController controller) {
+        // Check for several conditions to determine whether the Peek Promo can be shown.
+
+        // 1) If the Panel was never opened.
         if (getPromoOpenCount() > 0) return false;
 
-        // 3) User has not opted in.
+        // 2) User has not opted in.
         if (!isUserUndecided()) return false;
 
-        // 4) Selection was caused by a long press.
+        // 3) Selection was caused by a long press.
         if (controller.getSelectionType() != SelectionType.LONG_PRESS) return false;
 
-        // 5) Promo was not shown more than the maximum number of times defined by Finch.
+        // 4) Promo was not shown more than the maximum number of times defined by Finch.
         final int maxShowCount = ContextualSearchFieldTrial.getPeekPromoMaxShowCount();
         final int peekPromoShowCount = mPreferenceManager.getContextualSearchPeekPromoShowCount();
         if (peekPromoShowCount >= maxShowCount) return false;
 
-        // 6) Only then, show the promo.
+        // 5) Only then, show the promo.
         return true;
     }
 
@@ -205,6 +214,21 @@
     }
 
     /**
+     * Logs metrics related to the Peek Promo.
+     * @param wasPromoSeen Whether the Peek Promo was seen.
+     * @param wouldHaveShownPromo Whether the Promo would have shown.
+     */
+    public void logPeekPromoMetrics(boolean wasPromoSeen, boolean wouldHaveShownPromo) {
+        final boolean hasOpenedPanel = getPromoOpenCount() > 0;
+        ContextualSearchUma.logPeekPromoOutcome(wasPromoSeen, wouldHaveShownPromo, hasOpenedPanel);
+
+        if (wasPromoSeen) {
+            final int showCount = mPreferenceManager.getContextualSearchPeekPromoShowCount();
+            ContextualSearchUma.logPeekPromoShowCount(showCount, hasOpenedPanel);
+        }
+    }
+
+    /**
      * Registers that a tap has taken place by incrementing tap-tracking counters.
      */
     void registerTap() {
@@ -333,7 +357,7 @@
      * @return Whether the search provider icon should be animated.
      */
     boolean shouldAnimateSearchProviderIcon(SelectionType selectionType, boolean isShowing) {
-        if (isShowing || ContextualSearchFieldTrial.areExtraSearchBarAnimationsDisabled()) {
+        if (isShowing) {
             return false;
         }
 
@@ -426,10 +450,12 @@
      * Determines the best target language.
      */
     String bestTargetLanguage(List<String> targetLanguages) {
-        // For now, we just return the first language, unless it's English (due to over-usage).
+        // For now, we just return the first language, unless it's English
+        // (due to over-usage).
         // TODO(donnd): Improve this logic. Determining the right language seems non-trivial.
         // E.g. If this language doesn't match the user's server preferences, they might see a page
         // in one language and the one box translation in another, which might be confusing.
+        // Also this logic should only apply on Android, where English setup is over used.
         if (TextUtils.equals(targetLanguages.get(0), Locale.ENGLISH.getLanguage())
                 && targetLanguages.size() > 1) {
             return targetLanguages.get(1);
@@ -439,10 +465,10 @@
     }
 
     /**
-     * @return Whether translation should be enabled or not.
+     * @return Whether forcing a translation Onebox is disabled.
      */
-    boolean isTranslationEnabled() {
-        return ContextualSearchFieldTrial.isTranslationOneboxEnabled();
+    boolean disableForceTranslationOnebox() {
+        return ContextualSearchFieldTrial.disableForceTranslationOnebox();
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
index 614a818b..4264d9e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
@@ -5,14 +5,12 @@
 package org.chromium.chrome.browser.contextualsearch;
 
 import android.net.Uri;
-import android.text.TextUtils;
 
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.browser.search_engines.TemplateUrlService;
 
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.Locale;
 
 import javax.annotation.Nullable;
 
@@ -37,6 +35,8 @@
     private static final String GWS_QUERY_PARAM = "q";
     private static final String CTXS_PARAM_PATTERN = "(ctxs=[^&]+)";
     private static final String CTXR_PARAM = "ctxr";
+    private static final String CTXSL_TRANS_PARAM = "ctxsl_trans";
+    private static final String CTXSL_TRANS_PARAM_VALUE = "1";
     @VisibleForTesting static final String TLITE_SOURCE_LANGUAGE_PARAM = "tlitesl";
     private static final String TLITE_TARGET_LANGUAGE_PARAM = "tlitetl";
     private static final String TLITE_QUERY_PARAM = "tlitetxt";
@@ -203,39 +203,20 @@
      * @return A {@link Uri} that has additional parameters for Translate appropriately set.
      */
     private Uri makeTranslateUri(Uri baseUri, String sourceLanguage, String targetLanguage) {
-        // TODO(donnd): update to work for non-English.  See also getTranslateQuery.
-        if (!TextUtils.equals(targetLanguage, Locale.ENGLISH.getLanguage())) return baseUri;
         Uri resultUri = baseUri;
         if (!sourceLanguage.isEmpty() || !targetLanguage.isEmpty()) {
-            // We must replace the q= param, and there seems to be no good way other than clearing
-            // all the query params and adding them all back in, changing q=.
-            Uri.Builder builder = baseUri.buildUpon().clearQuery();
-            String query = null;
-            for (String param : baseUri.getQueryParameterNames()) {
-                String value = baseUri.getQueryParameter(param);
-                if (TextUtils.equals(param, GWS_QUERY_PARAM)) {
-                    query = value;
-                    value = getTranslateQuery();
-                }
-                builder.appendQueryParameter(param, value);
-            }
+            Uri.Builder builder = baseUri.buildUpon();
             if (!sourceLanguage.isEmpty()) {
                 builder.appendQueryParameter(TLITE_SOURCE_LANGUAGE_PARAM, sourceLanguage);
             }
             if (!targetLanguage.isEmpty()) {
                 builder.appendQueryParameter(TLITE_TARGET_LANGUAGE_PARAM, targetLanguage);
             }
-            builder.appendQueryParameter(TLITE_QUERY_PARAM, query);
+            builder.appendQueryParameter(
+                    TLITE_QUERY_PARAM, baseUri.getQueryParameter(GWS_QUERY_PARAM));
+            builder.appendQueryParameter(CTXSL_TRANS_PARAM, CTXSL_TRANS_PARAM_VALUE);
             resultUri = builder.build();
         }
         return resultUri;
     }
-
-    /**
-     * TODO(donnd): This translate API is evolving.  Update this code!
-     * TODO(donnd): As of Oct 2015 this will only work on production GWS to translate into English.
-     */
-    private String getTranslateQuery() {
-        return "Translate";
-    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
index a08f755..f10f973b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchUma.java
@@ -144,6 +144,13 @@
     private static final int RESULTS_NOT_SEEN_FROM_LONG_PRESS = 3;
     private static final int RESULTS_BY_GESTURE_BOUNDARY = 4;
 
+    // Constants used to log UMA "enum" histograms with details about the Peek Promo Outcome.
+    private static final int PEEK_PROMO_OUTCOME_SEEN_OPENED = 0;
+    private static final int PEEK_PROMO_OUTCOME_SEEN_NOT_OPENED = 1;
+    private static final int PEEK_PROMO_OUTCOME_NOT_SEEN_OPENED = 2;
+    private static final int PEEK_PROMO_OUTCOME_NOT_SEEN_NOT_OPENED = 3;
+    private static final int PEEK_PROMO_OUTCOME_BOUNDARY = 4;
+
     // Constants used to log UMA "enum" histograms with details about whether search results
     // were seen, and what the original triggering gesture was.
     private static final int PROMO_ENABLED_FROM_TAP = 0;
@@ -170,11 +177,28 @@
     private static final int RESOLVED_MULTI_WORD = 1;
     private static final int RESOLVED_BOUNDARY = 2;
 
-    // Constants used to log UMA "enum" histograms for paritally / fully loaded.
+    // Constants used to log UMA "enum" histograms for partially / fully loaded.
     private static final int PARTIALLY_LOADED = 0;
     private static final int FULLY_LOADED = 1;
     private static final int LOADED_BOUNDARY = 2;
 
+    // Constants used to log UMA "enum" histograms for triggering the Translate Onebox.
+    private static final int DID_FORCE_TRANSLATE = 0;
+    private static final int WOULD_FORCE_TRANSLATE = 1;
+    private static final int FORCE_TRANSLATE_BOUNDARY = 2;
+
+    // Constants used to log UMA "enum" histograms with details about whether the search
+    // provider sprite icon was animated, whether search results were seen and the triggering
+    // gesture. All new values should be inserted right before ICON_SPRITE_BOUNDARY.
+    private static final int ICON_SPRITE_ANIMATED_RESULTS_SEEN_FROM_TAP = 0;
+    private static final int ICON_SPRITE_ANIMATED_RESULTS_NOT_SEEN_FROM_TAP = 1;
+    private static final int ICON_SPRITE_NOT_ANIMATED_RESULTS_SEEN_FROM_TAP = 2;
+    private static final int ICON_SPRITE_NOT_ANIMATED_RESULTS_NOT_SEEN_FROM_TAP = 3;
+    private static final int ICON_SPRITE_ANIMATED_RESULTS_SEEN_FROM_LONG_PRESS = 4;
+    private static final int ICON_SPRITE_ANIMATED_RESULTS_NOT_SEEN_FROM_LONG_PRESS = 5;
+    private static final int ICON_SPRITE_NOT_ANIMATED_RESULTS_SEEN_FROM_LONG_PRESS = 6;
+    private static final int ICON_SPRITE_NOT_ANIMATED_RESULTS_NOT_SEEN_FROM_LONG_PRESS = 7;
+    private static final int ICON_SPRITE_BOUNDARY = 8;
 
     /**
      * Key used in maps from {state, reason} to state entry (exit) logging code.
@@ -208,6 +232,47 @@
         }
     }
 
+    static class IconSpriteAnimationKey {
+        final boolean mWasIconSpriteAnimated;
+        final boolean mWasPanelSeen;
+        final boolean mWasTap;
+        final int mHashCode;
+
+        IconSpriteAnimationKey(boolean wasIconSpriteAnimated, boolean wasPanelSeen,
+                boolean wasTap) {
+            mWasIconSpriteAnimated = wasIconSpriteAnimated;
+            mWasPanelSeen = wasPanelSeen;
+            mWasTap = wasTap;
+
+            // HashCode logic generated by Eclipse.
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + (mWasIconSpriteAnimated ? 1231 : 1237);
+            result = prime * result + (mWasPanelSeen ? 1231 : 1237);
+            result = prime * result + (mWasTap ? 1231 : 1237);
+            mHashCode = result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof IconSpriteAnimationKey)) {
+                return false;
+            }
+            if (obj == this) {
+                return true;
+            }
+            IconSpriteAnimationKey other = (IconSpriteAnimationKey) obj;
+            return other.mWasIconSpriteAnimated == mWasIconSpriteAnimated
+                    && other.mWasPanelSeen == mWasPanelSeen
+                    && other.mWasTap == mWasTap;
+        }
+
+        @Override
+        public int hashCode() {
+            return mHashCode;
+        }
+    }
+
     // TODO(donnd): switch from using Maps to some method that does not require creation of a key.
 
     // Entry code map: first entry into CLOSED.
@@ -420,6 +485,29 @@
         PROMO_BY_GESTURE_CODES = Collections.unmodifiableMap(codes);
     }
 
+    // Icon sprite animation code mapped: logged when ending a contextual search.
+    private static final Map<IconSpriteAnimationKey, Integer> ICON_SPRITE_ANIMATION_CODES;
+    static {
+        Map<IconSpriteAnimationKey, Integer> codes = new HashMap<IconSpriteAnimationKey, Integer>();
+        codes.put(new IconSpriteAnimationKey(true, true, true),
+                ICON_SPRITE_ANIMATED_RESULTS_SEEN_FROM_TAP);
+        codes.put(new IconSpriteAnimationKey(true, false, true),
+                ICON_SPRITE_ANIMATED_RESULTS_NOT_SEEN_FROM_TAP);
+        codes.put(new IconSpriteAnimationKey(false, true, true),
+                ICON_SPRITE_NOT_ANIMATED_RESULTS_SEEN_FROM_TAP);
+        codes.put(new IconSpriteAnimationKey(false, false, true),
+                ICON_SPRITE_NOT_ANIMATED_RESULTS_NOT_SEEN_FROM_TAP);
+        codes.put(new IconSpriteAnimationKey(true, true, false),
+                ICON_SPRITE_ANIMATED_RESULTS_SEEN_FROM_LONG_PRESS);
+        codes.put(new IconSpriteAnimationKey(true, false, false),
+                ICON_SPRITE_ANIMATED_RESULTS_NOT_SEEN_FROM_LONG_PRESS);
+        codes.put(new IconSpriteAnimationKey(false, true, false),
+                ICON_SPRITE_NOT_ANIMATED_RESULTS_SEEN_FROM_LONG_PRESS);
+        codes.put(new IconSpriteAnimationKey(false, false, false),
+                ICON_SPRITE_NOT_ANIMATED_RESULTS_NOT_SEEN_FROM_LONG_PRESS);
+        ICON_SPRITE_ANIMATION_CODES = Collections.unmodifiableMap(codes);
+    }
+
     /**
      * Logs the state of the Contextual Search preference. This function should be called if the
      * Contextual Search feature is active, and will track the different preference settings
@@ -525,6 +613,42 @@
     }
 
     /**
+     * Logs the number of times the Peek Promo was seen.
+     * @param count Number of times the Peek Promo was seen.
+     * @param hasOpenedPanel Whether the Panel was opened.
+     */
+    public static void logPeekPromoShowCount(int count, boolean hasOpenedPanel) {
+        RecordHistogram.recordCountHistogram("Search.ContextualSearchPeekPromoCount", count);
+        if (hasOpenedPanel) {
+            RecordHistogram.recordCountHistogram(
+                    "Search.ContextualSearchPeekPromoCountUntilOpened", count);
+        }
+    }
+
+    /**
+     * Logs the Peek Promo Outcome.
+     * @param wasPromoSeen Whether the Peek Promo was seen.
+     * @param wouldHaveShownPromo Whether the Promo would have shown.
+     * @param hasOpenedPanel Whether the Panel was opened.
+     */
+    public static void logPeekPromoOutcome(boolean wasPromoSeen, boolean wouldHaveShownPromo,
+            boolean hasOpenedPanel) {
+        int outcome = -1;
+        if (wasPromoSeen) {
+            outcome = hasOpenedPanel
+                    ? PEEK_PROMO_OUTCOME_SEEN_OPENED : PEEK_PROMO_OUTCOME_SEEN_NOT_OPENED;
+        } else if (wouldHaveShownPromo) {
+            outcome = hasOpenedPanel
+                    ? PEEK_PROMO_OUTCOME_NOT_SEEN_OPENED : PEEK_PROMO_OUTCOME_NOT_SEEN_NOT_OPENED;
+        }
+
+        if (outcome != -1) {
+            RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchPeekPromoOutcome",
+                    outcome, PEEK_PROMO_OUTCOME_BOUNDARY);
+        }
+    }
+
+    /**
      * Logs the outcome of the promo (first run flow).
      * Logs multiple histograms; with and without the originating gesture.
      * @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
@@ -606,6 +730,22 @@
     }
 
     /**
+     * Logs whether search results were seen, whether the search provider icon sprite was animated
+     * when the panel first appeared, and the triggering gesture.
+     * @param wasIconSpriteAnimated Whether the search provider icon sprite was animated when the
+     *                              the panel first appeared.
+     * @param wasPanelSeen Whether the panel was seen.
+     * @param wasTap Whether the gesture that originally caused the panel to show was a Tap.
+     */
+    public static void logIconSpriteAnimated(boolean wasIconSpriteAnimated, boolean wasPanelSeen,
+            boolean wasTap) {
+        RecordHistogram.recordEnumeratedHistogram("Search.ContextualSearchIconSpriteAnimated",
+                ICON_SPRITE_ANIMATION_CODES.get(new IconSpriteAnimationKey(wasIconSpriteAnimated,
+                        wasPanelSeen, wasTap)),
+                ICON_SPRITE_BOUNDARY);
+    }
+
+    /**
      * Logs whether a selection is valid.
      * @param isSelectionValid Whether the selection is valid.
      */
@@ -737,6 +877,17 @@
     }
 
     /**
+     * Logs that the conditions are right to force the translation one-box, and whether it
+     * was actually forced or not.
+     * @param didForceTranslate Whether the translation onebox was forced.
+     */
+    public static void logTranslateOnebox(boolean didForceTranslate) {
+        int code = didForceTranslate ? DID_FORCE_TRANSLATE : WOULD_FORCE_TRANSLATE;
+        RecordHistogram.recordEnumeratedHistogram(
+                "Search.ContextualSearchShouldTranslate", code, FORCE_TRANSLATE_BOUNDARY);
+    }
+
+    /**
      * Gets the state-change code for the given parameters by doing a lookup in the given map.
      * @param state The panel state.
      * @param reason The reason the state changed.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionCallable.java b/chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionCallable.java
index 47b6436..607772c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionCallable.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/crash/LogcatExtractionCallable.java
@@ -159,6 +159,9 @@
             int len = mMinidumpFilenames.length;
             CrashFileManager fileManager = new CrashFileManager(mContext.getCacheDir());
             for (int i = 0; i < len; i++) {
+                // Output crash dump file path to logcat so non-browser crashes appear too.
+                Log.i(TAG, "Output crash dump:");
+                Log.i(TAG, fileManager.getCrashFile(mMinidumpFilenames[i]).getAbsolutePath());
                 processMinidump(logcatFile, mMinidumpFilenames[i], fileManager, i == len - 1);
             }
             return true;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeActivityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeActivityDelegate.java
deleted file mode 100644
index ba2ee636..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeActivityDelegate.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2015 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.
-
-package org.chromium.chrome.browser.dom_distiller;
-
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeActivity;
-import org.chromium.chrome.browser.widget.ReaderModeControl;
-import org.chromium.ui.resources.dynamics.DynamicResourceLoader;
-
-
-/**
- * Manager for the Reader Mode feature.
- * This class keeps track of the status of Reader Mode and coordinates the control
- * with the layout.
- */
-public class ReaderModeActivityDelegate {
-    private static final String TAG = "ReaderModeActivityDelegate";
-
-    private DynamicResourceLoader mResourceLoader;
-    private ReaderModeControl mControl;
-    private final ChromeActivity mActivity;
-    private ViewGroup mParentView;
-
-    /**
-     * Constructs the manager for the given activity, and will attach views to the given parent.
-     * @param activity             The {@code ChromeActivity} in use.
-     */
-    public ReaderModeActivityDelegate(ChromeActivity activity) {
-        mActivity = activity;
-    }
-
-    /**
-     * Initializes this manager.  Must be called before {@link #getReaderModeControl()}.
-     * @param parentView The parent view to attach Reader Mode UX to.
-     */
-    public void initialize(ViewGroup parentView) {
-        mParentView = parentView;
-    }
-
-    /**
-     * Destroys the Reader Mode activity delegate.
-     */
-    public void destroy() {
-        destroyReaderModeControl();
-        mParentView = null;
-    }
-
-    /**
-     * @param resourceLoader The {@link DynamicResourceLoader} to register and unregister the view.
-     */
-    public void setDynamicResourceLoader(DynamicResourceLoader resourceLoader) {
-        mResourceLoader = resourceLoader;
-        if (mControl != null) {
-            mResourceLoader.registerResource(R.id.reader_mode_view,
-                    mControl.getResourceAdapter());
-        }
-    }
-
-    /**
-     * Inflates the Reader Mode control, if needed.
-     */
-    public ReaderModeControl getReaderModeControl() {
-        assert mParentView != null;
-        if (mControl == null) {
-            LayoutInflater.from(mActivity).inflate(R.layout.reader_mode_control, mParentView);
-            mControl = (ReaderModeControl)
-                    mParentView.findViewById(R.id.reader_mode_view);
-            if (mResourceLoader != null) {
-                mResourceLoader.registerResource(R.id.reader_mode_view,
-                        mControl.getResourceAdapter());
-            }
-        }
-        assert mControl != null;
-        mControl.setVisibility(View.INVISIBLE);
-        return mControl;
-    }
-
-    /**
-     * Destroys the Reader Mode control.
-     */
-    public void destroyReaderModeControl() {
-        if (mControl != null) {
-            ((ViewGroup) mControl.getParent()).removeView(mControl);
-            mControl = null;
-            if (mResourceLoader != null) {
-                mResourceLoader.unregisterResource(R.id.reader_mode_view);
-            }
-        }
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeEdgeSwipeHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeEdgeSwipeHandler.java
deleted file mode 100644
index aee7546..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeEdgeSwipeHandler.java
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2015 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.
-
-package org.chromium.chrome.browser.dom_distiller;
-
-import org.chromium.chrome.browser.compositor.layouts.EdgeSwipeHandlerLayoutDelegate;
-import org.chromium.chrome.browser.compositor.layouts.LayoutProvider;
-import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeEventFilter.ScrollDirection;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeStaticEventFilter.ReaderModePanelSelector;
-
-/**
- * An {@link EdgeSwipeHandlerLayoutDelegate} that delegates all swipe events to the currently
- * active Reader Mode Panel.
- */
-public class ReaderModeEdgeSwipeHandler extends EdgeSwipeHandlerLayoutDelegate {
-    private final ReaderModePanelSelector mReaderModePanelSelector;
-
-    public ReaderModeEdgeSwipeHandler(ReaderModePanelSelector selector, LayoutProvider provider) {
-        super(provider);
-        mReaderModePanelSelector = selector;
-    }
-
-    @Override
-    public void swipeStarted(ScrollDirection direction, float x, float y) {
-        ReaderModePanel panel = mReaderModePanelSelector.getActiveReaderModePanel();
-        if (panel == null) super.swipeStarted(direction, x, y);
-        else panel.swipeStarted(direction, x, y);
-    }
-
-    @Override
-    public void swipeUpdated(float x, float y, float dx, float dy, float tx, float ty) {
-        ReaderModePanel panel = mReaderModePanelSelector.getActiveReaderModePanel();
-        if (panel == null) super.swipeUpdated(x, y, dx, dy, tx, ty);
-        else panel.swipeUpdated(x, y, dx, dy, tx, ty);
-    }
-
-    @Override
-    public void swipeFinished() {
-        ReaderModePanel panel = mReaderModePanelSelector.getActiveReaderModePanel();
-        if (panel == null) super.swipeFinished();
-        else panel.swipeFinished();
-    }
-
-    @Override
-    public boolean isSwipeEnabled(ScrollDirection direction) {
-        ReaderModePanel panel = mReaderModePanelSelector.getActiveReaderModePanel();
-        return panel != null && panel.isSwipeEnabled(direction);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
index d1c7dfa..734f3cd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -4,134 +4,213 @@
 
 package org.chromium.chrome.browser.dom_distiller;
 
-import android.app.Activity;
 import android.content.Context;
 import android.text.TextUtils;
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.CommandLine;
+import org.chromium.base.SysUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.contextualsearch.ContextualSearchManager;
-import org.chromium.chrome.browser.contextualsearch.ContextualSearchObserver;
-import org.chromium.chrome.browser.dom_distiller.ReaderModePanel.ReaderModePanelHost;
-import org.chromium.chrome.browser.gsa.GSAContextDisplaySelection;
+import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.StateChangeReason;
+import org.chromium.chrome.browser.compositor.bottombar.readermode.ReaderModePanel;
 import org.chromium.chrome.browser.infobar.InfoBar;
 import org.chromium.chrome.browser.infobar.InfoBarContainer;
 import org.chromium.chrome.browser.infobar.InfoBarContainer.InfoBarContainerObserver;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.browser.tabmodel.TabCreatorManager;
+import org.chromium.chrome.browser.tabmodel.TabModel;
+import org.chromium.chrome.browser.tabmodel.TabModelSelector;
+import org.chromium.chrome.browser.tabmodel.TabModelSelectorTabObserver;
 import org.chromium.components.dom_distiller.content.DistillablePageUtils;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
+import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.content_public.browser.WebContentsObserver;
 import org.chromium.ui.base.DeviceFormFactor;
+import org.chromium.ui.base.PageTransition;
+
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Manages UI effects for reader mode including hiding and showing the
  * reader mode and reader mode preferences toolbar icon and hiding the
  * top controls when a reader mode page has finished loading.
  */
-public class ReaderModeManager extends EmptyTabObserver
-        implements ContextualSearchObserver, InfoBarContainerObserver, ReaderModePanelHost {
+public class ReaderModeManager extends TabModelSelectorTabObserver
+        implements InfoBarContainerObserver, ReaderModeManagerDelegate {
 
     /**
-     * Observer for changes to the current status of reader mode.
+     * URL scheme for dom-distiller.
      */
-    public static interface ReaderModeManagerObserver {
-        /**
-         * Triggered on changes to the reader mode status for the owning tab.
-         *
-         * @param readerModeStatus The current status of reader mode.
-         * @see ReaderModeManager#POSSIBLE
-         * @see ReaderModeManager#NOT_POSSIBLE
-         * @see ReaderModeManager#STARTED
-         */
-        void onReaderModeStatusChanged(int readerModeStatus);
-    }
+    public static final String DOM_DISTILLER_SCHEME = "chrome-distiller";
 
     /**
      * POSSIBLE means reader mode can be entered.
      */
     public static final int POSSIBLE = 0;
+
     /**
      * NOT_POSSIBLE means reader mode cannot be entered.
      */
     public static final int NOT_POSSIBLE = 1;
+
     /**
      * STARTED means reader mode is currently in reader mode.
      */
     public static final int STARTED = 2;
 
-    /**
-     * The url of the last page visited if the last page was reader mode page.  Otherwise null.
-     */
+    // The url of the last page visited if the last page was reader mode page.  Otherwise null.
     private String mReaderModePageUrl;
 
-    /**
-     * Whether the page is an article or not.
-     */
-    private int mReaderModeStatus = NOT_POSSIBLE;
-
-    /**
-     * Whether the fact that the current web page was distillable or not has been recorded.
-     */
+    // Whether the fact that the current web page was distillable or not has been recorded.
     private boolean mIsUmaRecorded;
 
-    private WebContentsObserver mWebContentsObserver;
+    // The per-tab state of distillation.
+    private Map<Integer, ReaderModeTabInfo> mTabStatusMap;
 
-    private final Tab mTab;
+    // The current tab ID. This will change as the user switches between tabs.
+    private int mTabId;
 
-    private final ReaderModePanel mReaderModePanel;
+    // The ReaderModePanel that this class is managing.
+    private ReaderModePanel mReaderModePanel;
+
+    // The ChromeActivity that this panel exists in.
+    private ChromeActivity mChromeActivity;
+
+    // The primary means of getting the currently active tab.
+    private TabModelSelector mTabModelSelector;
 
     private final int mHeaderBackgroundColor;
+    private boolean mIsFullscreenModeEntered;
+    private boolean mIsInfobarContainerShown;
 
-    public ReaderModeManager(Tab tab, Context context) {
-        mTab = tab;
-        mTab.addObserver(this);
-        mReaderModePanel = isEnabled(context) ? new ReaderModePanel(this, context) : null;
-        mHeaderBackgroundColor = context != null
+    public ReaderModeManager(TabModelSelector selector, ChromeActivity activity) {
+        super(selector);
+        mTabId = Tab.INVALID_TAB_ID;
+        mTabModelSelector = selector;
+        mChromeActivity = activity;
+        mTabStatusMap = new HashMap<>();
+        mHeaderBackgroundColor = activity != null
                 ? ApiCompatibilityUtils.getColor(
-                        context.getResources(), R.color.reader_mode_header_bg)
+                        activity.getResources(), R.color.reader_mode_header_bg)
                 : 0;
     }
 
-    // EmptyTabObserver:
+    /**
+     * Clear the status map and references to other objects.
+     */
+    public void destroy() {
+        for (Map.Entry<Integer, ReaderModeTabInfo> e : mTabStatusMap.entrySet()) {
+            if (e.getValue().getWebContentsObserver() != null) {
+                e.getValue().getWebContentsObserver().destroy();
+            }
+        }
+        mTabStatusMap.clear();
+        mChromeActivity = null;
+        mReaderModePanel = null;
+        mTabModelSelector = null;
+    }
+
+    // TabModelSelectorTabObserver:
+
     @Override
-    public void onDestroyed(Tab tab) {
-        ContextualSearchManager contextualSearchManager = getContextualSearchManager(tab);
-        if (contextualSearchManager != null) contextualSearchManager.removeObserver(this);
+    public void onShown(Tab shownTab) {
+        int shownTabId = shownTab.getId();
 
-        if (mTab.getInfoBarContainer() != null) mTab.getInfoBarContainer().removeObserver(this);
+        Tab previousTab = mTabModelSelector.getTabById(mTabId);
+        mTabId = shownTabId;
 
-        if (mReaderModePanel != null) mReaderModePanel.onDestroy();
-
-        if (mWebContentsObserver != null) {
-            mWebContentsObserver.destroy();
-            mWebContentsObserver = null;
+        // If the reader panel was dismissed, stop here.
+        if (mTabStatusMap.containsKey(shownTabId)
+                && mTabStatusMap.get(shownTabId).isDismissed()) {
+            return;
         }
 
-        destroyReaderModeControl();
+        // Remove the infobar observer from the previous tab and attach it to the current one.
+        if (previousTab != null && previousTab.getInfoBarContainer() != null) {
+            previousTab.getInfoBarContainer().removeObserver(this);
+        }
+
+        if (shownTab.getInfoBarContainer() != null) {
+            shownTab.getInfoBarContainer().addObserver(this);
+        }
+
+        // If there is no state info for this tab, create it.
+        ReaderModeTabInfo tabInfo = mTabStatusMap.get(shownTabId);
+        if (tabInfo == null) {
+            tabInfo = new ReaderModeTabInfo();
+            tabInfo.setStatus(NOT_POSSIBLE);
+            tabInfo.setUrl(shownTab.getUrl());
+            mTabStatusMap.put(shownTabId, tabInfo);
+        }
+
+        // Make sure there is a WebContentsObserver on this tab's WebContents.
+        if (tabInfo.getWebContentsObserver() == null) {
+            tabInfo.setWebContentsObserver(createWebContentsObserver(shownTab.getWebContents()));
+        }
+
+        // Make sure there is a distillability delegate set on the WebContents.
+        setDistillabilityCallback();
+
+        requestReaderPanelShow(StateChangeReason.UNKNOWN);
+    }
+
+    @Override
+    public void onHidden(Tab tab) {
+        mReaderModePanel.closePanel(StateChangeReason.UNKNOWN, false);
+    }
+
+    @Override
+    public void onDestroyed(Tab tab) {
+        if (tab.getInfoBarContainer() != null) {
+            tab.getInfoBarContainer().removeObserver(this);
+        }
+        removeTabState(tab.getId());
+    }
+
+    /**
+     * Clean up the state associated with a tab.
+     * @param tabId The target tab ID.
+     */
+    private void removeTabState(int tabId) {
+        if (!mTabStatusMap.containsKey(tabId)) return;
+        ReaderModeTabInfo tabInfo = mTabStatusMap.get(tabId);
+        if (tabInfo.getWebContentsObserver() != null) {
+            tabInfo.getWebContentsObserver().destroy();
+        }
+        mTabStatusMap.remove(tabId);
     }
 
     @Override
     public void onContentChanged(Tab tab) {
-        if (mWebContentsObserver != null) {
-            mWebContentsObserver.destroy();
-            mWebContentsObserver = null;
+        // Only listen to events on the currently active tab.
+        if (tab.getId() != mTabId) return;
+
+        if (mTabStatusMap.containsKey(mTabId)) {
+            // If the panel was closed using the "x" icon, don't show it again for this tab.
+            if (mTabStatusMap.get(mTabId).isDismissed()) return;
+            removeTabState(mTabId);
         }
+
+        ReaderModeTabInfo tabInfo = new ReaderModeTabInfo();
+        tabInfo.setStatus(NOT_POSSIBLE);
+        tabInfo.setUrl(tab.getUrl());
+        mTabStatusMap.put(tab.getId(), tabInfo);
+
         if (tab.getWebContents() != null) {
-            mWebContentsObserver = createWebContentsObserver(tab.getWebContents());
+            tabInfo.setWebContentsObserver(createWebContentsObserver(tab.getWebContents()));
             if (DomDistillerUrlUtils.isDistilledPage(tab.getUrl())) {
-                mReaderModeStatus = STARTED;
+                tabInfo.setStatus(STARTED);
                 mReaderModePageUrl = tab.getUrl();
-                if (mReaderModePanel != null) mReaderModePanel.updateBottomButtonBar();
+                mReaderModePanel.closePanel(StateChangeReason.CONTENT_CHANGED, true);
             }
+            // Make sure there is a distillability delegate set on the WebContents.
+            setDistillabilityCallback();
         }
-        ContextualSearchManager contextualSearchManager = getContextualSearchManager(tab);
-        if (contextualSearchManager != null) contextualSearchManager.addObserver(this);
 
         if (tab.getInfoBarContainer() != null) tab.getInfoBarContainer().addObserver(this);
     }
@@ -140,36 +219,37 @@
     public void onToggleFullscreenMode(Tab tab, boolean enable) {
         if (mReaderModePanel == null) return;
 
+        // Temporarily hide the reader mode panel while fullscreen is enabled.
         if (enable) {
-            mReaderModePanel.onEnterFullscreen();
+            mIsFullscreenModeEntered = true;
+            mReaderModePanel.closePanel(StateChangeReason.FULLSCREEN_ENTERED, false);
         } else {
-            mReaderModePanel.onExitFullscreen();
+            mIsFullscreenModeEntered = false;
+            requestReaderPanelShow(StateChangeReason.FULLSCREEN_EXITED);
         }
     }
 
-    // ContextualSearchObserver:
-    @Override
-    public void onShowContextualSearch(GSAContextDisplaySelection selectionContext) {
-        if (mReaderModePanel != null) mReaderModePanel.hideButtonBar();
-    }
-
-    @Override
-    public void onHideContextualSearch() {
-        if (mReaderModePanel != null) mReaderModePanel.unhideButtonBar();
-    }
-
     // InfoBarContainerObserver:
+
     @Override
     public void onAddInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isFirst) {
-        if (isFirst && mReaderModePanel != null) mReaderModePanel.onShowInfobarContainer();
+        // Temporarily hides the reader mode button while the infobars are shown.
+        if (isFirst && mReaderModePanel != null) {
+            mIsInfobarContainerShown = true;
+            mReaderModePanel.closePanel(StateChangeReason.INFOBAR_SHOWN, false);
+        }
     }
 
     @Override
     public void onRemoveInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isLast) {
-        if (isLast && mReaderModePanel != null) mReaderModePanel.onHideInfobarContainer();
+        // Re-shows the reader mode button if necessary once the infobars are dismissed.
+        if (isLast && mReaderModePanel != null) {
+            mIsInfobarContainerShown = false;
+            requestReaderPanelShow(StateChangeReason.INFOBAR_HIDDEN);
+        }
     }
 
-    // ReaderModePanelHost:
+    // ReaderModeManagerDelegate:
 
     @Override
     public int getReaderModeHeaderBackgroundColor() {
@@ -178,69 +258,58 @@
 
     @Override
     public int getReaderModeStatus() {
-        return mReaderModeStatus;
+        int currentTabId = mTabModelSelector.getCurrentTabId();
+        if (currentTabId == Tab.INVALID_TAB_ID) return NOT_POSSIBLE;
+
+        if (!mTabStatusMap.containsKey(currentTabId)) return NOT_POSSIBLE;
+        return mTabStatusMap.get(currentTabId).getStatus();
     }
 
     @Override
-    public Tab getTab() {
-        return mTab;
+    public void setReaderModePanel(ReaderModePanel panel) {
+        mReaderModePanel = panel;
     }
 
     @Override
-    public boolean isInsideDismissButton(float x, float y) {
-        ReaderModeActivityDelegate delegate = getReaderModeActivityDelegate();
-        if (delegate == null) return false;
-        return delegate.getReaderModeControl().isInsideDismissButton(x, y);
+    public ChromeActivity getChromeActivity() {
+        return mChromeActivity;
     }
 
     @Override
-    public void createReaderModeControl() {
-        ReaderModeActivityDelegate delegate = getReaderModeActivityDelegate();
-        if (delegate != null) delegate.getReaderModeControl();
+    public void onCloseButtonPressed() {
+        int currentTabId = mTabModelSelector.getCurrentTabId();
+        if (currentTabId == Tab.INVALID_TAB_ID) return;
+
+        if (!mTabStatusMap.containsKey(currentTabId)) return;
+        ReaderModeTabInfo tabInfo = mTabStatusMap.get(currentTabId);
+        tabInfo.setIsDismissed(true);
+        if (tabInfo.getWebContentsObserver() != null) {
+            tabInfo.getWebContentsObserver().destroy();
+        }
     }
 
     @Override
-    public void destroyReaderModeControl() {
-        ReaderModeActivityDelegate delegate = getReaderModeActivityDelegate();
-        if (delegate != null) delegate.destroyReaderModeControl();
-    }
-
-    /**
-     * @return The panel associated with the managed tab.
-     */
-    public ReaderModePanel getReaderModePanel() {
-        return mReaderModePanel;
-    }
-
-    private ReaderModeActivityDelegate getReaderModeActivityDelegate() {
-        return mTab.getReaderModeActivityDelegate();
+    public void onPanelPeek() {
+        String distillerUrl = DomDistillerUrlUtils.getDistillerViewUrlFromUrl(
+                DOM_DISTILLER_SCHEME, mTabModelSelector.getCurrentTab().getUrl());
+        // Load the distilled page URL when the visibility of the panel changes.
+        mReaderModePanel.loadUrlInPanel(distillerUrl, false);
     }
 
     private WebContentsObserver createWebContentsObserver(WebContents webContents) {
+        final int readerTabId = mTabModelSelector.getCurrentTabId();
+        if (readerTabId == Tab.INVALID_TAB_ID) return null;
+
         return new WebContentsObserver(webContents) {
             @Override
-            public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
-                if (!isMainFrame) return;
-                if (DomDistillerUrlUtils.isDistilledPage(mTab.getUrl())) return;
-                updateStatusBasedOnReaderModeCriteria(true);
-            }
-
-            @Override
-            public void didFailLoad(boolean isProvisionalLoad, boolean isMainFrame, int errorCode,
-                        String description, String failingUrl, boolean wasIgnoredByHandler) {
-                if (!isMainFrame) return;
-                if (DomDistillerUrlUtils.isDistilledPage(mTab.getUrl())) return;
-                updateStatusBasedOnReaderModeCriteria(true);
-            }
-
-            @Override
             public void didStartProvisionalLoadForFrame(long frameId, long parentFrameId,
                     boolean isMainFrame, String validatedUrl, boolean isErrorPage,
                     boolean isIframeSrcdoc) {
                 if (!isMainFrame) return;
+                mTabStatusMap.get(readerTabId).setUrl(validatedUrl);
                 if (DomDistillerUrlUtils.isDistilledPage(validatedUrl)) {
-                    mReaderModeStatus = STARTED;
-                    if (mReaderModePanel != null) mReaderModePanel.updateBottomButtonBar();
+                    mTabStatusMap.get(readerTabId).setStatus(STARTED);
+                    mReaderModePanel.closePanel(StateChangeReason.UNKNOWN, true);
                     mReaderModePageUrl = validatedUrl;
                 }
             }
@@ -254,51 +323,115 @@
                 if (isNavigationInPage) return;
                 if (DomDistillerUrlUtils.isDistilledPage(url)) return;
 
-                mReaderModeStatus = POSSIBLE;
+                mTabStatusMap.get(readerTabId).setStatus(POSSIBLE);
                 if (!TextUtils.equals(url,
                         DomDistillerUrlUtils.getOriginalUrlFromDistillerUrl(
                                 mReaderModePageUrl))) {
-                    mReaderModeStatus = NOT_POSSIBLE;
+                    mTabStatusMap.get(readerTabId).setStatus(NOT_POSSIBLE);
                     mIsUmaRecorded = false;
-                    // Do not call updateStatusBasedOnReaderModeCriteria here.
-                    // For ADABOOST_MODEL, it is unlikely to get valid info at this event.
                 }
                 mReaderModePageUrl = null;
-                if (mReaderModePanel != null) mReaderModePanel.updateBottomButtonBar();
+                if (mTabStatusMap.containsKey(readerTabId)
+                        && mTabStatusMap.get(readerTabId).getStatus() != POSSIBLE) {
+                    mReaderModePanel.closePanel(StateChangeReason.UNKNOWN, false);
+                } else {
+                    requestReaderPanelShow(StateChangeReason.UNKNOWN);
+                }
             }
         };
     }
 
-    // Updates reader mode status based on whether or not the page should be viewed in reader mode.
-    private void updateStatusBasedOnReaderModeCriteria(final boolean forceRecord) {
-        if (mTab.getWebContents() == null) return;
-        if (mTab.getContentViewCore() == null) return;
+    /**
+     * This is a wrapper for "requestPanelShow" that checks if reader mode is possible before
+     * showing.
+     * @param reason The reason the panel is requesting to be shown.
+     */
+    private void requestReaderPanelShow(StateChangeReason reason) {
+        int currentTabId = mTabModelSelector.getCurrentTabId();
+        if (currentTabId == Tab.INVALID_TAB_ID) return;
 
-        DistillablePageUtils.isPageDistillable(mTab.getWebContents(),
-                mTab.getContentViewCore().getIsMobileOptimizedHint(),
-                new DistillablePageUtils.PageDistillableCallback() {
-                    @Override
-                    public void onIsPageDistillableResult(boolean isDistillable) {
-                        if (isDistillable) {
-                            mReaderModeStatus = POSSIBLE;
-                        } else {
-                            mReaderModeStatus = NOT_POSSIBLE;
-                        }
-                        if (!mIsUmaRecorded && (mReaderModeStatus == POSSIBLE || forceRecord)) {
-                            mIsUmaRecorded = true;
-                            RecordHistogram.recordBooleanHistogram(
-                                    "DomDistiller.PageDistillable", mReaderModeStatus == POSSIBLE);
-                        }
-                        if (mReaderModePanel != null) mReaderModePanel.updateBottomButtonBar();
-                    }
-                });
+        if (mReaderModePanel == null || !mTabStatusMap.containsKey(currentTabId)
+                || mTabStatusMap.get(currentTabId).getStatus() == NOT_POSSIBLE
+                || mTabStatusMap.get(currentTabId).isDismissed()
+                || mIsInfobarContainerShown
+                || mIsFullscreenModeEntered) {
+            return;
+        }
+        mReaderModePanel.requestPanelShow(reason);
     }
 
-    private ContextualSearchManager getContextualSearchManager(Tab tab) {
-        if (tab == null || tab.getWindowAndroid() == null) return null;
-        Activity activity = tab.getWindowAndroid().getActivity().get();
-        if (!(activity instanceof ChromeActivity)) return null;
-        return ((ChromeActivity) activity).getContextualSearchManager();
+    /**
+     * Orientation change event handler. Simply close the panel.
+     */
+    public void onOrientationChange() {
+        if (mReaderModePanel == null) return;
+        // Close to reset the panel then immediately show again.
+        mReaderModePanel.closePanel(StateChangeReason.UNKNOWN, false);
+        requestReaderPanelShow(StateChangeReason.UNKNOWN);
+    }
+
+    /**
+     * Open a link from the panel in a new tab.
+     * @param url The URL to load.
+     */
+    public void createNewTab(String url) {
+        if (mChromeActivity == null) return;
+
+        Tab currentTab = mTabModelSelector.getCurrentTab();
+        if (currentTab == null) return;
+
+        TabCreatorManager.TabCreator tabCreator =
+                mChromeActivity.getTabCreator(currentTab.isIncognito());
+        if (tabCreator == null) return;
+
+        tabCreator.createNewTab(new LoadUrlParams(url, PageTransition.LINK),
+                TabModel.TabLaunchType.FROM_LINK, mChromeActivity.getActivityTab());
+    }
+
+    // Set the callback for updating reader mode status based on whether or not the page should
+    // be viewed in reader mode.
+    private void setDistillabilityCallback() {
+        Tab currentTab = mTabModelSelector.getCurrentTab();
+        if (currentTab == null || currentTab.getWebContents() == null
+                || currentTab.getContentViewCore() == null) {
+            return;
+        }
+
+        final int readerTabId = currentTab.getId();
+        if (mTabStatusMap.get(readerTabId).isCallbackSet()) {
+            return;
+        }
+
+        DistillablePageUtils.setDelegate(currentTab.getWebContents(),
+                new DistillablePageUtils.PageDistillableDelegate() {
+                    @Override
+                    public void onIsPageDistillableResult(boolean isDistillable, boolean isLast) {
+                        if (!mTabStatusMap.containsKey(readerTabId)) return;
+                        ReaderModeTabInfo tabInfo = mTabStatusMap.get(readerTabId);
+
+                        Tab readerTab = mTabModelSelector.getTabById(readerTabId);
+                        // Make sure the page didn't navigate while waiting for a response.
+                        if (!readerTab.getUrl().equals(tabInfo.getUrl())) return;
+
+                        if (isDistillable) {
+                            tabInfo.setStatus(POSSIBLE);
+                            // The user may have changed tabs.
+                            if (readerTabId == mTabModelSelector.getCurrentTabId()) {
+                                // TODO(mdjones): Add reason DISTILLER_STATE_CHANGE.
+                                requestReaderPanelShow(StateChangeReason.UNKNOWN);
+                            }
+                        } else {
+                            tabInfo.setStatus(NOT_POSSIBLE);
+                        }
+                        if (!mIsUmaRecorded && (tabInfo.getStatus() == POSSIBLE || isLast)) {
+                            mIsUmaRecorded = true;
+                            RecordHistogram.recordBooleanHistogram(
+                                    "DomDistiller.PageDistillable",
+                                    tabInfo.getStatus() == POSSIBLE);
+                        }
+                    }
+                });
+        mTabStatusMap.get(readerTabId).setIsCallbackSet(true);
     }
 
     /**
@@ -312,7 +445,8 @@
                 && !CommandLine.getInstance().hasSwitch(
                         ChromeSwitches.DISABLE_READER_MODE_BOTTOM_BAR)
                 && !DeviceFormFactor.isTablet(context)
-                && DomDistillerTabUtils.isDistillerHeuristicsEnabled();
+                && DomDistillerTabUtils.isDistillerHeuristicsEnabled()
+                && !SysUtils.isLowEndDevice();
         return enabled;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
deleted file mode 100644
index 0b892fc..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModePanel.java
+++ /dev/null
@@ -1,877 +0,0 @@
-// Copyright 2015 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.
-
-package org.chromium.chrome.browser.dom_distiller;
-
-import static org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.AnimatableAnimation.createAnimation;
-
-import android.content.Context;
-import android.os.SystemClock;
-
-import org.chromium.base.CommandLine;
-import org.chromium.base.metrics.RecordHistogram;
-import org.chromium.base.metrics.RecordUserAction;
-import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.WebContentsFactory;
-import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
-import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
-import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeEventFilter.ScrollDirection;
-import org.chromium.chrome.browser.compositor.scene_layer.ReaderModeSceneLayer;
-import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeButtonView.ReaderModeButtonViewDelegate;
-import org.chromium.chrome.browser.tab.EmptyTabObserver;
-import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.util.MathUtils;
-import org.chromium.content.browser.ContentView;
-import org.chromium.content.browser.ContentViewClient;
-import org.chromium.content.browser.ContentViewCore;
-import org.chromium.content_public.browser.NavigationController;
-import org.chromium.content_public.browser.WebContents;
-import org.chromium.content_public.browser.WebContentsObserver;
-import org.chromium.ui.base.WindowAndroid;
-import org.chromium.ui.resources.ResourceManager;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * Manages UI effects for reader mode including hiding and showing the
- * reader mode and reader mode preferences toolbar icon and hiding the
- * top controls when a reader mode page has finished loading.
- *
- * TODO(aruslan): combine with ContextualSearchPanel.
- */
-public class ReaderModePanel implements ChromeAnimation.Animatable<ReaderModePanel.Property> {
-    // TODO(aruslan): pull this from the FullscreenManager.
-    private static final float TOOLBAR_HEIGHT_DP = 56.0f;
-
-    private static final float PANEL_HEIGHT_DP = TOOLBAR_HEIGHT_DP;
-    private static final float SHADOW_HEIGHT_DP = 4.0f;
-    private static final float MINIMAL_BORDER_X_DP = 4.0f;
-    private static final float DARKEN_LAYOUTTAB_BRIGHTNESS = 0.3f;
-    private static final float MAX_LAYOUTTAB_DISPLACEMENT = 3.0f * TOOLBAR_HEIGHT_DP;
-
-    private static final float SNAP_BACK_THRESHOLD = 0.3f;
-    private static final long BASE_ANIMATION_DURATION_MS = 500;
-
-    /**
-     * Panel's host interface.
-     */
-    public interface ReaderModePanelHost {
-        /**
-         * @return Reader mode header background color.
-         */
-        int getReaderModeHeaderBackgroundColor();
-
-        /**
-         * @return One of ReaderModeManager.POSSIBLE, NOT_POSSIBLE, STARTED constants.
-         */
-        int getReaderModeStatus();
-
-        /**
-         * @return An associated tab.
-         */
-        Tab getTab();
-
-        /**
-         * @param X X-coordinate in dp
-         * @param Y Y-coordinate in dp
-         * @return Whether a given coordinates are within the bounds of the "dismiss" button
-         */
-        boolean isInsideDismissButton(float x, float y);
-
-        /**
-         * Creates the Reader Mode control if necessary.
-         */
-        void createReaderModeControl();
-
-        /**
-         * Destroys the Reader Mode control.
-         */
-        void destroyReaderModeControl();
-    }
-
-    /**
-     * Layout integration interface.
-     */
-    public interface ReaderModePanelLayoutDelegate {
-        /**
-         * Requests a next update to refresh the transforms and changing properties.
-         */
-        void requestUpdate();
-
-        /**
-         * Sets the brightness of the LayoutTab to a given value.
-         * @param v Brightness
-         */
-        void setLayoutTabBrightness(float v);
-
-        /**
-         * Sets the Y offset of the LayoutTab to a given value.
-         * @param v Y-offset in dp
-         */
-        void setLayoutTabY(float v);
-    }
-
-    /**
-     * Properties that can be animated by using a
-     * {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable}.
-     */
-    public enum Property {
-        /**
-         * Parametric vertical slider from
-         * -1.0 (panel is out of screen) to
-         * 0.0 (panel is on screen) to
-         * 1.0 (panel covers the entire screen)
-         */
-        SLIDING_T,
-        /**
-         * Horizontal slider, offset in dp
-         */
-        X,
-    }
-
-    private float mSlidingT;
-    private float mX;
-
-    private ScrollDirection mSwipeDirection;  // set in swipeStarted
-    private float mInitialPanelDistanceFromBottom;  // distance from the bottom at swipeStarted
-    private float mInitialX;  // X at swipeStarted
-
-    /**
-     * The animation set.
-     */
-    private ChromeAnimation<ChromeAnimation.Animatable<?>> mLayoutAnimations;
-
-    private boolean mIsReaderModePanelHidden;
-    private boolean mIsReaderModePanelDismissed;
-    private boolean mIsFullscreenModeEntered;
-    private boolean mIsInfobarContainerShown;
-
-    private ContentViewCore mDistilledContentViewCore;
-    private boolean mDidStartLoad;
-    private boolean mDidFinishLoad;
-    private WebContentsObserver mDistilledContentObserver;
-    private boolean mDidFirstNonEmptyDistilledPaint;
-    private ReaderModePanelLayoutDelegate mLayoutDelegate;
-    private WebContents mOriginalWebContent;
-
-    private float mLayoutWidth;
-    private float mLayoutHeight;
-    private boolean mIsToolbarShowing;
-    private float mDpToPx;
-
-    /**
-     * ContentViewClient state to override when the distilled ContentViewCore is set on the Tab.
-     */
-    private float mTopControlsOffsetYPix;
-    private float mContentOffsetYPix;
-    private float mOverdrawBottomHeightPix;
-
-    /**
-     * The {@link ReaderModePanelHost} used to get reader mode status and the associated tab.
-     */
-    private final ReaderModePanelHost mReaderModeHost;
-
-    /**
-     * The SceneLayer responsible for drawing the panel.
-     */
-    private ReaderModeSceneLayer mSceneLayer;
-
-    /**
-     * Non-animated button support.
-     */
-    private boolean mAllowAnimatedButton;
-    private ReaderModeButtonView mReaderModeButtonView;
-
-    public ReaderModePanel(ReaderModePanelHost readerModeHost, Context context) {
-        mReaderModeHost = readerModeHost;
-
-        // Make sure all WebContents are destroyed when a tab is closed: crbug.com/496653
-        mReaderModeHost.getTab().addObserver(new EmptyTabObserver() {
-            @Override
-            public void onDestroyed(Tab tab) {
-                destroyCachedOriginalWebContent();
-                destroyDistilledContentViewCore();
-            }
-        });
-
-        mAllowAnimatedButton = CommandLine.getInstance().hasSwitch(
-                ChromeSwitches.ENABLE_READER_MODE_BUTTON_ANIMATION);
-
-        mLayoutWidth = 0.0f;
-        mLayoutHeight = 0.0f;
-        mDpToPx = 1.0f;
-
-        mSlidingT = -1.0f;
-        mX = 0.0f;
-
-        float dpToPx = context.getResources().getDisplayMetrics().density;
-        mSceneLayer = new ReaderModeSceneLayer(dpToPx);
-    }
-
-    /**
-     * Get this panel's SceneLayer.
-     * NOTE(mdjones): This overrides a method in OverlayPanel once the refactor is complete.
-     */
-    public SceneLayer getSceneLayer() {
-        return mSceneLayer;
-    }
-
-    /**
-     * Update this panel's SceneLayer.
-     * NOTE(mdjones): This overrides a method in OverlayPanel once the refactor is complete.
-     * @param resourceManager Resource manager for static resources.
-     */
-    public void updateSceneLayer(ResourceManager resourceManager) {
-        mSceneLayer.update(this, resourceManager);
-    }
-
-    /**
-     * Destroys the panel and associated resources.
-     */
-    public void onDestroy() {
-        hideButtonBar();
-    }
-
-    /**
-     * Set the layout delegate.
-     * @param layoutDelegate A {@link ReaderModePanelLayoutDelegate} to call.
-     */
-    public void setLayoutDelegate(ReaderModePanelLayoutDelegate layoutDelegate) {
-        mLayoutDelegate = layoutDelegate;
-        requestUpdate();
-    }
-
-    // ChromeAnimation.Animatable<Property>:
-
-    private void setSlidingT(float val) {
-        mSlidingT = val;
-        if (mLayoutDelegate != null) {
-            mLayoutDelegate.setLayoutTabBrightness(getTabBrightness());
-            mLayoutDelegate.setLayoutTabY(getTabYOffset());
-        }
-    }
-
-    @Override
-    public void setProperty(Property prop, float val) {
-        switch (prop) {
-            case SLIDING_T:
-                setSlidingT(val);
-                break;
-            case X:
-                mX = val;
-                break;
-        }
-    }
-
-    private static float clamp(float val, float lower, float higher) {
-        return val < lower ? lower : (val > higher ? higher : val);
-    }
-
-    private static float interp(float factor, float start, float end) {
-        return start + clamp(factor, 0.0f, 1.0f) * (end - start);
-    }
-
-    private float getPanelDistanceFromBottom() {
-        if (mSlidingT < 0.0f) return interp(mSlidingT + 1.0f, 0.0f, PANEL_HEIGHT_DP);
-        return PANEL_HEIGHT_DP + interp(mSlidingT, 0.0f, getFullscreenHeight());
-    }
-
-    private float getSlidingTForPanelDistanceFromBottom(float distanceFromBottom) {
-        if (distanceFromBottom >= PANEL_HEIGHT_DP) {
-            return interp(
-                    (distanceFromBottom - PANEL_HEIGHT_DP) / getFullscreenHeight(),
-                    0.0f, 1.0f);
-        }
-        return interp(
-                (PANEL_HEIGHT_DP - distanceFromBottom) / PANEL_HEIGHT_DP,
-                0.0f, -1.0f);
-    }
-
-    private float getDistilledContentDistanceFromBottom() {
-        if (mSlidingT < 0.0f) return interp(mSlidingT + 1.0f, -PANEL_HEIGHT_DP, 0.0f);
-        return interp(mSlidingT, 0.0f, getFullscreenHeight());
-    }
-
-    private static float snapBackSlidingT(float v) {
-        // We snap asymmetrically: 30% is enough to get it opened, but 70% is necessary to dismiss.
-        v = (v < -1.0f + SNAP_BACK_THRESHOLD) ? v : (v >= SNAP_BACK_THRESHOLD ? v : 0.0f);
-        return Math.signum(v);
-    }
-
-    private static float snapBackX(float v) {
-        // Horizontally we snap symmetrically: more than 70% to each side to dismiss.
-        v = (v < -1.0f + SNAP_BACK_THRESHOLD) ? v : (v >= 1.0f - SNAP_BACK_THRESHOLD ? v : 0.0f);
-        return Math.signum(v);
-    }
-
-    // Gesture handling:
-
-    /**
-     * @param direction Swipe direction to test
-     * @return Whether the swipe in a given direction is enabled
-     */
-    public boolean isSwipeEnabled(ScrollDirection direction) {
-        return !isAnimating();
-    }
-
-    /**
-     * Called when the swipe is started.
-     * @param direction Swipe direction
-     * @param x X-coordinate of the starting point in dp
-     * @param y Y-coordinate of the starting point in dp
-     */
-    public void swipeStarted(ScrollDirection direction, float x, float y) {
-        if (isAnimating()) return;
-
-        mSwipeDirection = direction;
-        mInitialPanelDistanceFromBottom = getPanelDistanceFromBottom();
-        mX = getX();
-
-        if (mSwipeDirection == ScrollDirection.UP) activatePreviewOfDistilledMode();
-
-        requestUpdate();
-    }
-
-    /**
-     * Called when the swipe is continued.
-     * @param tx X-offset since the start of the swipe in dp
-     * @param ty Y-offset since the start of the swipe in dp
-     */
-    public void swipeUpdated(float x, float y, float dx, float dy, float tx, float ty) {
-        if (isAnimating()) return;
-
-        if (mSwipeDirection == ScrollDirection.LEFT || mSwipeDirection == ScrollDirection.RIGHT) {
-            setProperty(ReaderModePanel.Property.X, clamp(mInitialX + tx,
-                    -mLayoutWidth + MINIMAL_BORDER_X_DP, mLayoutWidth - MINIMAL_BORDER_X_DP));
-        } else {
-            setProperty(ReaderModePanel.Property.SLIDING_T,
-                    getSlidingTForPanelDistanceFromBottom(mInitialPanelDistanceFromBottom - ty));
-        }
-        requestUpdate();
-    }
-
-    /**
-     * Called when the swipe is finished.
-     */
-    public void swipeFinished() {
-        if (isAnimating()) return;
-
-        final float snappedX = snapBackX(mX / mLayoutWidth) * mLayoutWidth;
-        final float snappedSlidingT = snapBackSlidingT(mSlidingT);
-        if (snappedX <= -mLayoutWidth || snappedX >= mLayoutWidth) dismissButtonBar();
-        if (snappedSlidingT < 0.0f) dismissButtonBar();
-
-        animateTo(snappedX, snappedSlidingT, true);
-    }
-
-    // Panel layout handling:
-
-    /**
-     * @return Whether the panel should be shown.
-     */
-    public boolean isShowing() {
-        return isPanelWithinScreenBounds() || isAnimating() || mDistilledContentViewCore != null;
-    }
-
-    /**
-     * @return Whether the panel is within screen bounds.
-     */
-    private boolean isPanelWithinScreenBounds() {
-        return mSlidingT > -1.0f;
-    }
-
-    /**
-     * @return The fullscreen height.
-     */
-    private float getFullscreenHeight() {
-        return mLayoutHeight + TOOLBAR_HEIGHT_DP;
-    }
-
-    public float getFullscreenY(float y) {
-        if (mIsToolbarShowing) y += TOOLBAR_HEIGHT_DP * mDpToPx;
-        return y;
-    }
-
-    public float getPanelY() {
-        return getFullscreenHeight() - getPanelDistanceFromBottom() - SHADOW_HEIGHT_DP;
-    }
-
-    public float getDistilledContentY() {
-        return getFullscreenHeight() - getDistilledContentDistanceFromBottom() - SHADOW_HEIGHT_DP;
-    }
-
-    public float getWidth() {
-        return mLayoutWidth;
-    }
-
-    public float getPanelHeight() {
-        return getPanelDistanceFromBottom();
-    }
-
-    public float getMarginTop() {
-        return SHADOW_HEIGHT_DP;
-    }
-
-    public float getDistilledHeight() {
-        return getDistilledContentDistanceFromBottom();
-    }
-
-    public float getX() {
-        return mX;
-    }
-
-    public float getTextOpacity() {
-        return interp(mSlidingT, 1.0f, 0.0f);
-    }
-
-    public float getTabBrightness() {
-        return interp(mSlidingT, 1.0f, DARKEN_LAYOUTTAB_BRIGHTNESS);
-    }
-
-    public float getTabYOffset() {
-        return interp(mSlidingT, 0.0f, -MAX_LAYOUTTAB_DISPLACEMENT);
-    }
-
-    /**
-     * @param currentOffset The current top controls offset in dp.
-     * @return {@link Float#NaN} if no offset should be used, or a value in dp
-     *         if the top controls offset should be overridden.
-     */
-    public float getTopControlsOffset(float currentOffsetDp) {
-        if (mSlidingT <= 0.0f) return Float.NaN;
-        return MathUtils.clamp(getTabYOffset(), -TOOLBAR_HEIGHT_DP, Math.min(currentOffsetDp, 0f));
-    }
-
-
-    public ContentViewCore getDistilledContentViewCore() {
-        return mDistilledContentViewCore;
-    }
-
-    public boolean didFirstNonEmptyDistilledPaint() {
-        return mDidFirstNonEmptyDistilledPaint;
-    }
-
-    public int getReaderModeHeaderBackgroundColor() {
-        return mReaderModeHost.getReaderModeHeaderBackgroundColor();
-    }
-
-    /**
-     * Called when the size of the view has changed.
-     *
-     * @param width  The new width in dp.
-     * @param height The new width in dp.
-     * @param isToolbarShowing Whether the Toolbar is showing.
-     * @param dpToPx Multipler to convert from dp to pixels.
-     */
-    public void onSizeChanged(float width, float height, boolean isToolbarShowing, float dpToPx) {
-        mLayoutWidth = width;
-        mLayoutHeight = height;
-        mIsToolbarShowing = isToolbarShowing;
-        mDpToPx = dpToPx;
-    }
-
-    // Layout integration:
-
-    /**
-     * Requests a new frame to be updated and rendered.
-     */
-    private void requestUpdate() {
-        if (mLayoutDelegate != null) mLayoutDelegate.requestUpdate();
-    }
-
-    // Animation handling:
-
-    /**
-     * @return Whether a panel animation is in progress.
-     */
-    private boolean isAnimating() {
-        return mLayoutAnimations != null && !mLayoutAnimations.finished();
-    }
-
-    /**
-     * Animates to a given target value.
-     * @param targetX A target value for the X parameter
-     * @param targetSlidingT A target value for the SlidingT parameter
-     */
-    private void animateTo(float targetX, float targetSlidingT, boolean animate) {
-        if (targetSlidingT > 0.0f) activatePreviewOfDistilledMode();
-
-        if (isAnimating()) {
-            mLayoutAnimations.cancel(this, Property.SLIDING_T);
-            mLayoutAnimations.cancel(this, Property.X);
-        }
-        if (mLayoutAnimations == null || mLayoutAnimations.finished()) {
-            mLayoutAnimations = new ChromeAnimation<Animatable<?>>();
-        }
-
-        mLayoutAnimations.add(createAnimation(
-                this, Property.SLIDING_T, mSlidingT, targetSlidingT,
-                BASE_ANIMATION_DURATION_MS, 0, false,
-                ChromeAnimation.getDecelerateInterpolator()));
-        mLayoutAnimations.add(createAnimation(
-                this, Property.X, mX, targetX,
-                BASE_ANIMATION_DURATION_MS, 0, false,
-                ChromeAnimation.getDecelerateInterpolator()));
-        mLayoutAnimations.start();
-
-        if (!animate) mLayoutAnimations.updateAndFinish();
-        requestUpdate();
-    }
-
-    /**
-     * Steps the animation forward and updates all the animated values.
-     * @param time      The current time of the app in ms.
-     * @param jumpToEnd Whether to finish the animation.
-     * @return          Whether the animation was finished.
-     */
-    public boolean onUpdateAnimation(long time, boolean jumpToEnd) {
-        boolean finished = true;
-        if (mLayoutAnimations != null) {
-            if (jumpToEnd) {
-                finished = mLayoutAnimations.finished();
-                mLayoutAnimations.updateAndFinish();
-            } else {
-                finished = mLayoutAnimations.update(time);
-            }
-
-            if (finished || jumpToEnd) {
-                mLayoutAnimations = null;
-                onAnimationFinished();
-            }
-            requestUpdate();
-        }
-        return finished;
-    }
-
-    /**
-     * Called when layout-specific actions are needed after the animation finishes.
-     */
-    private void onAnimationFinished() {
-        if (mSlidingT >= 1.0f) enterDistilledMode();
-        updateBottomButtonBar();
-    }
-
-    // Gesture handling:
-
-    /**
-     * @param y The y coordinate in dp.
-     * @return Whether the given |y| coordinate is inside the Reader mode area.
-     */
-    public boolean isYCoordinateInsideReaderModePanel(float y) {
-        return y >= getPanelY() || y >= getDistilledContentY();
-    }
-
-    /**
-     * Handles a click in the panel area.
-     * @param x X-coordinate in dp
-     * @param y Y-coordinate in dp
-     */
-    public void handleClick(long time, float x, float y) {
-        if (mReaderModeHost.isInsideDismissButton(x * mDpToPx + mX, PANEL_HEIGHT_DP / 2)) {
-            dismissButtonBar();
-            return;
-        }
-
-        animateTo(mX, 1.0f, true);
-    }
-
-    /**
-     * @return Whether the reader mode could be currently allowed.
-     */
-    public boolean isReaderModeCurrentlyAllowed() {
-        return !mIsReaderModePanelHidden && !mIsReaderModePanelDismissed
-                && !mIsFullscreenModeEntered && !mIsInfobarContainerShown
-                && mReaderModeHost.getTab() != null
-                && mReaderModeHost.getTab().getContentViewCore() != null
-                && mReaderModeHost.getTab().getContentViewCore().getContext() != null
-                && mReaderModeHost.getTab().getWebContents() != null;
-    }
-
-    private void nonAnimatedUpdateButtomButtonBar() {
-        final int status = mReaderModeHost.getReaderModeStatus();
-        final Tab tab = mReaderModeHost.getTab();
-
-        if (mReaderModeButtonView != null
-                && (status != ReaderModeManager.POSSIBLE || !isReaderModeCurrentlyAllowed())) {
-            // Unfortunately, dismiss() couldn't be used because it might attempt to remove a view
-            // while in onLayout, thus causing crash.
-            final ReaderModeButtonView buttonView = mReaderModeButtonView;
-            mReaderModeButtonView.post(new Runnable() {
-                @Override
-                public void run() {
-                    // Unfortunately, dismiss() couldn't be used because it might attempt
-                    // to remove a view while in onLayout, thus causing crash.
-                    buttonView.removeFromParentView();
-                }
-            });
-            mReaderModeButtonView = null;
-            return;
-        }
-
-        if (mReaderModeButtonView == null
-                && (status == ReaderModeManager.POSSIBLE && isReaderModeCurrentlyAllowed())) {
-            mReaderModeButtonView = ReaderModeButtonView.create(tab.getContentViewCore(),
-                    new ReaderModeButtonViewDelegate() {
-                        @Override
-                        public void onSwipeAway() {
-                            dismissButtonBar();
-                        }
-
-                        @Override
-                        public void onClick() {
-                            nonAnimatedEnterDistilledMode();
-                        }
-                    });
-        }
-    }
-
-    /**
-     * Updates the visibility of the reader mode button bar as required.
-     */
-    public void updateBottomButtonBar() {
-        if (!mAllowAnimatedButton) {
-            nonAnimatedUpdateButtomButtonBar();
-            return;
-        }
-
-        if (isAnimating()) {
-            mReaderModeHost.createReaderModeControl();
-            return;
-        }
-
-        final int status = mReaderModeHost.getReaderModeStatus();
-        if (isPanelWithinScreenBounds()
-                && (status != ReaderModeManager.POSSIBLE || !isReaderModeCurrentlyAllowed())) {
-            animateTo(0.0f, -1.0f, true);
-            mReaderModeHost.destroyReaderModeControl();
-            destroyCachedOriginalWebContent();
-            destroyDistilledContentViewCore();
-            requestUpdate();
-            return;
-        }
-
-        if (!isPanelWithinScreenBounds()
-                && (status == ReaderModeManager.POSSIBLE && isReaderModeCurrentlyAllowed())) {
-            animateTo(0.0f, 0.0f, true);
-            mReaderModeHost.createReaderModeControl();
-            requestUpdate();
-            return;
-        }
-    }
-
-    private ContentViewCore createDistillerContentViewCore(
-            Context context, WindowAndroid windowAndroid) {
-        boolean isHostTabIncognito =
-                mReaderModeHost.getTab().getContentViewCore().getWebContents().isIncognito();
-        ContentViewCore cvc = new ContentViewCore(context);
-        ContentView cv = ContentView.createContentView(context, cvc);
-        cvc.initialize(cv, cv, WebContentsFactory.createWebContents(isHostTabIncognito, true),
-                windowAndroid);
-        cvc.setContentViewClient(new ContentViewClient() {
-            @Override
-            public void onOffsetsForFullscreenChanged(float topControlsOffsetYPix,
-                    float contentOffsetYPix, float overdrawBottomHeightPix) {
-                super.onOffsetsForFullscreenChanged(topControlsOffsetYPix, contentOffsetYPix,
-                        overdrawBottomHeightPix);
-                mTopControlsOffsetYPix = topControlsOffsetYPix;
-                mContentOffsetYPix = contentOffsetYPix;
-                mOverdrawBottomHeightPix = overdrawBottomHeightPix;
-            }
-        });
-        return cvc;
-    }
-
-    /**
-     * Prepares the distilled mode.
-     */
-    public void activatePreviewOfDistilledMode() {
-        final long start = SystemClock.elapsedRealtime();
-
-        if (mDistilledContentViewCore != null) return;
-
-        mDidFirstNonEmptyDistilledPaint = false;
-        mDidStartLoad = false;
-        mDidFinishLoad = false;
-
-        destroyCachedOriginalWebContent();
-        mDistilledContentViewCore = createDistillerContentViewCore(
-                mReaderModeHost.getTab().getContentViewCore().getContext(),
-                mReaderModeHost.getTab().getWindowAndroid());
-
-        mergeNavigationHistory(mDistilledContentViewCore.getWebContents(),
-                mReaderModeHost.getTab().getWebContents());
-
-        mDistilledContentObserver = new WebContentsObserver(
-                mDistilledContentViewCore.getWebContents()) {
-            @Override
-            public void didFirstVisuallyNonEmptyPaint() {
-                super.didFirstVisuallyNonEmptyPaint();
-                mDidFirstNonEmptyDistilledPaint = true;
-
-                RecordHistogram.recordTimesHistogram("DomDistiller.Time.SwipeToPaint",
-                        SystemClock.elapsedRealtime() - start, TimeUnit.MILLISECONDS);
-            }
-
-            @Override
-            public void didStartLoading(String url) {
-                super.didStartLoading(url);
-                mDidStartLoad = true;
-            }
-
-            @Override
-            public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
-                super.didFinishLoad(frameId, validatedUrl, isMainFrame);
-                if (isMainFrame) mDidFinishLoad = true;
-            }
-        };
-        mReaderModeHost.getTab().attachOverlayContentViewCore(
-                mDistilledContentViewCore, true, false);
-        DomDistillerTabUtils.distillAndView(
-                mReaderModeHost.getTab().getContentViewCore().getWebContents(),
-                mDistilledContentViewCore.getWebContents());
-        mDistilledContentViewCore.onShow();
-    }
-
-    private void nonAnimatedEnterDistilledMode() {
-        RecordUserAction.record("DomDistiller_DistilledPageOpened");
-        DomDistillerTabUtils.distillCurrentPageAndView(mReaderModeHost.getTab().getWebContents());
-        nonAnimatedUpdateButtomButtonBar();
-    }
-
-    private static void mergeNavigationHistory(WebContents target, WebContents source) {
-        target.getNavigationController().clearHistory();
-        NavigationController distilled = target.getNavigationController();
-        NavigationController original = source.getNavigationController();
-        if (distilled.canPruneAllButLastCommitted()) {
-            distilled.copyStateFromAndPrune(original, false);
-        } else if (distilled.canCopyStateOver()) {
-            distilled.copyStateFrom(original);
-        }
-    }
-
-    private void enterDistilledMode() {
-        if (!isReaderModeCurrentlyAllowed()) return;
-
-        RecordUserAction.record("DomDistiller_DistilledPageOpened");
-        mSlidingT = -1.0f;
-        requestUpdate();
-
-        mDistilledContentViewCore.getWebContents().updateTopControlsState(true, false, false);
-
-        mReaderModeHost.getTab().detachOverlayContentViewCore(mDistilledContentViewCore);
-        mDistilledContentObserver.destroy();
-        mDistilledContentObserver = null;
-
-        mOriginalWebContent = mReaderModeHost.getTab().getWebContents();
-
-        mDistilledContentViewCore.setContentViewClient(new ContentViewClient());
-        mReaderModeHost.getTab().swapContentViewCore(mDistilledContentViewCore, false,
-                mDidStartLoad, mDidFinishLoad);
-        mDistilledContentViewCore.getContentViewClient().onOffsetsForFullscreenChanged(
-                mTopControlsOffsetYPix, mContentOffsetYPix, mOverdrawBottomHeightPix);
-
-        mDistilledContentViewCore = null;
-        destroyDistilledContentViewCore();
-
-        if (mLayoutDelegate != null) {
-            mLayoutDelegate.setLayoutTabBrightness(1.0f);
-            mLayoutDelegate.setLayoutTabY(0.0f);
-        }
-
-        updateBottomButtonBar();
-    }
-
-    private void destroyCachedOriginalWebContent() {
-        if (mOriginalWebContent != null) {
-            mOriginalWebContent.destroy();
-            mOriginalWebContent = null;
-        }
-    }
-
-    private void destroyDistilledContentViewCore() {
-        if (mDistilledContentObserver != null) {
-            mDistilledContentObserver.destroy();
-            mDistilledContentObserver = null;
-        }
-
-        if (mDistilledContentViewCore == null) return;
-
-        mReaderModeHost.getTab().detachOverlayContentViewCore(mDistilledContentViewCore);
-
-        mDistilledContentViewCore.getWebContents().destroy();
-        mDistilledContentViewCore.destroy();
-        mDistilledContentViewCore = null;
-    }
-
-    /**
-     * Hides the reader mode button bar if shown.
-     */
-    public void hideButtonBar() {
-        mIsReaderModePanelHidden = true;
-        mLayoutAnimations = null;
-        updateBottomButtonBar();
-    }
-
-    /**
-     * Dismisses the reader mode button bar if shown.
-     */
-    public void dismissButtonBar() {
-        mIsReaderModePanelDismissed = true;
-        mLayoutAnimations = null;
-        updateBottomButtonBar();
-    }
-
-    /**
-     * Shows the reader mode button bar if necessary.
-     */
-    public void unhideButtonBar() {
-        mIsReaderModePanelHidden = false;
-        updateBottomButtonBar();
-    }
-
-    /**
-     * Temporarily hides the reader mode button while the video is shown.
-     */
-    public void onEnterFullscreen() {
-        mIsFullscreenModeEntered = true;
-        mLayoutAnimations = null;
-        updateBottomButtonBar();
-    }
-
-    /**
-     * Re-shows the reader mode button if necessary once the video is exited.
-     */
-    public void onExitFullscreen() {
-        mIsFullscreenModeEntered = false;
-        updateBottomButtonBar();
-    }
-
-    /**
-     * Temporarily hides the reader mode button while the infobars are shown.
-     */
-    public void onShowInfobarContainer() {
-        mIsInfobarContainerShown = true;
-        mLayoutAnimations = null;
-        updateBottomButtonBar();
-    }
-
-    /**
-     * Re-shows the reader mode button if necessary once the infobars are dismissed.
-     */
-    public void onHideInfobarContainer() {
-        mIsInfobarContainerShown = false;
-        updateBottomButtonBar();
-    }
-
-    /**
-      * @param tab A {@link Tab}.
-      * @return The panel associated with a given Tab.
-      */
-    public static ReaderModePanel getReaderModePanel(Tab tab) {
-        ReaderModeManager manager = tab.getReaderModeManager();
-        if (manager == null) return null;
-        return manager.getReaderModePanel();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeStaticEventFilter.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeStaticEventFilter.java
deleted file mode 100644
index e97ca86..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeStaticEventFilter.java
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2015 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.
-
-package org.chromium.chrome.browser.dom_distiller;
-
-import android.content.Context;
-import android.view.MotionEvent;
-
-import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeHandler;
-import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
-import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilterHost;
-import org.chromium.chrome.browser.contextualsearch.SwipeRecognizer;
-
-/**
- * A {@link EventFilter} used to filter events in the Reader Mode Bar, when displayed
- * in the StaticLayout.
- */
-public class ReaderModeStaticEventFilter extends EventFilter {
-    /**
-     * The @{link ReaderModePanelSelector} that gives access to a panel controlling Reader Mode UI.
-     */
-    private final ReaderModePanelSelector mReaderModePanelSelector;
-
-    /**
-     * The @{link SwipeRecognizer} that recognizes directional swipe gestures.
-     */
-    private final SwipeRecognizer mSwipeRecognizer;
-
-    private final ReaderModeTapHandler mTapHandler;
-
-    /**
-     * Interface to handle taps on the reader mode bar.
-     */
-    public interface ReaderModeTapHandler {
-        /**
-         * Handle a tap event on the reader mode bar.
-         * @param time The time of the tap event.
-         * @param x The x position of the tap event.
-         * @param y The y position of the tap event.
-         */
-        void handleTapReaderModeBar(long time, float x, float y);
-    }
-
-    /**
-     * Interface to get the currently active Reader Mode Panel if any.
-     */
-    public interface ReaderModePanelSelector {
-        /**
-         * @return Currently active reader mode panel, or null.
-         */
-        ReaderModePanel getActiveReaderModePanel();
-    }
-
-    /**
-     * Constructs a {@link ReaderModeStaticEventFilter}.
-     *
-     * @param context The current Android {@link Context}.
-     * @param host The @{link EventFilterHost} associated to this filter.
-     * @param readerModePanelSelector The @{link ReaderModePanelSelector} to access an active panel.
-     * @param swipeHandler The @{link EdgeSwipeHandler} for Reader Mode events.
-     */
-    public ReaderModeStaticEventFilter(Context context, EventFilterHost host,
-            ReaderModePanelSelector readerModePanelSelector, EdgeSwipeHandler swipeHandler,
-            ReaderModeTapHandler tapHandler) {
-        super(context, host);
-
-        mReaderModePanelSelector = readerModePanelSelector;
-        mSwipeRecognizer = new SwipeRecognizerImpl(context);
-        mSwipeRecognizer.setSwipeHandler(swipeHandler);
-        mTapHandler = tapHandler;
-    }
-
-    @Override
-    protected boolean onInterceptTouchEventInternal(MotionEvent event, boolean isKeyboardShowing) {
-        ReaderModePanel readerModePanel = mReaderModePanelSelector.getActiveReaderModePanel();
-        return readerModePanel != null && readerModePanel.isShowing()
-                && readerModePanel.isYCoordinateInsideReaderModePanel(
-                        readerModePanel.getFullscreenY(event.getY()) * mPxToDp);
-    }
-
-    @Override
-    protected boolean onTouchEventInternal(MotionEvent event) {
-        mSwipeRecognizer.onTouchEvent(event);
-        return true;
-    }
-
-    private class SwipeRecognizerImpl extends SwipeRecognizer {
-        public SwipeRecognizerImpl(Context context) {
-            super(context);
-        }
-
-        @Override
-        public boolean onSingleTapUp(MotionEvent event) {
-            if (mTapHandler == null) return true;
-            ReaderModePanel readerModePanel = mReaderModePanelSelector.getActiveReaderModePanel();
-            if (readerModePanel == null) return true;
-
-            mTapHandler.handleTapReaderModeBar(event.getEventTime(),
-                    event.getX() * mPxToDp,
-                    readerModePanel.getFullscreenY(event.getY()) * mPxToDp);
-            return true;
-        }
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTabInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTabInfo.java
new file mode 100644
index 0000000..050caa4
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeTabInfo.java
@@ -0,0 +1,100 @@
+// Copyright 2015 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.
+
+package org.chromium.chrome.browser.dom_distiller;
+
+import org.chromium.content_public.browser.WebContentsObserver;
+
+/**
+ * This class tracks the per-tab state of reader mode.
+ */
+public class ReaderModeTabInfo {
+    // The WebContentsObserver responsible for updates to the distillation status of the tab.
+    private WebContentsObserver mWebContentsObserver;
+
+    // The distillation status of the tab.
+    private int mStatus;
+
+    // If the panel was closed due to the close button.
+    private boolean mIsDismissed;
+
+    // The URL that distiller is using for this tab. This is used to check if a result comes
+    // back from distiller and the user has already loaded a new URL.
+    private String mCurrentUrl;
+
+    // The distillability heuristics now use a callback to notify the manager that a page can
+    // be distilled. This flag is used to detect if the callback is set for this tab.
+    private boolean mIsCallbackSet;
+
+    /**
+     * @param observer The WebContentsObserver for the tab this object represents.
+     */
+    public void setWebContentsObserver(WebContentsObserver observer) {
+        mWebContentsObserver = observer;
+    }
+
+    /**
+     * @return The WebContentsObserver for the tab this object represents.
+     */
+    public WebContentsObserver getWebContentsObserver() {
+        return mWebContentsObserver;
+    }
+
+    /**
+     * @param status The status of reader mode for this object's tab.
+     */
+    public void setStatus(int status) {
+        mStatus = status;
+    }
+
+    /**
+     * @return The reader mode status for this object's tab.
+     */
+    public int getStatus() {
+        return mStatus;
+    }
+
+    /**
+     * @return If the panel has been dismissed for this object's tab.
+     */
+    public boolean isDismissed() {
+        return mIsDismissed;
+    }
+
+    /**
+     * @param dismissed Set the panel as dismissed for this object's tab.
+     */
+    public void setIsDismissed(boolean dismissed) {
+        mIsDismissed = dismissed;
+    }
+
+    /**
+     * @param url The URL being processed by reader mode.
+     */
+    public void setUrl(String url) {
+        mCurrentUrl = url;
+    }
+
+    /**
+     * @return The last URL being processed by reader mode.
+     */
+    public String getUrl() {
+        return mCurrentUrl;
+    }
+
+    /**
+     * @return If the distillability callback is set for this object's tab.
+     */
+    public boolean isCallbackSet() {
+        return mIsCallbackSet;
+    }
+
+    /**
+     * @param isSet Set if this object's tab has a distillability callback.
+     */
+    public void setIsCallbackSet(boolean isSet) {
+        mIsCallbackSet = isSet;
+    }
+}
+
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkItemsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkItemsAdapter.java
index 957fe77..183016b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkItemsAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkItemsAdapter.java
@@ -12,6 +12,7 @@
 import android.view.ViewGroup;
 
 import org.chromium.base.annotations.SuppressFBWarnings;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkItem;
 import org.chromium.chrome.browser.bookmark.BookmarksBridge.BookmarkModelObserver;
@@ -326,7 +327,11 @@
 
     @Override
     public void onAllBookmarksStateSet() {
-        setBookmarks(null, mDelegate.getModel().getAllBookmarkIDsOrderedByCreationDate());
+        List<BookmarkId> bookmarkIds =
+                mDelegate.getModel().getAllBookmarkIDsOrderedByCreationDate();
+        RecordHistogram.recordCountHistogram("EnhancedBookmarks.AllBookmarksCount",
+                bookmarkIds.size());
+        setBookmarks(null, bookmarkIds);
     }
 
     @Override
@@ -338,6 +343,8 @@
     @Override
     public void onFilterStateSet(EnhancedBookmarkFilter filter) {
         assert filter == EnhancedBookmarkFilter.OFFLINE_PAGES;
+        List<BookmarkId> bookmarkIds = mDelegate.getModel().getBookmarkIDsByFilter(filter);
+        RecordHistogram.recordCountHistogram("OfflinePages.OfflinePageCount", bookmarkIds.size());
         setBookmarks(null, mDelegate.getModel().getBookmarkIDsByFilter(filter));
         mDelegate.getModel().getOfflinePageBridge().checkOfflinePageMetadata();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
index 601b7d41..99c8f0c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkManager.java
@@ -31,7 +31,6 @@
 import org.chromium.chrome.browser.snackbar.SnackbarManager;
 import org.chromium.chrome.browser.snackbar.SnackbarManager.SnackbarManageable;
 import org.chromium.components.bookmarks.BookmarkId;
-import org.chromium.components.variations.VariationsAssociatedData;
 import org.chromium.ui.base.DeviceFormFactor;
 
 import java.io.UnsupportedEncodingException;
@@ -51,8 +50,6 @@
 public class EnhancedBookmarkManager implements EnhancedBookmarkDelegate {
     private static final String PREF_LAST_USED_URL = "enhanced_bookmark_last_used_url";
     private static final int FAVICON_MAX_CACHE_SIZE_BYTES = 10 * 1024 * 1024; // 10MB
-    private static final String FIELD_TRIAL_NAME = "EnhancedBookmarks";
-    private static final String DEFAULT_FOLDER = "default_folder";
 
     private Activity mActivity;
     private ViewGroup mMainView;
@@ -547,14 +544,7 @@
             state.mUrl = url;
 
             if (url.equals(UrlConstants.BOOKMARKS_URL)) {
-                if (VariationsAssociatedData
-                        .getVariationParamValue(FIELD_TRIAL_NAME, DEFAULT_FOLDER)
-                        .equals("mobile")) {
-                    state.mFolder = bookmarkModel.getMobileFolderId();
-                    state.mState = STATE_FOLDER;
-                } else {
-                    state.mState = STATE_ALL_BOOKMARKS;
-                }
+                state.mState = STATE_ALL_BOOKMARKS;
             } else if (url.startsWith(UrlConstants.BOOKMARKS_FOLDER_URL)) {
                 String suffix = decodeSuffix(url, UrlConstants.BOOKMARKS_FOLDER_URL);
                 if (!suffix.isEmpty()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java
index 55c209f..938d8380 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarkUtils.java
@@ -191,12 +191,14 @@
 
             @Override
             public void onDismissNoAction(Object actionData) {
+                RecordUserAction.record("EnhancedBookmarks.EditAfterCreateButtonNotClicked");
                 // This method will be called only if the snackbar is dismissed by timeout.
                 bookmarkModel.destroy();
             }
 
             @Override
             public void onAction(Object actionData) {
+                RecordUserAction.record("EnhancedBookmarks.EditAfterCreateButtonClicked");
                 // Show edit activity with the name of parent folder highlighted.
                 startEditActivity(activity, bookmarkId, null);
                 bookmarkModel.destroy();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarksModel.java b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarksModel.java
index 35f24c1..5ec6761 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarksModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/enhancedbookmarks/EnhancedBookmarksModel.java
@@ -8,6 +8,7 @@
 
 import org.chromium.base.ObserverList;
 import org.chromium.base.VisibleForTesting;
+import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.browser.ChromeBrowserProviderClient;
 import org.chromium.chrome.browser.bookmark.BookmarksBridge;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge;
@@ -23,9 +24,11 @@
 import org.chromium.content_public.browser.WebContents;
 
 import java.util.ArrayList;
+import java.util.Calendar;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.concurrent.TimeUnit;
 
 /**
  * A class that encapsulates {@link BookmarksBridge} and provides extra features such as undo, large
@@ -236,6 +239,8 @@
             final AddBookmarkCallback callback) {
         assert bookmarkId.getId() != ChromeBrowserProviderClient.INVALID_BOOKMARK_ID;
         if (mOfflinePageBridge != null) {
+            RecordHistogram.recordBooleanHistogram("OfflinePages.IncognitoSave",
+                    webContents.isIncognito());
             mOfflinePageBridge.savePage(webContents, bookmarkId, new SavePageCallback() {
                 @Override
                 public void onSavePageDone(int savePageResult, String url) {
@@ -262,7 +267,7 @@
 
     /**
      * Retrieves the url to launch a bookmark or saved page. If latter, also marks it as being
-     * accessed.
+     * accessed and reports the UMAs.
      *
      * @parma context Context for checking connection.
      * @param bookmarkId ID of the bookmark to launch.
@@ -270,17 +275,36 @@
      */
     public String getLaunchUrlAndMarkAccessed(Context context, BookmarkId bookmarkId) {
         String url = getBookmarkById(bookmarkId).getUrl();
-        // When there is a network connection, we visit original URL online.
-        if (mOfflinePageBridge == null || OfflinePageUtils.isConnected(context)) return url;
+        if (mOfflinePageBridge == null) return url;
 
-        // Return the offline url for the offline page if one exists.
+        // Returns the original URL if the offline copy was not found.
         OfflinePageItem page = mOfflinePageBridge.getPageByBookmarkId(bookmarkId);
         if (page == null) return url;
 
+        boolean isConnected = OfflinePageUtils.isConnected(context);
+        RecordHistogram.recordBooleanHistogram("OfflinePages.OnlineOnOpen", isConnected);
+
+        // When there is a network connection, we visit original URL online.
+        if (isConnected) return url;
+
+        // The last access time was set to same as creation time when the page was created.
+        int currentMinutes = Calendar.getInstance().get(Calendar.MINUTE);
+        int maxMinutes = (int) TimeUnit.DAYS.toMinutes(90);
+        if (page.getCreationTimeMs() == page.getLastAccessTimeMs()) {
+            RecordHistogram.recordCustomCountHistogram("OfflinePages.FirstOpenSinceCreated",
+                    (int) (currentMinutes - page.getCreationTimeMs() / (1000 * 60)), 1, maxMinutes,
+                    50);
+        } else {
+            RecordHistogram.recordCustomCountHistogram("OfflinePages.OpenSinceLastOpen",
+                    (int) (currentMinutes - page.getLastAccessTimeMs() / (1000 * 60)), 1,
+                    maxMinutes, 50);
+        }
+
         // Mark that the offline page has been accessed, that will cause last access time and access
         // count being updated.
         mOfflinePageBridge.markPageAccessed(bookmarkId);
 
+        // Returns the offline URL for offine access.
         return page.getOfflineUrl();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DataReductionProxyFirstRunFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DataReductionProxyFirstRunFragment.java
index 1b3024cb..07d980f6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DataReductionProxyFirstRunFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/DataReductionProxyFirstRunFragment.java
@@ -5,12 +5,12 @@
 package org.chromium.chrome.browser.firstrun;
 
 import android.os.Bundle;
+import android.support.v7.widget.SwitchCompat;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.Button;
-import android.widget.Switch;
 
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
@@ -31,7 +31,7 @@
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
 
-        final Switch enableDataSaverSwitch = (Switch) view
+        final SwitchCompat enableDataSaverSwitch = (SwitchCompat) view
                 .findViewById(R.id.enable_data_saver_switch);
         Button nextButton = (Button) view.findViewById(R.id.next_button);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastRouteController.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastRouteController.java
index 166d997..13536c0e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastRouteController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastRouteController.java
@@ -454,6 +454,8 @@
             String messageType = jsonMessage.getString("type");
             if ("client_connect".equals(messageType)) {
                 success = handleClientConnectMessage(jsonMessage);
+            } else if ("leave_session".equals(messageType)) {
+                success = handleLeaveSessionMessage(jsonMessage);
             } else if ("v2_message".equals(messageType)) {
                 success = handleCastV2Message(jsonMessage);
             } else if ("app_message".equals(messageType)) {
@@ -484,6 +486,34 @@
         return true;
     }
 
+    // An example of the leave_session message.
+    //    {
+    //        "type": "leave_message",
+    //        "message": "<cast session id>",
+    //        "sequenceNumber": 0,  // optional
+    //        "timeoutMillis": 0,
+    //        "clientId": "<client id>"
+    //    }
+    private boolean handleLeaveSessionMessage(JSONObject jsonMessage) throws JSONException {
+        String clientId = jsonMessage.getString("clientId");
+
+        if (!mClients.contains(clientId)) return false;
+
+        String sessionId = jsonMessage.getString("message");
+        if (!mSessionId.equals(sessionId)) return false;
+
+        int sequenceNumber = jsonMessage.optInt("sequenceNumber", INVALID_SEQUENCE_NUMBER);
+
+        // TODO(avayvod): "leave" the other clients with the matching origin/tab id.
+        // See https://crbug.com/549957.
+        mRouteDelegate.onMessage(mMediaRouteId,
+                buildInternalMessage("leave_session", null, clientId, sequenceNumber));
+
+        mClients.remove(clientId);
+
+        return true;
+    }
+
     // An example of the Cast V2 message:
     //    {
     //        "type": "v2_message",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
index cb76110..2122168a2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPage.java
@@ -18,10 +18,12 @@
 import android.view.View;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.CommandLine;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.NativePage;
 import org.chromium.chrome.browser.UrlConstants;
 import org.chromium.chrome.browser.compositor.layouts.content.InvalidationAwareThumbnailProvider;
@@ -118,7 +120,7 @@
          *
          * @param scrollPercentage The percentage the search box has been scrolled off the page.
          */
-        void onScrollChanged(float scrollPercentage);
+        void onNtpScrollChanged(float scrollPercentage);
     }
 
     /**
@@ -244,7 +246,12 @@
         public void open(MostVisitedItem item) {
             if (mIsDestroyed) return;
             recordOpenedMostVisitedItem(item);
-            mTab.loadUrl(new LoadUrlParams(item.getUrl(), PageTransition.AUTO_BOOKMARK));
+            open(item.getUrl());
+        }
+
+        @Override
+        public void open(String url) {
+            mTab.loadUrl(new LoadUrlParams(url, PageTransition.AUTO_BOOKMARK));
         }
 
         @Override
@@ -476,8 +483,13 @@
     }
 
     private void updateSearchProviderHasLogo() {
-        mSearchProviderHasLogo = !mOptOutPromoShown
-                && TemplateUrlService.getInstance().isDefaultSearchEngineGoogle();
+        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_NTP_SNIPPETS)) {
+            mSearchProviderHasLogo = false;
+            if (mNewTabPageView != null) mNewTabPageView.setSearchProviderHasLogo(false);
+        } else {
+            mSearchProviderHasLogo = !mOptOutPromoShown
+                    && TemplateUrlService.getInstance().isDefaultSearchEngineGoogle();
+        }
     }
 
     private void onSearchEngineUpdated() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index d01be4d..6cb1f91 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -15,6 +15,8 @@
 import android.os.Build;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
 import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
 import android.text.Editable;
 import android.text.TextUtils;
 import android.text.TextWatcher;
@@ -32,8 +34,10 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
+import org.chromium.base.CommandLine;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.favicon.FaviconHelper.IconAvailabilityCallback;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
@@ -41,6 +45,7 @@
 import org.chromium.chrome.browser.ntp.LogoBridge.LogoObserver;
 import org.chromium.chrome.browser.ntp.MostVisitedItem.MostVisitedItemManager;
 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsManager;
 import org.chromium.chrome.browser.preferences.DocumentModeManager;
 import org.chromium.chrome.browser.profiles.MostVisitedSites.MostVisitedURLsObserver;
 import org.chromium.chrome.browser.profiles.MostVisitedSites.ThumbnailCallback;
@@ -73,12 +78,14 @@
     private View mMostVisitedPlaceholder;
     private View mOptOutView;
     private View mNoSearchLogoSpacer;
+    private RecyclerView mSnippetsView;
 
     private OnSearchBoxScrollListener mSearchBoxScrollListener;
 
     private NewTabPageManager mManager;
     private MostVisitedDesign mMostVisitedDesign;
     private MostVisitedItem[] mMostVisitedItems;
+    private SnippetsManager mSnippetsManager;
     private boolean mFirstShow = true;
     private boolean mSearchProviderHasLogo = true;
     private boolean mHasReceivedMostVisitedSites;
@@ -124,6 +131,9 @@
         /** Opens the recent tabs page in the current tab. */
         void navigateToRecentTabs();
 
+        /** Opens a given URL in the current tab. */
+        void open(String url);
+
         /**
          * Animates the search box up into the omnibox and bring up the keyboard.
          * @param beginVoiceSearch Whether to begin a voice search.
@@ -307,6 +317,14 @@
                 mMostVisitedDesign.getNumberOfTiles(searchProviderHasLogo));
 
         if (mManager.shouldShowOptOutPromo()) showOptOutPromo();
+
+        // Set up snippets
+        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_NTP_SNIPPETS)) {
+            mSnippetsView = (RecyclerView) findViewById(R.id.snippets_card_list);
+            mSnippetsView.setVisibility(View.VISIBLE);
+            mSnippetsView.setLayoutManager(new LinearLayoutManager(getContext()));
+            mSnippetsManager = new SnippetsManager(mManager, mSnippetsView);
+        }
     }
 
     private int getTabsMovedIllustration() {
@@ -385,7 +403,7 @@
         updateVisualsForToolbarTransition(percentage);
 
         if (mSearchBoxScrollListener != null) {
-            mSearchBoxScrollListener.onScrollChanged(percentage);
+            mSearchBoxScrollListener.onNtpScrollChanged(percentage);
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java
new file mode 100644
index 0000000..d9e3708
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetCardItemViewHolder.java
@@ -0,0 +1,84 @@
+// Copyright 2015 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.
+
+package org.chromium.chrome.browser.ntp.snippets;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsManager.SnippetArticle;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsManager.SnippetListItem;
+
+/**
+ * A class that represents the view for a single card snippet.
+ */
+class SnippetCardItemViewHolder extends SnippetListItemViewHolder implements View.OnClickListener {
+    public TextView mHeadlineTextView;
+    public TextView mPublisherTextView;
+    public TextView mArticleSnippetTextView;
+    public TextView mReadMoreLinkTextView;
+    public ImageView mThumbnailView;
+    public String mUrl;
+
+    /**
+     * Creates the CardView object to display snippets information
+     *
+     * @param parent The parent view for the card
+     * @return a CardView object for displaying snippets
+     */
+    public static View createView(ViewGroup parent) {
+        return LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.new_tab_page_snippets_card, parent, false);
+    }
+
+    /**
+     * Constructs a SnippetCardItemView item used to display snippets
+     *
+     * @param cardView The View for the snippet card
+     * @param manager The SnippetsManager object used to open an article
+     */
+    public SnippetCardItemViewHolder(View cardView, SnippetsManager manager) {
+        super(cardView, manager);
+
+        cardView.setOnClickListener(this);
+        mThumbnailView = (ImageView) cardView.findViewById(R.id.article_thumbnail);
+        mHeadlineTextView = (TextView) cardView.findViewById(R.id.article_headline);
+        mPublisherTextView = (TextView) cardView.findViewById(R.id.article_publisher);
+        mArticleSnippetTextView = (TextView) cardView.findViewById(R.id.article_snippet);
+        mReadMoreLinkTextView = (TextView) cardView.findViewById(R.id.read_more_link);
+        mReadMoreLinkTextView.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                loadUrl(mUrl);
+            }
+        });
+    }
+
+    @Override
+    public void onClick(View v) {
+        // Toggle visibility of snippet text
+        int visibility =
+                (mArticleSnippetTextView.getVisibility() == View.GONE) ? View.VISIBLE : View.GONE;
+
+        mArticleSnippetTextView.setVisibility(visibility);
+        mReadMoreLinkTextView.setVisibility(visibility);
+    }
+
+    @Override
+    public void onBindViewHolder(SnippetListItem snippetItem) {
+        SnippetArticle item = (SnippetArticle) snippetItem;
+
+        mHeadlineTextView.setText(item.mTitle);
+        mPublisherTextView.setText(item.mPublisher);
+        mArticleSnippetTextView.setText(item.mSnippet);
+        mUrl = item.mUrl;
+
+        item.setThumbnailOnView(mThumbnailView);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderItemViewHolder.java
new file mode 100644
index 0000000..05eda5a
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetHeaderItemViewHolder.java
@@ -0,0 +1,46 @@
+// Copyright 2015 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.
+
+package org.chromium.chrome.browser.ntp.snippets;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsManager.SnippetHeader;
+import org.chromium.chrome.browser.ntp.snippets.SnippetsManager.SnippetListItem;
+
+/**
+ * A class that represents the view for a header of a group of card snippets.
+ */
+class SnippetHeaderItemViewHolder extends SnippetListItemViewHolder {
+    private TextView mHeaderTextView;
+
+    public SnippetHeaderItemViewHolder(View view, SnippetsManager manager) {
+        super(view, manager);
+        mHeaderTextView = (TextView) view.findViewById(R.id.snippets_list_header);
+    }
+
+    /**
+     * Creates the TextView object for displaying the header for a group of snippets
+     *
+     * @param parent The parent view for the header
+     * @return a TextView object for displaying a header for a group of snippets
+     */
+    public static View createView(ViewGroup parent) {
+        return LayoutInflater.from(parent.getContext())
+                .inflate(R.layout.new_tab_page_snippets_header, parent, false);
+    }
+
+    @Override
+    public void onBindViewHolder(SnippetListItem snippetItem) {
+        SnippetHeader item = (SnippetHeader) snippetItem;
+
+        String headerText = mHeaderTextView.getContext().getString(
+                R.string.snippets_header, item.mRecommendationBasis);
+        mHeaderTextView.setText(headerText);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetListItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetListItemViewHolder.java
new file mode 100644
index 0000000..75dc552
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetListItemViewHolder.java
@@ -0,0 +1,46 @@
+// Copyright 2015 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.
+
+package org.chromium.chrome.browser.ntp.snippets;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+import org.chromium.chrome.browser.ntp.snippets.SnippetsManager.SnippetListItem;
+
+/**
+ * A class that represents an item we want to display in our list of card snippets.
+ */
+abstract class SnippetListItemViewHolder extends RecyclerView.ViewHolder {
+    private final SnippetsManager mManager;
+
+    /**
+     * Constructs a SnippetListItemViewHolder item used to display a component in the list of
+     * snippets (e.g., header, article snippet, separator, etc.)
+     *
+     * @param cardView The View for this item
+     * @param manager The SnippetsManager object used to open an article
+     */
+    public SnippetListItemViewHolder(View itemView, SnippetsManager manager) {
+        super(itemView);
+        mManager = manager;
+    }
+
+    /**
+     * Opens the given URL
+     *
+     * @param url The URL to open.
+     */
+    protected void loadUrl(String url) {
+        mManager.loadUrl(url);
+    }
+
+    /**
+     * Called when the snippets adapter is requested to update the currently visible ViewHolder with
+     * data.
+     *
+     * @param article The SnippetListItem object that holds the data for this ViewHolder
+     */
+    public abstract void onBindViewHolder(SnippetListItem snippetItem);
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsAdapter.java
new file mode 100644
index 0000000..fd481a4
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsAdapter.java
@@ -0,0 +1,71 @@
+// Copyright 2015 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.
+
+package org.chromium.chrome.browser.ntp.snippets;
+
+import android.support.v7.widget.RecyclerView.Adapter;
+import android.view.ViewGroup;
+
+import org.chromium.chrome.browser.ntp.snippets.SnippetsManager.SnippetListItem;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A class that represents the adapter backing the snippets RecyclerView.
+ */
+class SnippetsAdapter extends Adapter<SnippetListItemViewHolder> {
+    private List<SnippetListItem> mSnippetListItems;
+    private final SnippetsManager mManager;
+
+    /**
+     * Constructs a SnippetsAdapter object that backs the Snippets RecyclerView on the NTP
+     *
+     * @param snippetsManager SnippetsManager object used to open an article
+     */
+    public SnippetsAdapter(SnippetsManager snippetsManager) {
+        mManager = snippetsManager;
+        mSnippetListItems = Collections.emptyList();
+    }
+
+    /**
+     * Set the list of items to display in the snippets RecyclerView
+     *
+     * @param listItems the new list of items to display
+     */
+    public void setSnippetListItems(List<SnippetListItem> listItems) {
+        mSnippetListItems = listItems;
+        notifyDataSetChanged();
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return mSnippetListItems.get(position).getType();
+    }
+
+    @Override
+    public SnippetListItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if (viewType == SnippetsManager.SNIPPET_ITEM_TYPE_HEADER) {
+            return new SnippetHeaderItemViewHolder(
+                    SnippetHeaderItemViewHolder.createView(parent), mManager);
+        }
+
+        if (viewType == SnippetsManager.SNIPPET_ITEM_TYPE_SNIPPET) {
+            return new SnippetCardItemViewHolder(
+                    SnippetCardItemViewHolder.createView(parent), mManager);
+        }
+
+        return null;
+    }
+
+    @Override
+    public void onBindViewHolder(SnippetListItemViewHolder holder, final int position) {
+        holder.onBindViewHolder(mSnippetListItems.get(position));
+    }
+
+    @Override
+    public int getItemCount() {
+        return mSnippetListItems.size();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java
new file mode 100644
index 0000000..b8378b8
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsManager.java
@@ -0,0 +1,244 @@
+// Copyright 2015 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.
+
+package org.chromium.chrome.browser.ntp.snippets;
+
+import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.support.v7.widget.RecyclerView;
+import android.util.JsonReader;
+import android.widget.ImageView;
+
+import org.chromium.base.Log;
+import org.chromium.base.StreamUtil;
+import org.chromium.chrome.browser.ntp.NewTabPageView.NewTabPageManager;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A class that stores and manages the article snippets that will be shown on the NTP.
+ */
+public class SnippetsManager {
+    private static final String TAG = "SnippetsManager";
+
+    /**
+     * Describes the header of a group of similar card snippets
+     */
+    public static final int SNIPPET_ITEM_TYPE_HEADER = 1;
+    /**
+     * Describes a single card snippet
+     */
+    public static final int SNIPPET_ITEM_TYPE_SNIPPET = 2;
+
+    private NewTabPageManager mNewTabPageManager;
+    private SnippetsAdapter mDataAdapter;
+
+    /** Base type for anything to add to the snippets view
+     */
+    public interface SnippetListItem {
+        /**
+         * Returns the type of this snippet item (SNIPPET_ITEM_TYPE_HEADER or
+         * SNIPPET_ITEM_TYPE_SNIPPET). This is so we can distinguish between different elements
+         * that are held in a single RecyclerView holder.
+         *
+         * @return the type of this list item.
+         */
+        public int getType();
+    }
+
+    /** Represents the data for a header of a group of snippets
+     */
+    public static class SnippetHeader implements SnippetListItem {
+        public final String mRecommendationBasis;
+
+        public SnippetHeader(String recommendationBasis) {
+            mRecommendationBasis = recommendationBasis;
+        }
+
+        @Override
+        public int getType() {
+            return SNIPPET_ITEM_TYPE_HEADER;
+        }
+    }
+
+    /**
+     * Represents the data for a card snippet.
+     */
+    public static class SnippetArticle implements SnippetListItem {
+        public final String mTitle;
+        public final String mPublisher;
+        public final String mSnippet;
+        public final String mUrl;
+        public final String mThumbnailPath;
+
+        private ThumbnailRenderingTask mThumbnailRenderingTask;
+
+        // Async task to create the thumbnail from a local file
+        // TODO(maybelle): This task to retrieve the thumbnail from local disk is temporary while
+        // we are prototyping this feature for clank. For the real production feature, we
+        // will likely have to download/decode the thumbnail on the native side.
+        private static class ThumbnailRenderingTask extends AsyncTask<String, Void, Drawable> {
+            private ImageView mThumbnailView;
+
+            ThumbnailRenderingTask(ImageView thumbnailView) {
+                mThumbnailView = thumbnailView;
+            }
+
+            @Override
+            protected Drawable doInBackground(String... params) {
+                String thumbnailPath = params[0];
+                return Drawable.createFromPath(thumbnailPath);
+            }
+
+            @Override
+            protected void onPostExecute(Drawable thumbnail) {
+                mThumbnailView.setImageDrawable(thumbnail);
+            }
+        }
+
+        public SnippetArticle(
+                String title, String publisher, String snippet, String url, String thumbnailPath) {
+            mTitle = title;
+            mPublisher = publisher;
+            mSnippet = snippet;
+            mUrl = url;
+            mThumbnailPath = thumbnailPath;
+        }
+
+        @Override
+        public int getType() {
+            return SNIPPET_ITEM_TYPE_SNIPPET;
+        }
+
+        /**
+         * Retrieves this SnippetArticle's thumbnail asynchronously and sets it onto the given
+         * ImageView.
+         *
+         * @param view The ImageView to set the thumbnail onto.
+         */
+        public void setThumbnailOnView(ImageView view) {
+            if (mThumbnailRenderingTask != null) mThumbnailRenderingTask.cancel(true);
+
+            mThumbnailRenderingTask = new ThumbnailRenderingTask(view);
+            mThumbnailRenderingTask.executeOnExecutor(
+                    AsyncTask.THREAD_POOL_EXECUTOR, mThumbnailPath);
+        }
+    }
+
+    private class ReadFileTask extends AsyncTask<Void, Void, List<SnippetListItem>> {
+        @Override
+        protected List<SnippetListItem> doInBackground(Void... params) {
+            FileInputStream fis = null;
+            try {
+                fis = new FileInputStream(
+                        new File(Environment.getExternalStorageDirectory().getPath()
+                                + "/chrome/reading_list.json"));
+                List<SnippetListItem> listSnippetsGroups = readJsonStream(fis);
+                return listSnippetsGroups;
+            } catch (IOException ex) {
+                Log.e(TAG, "Exception reading file: %s ", ex);
+            } finally {
+                StreamUtil.closeQuietly(fis);
+            }
+            return null;
+        }
+
+        @Override
+        protected void onPostExecute(List<SnippetListItem> listSnippetsGroups) {
+            if (listSnippetsGroups == null) return;
+
+            mDataAdapter.setSnippetListItems(listSnippetsGroups);
+        }
+
+        private List<SnippetListItem> readJsonStream(InputStream in) throws IOException {
+            JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
+            try {
+                return readRecommendationsArray(reader);
+            } finally {
+                reader.close();
+            }
+        }
+
+        private List<SnippetListItem> readRecommendationsArray(JsonReader reader)
+                throws IOException {
+            List<SnippetListItem> listSnippetItems = new ArrayList<SnippetListItem>();
+            reader.beginArray();
+            while (reader.hasNext()) {
+                readSnippetGroup(listSnippetItems, reader);
+            }
+            reader.endArray();
+            return listSnippetItems;
+        }
+
+        private void readSnippetGroup(List<SnippetListItem> listSnippetItems, JsonReader reader)
+                throws IOException {
+            reader.beginObject();
+            while (reader.hasNext()) {
+                String name = reader.nextName();
+                if (name.equals("recommendation_basis")) {
+                    listSnippetItems.add(new SnippetHeader(reader.nextString()));
+                } else if (name.equals("articles")) {
+                    readArticlesArray(listSnippetItems, reader);
+                }
+            }
+            reader.endObject();
+        }
+
+        private void readArticlesArray(List<SnippetListItem> listSnippetItems, JsonReader reader)
+                throws IOException {
+            reader.beginArray();
+            while (reader.hasNext()) {
+                listSnippetItems.add(readArticleDetails(reader));
+            }
+            reader.endArray();
+        }
+
+        private SnippetArticle readArticleDetails(JsonReader reader) throws IOException {
+            String headline = "";
+            String publisher = "";
+            String snippets = "";
+            String url = "";
+            String thumbnail = "";
+
+            reader.beginObject();
+            while (reader.hasNext()) {
+                String name = reader.nextName();
+                if (name.equals("headline")) {
+                    headline = reader.nextString();
+                } else if (name.equals("publisher")) {
+                    publisher = reader.nextString();
+                } else if (name.equals("snippet")) {
+                    snippets = reader.nextString();
+                } else if (name.equals("url")) {
+                    url = reader.nextString();
+                } else if (name.equals("thumbnail")) {
+                    thumbnail = reader.nextString();
+                } else {
+                    reader.skipValue();
+                }
+            }
+            reader.endObject();
+            return new SnippetsManager.SnippetArticle(
+                    headline, publisher, snippets, url, thumbnail);
+        }
+    }
+
+    public SnippetsManager(NewTabPageManager tabManager, RecyclerView mSnippetsView) {
+        mNewTabPageManager = tabManager;
+        mDataAdapter = new SnippetsAdapter(this);
+        mSnippetsView.setAdapter(mDataAdapter);
+        new ReadFileTask().execute();
+    }
+
+    public void loadUrl(String url) {
+        mNewTabPageManager.open(url);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index 0ec3d0e..4a48524 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -16,6 +16,8 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.components.bookmarks.BookmarkId;
 import org.chromium.components.bookmarks.BookmarkType;
+import org.chromium.components.offlinepages.DeletePageResult;
+import org.chromium.components.offlinepages.SavePageResult;
 import org.chromium.content_public.browser.WebContents;
 
 import java.util.ArrayList;
@@ -89,6 +91,14 @@
         public void offlinePageDeleted(BookmarkId bookmarkId) {}
     }
 
+    private static long getTotalSize(List<OfflinePageItem> offlinePages) {
+        long totalSize = 0;
+        for (OfflinePageItem offlinePage : offlinePages) {
+            totalSize += offlinePage.getFileSize();
+        }
+        return totalSize;
+    }
+
     private static void recordFreeSpaceHistograms(
             final String percentageName, final String bytesName) {
         new AsyncTask<Void, Void, Void>() {
@@ -105,6 +115,43 @@
     }
 
     /**
+     * Records histograms related to the cost of storage. It is meant to be used after user
+     * takes an action: save, delete or delete in bulk.
+     *
+     * @param totalPageSizeBefore Total size of the pages before the action was taken.
+     * @param totalPageSizeAfter Total size of the pages after the action was taken.
+     */
+    private static void recordStorageHistograms(
+            final long totalPageSizeBefore, final long totalPageSizeAfter) {
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                // Total space taken by offline pages.
+                int totalPageSizeInMB = (int) (totalPageSizeAfter / (1024 * 1024));
+                RecordHistogram.recordCustomCountHistogram(
+                        "OfflinePages.TotalPageSize", totalPageSizeInMB, 1, 10000, 50);
+
+                // How much of the total space the offline pages take.
+                int totalPageSizePercentage = (int) (1.0 * totalPageSizeAfter
+                        / OfflinePageUtils.getTotalSpaceInBytes() * 100);
+                RecordHistogram.recordEnumeratedHistogram(
+                        "OfflinePages.TotalPageSizePercentage", totalPageSizePercentage, 101);
+                if (totalPageSizeBefore > 0) {
+                    // If the user is deleting the pages, perhaps they are running out of free
+                    // space. Report the size before the operation, where a base for calculation
+                    // of total free space includes space taken by offline pages.
+                    int percentageOfFree = (int) (1.0 * totalPageSizeBefore
+                            / (totalPageSizeBefore + OfflinePageUtils.getFreeSpaceInBytes()) * 100);
+                    RecordHistogram.recordEnumeratedHistogram(
+                            "OfflinePages.DeletePage.TotalPageSizeAsPercentageOfFreeSpace",
+                            percentageOfFree, 101);
+                }
+                return null;
+            }
+        }.execute();
+    }
+
+    /**
      * Creates offline pages bridge for a given profile.
      */
     @VisibleForTesting
@@ -198,9 +245,19 @@
         assert mIsNativeOfflinePageModelLoaded;
         assert webContents != null;
 
+        SavePageCallback callbackWrapper = new SavePageCallback() {
+            @Override
+            public void onSavePageDone(int savePageResult, String url) {
+                if (savePageResult == SavePageResult.SUCCESS) {
+                    long totalPageSizeAfter = getTotalSize(getAllPages());
+                    recordStorageHistograms(0, totalPageSizeAfter);
+                }
+                callback.onSavePageDone(savePageResult, url);
+            }
+        };
         recordFreeSpaceHistograms(
                 "OfflinePages.SavePage.FreeSpacePercentage", "OfflinePages.SavePage.FreeSpaceMB");
-        nativeSavePage(mNativeOfflinePageBridge, callback, webContents, bookmarkId.getId());
+        nativeSavePage(mNativeOfflinePageBridge, callbackWrapper, webContents, bookmarkId.getId());
     }
 
     /**
@@ -221,12 +278,14 @@
      * @see DeletePageCallback
      */
     @VisibleForTesting
-    public void deletePage(final BookmarkId bookmarkId, final DeletePageCallback callback) {
+    public void deletePage(final BookmarkId bookmarkId, DeletePageCallback callback) {
         assert mIsNativeOfflinePageModelLoaded;
 
         recordFreeSpaceHistograms("OfflinePages.DeletePage.FreeSpacePercentage",
                 "OfflinePages.DeletePage.FreeSpaceMB");
-        nativeDeletePage(mNativeOfflinePageBridge, callback, bookmarkId.getId());
+
+        DeletePageCallback callbackWrapper = wrapCallbackWithHistogramReporting(callback);
+        nativeDeletePage(mNativeOfflinePageBridge, callbackWrapper, bookmarkId.getId());
     }
 
     /**
@@ -242,7 +301,12 @@
         for (int i = 0; i < ids.length; i++) {
             ids[i] = bookmarkIds.get(i).getId();
         }
-        nativeDeletePages(mNativeOfflinePageBridge, callback, ids);
+
+        recordFreeSpaceHistograms("OfflinePages.DeletePage.FreeSpacePercentage",
+                "OfflinePages.DeletePage.FreeSpaceMB");
+
+        DeletePageCallback callbackWrapper = wrapCallbackWithHistogramReporting(callback);
+        nativeDeletePages(mNativeOfflinePageBridge, callbackWrapper, ids);
     }
 
     /**
@@ -270,6 +334,21 @@
         nativeCheckMetadataConsistency(mNativeOfflinePageBridge);
     }
 
+    private DeletePageCallback wrapCallbackWithHistogramReporting(
+            final DeletePageCallback callback) {
+        final long totalPageSizeBefore = getTotalSize(getAllPages());
+        return new DeletePageCallback() {
+            @Override
+            public void onDeletePageDone(int deletePageResult) {
+                if (deletePageResult == DeletePageResult.SUCCESS) {
+                    long totalPageSizeAfter = getTotalSize(getAllPages());
+                    recordStorageHistograms(totalPageSizeBefore, totalPageSizeAfter);
+                }
+                callback.onDeletePageDone(deletePageResult);
+            }
+        };
+    }
+
     @CalledByNative
     private void offlinePageModelLoaded() {
         mIsNativeOfflinePageModelLoaded = true;
@@ -295,17 +374,19 @@
 
     @CalledByNative
     private static void createOfflinePageAndAddToList(List<OfflinePageItem> offlinePagesList,
-            String url, long bookmarkId, String offlineUrl, long fileSize, int accessCount,
-            long lastAccessTimeMs) {
+            String url, long bookmarkId, String offlineUrl, long fileSize, long creationTime,
+            int accessCount, long lastAccessTimeMs) {
         offlinePagesList.add(createOfflinePageItem(
-                url, bookmarkId, offlineUrl, fileSize, accessCount, lastAccessTimeMs));
+                url, bookmarkId, offlineUrl, fileSize, creationTime, accessCount,
+                lastAccessTimeMs));
     }
 
     @CalledByNative
     private static OfflinePageItem createOfflinePageItem(String url, long bookmarkId,
-            String offlineUrl, long fileSize, int accessCount, long lastAccessTimeMs) {
+            String offlineUrl, long fileSize, long creationTime, int accessCount,
+            long lastAccessTimeMs) {
         return new OfflinePageItem(
-                url, bookmarkId, offlineUrl, fileSize, accessCount, lastAccessTimeMs);
+                url, bookmarkId, offlineUrl, fileSize, creationTime, accessCount, lastAccessTimeMs);
     }
 
     private static native boolean nativeIsOfflinePagesEnabled();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java
index 2ca4478..cbc4c31 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageItem.java
@@ -16,15 +16,17 @@
     private final BookmarkId mBookmarId;
     private final String mOfflineUrl;
     private final long mFileSize;
+    private final long mCreationTimeMs;
     private final int mAccessCount;
     private final long mLastAccessTimeMs;
 
     public OfflinePageItem(String url, long bookmarkId, String offlineUrl, long fileSize,
-            int accessCount, long lastAccessTimeMs) {
+            long creationTimeMs, int accessCount, long lastAccessTimeMs) {
         mUrl = url;
         mBookmarId = new BookmarkId(bookmarkId, BookmarkType.NORMAL);
         mOfflineUrl = offlineUrl;
         mFileSize = fileSize;
+        mCreationTimeMs = creationTimeMs;
         mAccessCount = accessCount;
         mLastAccessTimeMs = lastAccessTimeMs;
     }
@@ -53,6 +55,11 @@
         return mFileSize;
     }
 
+    /** @return Time in milliseconds the offline page was created. */
+    public long getCreationTimeMs() {
+        return mCreationTimeMs;
+    }
+
     /** @return Number of times that the offline page has been accessed. */
     @VisibleForTesting
     public int getAccessCount() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CameraInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CameraInfo.java
index d054ebd..8b225f18 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CameraInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CameraInfo.java
@@ -18,8 +18,8 @@
     }
 
     protected void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito) {
+            String origin, String embedder, ContentSetting value, boolean isIncognito) {
         WebsitePreferenceBridge.nativeSetCameraSettingForOrigin(
-                origin, embedder, value, isIncognito);
+                origin, embedder, value.toInt(), isIncognito);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CookieInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CookieInfo.java
index 8a74e36..b499213 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CookieInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/CookieInfo.java
@@ -18,8 +18,8 @@
     }
 
     protected void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito) {
+            String origin, String embedder, ContentSetting value, boolean isIncognito) {
         WebsitePreferenceBridge.nativeSetCookieSettingForOrigin(
-                origin, embedder, value, isIncognito);
+                origin, embedder, value.toInt(), isIncognito);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/FullscreenInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/FullscreenInfo.java
index d943499f..6bebf80a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/FullscreenInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/FullscreenInfo.java
@@ -20,8 +20,8 @@
 
     @Override
     protected void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito) {
+            String origin, String embedder, ContentSetting value, boolean isIncognito) {
         WebsitePreferenceBridge.nativeSetFullscreenSettingForOrigin(
-                origin, embedder, value, isIncognito);
+                origin, embedder, value.toInt(), isIncognito);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/GeolocationInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/GeolocationInfo.java
index a365126..af8755b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/GeolocationInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/GeolocationInfo.java
@@ -20,8 +20,8 @@
 
     @Override
     protected void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito) {
+            String origin, String embedder, ContentSetting value, boolean isIncognito) {
         WebsitePreferenceBridge.nativeSetGeolocationSettingForOrigin(
-                origin, embedder, value, isIncognito);
+                origin, embedder, value.toInt(), isIncognito);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MicrophoneInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MicrophoneInfo.java
index ba9d4e8..b3fa056 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MicrophoneInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MicrophoneInfo.java
@@ -18,8 +18,8 @@
     }
 
     protected void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito) {
+            String origin, String embedder, ContentSetting value, boolean isIncognito) {
         WebsitePreferenceBridge.nativeSetMicrophoneSettingForOrigin(
-                origin, embedder, value, isIncognito);
+                origin, embedder, value.toInt(), isIncognito);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MidiInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MidiInfo.java
index be90e8f..1a4eb14 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MidiInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/MidiInfo.java
@@ -17,7 +17,8 @@
     }
 
     protected void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito) {
-        WebsitePreferenceBridge.nativeSetMidiSettingForOrigin(origin, embedder, value, isIncognito);
+            String origin, String embedder, ContentSetting value, boolean isIncognito) {
+        WebsitePreferenceBridge.nativeSetMidiSettingForOrigin(
+                origin, embedder, value.toInt(), isIncognito);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/PermissionInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/PermissionInfo.java
index aeff056..b9f0f001 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/PermissionInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/PermissionInfo.java
@@ -48,13 +48,12 @@
      * Sets the native ContentSetting value for this origin.
      */
     public void setContentSetting(ContentSetting value) {
-        setNativePreferenceValue(
-                mOrigin, getEmbedderSafe(), value.toInt(), mIsIncognito);
+        setNativePreferenceValue(mOrigin, getEmbedderSafe(), value, mIsIncognito);
     }
 
     protected abstract int getNativePreferenceValue(
             String origin, String embedder, boolean isIncognito);
 
     protected abstract void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito);
+            String origin, String embedder, ContentSetting value, boolean isIncognito);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ProtectedMediaIdentifierInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ProtectedMediaIdentifierInfo.java
index 55d7edd..cea301c9 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ProtectedMediaIdentifierInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/ProtectedMediaIdentifierInfo.java
@@ -21,8 +21,8 @@
 
     @Override
     protected void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito) {
+            String origin, String embedder, ContentSetting value, boolean isIncognito) {
         WebsitePreferenceBridge.nativeSetProtectedMediaIdentifierSettingForOrigin(
-                origin, embedder, value, isIncognito);
+                origin, embedder, value.toInt(), isIncognito);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/PushNotificationInfo.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/PushNotificationInfo.java
index d80b9912..2c301a5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/PushNotificationInfo.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/website/PushNotificationInfo.java
@@ -20,8 +20,8 @@
 
     @Override
     protected void setNativePreferenceValue(
-            String origin, String embedder, int value, boolean isIncognito) {
+            String origin, String embedder, ContentSetting value, boolean isIncognito) {
         WebsitePreferenceBridge.nativeSetPushNotificationSettingForOrigin(
-                origin, embedder, value, isIncognito);
+                origin, embedder, value.toInt(), isIncognito);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
index f9d849a4..2a3bb27 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/Tab.java
@@ -49,8 +49,6 @@
 import org.chromium.chrome.browser.crash.MinidumpUploadService;
 import org.chromium.chrome.browser.customtabs.CustomTabActivity;
 import org.chromium.chrome.browser.device.DeviceClassManager;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeActivityDelegate;
-import org.chromium.chrome.browser.dom_distiller.ReaderModeManager;
 import org.chromium.chrome.browser.download.ChromeDownloadDelegate;
 import org.chromium.chrome.browser.enhancedbookmarks.EnhancedBookmarkUtils;
 import org.chromium.chrome.browser.fullscreen.FullscreenManager;
@@ -356,8 +354,6 @@
 
     protected Handler mHandler;
 
-    private final ReaderModeManager mReaderModeManager;
-
     private class TabContentViewClient extends ContentViewClient {
         @Override
         public void onBackgroundColorChanged(int color) {
@@ -580,7 +576,6 @@
             }
         };
 
-        mReaderModeManager = new ReaderModeManager(this, activity);
         mTabRedirectHandler = new TabRedirectHandler(activity);
         addObserver(mTabObserver);
 
@@ -1367,14 +1362,6 @@
     }
 
     /**
-     * TODO(aruslan): remove this.
-     * Temporary overload to avoid 2-way commit.
-     */
-    public void attachOverlayContentViewCore(ContentViewCore content, boolean visible) {
-        attachOverlayContentViewCore(content, visible, true);
-    }
-
-    /**
      * Removes a {@link ContentViewCore} overlay object from this {@link Tab}.  This
      * {@link ContentViewCore} must have previously been added via
      * {@link #attachOverlayContentViewCore(ContentViewCore, boolean)}.
@@ -2802,17 +2789,6 @@
     }
 
     /**
-     * @return The reader mode manager for this tab that handles UI events for reader mode.
-     */
-    public ReaderModeManager getReaderModeManager() {
-        return mReaderModeManager;
-    }
-
-    public ReaderModeActivityDelegate getReaderModeActivityDelegate() {
-        return mActivity == null ? null : mActivity.getReaderModeActivityDelegate();
-    }
-
-    /**
      * Check whether the context menu download should be intercepted.
      *
      * @param url URL to be downloaded.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 3c9dec0..dd95c2a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -785,7 +785,7 @@
     @Override
     public void openHomepage() {
         Tab currentTab = mToolbarModel.getTab();
-        assert currentTab != null;
+        if (currentTab == null) return;
         Context context = mToolbar.getContext();
         String homePageUrl = HomepageManager.getHomepageUri(context);
         if (TextUtils.isEmpty(homePageUrl)) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
index 40461cf..59465c13 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarPhone.java
@@ -648,7 +648,7 @@
 
     // NewTabPage.OnSearchBoxScrollListener
     @Override
-    public void onScrollChanged(float scrollPercentage) {
+    public void onNtpScrollChanged(float scrollPercentage) {
         if (scrollPercentage == mNtpSearchBoxScrollPercent) return;
 
         mNtpSearchBoxScrollPercent = scrollPercentage;
@@ -794,6 +794,7 @@
                         ? LOCATION_BAR_TRANSPARENT_BACKGROUND_ALPHA : 255;
         setAncestorsShouldClipChildren(true);
         mNtpSearchBoxScrollPercent = UNINITIALIZED_PERCENT;
+        updateUrlExpansionPercent();
     }
 
     private void updateNtpTransitionAnimation(NewTabPage ntp) {
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index ea72be5..291fdb49 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -1748,6 +1748,12 @@
       <message name="IDS_REMOVE_ALL" desc="Context menu option to clear the list of recently closed tabs">
         Remove all
       </message>
+      <message name="IDS_SNIPPETS_HEADER" desc="Header for a group of content snippets">
+        For readers of <ph name="PUBLISHER">%1$s<ex>The New York Times</ex></ph>
+      </message>
+      <message name="IDS_SNIPPETS_NTP_READ_MORE_LINK_TEXT" desc="Link to an article this snippet is describing">
+        Read more
+      </message>
 
       <!-- Toolbar button strings -->
       <message name="IDS_OPEN_TABS" desc="Text for button to enter the tab switcher and show tabs that are open on this device">
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
index 3b8e1b6..8bc5a6d 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -176,7 +176,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                viewCore.getInputConnectionForTest().setComposingText(
+                viewCore.getImeAdapterForTest().getInputConnectionForTest().setComposingText(
                         inputText, 1);
             }
         });
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
index db03cdc4..89f31f1 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/compositor/layouts/LayoutManagerTest.java
@@ -131,7 +131,7 @@
                     }
                 });
         mManager = mManagerPhone;
-        mManager.init(mTabModelSelector, null, null, container, null, null);
+        mManager.init(mTabModelSelector, null, null, container, null, null, null);
         initializeMotionEvent();
     }
 
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
index 521b80b..78e8c44 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -455,12 +455,6 @@
         String message = "but there was no loaded URL!";
         if (mFakeServer != null) {
             doesMatch = mFakeServer.getLoadedUrl().contains("q=" + searchTerm);
-            // TODO(donnd): remove the following line once the Translate API is updated!
-            // The current Translate API requires a change to the query parameter so
-            // checking it for the search term does not work.  We plan to fix this very
-            // soon, and this workaround allows tests to work until then, but needs to be
-            // removed when we switch to the new API.  See crbug.com/413717.
-            doesMatch = doesMatch || mFakeServer.getLoadedUrl().contains("tlitetxt=" + searchTerm);
             message = "in URL: " + mFakeServer.getLoadedUrl();
         }
         assertTrue("Expected to find searchTerm " + searchTerm + ", " + message, doesMatch);
@@ -755,12 +749,12 @@
         // TODO(pedrosimonetti): This is not reliable. Find a better approach.
         // We use the far right side (x == 0.9f) to prevent simulating a tap on top of an
         // existing long-press selection (the pins are a tap target). This might not work on RTL.
-        // We are using y == 0.2f because otherwise it will fail for long press cases.
+        // We are using y == 0.35f because otherwise it will fail for long press cases.
         // It might be better to get the position of the Panel and tap just about outside
         // the Panel. I suspect some Flaky tests are caused by this problem (ones involving
         // long press and trying to close with the bar peeking, with a long press selection
         // established).
-        tapBasePage(0.9f, 0.2f);
+        tapBasePage(0.9f, 0.35f);
         waitForPanelToCloseAndAssert();
     }
 
@@ -2568,13 +2562,14 @@
     @SmallTest
     @Feature({"ContextualSearch"})
     @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
-    @CommandLineFlags.Add(ContextualSearchFieldTrial.TRANSLATION_ONEBOX_ENABLED + "=true")
     public void testTapWithLanguage() throws InterruptedException, TimeoutException {
-        // Tapping a german word should trigger translation.
+        // Tapping a German word should trigger translation.
         simulateTapSearch("german");
 
         // Make sure we tried to trigger translate.
-        assertTrue(mManager.getRequest().isTranslationForced());
+        assertTrue("Translation was not forced with the current request URL: "
+                        + mManager.getRequest().getSearchUrl(),
+                mManager.getRequest().isTranslationForced());
     }
 
     /**
@@ -2583,7 +2578,6 @@
     @SmallTest
     @Feature({"ContextualSearch"})
     @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE)
-    @CommandLineFlags.Add(ContextualSearchFieldTrial.TRANSLATION_ONEBOX_ENABLED + "=true")
     public void testTapWithoutLanguage() throws InterruptedException, TimeoutException {
         // Tapping an English word should NOT trigger translation.
         simulateTapSearch("search");
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
index 7e5fad85..7dd8912 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/FirstRunFlowSequencerTest.java
@@ -16,6 +16,7 @@
 import org.chromium.base.ActivityState;
 import org.chromium.base.ApplicationStatus;
 import org.chromium.base.BaseChromiumApplication;
+import org.chromium.base.test.shadows.ShadowMultiDex;
 import org.chromium.base.test.util.Feature;
 import org.chromium.testing.local.LocalRobolectricTestRunner;
 import org.junit.After;
@@ -31,7 +32,8 @@
  * first run.
  */
 @RunWith(LocalRobolectricTestRunner.class)
-@Config(manifest = Config.NONE, application = BaseChromiumApplication.class)
+@Config(manifest = Config.NONE, application = BaseChromiumApplication.class,
+        shadows = {ShadowMultiDex.class})
 public class FirstRunFlowSequencerTest {
     /** Information for Google OS account */
     private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 8ff34ec21..16c2946 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -1569,7 +1569,7 @@
     Previous password
   </message>
   <message name="IDS_LOGIN_SAML_NOTICE" desc="Text message displayed above SAML portal to early indicate that the user is being redirected to another sign-in provider. This is the version of the string used in the GAIA flow.">
-    This sign-in service is hosted by <ph name="SAML_DOMAIN">$1<ex>saml.com</ex></ph>.
+    This sign-in service is hosted by <ph name="SAML_DOMAIN">$1<ex>saml.com</ex></ph>
   </message>
   <message name="IDS_LOGIN_CONFIRM_PASSWORD_TITLE" desc="Title for the confirm password dialog.">
     Please re-enter your password to update your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> profile.
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index c377fdf..afee6e78 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -351,6 +351,9 @@
       <message name="IDS_WEBSITE_SETTINGS_UNKNOWN_TRANSPORT" desc="Text that is displayed in the header of the Website Settings popup if Chrome cannot determine what kind of transport the website used. This string must be the same as IDS_WEBSITE_SETTINGS_NON_SECURE_TRANSPORT.">
         Your connection to this site is not private.
       </message>
+      <message name="IDS_WEBSITE_SETTINGS_DETAILS_LINK" desc="Link in the Website Settings that opens up additional security details about the current page in the DevTools Security panel.">
+        Details
+      </message>
       <message name="IDS_WEBSITE_SETTINGS_CT_ERROR" desc="Text that is displayed in the header of the Website Settings popup if the website has provided Signed Certificate Timestamps but none are valid.">
         This site supplied invalid Certificate Transparency information.
       </message>
@@ -4100,9 +4103,6 @@
         <message name="IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_LIST" desc="Permission string for access to a list of USB devices.">
           Access any of these USB devices
         </message>
-        <message name="IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_LIST_ITEM" desc="Line item for a USB device listed under IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_LIST.">
-          <ph name="DEVICE_NAME_AND_VENDOR">$1<ex>SoundKnob from Griffin Technology</ex></ph>
-        </message>
         <message name="IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_LIST_ITEM_UNKNOWN_PRODUCT" desc="Line item for a USB device listed under IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_LIST that has an unknown product ID.">
           unknown devices from <ph name="VENDOR_NAME">$1<ex>Griffin Technology</ex></ph>
         </message>
@@ -6664,6 +6664,14 @@
           Enables the use of an AppContainer on sandboxed processes to improve security.
         </message>
       </if>
+      <if expr="toolkit_views">
+        <message name="IDS_FLAGS_AUTOFILL_CREDIT_CARD_UPLOAD_NAME" desc="Name of the flag to enable uploading Autofill credit cards.">
+          Enable offering upload of Autofilled credit cards
+        </message>
+        <message name="IDS_FLAGS_AUTOFILL_CREDIT_CARD_UPLOAD_DESCRIPTION" desc="Description of the flag to enable uploading Autofill credit cards.">
+          Enables a new option to upload credit cards to Google Payments for sync to all Chrome devices.
+        </message>
+      </if>
 
       <!-- WebRTC logs -->
       <message name="IDS_WEBRTC_LOGS_TITLE" desc="Title for the chrome://webrtc-logs page.">
@@ -7687,6 +7695,12 @@
       <message name="IDS_CLEAR_BROWSING_DATA_CALCULATING" desc="A text that is shown while the data volume is being counted.">
         Calculating...
       </message>
+      <message name="IDS_CLEAR_BROWSING_DATA_UNKNOWN_SIZE" desc="A text that is shown when the data volume could not be calculated. This string refers to uncountable objects, such as cache.">
+        unknown size
+      </message>
+      <message name="IDS_CLEAR_BROWSING_DATA_UNKNOWN_AMOUNT" desc="A text that is shown when the data volume could not be calculated. This string refers to countable objects, such as history entries or passwords.">
+        unknown amount
+      </message>
       <message name="IDS_DEL_BROWSING_HISTORY_COUNTER" desc="A counter showing how many items of browsing history the user has.">
         {COUNT, plural,
          =0 {none}
@@ -7702,6 +7716,9 @@
       <message name="IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE" desc="A counter showing that the user has less than X megabytes of cache. The value X will be substituted.">
         less than <ph name="UPPER_ESTIMATE">$1<ex>328 MB</ex></ph>
       </message>
+      <message name="IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY" desc="A counter showing that the user's cache is almost empty, having less than 1 MB of data.">
+        less than 1 MB
+      </message>
       <message name="IDS_DEL_PASSWORDS_COUNTER" desc="A counter showing how many passwords the user has.">
         {COUNT, plural,
          =0 {none}
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 9ce0d83..2abd33b 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2124,6 +2124,15 @@
      SINGLE_VALUE_TYPE_AND_VALUE(switches::kDisableAutoHidingToolbarThreshold,
                                  "0")},
 #endif
+#if defined(TOOLKIT_VIEWS)
+    {"enable-autofill-credit-card-upload",
+     IDS_FLAGS_AUTOFILL_CREDIT_CARD_UPLOAD_NAME,
+     IDS_FLAGS_AUTOFILL_CREDIT_CARD_UPLOAD_DESCRIPTION,
+     kOsCrOS | kOsWin | kOsLinux,
+     ENABLE_DISABLE_VALUE_TYPE(
+         autofill::switches::kEnableOfferUploadCreditCards,
+         autofill::switches::kDisableOfferUploadCreditCards)},
+#endif  // defined(TOOLKIT_VIEWS)
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
     // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/about_flags_unittest.cc b/chrome/browser/about_flags_unittest.cc
index 8baff519..ca5ebb95 100644
--- a/chrome/browser/about_flags_unittest.cc
+++ b/chrome/browser/about_flags_unittest.cc
@@ -817,6 +817,18 @@
   }
 }
 
+TEST_F(AboutFlagsTest, GetFlagFeatureEntries) {
+  base::ListValue supported_entries;
+  base::ListValue unsupported_entries;
+  GetFlagFeatureEntries(&flags_storage_, kGeneralAccessFlagsOnly,
+                        &supported_entries, &unsupported_entries);
+  // All |kEntries| except for |kFlags3| should be supported.
+  EXPECT_EQ(6u, supported_entries.GetSize());
+  EXPECT_EQ(1u, unsupported_entries.GetSize());
+  EXPECT_EQ(arraysize(kEntries),
+            supported_entries.GetSize() + unsupported_entries.GetSize());
+}
+
 class AboutFlagsHistogramTest : public ::testing::Test {
  protected:
   // This is a helper function to check that all IDs in enum LoginCustomFlags in
diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc
index 50448bcd..453d439 100644
--- a/chrome/browser/android/chrome_jni_registrar.cc
+++ b/chrome/browser/android/chrome_jni_registrar.cc
@@ -22,7 +22,6 @@
 #include "chrome/browser/android/compositor/compositor_view.h"
 #include "chrome/browser/android/compositor/layer_title_cache.h"
 #include "chrome/browser/android/compositor/scene_layer/contextual_search_scene_layer.h"
-#include "chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.h"
 #include "chrome/browser/android/compositor/scene_layer/scene_layer.h"
 #include "chrome/browser/android/compositor/scene_layer/static_tab_scene_layer.h"
 #include "chrome/browser/android/compositor/scene_layer/tab_list_scene_layer.h"
@@ -314,7 +313,6 @@
     {"ProfileDownloader", RegisterProfileDownloader},
     {"ProfileSyncService", ProfileSyncServiceAndroid::Register},
     {"RapporServiceBridge", rappor::RegisterRapporServiceBridge},
-    {"ReaderModeSceneLayer", RegisterReaderModeSceneLayer},
     {"RecentlyClosedBridge", RecentlyClosedTabsBridge::Register},
     {"RecordCastAction", remote_media::RegisterRecordCastAction},
     {"RemoteMediaPlayerBridge",
diff --git a/chrome/browser/android/compositor/layer/reader_mode_layer.cc b/chrome/browser/android/compositor/layer/reader_mode_layer.cc
deleted file mode 100644
index 4cb8188..0000000
--- a/chrome/browser/android/compositor/layer/reader_mode_layer.cc
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright 2015 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 "chrome/browser/android/compositor/layer/reader_mode_layer.h"
-
-#include "cc/layers/layer.h"
-#include "cc/layers/nine_patch_layer.h"
-#include "cc/layers/solid_color_layer.h"
-#include "cc/layers/ui_resource_layer.h"
-#include "cc/output/filter_operation.h"
-#include "cc/output/filter_operations.h"
-#include "cc/resources/scoped_ui_resource.h"
-#include "content/public/browser/android/compositor.h"
-#include "content/public/browser/android/content_view_core.h"
-#include "content/public/browser/web_contents.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/android/resources/resource_manager.h"
-
-namespace chrome {
-namespace android {
-
-// static
-scoped_refptr<ReaderModeLayer> ReaderModeLayer::Create(
-    ui::ResourceManager* resource_manager) {
-  return make_scoped_refptr(new ReaderModeLayer(resource_manager));
-}
-
-void ReaderModeLayer::SetProperties(
-    int panel_background_resource_id,
-    int panel_text_resource_id,
-    content::ContentViewCore* reader_mode_content_view_core,
-    float panel_y,
-    float panel_width,
-    float panel_margin_top,
-    float panel_height,
-    float distilled_y,
-    float distilled_height,
-    float x,
-    float panel_text_opacity,
-    int header_background_color) {
-  // Grab the dynamic Reader Mode Text resource.
-  ui::ResourceManager::Resource* panel_text_resource =
-      resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_DYNAMIC,
-                                     panel_text_resource_id);
-
-  // Grab required static resources.
-  ui::ResourceManager::Resource* panel_background_resource =
-      resource_manager_->GetResource(ui::ANDROID_RESOURCE_TYPE_STATIC,
-                                     panel_background_resource_id);
-
-  DCHECK(panel_background_resource);
-
-  cc::FilterOperations blur_filter;
-
-  // ---------------------------------------------------------------------------
-  // Reader Mode Bar Background
-  // ---------------------------------------------------------------------------
-  gfx::Size background_size(panel_width, panel_height);
-  panel_background_->SetUIResourceId(
-      panel_background_resource->ui_resource->id());
-  panel_background_->SetBorder(
-      panel_background_resource->Border(background_size));
-  panel_background_->SetAperture(panel_background_resource->aperture);
-  panel_background_->SetBounds(background_size);
-  panel_background_->SetPosition(gfx::PointF(0.0f, panel_y));
-  panel_background_->SetOpacity(panel_text_opacity);
-
-  // ---------------------------------------------------------------------------
-  // Reader Mode Bar Text
-  // ---------------------------------------------------------------------------
-  if (panel_text_resource) {
-    // Centralizes the text vertically in the Reader Mode panel.
-    panel_text_->SetUIResourceId(
-        panel_text_resource->ui_resource->id());
-    panel_text_->SetBounds(panel_text_resource->size);
-    panel_text_->SetPosition(gfx::PointF(0.f, panel_margin_top + panel_y));
-    panel_text_->SetFilters(blur_filter);
-    panel_text_->SetOpacity(panel_text_opacity);
-  }
-
-  // ---------------------------------------------------------------------------
-  // Reader Mode Content View
-  // ---------------------------------------------------------------------------
-  content_shadow_->SetUIResourceId(
-      panel_background_resource->ui_resource->id());
-  content_shadow_->SetBorder(
-      panel_background_resource->Border(background_size));
-  content_shadow_->SetAperture(panel_background_resource->aperture);
-  content_shadow_->SetBounds(background_size);
-  content_shadow_->SetPosition(gfx::PointF(0.f, distilled_y));
-
-  content_solid_->SetBounds(background_size);
-  content_solid_->SetPosition(gfx::PointF(0.f, panel_margin_top + distilled_y));
-  content_solid_->SetBackgroundColor(header_background_color);
-
-  content_view_container_->SetPosition(
-      gfx::PointF(0.f, panel_margin_top + distilled_y));
-  content_view_container_->SetOpacity(1.0f - panel_text_opacity);
-
-  if (reader_mode_content_view_core &&
-      reader_mode_content_view_core->GetLayer().get()) {
-    scoped_refptr<cc::Layer> content_view_layer =
-        reader_mode_content_view_core->GetLayer();
-    if (content_view_layer->parent() != content_view_container_) {
-      content_view_container_->AddChild(content_view_layer);
-      content_view_container_->SetFilters(blur_filter);
-    }
-  } else {
-    content_view_container_->RemoveAllChildren();
-  }
-
-  // ---------------------------------------------------------------------------
-  // Reader Mode Panel.
-  // ---------------------------------------------------------------------------
-  layer_->SetPosition(gfx::PointF(x, 0.f));
-}
-
-ReaderModeLayer::ReaderModeLayer(ui::ResourceManager* resource_manager)
-    : resource_manager_(resource_manager),
-      layer_(cc::Layer::Create(content::Compositor::LayerSettings())),
-      panel_background_(
-          cc::NinePatchLayer::Create(content::Compositor::LayerSettings())),
-      panel_text_(
-          cc::UIResourceLayer::Create(content::Compositor::LayerSettings())),
-      content_shadow_(
-          cc::NinePatchLayer::Create(content::Compositor::LayerSettings())),
-      content_solid_(
-          cc::SolidColorLayer::Create(content::Compositor::LayerSettings())),
-      content_view_container_(
-          cc::Layer::Create(content::Compositor::LayerSettings())) {
-  layer_->SetMasksToBounds(false);
-
-  // Reader Mode Background
-  panel_background_->SetIsDrawable(true);
-  panel_background_->SetFillCenter(true);
-  layer_->AddChild(panel_background_);
-
-  // Reader Mode Text
-  panel_text_->SetIsDrawable(true);
-  layer_->AddChild(panel_text_);
-
-  // Reader Mode Content shadow
-  content_shadow_->SetIsDrawable(true);
-  content_shadow_->SetFillCenter(true);
-  layer_->AddChild(content_shadow_);
-
-  // Reader Mode Content solid background
-  content_solid_->SetIsDrawable(true);
-  layer_->AddChild(content_solid_);
-
-  // Reader Mode Content View
-  layer_->AddChild(content_view_container_);
-}
-
-ReaderModeLayer::~ReaderModeLayer() {
-}
-
-scoped_refptr<cc::Layer> ReaderModeLayer::layer() {
-  return layer_;
-}
-
-}  //  namespace android
-}  //  namespace chrome
diff --git a/chrome/browser/android/compositor/layer/reader_mode_layer.h b/chrome/browser/android/compositor/layer/reader_mode_layer.h
deleted file mode 100644
index 940dd22..0000000
--- a/chrome/browser/android/compositor/layer/reader_mode_layer.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef CHROME_BROWSER_ANDROID_COMPOSITOR_LAYER_READER_MODE_LAYER_H_
-#define CHROME_BROWSER_ANDROID_COMPOSITOR_LAYER_READER_MODE_LAYER_H_
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/android/compositor/layer/layer.h"
-
-namespace cc {
-class Layer;
-class NinePatchLayer;
-class SolidColorLayer;
-class UIResourceLayer;
-}
-
-namespace content {
-class ContentViewCore;
-}
-
-namespace ui {
-class ResourceManager;
-}
-
-namespace chrome {
-namespace android {
-
-class ReaderModeLayer : public Layer {
- public:
-  static scoped_refptr<ReaderModeLayer> Create(
-      ui::ResourceManager* resource_manager);
-
-  void SetProperties(int panel_background_resource_id,
-                     int panel_text_resource_id,
-                     content::ContentViewCore* reader_mode_content_view_core,
-                     float panel_y,
-                     float panel_width,
-                     float panel_margin_top,
-                     float panel_height,
-                     float distilled_y,
-                     float distilled_height,
-                     float x,
-                     float panel_text_opacity,
-                     int header_background_color);
-
-  scoped_refptr<cc::Layer> layer() override;
-
- protected:
-  explicit ReaderModeLayer(ui::ResourceManager* resource_manager);
-  ~ReaderModeLayer() override;
-
- private:
-  ui::ResourceManager* resource_manager_;
-
-  scoped_refptr<cc::Layer> layer_;
-  scoped_refptr<cc::NinePatchLayer> panel_background_;
-  scoped_refptr<cc::UIResourceLayer> panel_text_;
-  scoped_refptr<cc::NinePatchLayer> content_shadow_;
-  scoped_refptr<cc::SolidColorLayer> content_solid_;
-  scoped_refptr<cc::Layer> content_view_container_;
-};
-
-}  //  namespace android
-}  //  namespace chrome
-
-#endif  // CHROME_BROWSER_ANDROID_COMPOSITOR_LAYER_READER_MODE_LAYER_H_
diff --git a/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.cc b/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.cc
deleted file mode 100644
index 2817feb..0000000
--- a/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2015 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 "chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.h"
-
-#include "base/android/jni_android.h"
-#include "chrome/browser/android/compositor/layer/reader_mode_layer.h"
-#include "content/public/browser/android/content_view_core.h"
-#include "jni/ReaderModeSceneLayer_jni.h"
-#include "ui/android/resources/resource_manager_impl.h"
-
-namespace chrome {
-namespace android {
-
-ReaderModeSceneLayer::ReaderModeSceneLayer(JNIEnv* env, jobject jobj)
-    : SceneLayer(env, jobj) {
-}
-
-ReaderModeSceneLayer::~ReaderModeSceneLayer() {
-}
-
-void ReaderModeSceneLayer::UpdateReaderModeLayer(
-    JNIEnv* env,
-    jobject object,
-    jint panel_background_resource_id,
-    jint panel_text_resource_id,
-    jobject jreader_mode_content_view_core,
-    jfloat panel_y,
-    jfloat panel_width,
-    jfloat panel_margin_top,
-    jfloat panel_height,
-    jfloat distilled_y,
-    jfloat distilled_height,
-    jfloat x,
-    jfloat panel_text_opacity,
-    jint header_background_color,
-    jobject jresource_manager) {
-  ui::ResourceManager* resource_manager =
-      ui::ResourceManagerImpl::FromJavaObject(jresource_manager);
-  // Lazily construct the reader mode layer, as the feature is only
-  // conditionally enabled.
-  if (!reader_mode_layer_.get()) {
-    if (!resource_manager)
-      return;
-    reader_mode_layer_ = ReaderModeLayer::Create(resource_manager);
-    layer_->AddChild(reader_mode_layer_->layer());
-  }
-
-  // NOTE(pedrosimonetti): The ContentViewCore might not exist at this time if
-  // the Reader Mode has not been requested yet. In this case,
-  // we'll pass NULL to Reader Mode's Layer Tree.
-  content::ContentViewCore* content_view_core =
-      !jreader_mode_content_view_core ? NULL
-                          : content::ContentViewCore::GetNativeContentViewCore(
-                                env, jreader_mode_content_view_core);
-
-  reader_mode_layer_->SetProperties(
-      panel_background_resource_id, panel_text_resource_id,
-      content_view_core,
-      panel_y, panel_width, panel_margin_top, panel_height,
-      distilled_y, distilled_height,
-      x,
-      panel_text_opacity, header_background_color);
-}
-
-static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& jobj) {
-  // This will automatically bind to the Java object and pass ownership there.
-  ReaderModeSceneLayer* tree_provider =
-      new ReaderModeSceneLayer(env, jobj);
-  return reinterpret_cast<intptr_t>(tree_provider);
-}
-
-bool RegisterReaderModeSceneLayer(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-}  // namespace android
-}  // namespace chrome
diff --git a/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.h b/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.h
deleted file mode 100644
index cf1e7f09..0000000
--- a/chrome/browser/android/compositor/scene_layer/reader_mode_scene_layer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright 2015 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.
-
-#ifndef CHROME_BROWSER_ANDROID_COMPOSITOR_SCENE_LAYER_READER_MODE_SCENE_LAYER_H_
-#define CHROME_BROWSER_ANDROID_COMPOSITOR_SCENE_LAYER_READER_MODE_SCENE_LAYER_H_
-
-#include <vector>
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_weak_ref.h"
-#include "base/android/scoped_java_ref.h"
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "chrome/browser/android/compositor/scene_layer/scene_layer.h"
-
-namespace chrome {
-namespace android {
-class ReaderModeLayer;
-
-class ReaderModeSceneLayer : public SceneLayer {
- public:
-  ReaderModeSceneLayer(JNIEnv* env, jobject jobj);
-  ~ReaderModeSceneLayer() override;
-
-  void UpdateReaderModeLayer(JNIEnv* env,
-                             jobject object,
-                             jint panel_background_resource_id,
-                             jint panel_text_resource_id,
-                             jobject jreader_mode_content_view_core,
-                             jfloat panel_y,
-                             jfloat panel_width,
-                             jfloat panel_margin_top,
-                             jfloat panel_height,
-                             jfloat distilled_y,
-                             jfloat distilled_height,
-                             jfloat x,
-                             jfloat panel_text_opacity,
-                             jint header_background_color,
-                             jobject jresource_manager);
-
- private:
-  scoped_refptr<ReaderModeLayer> reader_mode_layer_;
-
-  DISALLOW_COPY_AND_ASSIGN(ReaderModeSceneLayer);
-};
-
-bool RegisterReaderModeSceneLayer(JNIEnv* env);
-
-}  // namespace android
-}  // namespace chrome
-
-#endif  // CHROME_BROWSER_ANDROID_COMPOSITOR_SCENE_LAYER_READER_MODE_SCENE_LAYER_H_
diff --git a/chrome/browser/android/data_usage/data_use_tab_helper.cc b/chrome/browser/android/data_usage/data_use_tab_helper.cc
new file mode 100644
index 0000000..4d1dabf
--- /dev/null
+++ b/chrome/browser/android/data_usage/data_use_tab_helper.cc
@@ -0,0 +1,57 @@
+// Copyright 2015 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 "chrome/browser/android/data_usage/data_use_tab_helper.h"
+
+#include "base/logging.h"
+#include "chrome/browser/android/data_usage/data_use_ui_tab_model.h"
+#include "chrome/browser/android/data_usage/data_use_ui_tab_model_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/session_tab_helper.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/navigation_handle.h"
+#include "ui/base/page_transition_types.h"
+
+namespace content {
+class RenderFrameHost;
+}
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(DataUseTabHelper);
+
+DataUseTabHelper::~DataUseTabHelper() {}
+
+DataUseTabHelper::DataUseTabHelper(content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+}
+
+void DataUseTabHelper::ReadyToCommitNavigation(
+    content::NavigationHandle* navigation_handle) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  // Notify the DataUseUITabModel.
+  chrome::android::DataUseUITabModel* data_use_ui_tab_model =
+      chrome::android::DataUseUITabModelFactory::GetForBrowserContext(
+          Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+  if (data_use_ui_tab_model) {
+    data_use_ui_tab_model->ReportBrowserNavigation(
+        navigation_handle->GetURL(),
+        ui::PageTransitionFromInt(navigation_handle->GetPageTransition()),
+        SessionTabHelper::IdForTab(web_contents()));
+  }
+}
+
+void DataUseTabHelper::FrameDeleted(
+    content::RenderFrameHost* render_frame_host) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  // Notify the DataUseUITabModel.
+  chrome::android::DataUseUITabModel* data_use_ui_tab_model =
+      chrome::android::DataUseUITabModelFactory::GetForBrowserContext(
+          Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+  if (data_use_ui_tab_model) {
+    data_use_ui_tab_model->ReportTabClosure(
+        SessionTabHelper::IdForTab(web_contents()));
+  }
+}
diff --git a/chrome/browser/android/data_usage/data_use_tab_helper.h b/chrome/browser/android/data_usage/data_use_tab_helper.h
new file mode 100644
index 0000000..041c853
--- /dev/null
+++ b/chrome/browser/android/data_usage/data_use_tab_helper.h
@@ -0,0 +1,37 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_TAB_HELPER_H_
+#define CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_TAB_HELPER_H_
+
+#include "base/macros.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+class RenderFrameHost;
+class NavigationHandle;
+}
+
+// Per-tab class to manage tab closures and navigations, so that data usage per
+// tab can be properly recorded..
+class DataUseTabHelper : public content::WebContentsObserver,
+                         public content::WebContentsUserData<DataUseTabHelper> {
+ public:
+  ~DataUseTabHelper() override;
+
+ private:
+  friend class content::WebContentsUserData<DataUseTabHelper>;
+
+  explicit DataUseTabHelper(content::WebContents* web_contents);
+
+  // Overridden from content::WebContentsObserver:
+  void ReadyToCommitNavigation(
+      content::NavigationHandle* navigation_handle) override;
+  void FrameDeleted(content::RenderFrameHost* render_frame_host) override;
+
+  DISALLOW_COPY_AND_ASSIGN(DataUseTabHelper);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_TAB_HELPER_H_
diff --git a/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc b/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
index 16cece8..cc69f75 100644
--- a/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
+++ b/chrome/browser/android/data_usage/data_use_tab_ui_manager_android.cc
@@ -4,7 +4,13 @@
 
 #include "chrome/browser/android/data_usage/data_use_tab_ui_manager_android.h"
 
+#include <string>
+
 #include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "chrome/browser/android/data_usage/data_use_ui_tab_model.h"
+#include "chrome/browser/android/data_usage/data_use_ui_tab_model_factory.h"
+#include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_android.h"
 #include "jni/DataUseTabUIManager_jni.h"
 
@@ -13,9 +19,11 @@
                                      const JavaParamRef<jclass>& clazz,
                                      jint tab_id,
                                      const JavaParamRef<jobject>& jprofile) {
-  // TODO(megjablon): Get the DataUseTabUIManager which is a keyed service and
-  // ask it if data use tracking has started.
-  // Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  chrome::android::DataUseUITabModel* data_use_ui_tab_model =
+      chrome::android::DataUseUITabModelFactory::GetForBrowserContext(profile);
+  if (data_use_ui_tab_model)
+    return data_use_ui_tab_model->HasDataUseTrackingStarted(tab_id);
   return false;
 }
 
@@ -24,9 +32,11 @@
                                    const JavaParamRef<jclass>& clazz,
                                    jint tab_id,
                                    const JavaParamRef<jobject>& jprofile) {
-  // TODO(megjablon): Get the DataUseTabUIManager which is a keyed service and
-  // ask it if data use tracking has ended.
-  // Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  chrome::android::DataUseUITabModel* data_use_ui_tab_model =
+      chrome::android::DataUseUITabModelFactory::GetForBrowserContext(profile);
+  if (data_use_ui_tab_model)
+    return data_use_ui_tab_model->HasDataUseTrackingEnded(tab_id);
   return false;
 }
 
@@ -35,10 +45,16 @@
                                   const JavaParamRef<jclass>& clazz,
                                   jint tab_id,
                                   const JavaParamRef<jstring>& url,
-                                  const JavaParamRef<jstring>& packageName,
+                                  const JavaParamRef<jstring>& package_name,
                                   const JavaParamRef<jobject>& jprofile) {
-  // TODO(megjablon): Get the DataUseTabUIManager which is a keyed service and
-  // tell it about the custom tab package.
+  Profile* profile = ProfileAndroid::FromProfileAndroid(jprofile);
+  chrome::android::DataUseUITabModel* data_use_ui_tab_model =
+      chrome::android::DataUseUITabModelFactory::GetForBrowserContext(profile);
+  if (data_use_ui_tab_model) {
+    data_use_ui_tab_model->ReportCustomTabInitialNavigation(
+        tab_id, ConvertJavaStringToUTF8(env, url),
+        ConvertJavaStringToUTF8(env, package_name));
+  }
 }
 
 bool RegisterDataUseTabUIManager(JNIEnv* env) {
diff --git a/chrome/browser/android/data_usage/data_use_ui_tab_model.cc b/chrome/browser/android/data_usage/data_use_ui_tab_model.cc
new file mode 100644
index 0000000..95e8628
--- /dev/null
+++ b/chrome/browser/android/data_usage/data_use_ui_tab_model.cc
@@ -0,0 +1,124 @@
+// Copyright 2015 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 "chrome/browser/android/data_usage/data_use_ui_tab_model.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "content/public/browser/browser_thread.h"
+#include "url/gurl.h"
+
+namespace chrome {
+
+namespace android {
+
+DataUseUITabModel::DataUseUITabModel(
+    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+    : io_task_runner_(io_task_runner) {
+  DCHECK(io_task_runner_);
+}
+
+DataUseUITabModel::~DataUseUITabModel() {}
+
+void DataUseUITabModel::ReportBrowserNavigation(
+    const GURL& gurl,
+    ui::PageTransition page_transition,
+    int32_t tab_id) const {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // TODO(tbansal): Post to DataUseTabModel on IO thread.
+}
+
+void DataUseUITabModel::ReportTabClosure(int32_t tab_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  // TODO(tbansal): Post to DataUseTabModel on IO thread.
+
+  // Clear out local state.
+  TabEvents::iterator it = tab_events_.find(tab_id);
+  if (it == tab_events_.end())
+    return;
+  tab_events_.erase(it);
+}
+
+void DataUseUITabModel::ReportCustomTabInitialNavigation(
+    int32_t tab_id,
+    const std::string& url,
+    const std::string& package_name) {
+  // TODO(tbansal): Post to DataUseTabModel on IO thread.
+}
+
+void DataUseUITabModel::OnTrackingStarted(int32_t tab_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (MaybeCreateTabEvent(tab_id, DATA_USE_TRACKING_STARTED))
+    return;
+  // Since tracking started before the UI could indicate that it ended, it is
+  // not useful for UI to show that it started again.
+  RemoveTabEvent(tab_id, DATA_USE_TRACKING_ENDED);
+}
+
+void DataUseUITabModel::OnTrackingEnded(int32_t tab_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (MaybeCreateTabEvent(tab_id, DATA_USE_TRACKING_ENDED))
+    return;
+  // Since tracking ended before the UI could indicate that it stated, it is not
+  // useful for UI to show that it ended.
+  RemoveTabEvent(tab_id, DATA_USE_TRACKING_STARTED);
+}
+
+bool DataUseUITabModel::HasDataUseTrackingStarted(int32_t tab_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  TabEvents::iterator it = tab_events_.find(tab_id);
+  if (it == tab_events_.end())
+    return false;
+
+  return RemoveTabEvent(tab_id, DATA_USE_TRACKING_STARTED);
+}
+
+bool DataUseUITabModel::HasDataUseTrackingEnded(int32_t tab_id) {
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  TabEvents::iterator it = tab_events_.find(tab_id);
+  if (it == tab_events_.end())
+    return false;
+
+  return RemoveTabEvent(tab_id, DATA_USE_TRACKING_ENDED);
+}
+
+bool DataUseUITabModel::MaybeCreateTabEvent(int32_t tab_id,
+                                            DataUseTrackingEvent event) {
+  TabEvents::iterator it = tab_events_.find(tab_id);
+  if (it == tab_events_.end()) {
+    tab_events_.insert(std::make_pair(tab_id, event));
+    return true;
+  }
+  return false;
+}
+
+bool DataUseUITabModel::RemoveTabEvent(int32_t tab_id,
+                                       DataUseTrackingEvent event) {
+  TabEvents::iterator it = tab_events_.find(tab_id);
+  DCHECK(it != tab_events_.end());
+  if (it->second == event) {
+    tab_events_.erase(it);
+    return true;
+  }
+  return false;
+}
+
+}  // namespace android
+
+}  // namespace chrome
diff --git a/chrome/browser/android/data_usage/data_use_ui_tab_model.h b/chrome/browser/android/data_usage/data_use_ui_tab_model.h
new file mode 100644
index 0000000..a8dc492f
--- /dev/null
+++ b/chrome/browser/android/data_usage/data_use_ui_tab_model.h
@@ -0,0 +1,113 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_UI_TAB_MODEL_H_
+#define CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_UI_TAB_MODEL_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <unordered_map>
+
+#include "base/gtest_prod_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
+#include "components/keyed_service/core/keyed_service.h"
+#include "ui/base/page_transition_types.h"
+
+class GURL;
+
+namespace chrome {
+
+namespace android {
+
+// DataUseUITabModel tracks data use tracking start and end transitions on the
+// browser's tabs. It serves as a bridge between the DataUseTabModel, which
+// lives on the IO thread, browser navigation events and tab closure events,
+// which are generated on the UI thread, and UI elements that appear when data
+// use tracking starts and ends in a Tab. DataUseUITabModel forwards navigation
+// and tab closure events to the DataUseTabModel, and receives tab tracking
+// transitions (start/end) from the DataUseTabModel, which it conveys to UI
+// notification logic. DataUseUITabModel is not thread-safe, and should be
+// accessed only on the UI thread.
+// TODO(tbansal): DataUseTabModel should notify DataUseUITabModel when a tab
+// is removed from the list of tabs.
+class DataUseUITabModel : public KeyedService {
+ public:
+  explicit DataUseUITabModel(
+      scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+  ~DataUseUITabModel() override;
+
+  // Reports a browser navigation to the DataUseTabModel on IO thread. Includes
+  // the |page_transition|, |tab_id|, and |gurl| for the navigation. Tabs that
+  // are restored when Chromium restarts are not reported.
+  void ReportBrowserNavigation(const GURL& gurl,
+                               ui::PageTransition page_transition,
+                               int32_t tab_id) const;
+
+  // Reports a tab closure for the tab with |tab_id| to the DataUseTabModel on
+  // IO thread. The tab could either have been closed or evicted from the memory
+  // by Android.
+  void ReportTabClosure(int32_t tab_id);
+
+  // Reports a custom tab navigation to the DataUseTabModel on the IO thread.
+  // Includes the |tab_id|, |url|, and |package_name| for the navigation.
+  void ReportCustomTabInitialNavigation(int32_t tab_id,
+                                        const std::string& url,
+                                        const std::string& package_name);
+
+  // Returns true if data use tracking has been started for the tab with id
+  // |tab_id|. Calling this function resets the state of the tab.
+  bool HasDataUseTrackingStarted(int32_t tab_id);
+
+  // Returns true if data use tracking has ended for the tab with id |tab_id|.
+  // Calling this function resets the state of the tab.
+  bool HasDataUseTrackingEnded(int32_t tab_id);
+
+ private:
+  FRIEND_TEST_ALL_PREFIXES(DataUseUITabModelTest, EntranceExitState);
+
+  // DataUseTrackingEvent indicates the state of a tab.
+  enum DataUseTrackingEvent {
+    // Indicates that data use tracking has started.
+    DATA_USE_TRACKING_STARTED,
+
+    // Indicates that data use tracking has ended.
+    DATA_USE_TRACKING_ENDED,
+  };
+
+  typedef std::unordered_map<int32_t, DataUseTrackingEvent> TabEvents;
+
+  // DataUseTabModel::Observer implementation:
+  // TODO(tbansal): Add override once DataUseTabModel is checked in.
+  void OnTrackingStarted(int32_t tab_id);
+  void OnTrackingEnded(int32_t tab_id);
+
+  // Creates |event| for tab with id |tab_id| and value |event|, if there is no
+  // existing entry for |tab_id|, and returns true. Otherwise, returns false
+  // without modifying the entry.
+  bool MaybeCreateTabEvent(int32_t tab_id, DataUseTrackingEvent event);
+
+  // Removes event entry for |tab_id|, if the entry is equal to |event|, and
+  // returns true. Otherwise, returns false without modifying the entry.
+  bool RemoveTabEvent(int32_t tab_id, DataUseTrackingEvent event);
+
+  // |tab_events_| stores tracking events of multiple tabs.
+  TabEvents tab_events_;
+
+  // |io_task_runner_| accesses DataUseTabModel members on IO thread.
+  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+  base::ThreadChecker thread_checker_;
+
+  DISALLOW_COPY_AND_ASSIGN(DataUseUITabModel);
+};
+
+}  // namespace android
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_UI_TAB_MODEL_H_
diff --git a/chrome/browser/android/data_usage/data_use_ui_tab_model_factory.cc b/chrome/browser/android/data_usage/data_use_ui_tab_model_factory.cc
new file mode 100644
index 0000000..8486810
--- /dev/null
+++ b/chrome/browser/android/data_usage/data_use_ui_tab_model_factory.cc
@@ -0,0 +1,44 @@
+// Copyright 2015 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 "chrome/browser/android/data_usage/data_use_ui_tab_model_factory.h"
+
+#include "base/memory/singleton.h"
+#include "chrome/browser/android/data_usage/data_use_ui_tab_model.h"
+#include "components/keyed_service/content/browser_context_dependency_manager.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace chrome {
+
+namespace android {
+
+// static
+DataUseUITabModelFactory* DataUseUITabModelFactory::GetInstance() {
+  return base::Singleton<DataUseUITabModelFactory>::get();
+}
+
+// static
+DataUseUITabModel* DataUseUITabModelFactory::GetForBrowserContext(
+    content::BrowserContext* context) {
+  return static_cast<DataUseUITabModel*>(
+      GetInstance()->GetServiceForBrowserContext(context, true));
+}
+
+DataUseUITabModelFactory::DataUseUITabModelFactory()
+    : BrowserContextKeyedServiceFactory(
+          "data_usage::DataUseUITabModel",
+          BrowserContextDependencyManager::GetInstance()) {}
+
+DataUseUITabModelFactory::~DataUseUITabModelFactory() {}
+
+KeyedService* DataUseUITabModelFactory::BuildServiceInstanceFor(
+    content::BrowserContext* /* context */) const {
+  return new DataUseUITabModel(
+      content::BrowserThread::GetMessageLoopProxyForThread(
+          content::BrowserThread::IO));
+}
+
+}  // namespace android
+
+}  // namespace chrome
diff --git a/chrome/browser/android/data_usage/data_use_ui_tab_model_factory.h b/chrome/browser/android/data_usage/data_use_ui_tab_model_factory.h
new file mode 100644
index 0000000..38ac8e0
--- /dev/null
+++ b/chrome/browser/android/data_usage/data_use_ui_tab_model_factory.h
@@ -0,0 +1,52 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_UI_TAB_MODEL_FACTORY_H_
+#define CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_UI_TAB_MODEL_FACTORY_H_
+
+#include "base/macros.h"
+#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
+
+namespace base {
+template <typename T>
+struct DefaultSingletonTraits;
+}
+
+namespace content {
+class BrowserContext;
+}
+
+namespace chrome {
+
+namespace android {
+
+class DataUseUITabModel;
+
+class DataUseUITabModelFactory : public BrowserContextKeyedServiceFactory {
+ public:
+  // Returns a singleton instance of DataUseUITabModelFactory.
+  static DataUseUITabModelFactory* GetInstance();
+
+  // Returns the DataUseUITabModel associated with |context|.
+  static DataUseUITabModel* GetForBrowserContext(
+      content::BrowserContext* context);
+
+ private:
+  friend struct base::DefaultSingletonTraits<DataUseUITabModelFactory>;
+
+  DataUseUITabModelFactory();
+  ~DataUseUITabModelFactory() override;
+
+  // BrowserContextKeyedServiceFactory:
+  KeyedService* BuildServiceInstanceFor(
+      content::BrowserContext* browser_context) const override;
+
+  DISALLOW_COPY_AND_ASSIGN(DataUseUITabModelFactory);
+};
+
+}  // namespace android
+
+}  // namespace chrome
+
+#endif  // CHROME_BROWSER_ANDROID_DATA_USAGE_DATA_USE_UI_TAB_MODEL_FACTORY_H_
diff --git a/chrome/browser/android/data_usage/data_use_ui_tab_model_unittest.cc b/chrome/browser/android/data_usage/data_use_ui_tab_model_unittest.cc
new file mode 100644
index 0000000..47ddf55
--- /dev/null
+++ b/chrome/browser/android/data_usage/data_use_ui_tab_model_unittest.cc
@@ -0,0 +1,101 @@
+// Copyright 2015 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 "chrome/browser/android/data_usage/data_use_ui_tab_model.h"
+
+#include <stdint.h>
+
+#include "chrome/browser/android/data_usage/data_use_ui_tab_model_factory.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/session_tab_helper.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/test/test_renderer_host.h"
+#include "content/public/test/web_contents_tester.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/page_transition_types.h"
+#include "url/gurl.h"
+
+namespace chrome {
+
+namespace android {
+
+class DataUseUITabModelTest : public ChromeRenderViewHostTestHarness {
+ public:
+  using ChromeRenderViewHostTestHarness::web_contents;
+
+  DataUseUITabModel* data_use_ui_tab_model() {
+    return chrome::android::DataUseUITabModelFactory::GetForBrowserContext(
+        Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+  }
+};
+
+// Tests that DataUseTabModel is notified of tab closure and navigation events.
+TEST_F(DataUseUITabModelTest, ReportTabEventsTest) {
+  data_use_ui_tab_model()->ReportBrowserNavigation(
+      GURL("https://www.example.com"),
+      ui::PageTransition::PAGE_TRANSITION_TYPED,
+      SessionTabHelper::IdForTab(web_contents()));
+  data_use_ui_tab_model()->ReportTabClosure(
+      SessionTabHelper::IdForTab(web_contents()));
+  // TODO(tbansal): Test that DataUseTabModel is notified.
+}
+
+// Tests if the Entrance/Exit UI state is tracked correctly.
+TEST_F(DataUseUITabModelTest, EntranceExitState) {
+  int32_t foo_tab_id = 1;
+  int32_t bar_tab_id = 2;
+  int32_t baz_tab_id = 3;
+
+  // ShowEntrance should return true only once.
+  data_use_ui_tab_model()->OnTrackingStarted(foo_tab_id);
+  EXPECT_TRUE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingEnded(foo_tab_id));
+
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(bar_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingEnded(bar_tab_id));
+
+  // ShowExit should return true only once.
+  data_use_ui_tab_model()->OnTrackingEnded(foo_tab_id);
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+  EXPECT_TRUE(data_use_ui_tab_model()->HasDataUseTrackingEnded(foo_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingEnded(foo_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+
+  // The tab enters the tracking state again.
+  data_use_ui_tab_model()->OnTrackingStarted(foo_tab_id);
+  EXPECT_TRUE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+
+  // The tab exits the tracking state.
+  data_use_ui_tab_model()->OnTrackingEnded(foo_tab_id);
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+
+  // The tab enters the tracking state again.
+  data_use_ui_tab_model()->OnTrackingStarted(foo_tab_id);
+  data_use_ui_tab_model()->OnTrackingStarted(foo_tab_id);
+  EXPECT_TRUE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(foo_tab_id));
+
+  // ShowExit should return true only once.
+  data_use_ui_tab_model()->OnTrackingEnded(bar_tab_id);
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(bar_tab_id));
+  EXPECT_TRUE(data_use_ui_tab_model()->HasDataUseTrackingEnded(bar_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingEnded(bar_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(bar_tab_id));
+
+  data_use_ui_tab_model()->ReportTabClosure(foo_tab_id);
+  data_use_ui_tab_model()->ReportTabClosure(bar_tab_id);
+
+  //  HasDataUseTrackingStarted/Ended should return false for closed tabs.
+  data_use_ui_tab_model()->OnTrackingStarted(baz_tab_id);
+  data_use_ui_tab_model()->ReportTabClosure(baz_tab_id);
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingStarted(baz_tab_id));
+  EXPECT_FALSE(data_use_ui_tab_model()->HasDataUseTrackingEnded(baz_tab_id));
+}
+
+}  // namespace android
+
+}  // namespace chrome
diff --git a/chrome/browser/android/data_usage/external_data_use_observer.h b/chrome/browser/android/data_usage/external_data_use_observer.h
index 5caa620..6a9c838 100644
--- a/chrome/browser/android/data_usage/external_data_use_observer.h
+++ b/chrome/browser/android/data_usage/external_data_use_observer.h
@@ -91,6 +91,10 @@
   // matching rule's label.
   bool Matches(const GURL& gurl, std::string* label) const;
 
+  DataUseTabModel* data_use_tab_model() const {
+    return data_use_tab_model_.get();
+  }
+
  private:
   FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, SingleRegex);
   FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, TwoRegex);
diff --git a/chrome/browser/android/offline_pages/offline_page_bridge.cc b/chrome/browser/android/offline_pages/offline_page_bridge.cc
index 6d6fcd0..adf054b 100644
--- a/chrome/browser/android/offline_pages/offline_page_bridge.cc
+++ b/chrome/browser/android/offline_pages/offline_page_bridge.cc
@@ -57,6 +57,7 @@
         offline_page.bookmark_id,
         ConvertUTF8ToJavaString(env, offline_page.GetOfflineURL().spec()).obj(),
         offline_page.file_size,
+        offline_page.creation_time.ToJavaTime(),
         offline_page.access_count,
         offline_page.last_access_time.ToJavaTime());
   }
@@ -147,6 +148,7 @@
       offline_page->bookmark_id,
       ConvertUTF8ToJavaString(env, offline_page->GetOfflineURL().spec()).obj(),
       offline_page->file_size,
+      offline_page->creation_time.ToJavaTime(),
       offline_page->access_count,
       offline_page->last_access_time.ToJavaTime());
 }
diff --git a/chrome/browser/android/preferences/website_preference_bridge.cc b/chrome/browser/android/preferences/website_preference_bridge.cc
index d47f4c9b..e5d3fc4 100644
--- a/chrome/browser/android/preferences/website_preference_bridge.cc
+++ b/chrome/browser/android/preferences/website_preference_bridge.cc
@@ -139,11 +139,11 @@
   }
 }
 
-static jint GetSettingForOrigin(JNIEnv* env,
-                                ContentSettingsType content_type,
-                                jstring origin,
-                                jstring embedder,
-                                jboolean is_incognito) {
+static ContentSetting GetSettingForOrigin(JNIEnv* env,
+                                          ContentSettingsType content_type,
+                                          jstring origin,
+                                          jstring embedder,
+                                          jboolean is_incognito) {
   GURL url(ConvertJavaStringToUTF8(env, origin));
   GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
   ContentSetting setting =
@@ -156,19 +156,9 @@
                                 ContentSettingsType content_type,
                                 jstring origin,
                                 ContentSettingsPattern secondary_pattern,
-                                jint value,
+                                ContentSetting setting,
                                 jboolean is_incognito) {
   GURL url(ConvertJavaStringToUTF8(env, origin));
-  ContentSetting setting = CONTENT_SETTING_DEFAULT;
-  switch (value) {
-    case -1: break;
-    case 0: setting = CONTENT_SETTING_DEFAULT; break;
-    case 1: setting = CONTENT_SETTING_ALLOW; break;
-    case 2: setting = CONTENT_SETTING_BLOCK; break;
-    default:
-      // Note: CONTENT_SETTINGS_ASK is not and should not be supported.
-      NOTREACHED();
-  }
   GetHostContentSettingsMap(is_incognito)
       ->SetContentSetting(ContentSettingsPattern::FromURLNoWildcard(url),
                           secondary_pattern, content_type, std::string(),
@@ -201,7 +191,7 @@
   GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
   SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_FULLSCREEN, origin,
                       ContentSettingsPattern::FromURLNoWildcard(embedder_url),
-                      value, is_incognito);
+                      (ContentSetting) value, is_incognito);
 }
 
 static void GetGeolocationOrigins(JNIEnv* env,
@@ -231,7 +221,7 @@
   GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
   SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_GEOLOCATION, origin,
                       ContentSettingsPattern::FromURLNoWildcard(embedder_url),
-                      value, is_incognito);
+                      (ContentSetting) value, is_incognito);
 }
 
 static void GetMidiOrigins(JNIEnv* env,
@@ -258,7 +248,7 @@
   GURL embedder_url(ConvertJavaStringToUTF8(env, embedder));
   SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MIDI_SYSEX, origin,
                       ContentSettingsPattern::FromURLNoWildcard(embedder_url),
-                      value, is_incognito);
+                      (ContentSetting) value, is_incognito);
 }
 
 static void GetProtectedMediaIdentifierOrigins(
@@ -291,7 +281,7 @@
   SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
                       origin,
                       ContentSettingsPattern::FromURLNoWildcard(embedder_url),
-                      value, is_incognito);
+                      (ContentSetting) value, is_incognito);
 }
 
 static void GetPushNotificationOrigins(JNIEnv* env,
@@ -322,19 +312,17 @@
   // permission types. See https://crbug.com/416894.
   Profile* profile = GetActiveUserProfile(is_incognito);
   GURL url = GURL(ConvertJavaStringToUTF8(env, origin));
-  ContentSetting setting = CONTENT_SETTING_DEFAULT;
-  switch (value) {
-    case -1:
+  ContentSetting setting = (ContentSetting) value;
+  switch (setting) {
+    case CONTENT_SETTING_DEFAULT:
       DesktopNotificationProfileUtil::ClearSetting(
           profile, ContentSettingsPattern::FromURLNoWildcard(url));
       break;
-    case 1:
+    case CONTENT_SETTING_ALLOW:
       DesktopNotificationProfileUtil::GrantPermission(profile, url);
-      setting = CONTENT_SETTING_ALLOW;
       break;
-    case 2:
+    case CONTENT_SETTING_BLOCK:
       DesktopNotificationProfileUtil::DenyPermission(profile, url);
-      setting = CONTENT_SETTING_BLOCK;
       break;
     default:
       NOTREACHED();
@@ -382,7 +370,8 @@
                                           jint value,
                                           jboolean is_incognito) {
   SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, origin,
-                      ContentSettingsPattern::Wildcard(), value, is_incognito);
+                      ContentSettingsPattern::Wildcard(),
+                      (ContentSetting) value, is_incognito);
 }
 
 static void SetCameraSettingForOrigin(JNIEnv* env,
@@ -392,7 +381,8 @@
                                       jint value,
                                       jboolean is_incognito) {
   SetSettingForOrigin(env, CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, origin,
-                      ContentSettingsPattern::Wildcard(), value, is_incognito);
+                      ContentSettingsPattern::Wildcard(),
+                      (ContentSetting) value, is_incognito);
 }
 
 static scoped_refptr<content_settings::CookieSettings> GetCookieSettings() {
diff --git a/chrome/browser/android/tab_state.cc b/chrome/browser/android/tab_state.cc
index 4cfb6e3..327bc8c 100644
--- a/chrome/browser/android/tab_state.cc
+++ b/chrome/browser/android/tab_state.cc
@@ -426,7 +426,7 @@
     return NULL;
 
   Profile* profile = ProfileManager::GetActiveUserProfile();
-  ScopedVector<content::NavigationEntry> scoped_entries =
+  std::vector<scoped_ptr<content::NavigationEntry>> entries =
       sessions::ContentSerializedNavigationBuilder::ToNavigationEntries(
           navigations, profile);
 
@@ -436,9 +436,8 @@
   params.initially_hidden = initially_hidden;
   scoped_ptr<WebContents> web_contents(WebContents::Create(params));
   web_contents->GetController().Restore(
-      current_entry_index,
-      NavigationController::RESTORE_CURRENT_SESSION,
-      &scoped_entries);
+      current_entry_index, NavigationController::RESTORE_CURRENT_SESSION,
+      &entries);
   return web_contents.release();
 }
 
diff --git a/chrome/browser/apps/guest_view/extension_view/extension_view_browsertest.cc b/chrome/browser/apps/guest_view/extension_view/extension_view_browsertest.cc
index 6fd4a2e..2af0469 100644
--- a/chrome/browser/apps/guest_view/extension_view/extension_view_browsertest.cc
+++ b/chrome/browser/apps/guest_view/extension_view/extension_view_browsertest.cc
@@ -79,10 +79,8 @@
 // Tests that <extensionview> can be created and added to the DOM.
 IN_PROC_BROWSER_TEST_F(ExtensionViewTest,
                        TestExtensionViewCreationShouldSucceed) {
-  const extensions::Extension* skeleton_app =
-      InstallPlatformApp("extension_view/skeleton");
-  TestHelper("testExtensionViewCreationShouldSucceed", "extension_view",
-             skeleton_app->id(), "");
+  TestHelper("testExtensionViewCreationShouldSucceed",
+             "extension_view/creation", "", "");
 }
 
 // Tests that verify that <extensionview> does not change extension ID if
diff --git a/chrome/browser/autocomplete/keyword_extensions_delegate_impl.cc b/chrome/browser/autocomplete/keyword_extensions_delegate_impl.cc
index 888de25..fa00baa 100644
--- a/chrome/browser/autocomplete/keyword_extensions_delegate_impl.cc
+++ b/chrome/browser/autocomplete/keyword_extensions_delegate_impl.cc
@@ -179,14 +179,14 @@
         // is true, because we wouldn't get results from the extension unless
         // the full keyword had been typed.
         int first_relevance = KeywordProvider::CalculateRelevance(
-            input.type(), true, true, input.prefer_keyword(),
+            input.type(), true, true, true, input.prefer_keyword(),
             input.allow_exact_keyword_match());
         // Because these matches are async, we should never let them become the
         // default match, lest we introduce race conditions in the omnibox user
         // interaction.
         extension_suggest_matches_.push_back(
             provider_->CreateAutocompleteMatch(
-                template_url, input, keyword.length(),
+                template_url, keyword.length(), input, keyword.length(),
                 base::UTF8ToUTF16(suggestion.content), false,
                 first_relevance - (i + 1)));
 
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index 288eafd..7cd7467 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -66,41 +66,6 @@
 
 namespace {
 
-// Records histogram about which auto-launch pattern (if any) was used to launch
-// the current process based on |command_line|.
-void RecordAutoLaunchState(const base::CommandLine& command_line) {
-  enum AutoLaunchState {
-    AUTO_LAUNCH_NONE = 0,
-    AUTO_LAUNCH_BACKGROUND = 1,
-    AUTO_LAUNCH_FOREGROUND = 2,
-    AUTO_LAUNCH_FOREGROUND_USELESS = 3,
-    AUTO_LAUNCH_NUM_STATES
-  } auto_launch_state = AUTO_LAUNCH_NONE;
-
-  if (command_line.HasSwitch(switches::kNoStartupWindow))
-    auto_launch_state = AUTO_LAUNCH_BACKGROUND;
-
-  if (command_line.HasSwitch(switches::kAutoLaunchAtStartup)) {
-    // The only purpose of kAutoLaunchAtStartup is to override a background
-    // auto-launch from kNoStartupWindow into a foreground auto-launch. It's a
-    // meaningless switch on its own.
-    if (auto_launch_state == AUTO_LAUNCH_BACKGROUND) {
-      auto_launch_state = AUTO_LAUNCH_FOREGROUND;
-    } else {
-      auto_launch_state = AUTO_LAUNCH_FOREGROUND_USELESS;
-    }
-  }
-
-  // Observe the AutoLaunchStates in the wild. According to the platform-
-  // specific implementations of EnableLaunchOnStartup(), we'd expect only Mac
-  // and Windows to have any sort of AutoLaunchState and only Windows should use
-  // FOREGROUND if at all (it was only used by a deprecated experiment and a
-  // master pref which may not be used much). Tighten up auto-launch settings
-  // based on the result of usage in the wild.
-  UMA_HISTOGRAM_ENUMERATION("BackgroundMode.OnStartup.AutoLaunchState",
-                            auto_launch_state, AUTO_LAUNCH_NUM_STATES);
-}
-
 // Enum for recording menu item clicks in UMA.
 // NOTE: Do not renumber these as that would confuse interpretation of
 // previously logged data. When making changes, also update histograms.xml.
@@ -320,7 +285,8 @@
   // are deleted and their names change.
   profile_cache_->AddObserver(this);
 
-  RecordAutoLaunchState(command_line);
+  UMA_HISTOGRAM_BOOLEAN("BackgroundMode.OnStartup.AutoLaunchState",
+                        command_line.HasSwitch(switches::kNoStartupWindow));
   UMA_HISTOGRAM_BOOLEAN("BackgroundMode.OnStartup.IsBackgroundModePrefEnabled",
                         IsBackgroundModePrefEnabled());
 
diff --git a/chrome/browser/chrome_browser_application_mac.mm b/chrome/browser/chrome_browser_application_mac.mm
index 1949c5e..6066d04 100644
--- a/chrome/browser/chrome_browser_application_mac.mm
+++ b/chrome/browser/chrome_browser_application_mac.mm
@@ -15,7 +15,6 @@
 #import "base/mac/scoped_nsobject.h"
 #import "base/mac/scoped_objc_class_swizzler.h"
 #import "base/metrics/histogram.h"
-#include "base/profiler/scoped_tracker.h"
 #include "base/strings/stringprintf.h"
 #import "base/strings/sys_string_conversions.h"
 #import "chrome/browser/app_controller_mac.h"
@@ -334,9 +333,6 @@
 
 - (void)sendEvent:(NSEvent*)event {
   base::mac::CallWithEHFrame(^{
-    // tracked_objects::ScopedTracker does not support parameterized
-    // instrumentations, so a big switch with each bunch instrumented is
-    // required.
     switch (event.type) {
       case NSLeftMouseDown:
       case NSRightMouseDown: {
@@ -349,80 +345,8 @@
         if (kioskMode && ([event type] == NSRightMouseDown || ctrlDown))
           break;
       }
-      // FALL THROUGH
-      case NSLeftMouseUp:
-      case NSRightMouseUp:
-      case NSMouseMoved:
-      case NSLeftMouseDragged:
-      case NSRightMouseDragged:
-      case NSMouseEntered:
-      case NSMouseExited:
-      case NSOtherMouseDown:
-      case NSOtherMouseUp:
-      case NSOtherMouseDragged: {
-        tracked_objects::ScopedTracker tracking_profile(
-            FROM_HERE_WITH_EXPLICIT_FUNCTION(
-                "463272 -[BrowserCrApplication sendEvent:] Mouse"));
-        base::mac::ScopedSendingEvent sendingEventScoper;
-        [super sendEvent:event];
-        break;
-      }
-
-      case NSKeyDown:
-      case NSKeyUp: {
-        tracked_objects::ScopedTracker tracking_profile(
-            FROM_HERE_WITH_EXPLICIT_FUNCTION(
-                "463272 -[BrowserCrApplication sendEvent:] Key"));
-        base::mac::ScopedSendingEvent sendingEventScoper;
-        [super sendEvent:event];
-        break;
-      }
-
-      case NSScrollWheel: {
-        tracked_objects::ScopedTracker tracking_profile(
-            FROM_HERE_WITH_EXPLICIT_FUNCTION(
-                "463272 -[BrowserCrApplication sendEvent:] ScrollWheel"));
-        base::mac::ScopedSendingEvent sendingEventScoper;
-        [super sendEvent:event];
-        break;
-      }
-
-      case NSEventTypeGesture:
-      case NSEventTypeMagnify:
-      case NSEventTypeSwipe:
-      case NSEventTypeRotate:
-      case NSEventTypeBeginGesture:
-      case NSEventTypeEndGesture: {
-        tracked_objects::ScopedTracker tracking_profile(
-            FROM_HERE_WITH_EXPLICIT_FUNCTION(
-                "463272 -[BrowserCrApplication sendEvent:] Gesture"));
-        base::mac::ScopedSendingEvent sendingEventScoper;
-        [super sendEvent:event];
-        break;
-      }
-
-      case NSAppKitDefined: {
-        tracked_objects::ScopedTracker tracking_profile(
-            FROM_HERE_WITH_EXPLICIT_FUNCTION(
-                "463272 -[BrowserCrApplication sendEvent:] AppKit"));
-        base::mac::ScopedSendingEvent sendingEventScoper;
-        [super sendEvent:event];
-        break;
-      }
-
-      case NSSystemDefined: {
-        tracked_objects::ScopedTracker tracking_profile(
-            FROM_HERE_WITH_EXPLICIT_FUNCTION(
-                "463272 -[BrowserCrApplication sendEvent:] System"));
-        base::mac::ScopedSendingEvent sendingEventScoper;
-        [super sendEvent:event];
-        break;
-      }
 
       default: {
-        tracked_objects::ScopedTracker tracking_profile(
-            FROM_HERE_WITH_EXPLICIT_FUNCTION(
-                "463272 -[BrowserCrApplication sendEvent:] Other"));
         base::mac::ScopedSendingEvent sendingEventScoper;
         [super sendEvent:event];
       }
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index d3d8f4f..2cd5a26b 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -109,6 +109,7 @@
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings.h"
 #include "components/data_reduction_proxy/content/browser/data_reduction_proxy_message_filter.h"
+#include "components/dom_distiller/core/dom_distiller_switches.h"
 #include "components/dom_distiller/core/url_constants.h"
 #include "components/google/core/browser/google_util.h"
 #include "components/metrics/client_info.h"
@@ -1582,6 +1583,7 @@
       switches::kProfilingAtStart,
       switches::kProfilingFile,
       switches::kProfilingFlush,
+      switches::kReaderModeHeuristics,
       switches::kUnsafelyTreatInsecureOriginAsSecure,
       translate::switches::kTranslateSecurityOrigin,
     };
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.cc b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
index 73563c3..15db4a5 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.cc
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.cc
@@ -9,6 +9,7 @@
 #include "ash/high_contrast/high_contrast_controller.h"
 #include "ash/metrics/user_metrics_recorder.h"
 #include "ash/session/session_state_delegate.h"
+#include "ash/shelf/shelf_layout_manager.h"
 #include "ash/shell.h"
 #include "ash/sticky_keys/sticky_keys_controller.h"
 #include "ash/system/tray/system_tray_notifier.h"
@@ -270,6 +271,33 @@
 
 }  // namespace
 
+class ChromeVoxPanelWidgetObserver : public views::WidgetObserver {
+ public:
+  ChromeVoxPanelWidgetObserver(views::Widget* widget,
+                               AccessibilityManager* manager)
+      : widget_(widget), manager_(manager) {
+    widget_->AddObserver(this);
+  }
+
+  void OnWidgetClosing(views::Widget* widget) override {
+    CHECK_EQ(widget_, widget);
+    widget->RemoveObserver(this);
+    manager_->OnChromeVoxPanelClosing();
+  }
+
+  void OnWidgetDestroying(views::Widget* widget) override {
+    CHECK_EQ(widget_, widget);
+    widget->RemoveObserver(this);
+    manager_->OnChromeVoxPanelDestroying();
+  }
+
+ private:
+  views::Widget* widget_;
+  AccessibilityManager* manager_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeVoxPanelWidgetObserver);
+};
+
 ///////////////////////////////////////////////////////////////////////////////
 // AccessibilityStatusEventDetails
 
@@ -377,6 +405,7 @@
       braille_display_connected_(false),
       scoped_braille_observer_(this),
       braille_ime_current_(false),
+      chromevox_panel_(nullptr),
       weak_ptr_factory_(this) {
   notification_registrar_.Add(this,
                               chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
@@ -419,6 +448,11 @@
       ui::A11Y_NOTIFICATION_NONE);
   NotifyAccessibilityStatusChanged(details);
   input_method::InputMethodManager::Get()->RemoveObserver(this);
+
+  if (chromevox_panel_) {
+    chromevox_panel_->Close();
+    chromevox_panel_ = nullptr;
+  }
 }
 
 bool AccessibilityManager::ShouldShowAccessibilityMenu() {
@@ -636,6 +670,11 @@
 }
 
 void AccessibilityManager::UnloadChromeVox() {
+  if (chromevox_panel_) {
+    chromevox_panel_->Close();
+    chromevox_panel_ = nullptr;
+  }
+
   if (chrome_vox_loaded_on_lock_screen_)
     UnloadChromeVoxFromLockScreen();
 
@@ -1138,6 +1177,12 @@
 
   should_speak_chrome_vox_announcements_on_user_screen_ =
       chrome_vox_loaded_on_lock_screen_;
+
+  if (!chromevox_panel_) {
+    chromevox_panel_ = new ChromeVoxPanel(profile_);
+    chromevox_panel_widget_observer_.reset(
+        new ChromeVoxPanelWidgetObserver(chromevox_panel_->GetWidget(), this));
+  }
 }
 
 void AccessibilityManager::PostUnloadChromeVox(Profile* profile) {
@@ -1148,4 +1193,16 @@
       std::vector<gfx::Rect>());
 }
 
+void AccessibilityManager::OnChromeVoxPanelClosing() {
+  aura::Window* root_window = chromevox_panel_->GetRootWindow();
+  chromevox_panel_widget_observer_.reset(nullptr);
+  chromevox_panel_ = nullptr;
+  ash::ShelfLayoutManager::ForShelf(root_window)->SetChromeVoxPanelHeight(0);
+}
+
+void AccessibilityManager::OnChromeVoxPanelDestroying() {
+  chromevox_panel_widget_observer_.reset(nullptr);
+  chromevox_panel_ = nullptr;
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/accessibility/accessibility_manager.h b/chrome/browser/chromeos/accessibility/accessibility_manager.h
index 26bdf40..9a905b9 100644
--- a/chrome/browser/chromeos/accessibility/accessibility_manager.h
+++ b/chrome/browser/chromeos/accessibility/accessibility_manager.h
@@ -16,6 +16,7 @@
 #include "base/scoped_observer.h"
 #include "base/time/time.h"
 #include "chrome/browser/chromeos/accessibility/accessibility_util.h"
+#include "chrome/browser/chromeos/accessibility/chromevox_panel.h"
 #include "chrome/browser/extensions/api/braille_display_private/braille_controller.h"
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
@@ -27,6 +28,7 @@
 namespace content {
 class RenderViewHost;
 }
+
 class Profile;
 
 namespace chromeos {
@@ -68,6 +70,8 @@
 typedef AccessibilityStatusCallbackList::Subscription
     AccessibilityStatusSubscription;
 
+class ChromeVoxPanelWidgetObserver;
+
 // AccessibilityManager changes the statuses of accessibility features
 // watching profile notifications and pref-changes.
 // TODO(yoshiki): merge MagnificationManager with AccessibilityManager.
@@ -200,6 +204,10 @@
   // chromeos/audio/chromeos_sounds.h.
   void PlayEarcon(int sound_key);
 
+  // Called by our widget observer when the ChromeVoxPanel is closing.
+  void OnChromeVoxPanelClosing();
+  void OnChromeVoxPanelDestroying();
+
   // Profile having the a11y context.
   Profile* profile() { return profile_; }
 
@@ -293,6 +301,9 @@
 
   bool braille_ime_current_;
 
+  ChromeVoxPanel* chromevox_panel_;
+  scoped_ptr<ChromeVoxPanelWidgetObserver> chromevox_panel_widget_observer_;
+
   base::WeakPtrFactory<AccessibilityManager> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(AccessibilityManager);
diff --git a/chrome/browser/chromeos/accessibility/chromevox_panel.cc b/chrome/browser/chromeos/accessibility/chromevox_panel.cc
new file mode 100644
index 0000000..9677ee0
--- /dev/null
+++ b/chrome/browser/chromeos/accessibility/chromevox_panel.cc
@@ -0,0 +1,146 @@
+// Copyright 2015 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 "ash/shelf/shelf_layout_manager.h"
+#include "ash/shell.h"
+#include "ash/shell_window_ids.h"
+#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
+#include "chrome/browser/chromeos/accessibility/chromevox_panel.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "content/public/browser/web_contents.h"
+#include "ui/chromeos/accessibility_types.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/widget/widget.h"
+#include "ui/wm/core/shadow_types.h"
+#include "ui/wm/core/window_animations.h"
+
+namespace {
+
+const int kPanelHeight = 35;
+const char kChromeVoxPanelRelativeUrl[] = "/cvox2/background/panel.html";
+const char kFullscreenURLFragment[] = "fullscreen";
+const char kDisableSpokenFeedbackURLFragment[] = "close";
+
+}  // namespace
+
+class ChromeVoxPanelWebContentsObserver : public content::WebContentsObserver {
+ public:
+  ChromeVoxPanelWebContentsObserver(content::WebContents* web_contents,
+                                    ChromeVoxPanel* panel)
+      : content::WebContentsObserver(web_contents), panel_(panel) {}
+  ~ChromeVoxPanelWebContentsObserver() override {}
+
+  // content::WebContentsObserver overrides.
+  void DidFirstVisuallyNonEmptyPaint() override {
+    panel_->DidFirstVisuallyNonEmptyPaint();
+  }
+
+  void DidFinishNavigation(
+      content::NavigationHandle* navigation_handle) override {
+    // The ChromeVox panel uses the URL fragment to communicate state
+    // to this panel host.
+    std::string fragment = web_contents()->GetLastCommittedURL().ref();
+    if (fragment == kDisableSpokenFeedbackURLFragment)
+      panel_->DisableSpokenFeedback();
+    else if (fragment == kFullscreenURLFragment)
+      panel_->EnterFullscreen();
+    else
+      panel_->ExitFullscreen();
+  }
+
+ private:
+  ChromeVoxPanel* panel_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeVoxPanelWebContentsObserver);
+};
+
+ChromeVoxPanel::ChromeVoxPanel(content::BrowserContext* browser_context)
+    : widget_(nullptr), web_view_(nullptr), fullscreen_(false) {
+  std::string url("chrome-extension://");
+  url += extension_misc::kChromeVoxExtensionId;
+  url += kChromeVoxPanelRelativeUrl;
+
+  views::WebView* web_view = new views::WebView(browser_context);
+  web_contents_observer_.reset(
+      new ChromeVoxPanelWebContentsObserver(web_view->GetWebContents(), this));
+  web_view->LoadInitialURL(GURL(url));
+  web_view_ = web_view;
+
+  widget_ = new views::Widget();
+  views::Widget::InitParams params(
+      views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
+  aura::Window* root_window = ash::Shell::GetPrimaryRootWindow();
+  params.parent = ash::Shell::GetContainer(
+      root_window, ash::kShellWindowId_SettingBubbleContainer);
+  params.delegate = this;
+  params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
+  params.bounds = gfx::Rect(0, 0, root_window->bounds().width(),
+                            root_window->bounds().height());
+  widget_->Init(params);
+  SetShadowType(widget_->GetNativeWindow(), wm::SHADOW_TYPE_RECTANGULAR);
+
+  ash::Shell::GetScreen()->AddObserver(this);
+}
+
+ChromeVoxPanel::~ChromeVoxPanel() {
+  ash::Shell::GetScreen()->RemoveObserver(this);
+}
+
+aura::Window* ChromeVoxPanel::GetRootWindow() {
+  return GetWidget()->GetNativeWindow()->GetRootWindow();
+}
+
+void ChromeVoxPanel::Close() {
+  widget_->Close();
+}
+
+void ChromeVoxPanel::DidFirstVisuallyNonEmptyPaint() {
+  widget_->Show();
+  ash::ShelfLayoutManager::ForShelf(GetRootWindow())
+      ->SetChromeVoxPanelHeight(kPanelHeight);
+}
+
+void ChromeVoxPanel::EnterFullscreen() {
+  fullscreen_ = true;
+  UpdateWidgetBounds();
+}
+
+void ChromeVoxPanel::ExitFullscreen() {
+  fullscreen_ = false;
+  UpdateWidgetBounds();
+}
+
+void ChromeVoxPanel::DisableSpokenFeedback() {
+  chromeos::AccessibilityManager::Get()->EnableSpokenFeedback(
+      false, ui::A11Y_NOTIFICATION_NONE);
+}
+
+const views::Widget* ChromeVoxPanel::GetWidget() const {
+  return widget_;
+}
+
+views::Widget* ChromeVoxPanel::GetWidget() {
+  return widget_;
+}
+
+void ChromeVoxPanel::DeleteDelegate() {
+  delete this;
+}
+
+views::View* ChromeVoxPanel::GetContentsView() {
+  return web_view_;
+}
+
+void ChromeVoxPanel::OnDisplayMetricsChanged(const gfx::Display& display,
+                                             uint32_t changed_metrics) {
+  UpdateWidgetBounds();
+}
+
+void ChromeVoxPanel::UpdateWidgetBounds() {
+  gfx::Rect bounds(GetRootWindow()->bounds().size());
+  if (!fullscreen_)
+    bounds.set_height(kPanelHeight);
+  widget_->SetBounds(bounds);
+}
diff --git a/chrome/browser/chromeos/accessibility/chromevox_panel.h b/chrome/browser/chromeos/accessibility/chromevox_panel.h
new file mode 100644
index 0000000..6079c079
--- /dev/null
+++ b/chrome/browser/chromeos/accessibility/chromevox_panel.h
@@ -0,0 +1,59 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_CHROMEVOX_PANEL_H_
+#define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_CHROMEVOX_PANEL_H_
+
+#include "base/macros.h"
+#include "ui/gfx/display_observer.h"
+#include "ui/views/widget/widget_delegate.h"
+
+class ChromeVoxPanelWebContentsObserver;
+
+namespace content {
+class BrowserContext;
+}
+
+namespace views {
+class Widget;
+}
+
+class ChromeVoxPanel : public views::WidgetDelegate,
+                       public gfx::DisplayObserver {
+ public:
+  explicit ChromeVoxPanel(content::BrowserContext* browser_context);
+  ~ChromeVoxPanel() override;
+
+  aura::Window* GetRootWindow();
+
+  void Close();
+  void DidFirstVisuallyNonEmptyPaint();
+  void EnterFullscreen();
+  void ExitFullscreen();
+  void DisableSpokenFeedback();
+
+  // WidgetDelegate overrides.
+  const views::Widget* GetWidget() const override;
+  views::Widget* GetWidget() override;
+  void DeleteDelegate() override;
+  views::View* GetContentsView() override;
+
+  // DisplayObserver overrides;
+  void OnDisplayAdded(const gfx::Display& new_display) override {}
+  void OnDisplayRemoved(const gfx::Display& old_display) override {}
+  void OnDisplayMetricsChanged(const gfx::Display& display,
+                               uint32_t changed_metrics) override;
+
+ private:
+  void UpdateWidgetBounds();
+
+  views::Widget* widget_;
+  scoped_ptr<ChromeVoxPanelWebContentsObserver> web_contents_observer_;
+  views::View* web_view_;
+  bool fullscreen_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeVoxPanel);
+};
+
+#endif  // CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_CHROMEVOX_PANEL_H_
diff --git a/chrome/browser/chromeos/login/webview_login_browsertest.cc b/chrome/browser/chromeos/login/webview_login_browsertest.cc
index bfb1fa2..2915529 100644
--- a/chrome/browser/chromeos/login/webview_login_browsertest.cc
+++ b/chrome/browser/chromeos/login/webview_login_browsertest.cc
@@ -27,17 +27,20 @@
   }
 
   void ExpectIdentifierPage() {
-    // First page: no back button, no close button, #identifier input field.
+    // First page: no back button, no close button, refresh button, #identifier
+    // input field.
     JsExpect("!$('gaia-navigation').backVisible");
     JsExpect("!$('gaia-navigation').closeVisible");
+    JsExpect("$('gaia-navigation').refreshVisible");
     JsExpect("$('signin-frame').src.indexOf('#identifier') != -1");
   }
 
   void ExpectPasswordPage() {
-    // Second page: back button, no close button, #challengepassword input
-    // field.
+    // Second page: back button, close button, no refresh button,
+    // #challengepassword input field.
     JsExpect("$('gaia-navigation').backVisible");
-    JsExpect("!$('gaia-navigation').closeVisible");
+    JsExpect("$('gaia-navigation').closeVisible");
+    JsExpect("!$('gaia-navigation').refreshVisible");
     JsExpect("$('signin-frame').src.indexOf('#challengepassword') != -1");
   }
 
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index 5b6cebf..eb0d7830 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -123,12 +123,16 @@
   return configurator_impl_.UseBackgroundDownloader();
 }
 
+// Returns a task runner to run blocking tasks. The task runner continues to run
+// after the browser shuts down, until the OS terminates the process. This
+// imposes certain requirements for the code using the task runner, such as
+// not accessing any global browser state while the code is running.
 scoped_refptr<base::SequencedTaskRunner>
 ChromeConfigurator::GetSequencedTaskRunner() const {
   return content::BrowserThread::GetBlockingPool()
       ->GetSequencedTaskRunnerWithShutdownBehavior(
           content::BrowserThread::GetBlockingPool()->GetSequenceToken(),
-          base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
+          base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
 }
 
 }  // namespace
diff --git a/chrome/browser/component_updater/recovery_component_installer.cc b/chrome/browser/component_updater/recovery_component_installer.cc
index 8943ab45..ea9b72e 100644
--- a/chrome/browser/component_updater/recovery_component_installer.cc
+++ b/chrome/browser/component_updater/recovery_component_installer.cc
@@ -315,6 +315,21 @@
 }
 #endif  // defined(OS_WIN)
 
+#if defined(OS_POSIX)
+// Sets the POSIX executable permissions on a file
+bool SetPosixExecutablePermission(const base::FilePath& path) {
+  int permissions = 0;
+  if (!base::GetPosixFilePermissions(path, &permissions))
+    return false;
+  const int kExecutableMask = base::FILE_PERMISSION_EXECUTE_BY_USER |
+                              base::FILE_PERMISSION_EXECUTE_BY_GROUP |
+                              base::FILE_PERMISSION_EXECUTE_BY_OTHERS;
+  if ((permissions & kExecutableMask) == kExecutableMask)
+    return true;  // No need to update
+  return base::SetPosixFilePermissions(path, permissions | kExecutableMask);
+}
+#endif  // defined(OS_POSIX)
+
 bool RecoveryComponentInstaller::Install(const base::DictionaryValue& manifest,
                                          const base::FilePath& unpack_path) {
   std::string name;
@@ -334,7 +349,7 @@
   if (!PathService::Get(DIR_RECOVERY_BASE, &path))
     return false;
   if (!base::PathExists(path) && !base::CreateDirectory(path))
-      return false;
+    return false;
   path = path.AppendASCII(version.GetString());
   if (base::PathExists(path) && !base::DeleteFile(path, true))
     return false;
@@ -347,6 +362,17 @@
   if (!base::PathExists(main_file))
     return false;
 
+#if defined(OS_POSIX)
+  // The current version of the CRX unzipping does not restore
+  // correctly the executable flags/permissions. See https://crbug.com/555011
+  if (!SetPosixExecutablePermission(main_file)) {
+    DVLOG(1) << "Recovery component failed to set the executable "
+                "permission on the file: "
+             << main_file.value();
+    return false;
+  }
+#endif
+
   // Run the recovery component.
   const bool is_deferred_run = false;
   const auto cmdline = GetRecoveryInstallCommandLine(
diff --git a/chrome/browser/devtools/devtools_toggle_action.cc b/chrome/browser/devtools/devtools_toggle_action.cc
index 20634c2..48b56337 100644
--- a/chrome/browser/devtools/devtools_toggle_action.cc
+++ b/chrome/browser/devtools/devtools_toggle_action.cc
@@ -45,6 +45,11 @@
 }
 
 // static
+DevToolsToggleAction DevToolsToggleAction::ShowSecurityPanel() {
+  return DevToolsToggleAction(kShowSecurityPanel);
+}
+
+// static
 DevToolsToggleAction DevToolsToggleAction::Inspect() {
   return DevToolsToggleAction(kInspect);
 }
diff --git a/chrome/browser/devtools/devtools_toggle_action.h b/chrome/browser/devtools/devtools_toggle_action.h
index 1e110a3..fa2b2e1 100644
--- a/chrome/browser/devtools/devtools_toggle_action.h
+++ b/chrome/browser/devtools/devtools_toggle_action.h
@@ -14,6 +14,7 @@
   enum Type {
     kShow,
     kShowConsole,
+    kShowSecurityPanel,
     kInspect,
     kToggle,
     kReveal,
@@ -37,6 +38,7 @@
 
   static DevToolsToggleAction Show();
   static DevToolsToggleAction ShowConsole();
+  static DevToolsToggleAction ShowSecurityPanel();
   static DevToolsToggleAction Inspect();
   static DevToolsToggleAction Toggle();
   static DevToolsToggleAction Reveal(const base::string16& url,
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index 41863af..0943fa8 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -1196,11 +1196,18 @@
 
 void DevToolsWindow::DoAction(const DevToolsToggleAction& action) {
   switch (action.type()) {
-    case DevToolsToggleAction::kShowConsole:
-      bindings_->CallClientFunction(
-          "DevToolsAPI.showConsole", NULL, NULL, NULL);
+    case DevToolsToggleAction::kShowConsole: {
+      base::StringValue panel_name("console");
+      bindings_->CallClientFunction("DevToolsAPI.showPanel", &panel_name, NULL,
+                                    NULL);
       break;
-
+    }
+    case DevToolsToggleAction::kShowSecurityPanel: {
+      base::StringValue panel_name("security");
+      bindings_->CallClientFunction("DevToolsAPI.showPanel", &panel_name, NULL,
+                                    NULL);
+      break;
+    }
     case DevToolsToggleAction::kInspect:
       bindings_->CallClientFunction(
           "DevToolsAPI.enterInspectElementMode", NULL, NULL, NULL);
diff --git a/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc b/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc
new file mode 100644
index 0000000..11c97d9
--- /dev/null
+++ b/chrome/browser/dom_distiller/distillable_page_utils_browsertest.cc
@@ -0,0 +1,155 @@
+// Copyright 2015 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 <string.h>
+
+#include "base/command_line.h"
+#include "base/thread_task_runner_handle.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "components/dom_distiller/content/browser/distillable_page_utils.h"
+#include "components/dom_distiller/core/dom_distiller_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace dom_distiller {
+
+using ::testing::_;
+using namespace switches::reader_mode_heuristics;
+
+namespace {
+
+const char kSimpleArticlePath[] = "/dom_distiller/simple_article.html";
+const char kArticlePath[] = "/dom_distiller/og_article.html";
+const char kNonArticlePath[] = "/dom_distiller/non_og_article.html";
+
+class Holder {
+ public:
+  virtual ~Holder() {}
+  virtual void OnResult(bool, bool) = 0;
+};
+
+class MockDelegate : public Holder {
+ public:
+  MOCK_METHOD2(OnResult, void(bool, bool));
+
+  base::Callback<void(bool, bool)> GetDelegate() {
+    return base::Bind(&MockDelegate::OnResult, base::Unretained(this));
+  }
+};
+
+}  // namespace
+
+template<const char Option[]>
+class DistillablePageUtilsBrowserTestOption : public InProcessBrowserTest {
+ public:
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    command_line->AppendSwitch(switches::kEnableDomDistiller);
+    command_line->AppendSwitchASCII(switches::kReaderModeHeuristics,
+        Option);
+  }
+
+  void SetUpOnMainThread() override {
+    InProcessBrowserTest::SetUpOnMainThread();
+    ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
+    web_contents_ =
+        browser()->tab_strip_model()->GetActiveWebContents();
+    setDelegate(web_contents_, holder_.GetDelegate());
+  }
+
+  void NavigateAndWait(const char* url) {
+    GURL article_url(url);
+    if (base::StartsWith(url, "/", base::CompareCase::SENSITIVE)) {
+      article_url = embedded_test_server()->GetURL(url);
+    }
+
+    // This blocks until the navigation has completely finished.
+    ui_test_utils::NavigateToURL(browser(), article_url);
+    content::WaitForLoadStop(web_contents_);
+
+    // Wait a bit for the message.
+    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+        FROM_HERE, base::MessageLoop::QuitWhenIdleClosure(),
+        base::TimeDelta::FromMilliseconds(100));
+    content::RunMessageLoop();
+  }
+
+  MockDelegate holder_;
+  content::WebContents* web_contents_;
+};
+
+
+using DistillablePageUtilsBrowserTestAlways =
+    DistillablePageUtilsBrowserTestOption<kAlwaysTrue>;
+
+IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestAlways,
+                       TestDelegate) {
+  // Run twice to make sure the delegate object is still alive.
+  for (int i = 0; i < 2; ++i) {
+    testing::InSequence dummy;
+    EXPECT_CALL(holder_, OnResult(true, true)).Times(1);
+    NavigateAndWait(kSimpleArticlePath);
+  }
+  // Test pages that we don't care about its distillability.
+  {
+    testing::InSequence dummy;
+    EXPECT_CALL(holder_, OnResult(_, _)).Times(0);
+    NavigateAndWait("about:blank");
+  }
+}
+
+
+using DistillablePageUtilsBrowserTestNone =
+    DistillablePageUtilsBrowserTestOption<kNone>;
+
+IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestNone,
+                       TestDelegate) {
+  EXPECT_CALL(holder_, OnResult(_, _)).Times(0);
+  NavigateAndWait(kSimpleArticlePath);
+}
+
+
+using DistillablePageUtilsBrowserTestOG =
+    DistillablePageUtilsBrowserTestOption<kOGArticle>;
+
+IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestOG,
+                       TestDelegate) {
+  {
+    testing::InSequence dummy;
+    EXPECT_CALL(holder_, OnResult(true, true)).Times(1);
+    NavigateAndWait(kArticlePath);
+  }
+  {
+    testing::InSequence dummy;
+    EXPECT_CALL(holder_, OnResult(false, true)).Times(1);
+    NavigateAndWait(kNonArticlePath);
+  }
+}
+
+
+using DistillablePageUtilsBrowserTestAdaboost =
+    DistillablePageUtilsBrowserTestOption<kAdaBoost>;
+
+IN_PROC_BROWSER_TEST_F(DistillablePageUtilsBrowserTestAdaboost,
+                       TestDelegate) {
+  {
+    testing::InSequence dummy;
+    EXPECT_CALL(holder_, OnResult(true, false)).Times(1);
+    EXPECT_CALL(holder_, OnResult(true, true)).Times(1);
+    NavigateAndWait(kSimpleArticlePath);
+  }
+  {
+    testing::InSequence dummy;
+    EXPECT_CALL(holder_, OnResult(false, false)).Times(1);
+    EXPECT_CALL(holder_, OnResult(false, true)).Times(1);
+    NavigateAndWait(kNonArticlePath);
+  }
+}
+
+}  // namespace dom_distiller
diff --git a/chrome/browser/download/save_page_browsertest.cc b/chrome/browser/download/save_page_browsertest.cc
index 36d155c..c1f44f4 100644
--- a/chrome/browser/download/save_page_browsertest.cc
+++ b/chrome/browser/download/save_page_browsertest.cc
@@ -900,12 +900,15 @@
 
 // Test suite that verifies that the frame tree "looks" the same before
 // and after a save-page-as.
-class SavePageMultiFrameBrowserTest : public SavePageSitePerProcessBrowserTest {
+class SavePageMultiFrameBrowserTest
+    : public SavePageSitePerProcessBrowserTest,
+      public ::testing::WithParamInterface<content::SavePageType> {
  protected:
   void TestMultiFramePage(content::SavePageType save_page_type,
                           const GURL& url,
                           int expected_number_of_frames,
-                          const std::vector<std::string>& expected_substrings) {
+                          const std::vector<std::string>& expected_substrings,
+                          bool skip_verification_of_original_page = false) {
     // Navigate to the test page and verify if test expectations
     // are met (this is mostly a sanity check - a failure to meet
     // expectations would probably mean that there is a test bug
@@ -913,10 +916,10 @@
     ui_test_utils::NavigateToURL(browser(), url);
     DLOG(INFO) << "Verifying test expectations for original page... : "
                << GetCurrentTab(browser())->GetLastCommittedURL();
-    // TODO(lukasza/paulmeyer): crbug.com/457440: Can uncomment
-    // the assertion below once find-in-page works for oop frames.
-    // AssertExpectationsAboutCurrentTab(expected_number_of_frames,
-    //                                   expected_substrings);
+    if (!skip_verification_of_original_page) {
+      AssertExpectationsAboutCurrentTab(expected_number_of_frames,
+                                        expected_substrings);
+    }
 
     // Save the page.
     base::FilePath full_file_name, dir;
@@ -974,40 +977,37 @@
   }
 };
 
-// TODO(lukasza): Pivot on mhtml-vs-complete-html using test params
-// (once all SavePageMultiFrameBrowserTest are enabled).
+// Test coverage for OOPIFs for CompleteHtml (crbug.com/526786) and
+// MHTML (crbug.com/538766) as well as for redirected iframes saved
+// as MHTML (crbug.com/539936).
+IN_PROC_BROWSER_TEST_P(SavePageMultiFrameBrowserTest, CrossSite) {
+  content::SavePageType save_page_type = GetParam();
 
-IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest,
-                       CrossSiteFrames_CompleteHtml) {
   std::vector<std::string> expected_substrings{
       "frames-xsite.htm: 896fd88d-a77a-4f46-afd8-24db7d5af9c2",
       "a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2",
       "b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa",
   };
+
   GURL url(
       embedded_test_server()->GetURL("a.com", "/save_page/frames-xsite.htm"));
-  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, url, 3,
-                     expected_substrings);
+
+  // TODO(lukasza): crbug.com/538766: Enable CrossSite testing of MHTML.
+  if (save_page_type == content::SAVE_PAGE_TYPE_AS_MHTML)
+    return;
+
+  // TODO(lukasza/paulmeyer): crbug.com/457440: Can enable verification
+  // of the original page once find-in-page works for OOP frames.
+  bool skip_verification_of_original_page = true;
+
+  TestMultiFramePage(save_page_type, url, 3, expected_substrings,
+                     skip_verification_of_original_page);
 }
 
-// Test for crbug.com/538766 and crbug.com/539936.
-// Disabled because both bugs are not yet fixed.
-IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest,
-                       DISABLED_CrossSiteFrames_MHTML) {
-  std::vector<std::string> expected_substrings{
-      "frames-xsite.htm: 896fd88d-a77a-4f46-afd8-24db7d5af9c2",
-      "a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2",
-      "b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa",
-  };
-  GURL url(
-      embedded_test_server()->GetURL("a.com", "/save_page/frames-xsite.htm"));
-  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_MHTML, url, 3,
-                     expected_substrings);
-}
+// Test for crbug.com/553478.
+IN_PROC_BROWSER_TEST_P(SavePageMultiFrameBrowserTest, DISABLED_ObjectElements) {
+  content::SavePageType save_page_type = GetParam();
 
-// Test for crbug.com/553478 (complete html part).
-IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest,
-                       DISABLED_ObjectElements_CompleteHtml) {
   // 4 = main frame + iframe + object w/ html doc + object w/ pdf doc
   // (svg and png objects do not get a separate frame)
   int expected_number_of_frames = 4;
@@ -1017,55 +1017,50 @@
       "a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2",
       "b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa",
   };
+
   GURL url(
       embedded_test_server()->GetURL("a.com", "/save_page/frames-objects.htm"));
-  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, url,
-                     expected_number_of_frames, expected_substrings);
+
+  TestMultiFramePage(save_page_type, url, expected_number_of_frames,
+                     expected_substrings);
 }
 
-// Test for crbug.com/553478 (mhtml part).
-// See crbug.com/553478#c3 for some MHTML-specific notes.
-IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest,
-                       DISABLED_ObjectElements_MHTML) {
-  // 4 = main frame + iframe + object w/ html doc + object w/ pdf doc
-  // (svg and png objects do not get a separate frame)
-  int expected_number_of_frames = 4;
+IN_PROC_BROWSER_TEST_P(SavePageMultiFrameBrowserTest, AboutBlank) {
+  content::SavePageType save_page_type = GetParam();
 
   std::vector<std::string> expected_substrings{
-      "frames-objects.htm: 8da13db4-a512-4d9b-b1c5-dc1c134234b9",
-      "a.htm: 1b8aae2b-e164-462f-bd5b-98aa366205f2",
+      "main: acb0609d-eb10-4c26-83e2-ad8afb7b0ff3",
+      "sub1: b124df3a-d39f-47a1-ae04-5bb5d0bf549e",
+      "sub2: 07014068-604d-45ae-884f-a068cfe7bc0a",
+      "sub3: 06cc8fcc-c692-4a1a-a10f-1645b746e8f4",
+  };
+
+  GURL url(embedded_test_server()->GetURL("a.com",
+                                          "/save_page/frames-about-blank.htm"));
+
+  TestMultiFramePage(save_page_type, url, 4, expected_substrings);
+}
+
+// Test for crbug.com/554666.
+IN_PROC_BROWSER_TEST_P(SavePageMultiFrameBrowserTest, NestedFrames) {
+  content::SavePageType save_page_type = GetParam();
+
+  std::vector<std::string> expected_substrings{
+      "frames-nested.htm: 4388232f-8d45-4d2e-9807-721b381be153",
+      "frames-nested2.htm: 6d23dc47-f283-4977-96ec-66bcf72301a4",
       "b.htm: 3a35f7fa-96a9-4487-9f18-4470263907fa",
   };
+
   GURL url(
-      embedded_test_server()->GetURL("a.com", "/save_page/frames-objects.htm"));
-  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_MHTML, url,
-                     expected_number_of_frames, expected_substrings);
+      embedded_test_server()->GetURL("a.com", "/save_page/frames-nested.htm"));
+
+  TestMultiFramePage(save_page_type, url, 3, expected_substrings);
 }
 
-IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest, AboutBlank_CompleteHtml) {
-  std::vector<std::string> expected_substrings{
-      "main: acb0609d-eb10-4c26-83e2-ad8afb7b0ff3",
-      "sub1: b124df3a-d39f-47a1-ae04-5bb5d0bf549e",
-      "sub2: 07014068-604d-45ae-884f-a068cfe7bc0a",
-      "sub3: 06cc8fcc-c692-4a1a-a10f-1645b746e8f4",
-  };
-  GURL url(embedded_test_server()->GetURL("a.com",
-                                          "/save_page/frames-about-blank.htm"));
-  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML, url, 4,
-                     expected_substrings);
-}
-
-IN_PROC_BROWSER_TEST_F(SavePageMultiFrameBrowserTest, AboutBlank_MHTML) {
-  std::vector<std::string> expected_substrings{
-      "main: acb0609d-eb10-4c26-83e2-ad8afb7b0ff3",
-      "sub1: b124df3a-d39f-47a1-ae04-5bb5d0bf549e",
-      "sub2: 07014068-604d-45ae-884f-a068cfe7bc0a",
-      "sub3: 06cc8fcc-c692-4a1a-a10f-1645b746e8f4",
-  };
-  GURL url(embedded_test_server()->GetURL("a.com",
-                                          "/save_page/frames-about-blank.htm"));
-  TestMultiFramePage(content::SAVE_PAGE_TYPE_AS_MHTML, url, 4,
-                     expected_substrings);
-}
+INSTANTIATE_TEST_CASE_P(
+    ,
+    SavePageMultiFrameBrowserTest,
+    ::testing::Values(content::SAVE_PAGE_TYPE_AS_COMPLETE_HTML,
+                      content::SAVE_PAGE_TYPE_AS_MHTML));
 
 }  // namespace
diff --git a/chrome/browser/extensions/all_urls_apitest.cc b/chrome/browser/extensions/all_urls_apitest.cc
index ef01f6a..1989d4e 100644
--- a/chrome/browser/extensions/all_urls_apitest.cc
+++ b/chrome/browser/extensions/all_urls_apitest.cc
@@ -22,23 +22,50 @@
 const std::string kAllUrlsTarget = "/extensions/api_test/all_urls/index.html";
 }
 
-class AllUrlsApiTest : public ExtensionApiTest {
+class AllUrlsApiTest : public ExtensionApiTest,
+                       public ExtensionRegistryObserver {
  protected:
-  AllUrlsApiTest() {}
+  AllUrlsApiTest() : wait_until_reload_(false),
+                     content_script_is_reloaded_(false),
+                     execute_script_is_reloaded_(false) {}
   ~AllUrlsApiTest() override {}
 
   const Extension* content_script() const { return content_script_.get(); }
   const Extension* execute_script() const { return execute_script_.get(); }
 
+  // ExtensionRegistryObserver implementation
+  void OnExtensionLoaded(
+      content::BrowserContext*,
+      const Extension* extension) override {
+    if (!wait_until_reload_)
+      return;
+
+    if (extension->id() == content_script_->id())
+      content_script_is_reloaded_ = true;
+    else if (extension->id() == execute_script_->id())
+      execute_script_is_reloaded_ = true;
+    if (content_script_is_reloaded_ && execute_script_is_reloaded_) {
+      base::MessageLoop::current()->QuitWhenIdle();
+      wait_until_reload_ = false;
+    }
+  }
+
   void WhitelistExtensions() {
+    ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> observer(this);
+    observer.Add(ExtensionRegistry::Get(browser()->profile()));
+
     ExtensionsClient::ScriptingWhitelist whitelist;
     whitelist.push_back(content_script_->id());
     whitelist.push_back(execute_script_->id());
     ExtensionsClient::Get()->SetScriptingWhitelist(whitelist);
     // Extensions will have certain permissions withheld at initialization if
     // they aren't whitelisted, so we need to reload them.
+    content_script_is_reloaded_ = false;
+    execute_script_is_reloaded_ = false;
+    wait_until_reload_ = true;
     extension_service()->ReloadExtension(content_script_->id());
     extension_service()->ReloadExtension(execute_script_->id());
+    base::MessageLoop::current()->Run();
   }
 
  private:
@@ -54,17 +81,14 @@
   scoped_refptr<const Extension> content_script_;
   scoped_refptr<const Extension> execute_script_;
 
+  bool wait_until_reload_;
+  bool content_script_is_reloaded_;
+  bool execute_script_is_reloaded_;
+
   DISALLOW_COPY_AND_ASSIGN(AllUrlsApiTest);
 };
 
-#if (defined(OS_WIN) && !defined(NDEBUG)) || defined(OS_CHROMEOS) || \
-    (defined(OS_MACOSX) && defined(ADDRESS_SANITIZER))
-// http://crbug.com/174341
-#define MAYBE_WhitelistedExtension DISABLED_WhitelistedExtension
-#else
-#define MAYBE_WhitelistedExtension WhitelistedExtension
-#endif
-IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, MAYBE_WhitelistedExtension) {
+IN_PROC_BROWSER_TEST_F(AllUrlsApiTest, WhitelistedExtension) {
 #if defined(OS_WIN) && defined(USE_ASH)
   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -134,18 +158,14 @@
 }
 
 // Disabled because sometimes bystander doesn't load.
-// TODO(devlin): Why?
 IN_PROC_BROWSER_TEST_F(AllUrlsApiTest,
-                       DISABLED_WhitelistedExtensionRunsOnExtensionPages) {
+                       WhitelistedExtensionRunsOnExtensionPages) {
   WhitelistExtensions();
   const Extension* bystander =
       LoadExtension(test_data_dir_.AppendASCII("all_urls")
                                   .AppendASCII("bystander"));
   ASSERT_TRUE(bystander);
 
-  // TODO(devlin): This test should probably go in the WhitelistedExtension test
-  // above, but that one has a bunch of disableds, so it wouldn't be very
-  // useful.
   GURL url(bystander->GetResourceURL("page.html"));
   ExtensionTestMessageListener listenerA(
       "content script: " + url.spec(), false);
diff --git a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
index b7306d0..2616be14e 100644
--- a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
+++ b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
@@ -9,12 +9,12 @@
 #include "base/memory/linked_ptr.h"
 #include "base/thread_task_runner_handle.h"
 #include "chrome/browser/extensions/api/gcd_private/privet_v3_session.h"
-#include "chrome/browser/local_discovery/privet_http.h"
-#include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h"
+#include "chrome/browser/local_discovery/endpoint_resolver.h"
 #include "chrome/browser/local_discovery/service_discovery_shared_client.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_context.h"
+#include "net/url_request/url_request_context_getter.h"
 
 namespace extensions {
 
@@ -86,14 +86,14 @@
 
   void OnServiceResolved(int session_id,
                          const CreateSessionCallback& callback,
-                         scoped_ptr<local_discovery::PrivetHTTPClient> client);
+                         const net::IPEndPoint& endpoint);
 
   scoped_refptr<local_discovery::ServiceDiscoverySharedClient>
       service_discovery_client_;
 
   struct SessionInfo {
     linked_ptr<PrivetV3Session> session;
-    linked_ptr<local_discovery::PrivetHTTPResolution> http_resolution;
+    linked_ptr<local_discovery::EndpointResolver> resolver;
   };
 
   std::map<int, SessionInfo> sessions_;
@@ -130,27 +130,24 @@
     return callback.Run(session_id, gcd_private::STATUS_SESSIONERROR,
                         base::DictionaryValue());
   }
-  scoped_ptr<local_discovery::PrivetHTTPAsynchronousFactory> factory(
-      local_discovery::PrivetHTTPAsynchronousFactory::CreateInstance(
-          browser_context_->GetRequestContext()));
   auto& session_data = sessions_[session_id];
-  session_data.http_resolution.reset(
-      factory->CreatePrivetHTTP(service_name).release());
-  session_data.http_resolution->Start(
-      base::Bind(&GcdPrivateAPIImpl::OnServiceResolved, base::Unretained(this),
-                 session_id, callback));
+  session_data.resolver.reset(new local_discovery::EndpointResolver());
+  session_data.resolver->Start(
+      service_name, base::Bind(&GcdPrivateAPIImpl::OnServiceResolved,
+                               base::Unretained(this), session_id, callback));
 }
 
-void GcdPrivateAPIImpl::OnServiceResolved(
-    int session_id,
-    const CreateSessionCallback& callback,
-    scoped_ptr<local_discovery::PrivetHTTPClient> client) {
-  if (!client) {
+void GcdPrivateAPIImpl::OnServiceResolved(int session_id,
+                                          const CreateSessionCallback& callback,
+                                          const net::IPEndPoint& endpoint) {
+  if (endpoint.address().empty()) {
     return callback.Run(session_id, gcd_private::STATUS_SERVICERESOLUTIONERROR,
                         base::DictionaryValue());
   }
   auto& session_data = sessions_[session_id];
-  session_data.session.reset(new PrivetV3Session(client.Pass()));
+  session_data.session.reset(
+      new PrivetV3Session(browser_context_->GetRequestContext(),
+                          net::HostPortPair::FromIPEndPoint(endpoint)));
   session_data.session->Init(base::Bind(callback, session_id));
 }
 
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_session.cc b/chrome/browser/extensions/api/gcd_private/privet_v3_session.cc
index 0ee8bb189..5564df32 100644
--- a/chrome/browser/extensions/api/gcd_private/privet_v3_session.cc
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_session.cc
@@ -12,6 +12,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "chrome/browser/local_discovery/privet_constants.h"
 #include "chrome/browser/local_discovery/privet_http.h"
+#include "chrome/browser/local_discovery/privet_http_impl.h"
 #include "chrome/browser/local_discovery/privet_url_fetcher.h"
 #include "chrome/common/cloud_print/cloud_print_constants.h"
 #include "crypto/hmac.h"
@@ -198,6 +199,7 @@
                               base::Unretained(this)));
     session_.reset();
   }
+  url_fetcher_.reset();
 }
 
 void PrivetV3Session::FetcherDelegate::OnTimeout() {
@@ -207,8 +209,12 @@
 }
 
 PrivetV3Session::PrivetV3Session(
-    scoped_ptr<local_discovery::PrivetHTTPClient> client)
-    : client_(client.Pass()), weak_ptr_factory_(this) {}
+    const scoped_refptr<net::URLRequestContextGetter>& context_getter,
+    const net::HostPortPair& host_port)
+    : client_(new local_discovery::PrivetHTTPClientImpl("",
+                                                        host_port,
+                                                        context_getter)),
+      weak_ptr_factory_(this) {}
 
 PrivetV3Session::~PrivetV3Session() {
   Cancel();
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_session.h b/chrome/browser/extensions/api/gcd_private/privet_v3_session.h
index 86745fa..eef8871 100644
--- a/chrome/browser/extensions/api/gcd_private/privet_v3_session.h
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_session.h
@@ -49,8 +49,9 @@
                               const base::DictionaryValue& response)>
       MessageCallback;
 
-  explicit PrivetV3Session(
-      scoped_ptr<local_discovery::PrivetHTTPClient> client);
+  PrivetV3Session(
+      const scoped_refptr<net::URLRequestContextGetter>& context_getter,
+      const net::HostPortPair& host_port);
   ~PrivetV3Session();
 
   // Initializes session. Queries /privet/info and returns supported pairing
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_session_unittest.cc b/chrome/browser/extensions/api/gcd_private/privet_v3_session_unittest.cc
index 0411ca0..ba5ec90 100644
--- a/chrome/browser/extensions/api/gcd_private/privet_v3_session_unittest.cc
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_session_unittest.cc
@@ -10,6 +10,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "chrome/browser/local_discovery/privet_http.h"
 #include "chrome/common/chrome_switches.h"
+#include "content/public/test/test_browser_thread_bundle.h"
 #include "content/public/test/test_utils.h"
 #include "crypto/hmac.h"
 #include "crypto/p224_spake.h"
@@ -48,47 +49,13 @@
     "  \"crypto\":[\"p224_spake2\"]"
     "}}";
 
-class MockPrivetHTTPClient : public PrivetHTTPClient {
- public:
-  MockPrivetHTTPClient() {
-    request_context_ = new net::TestURLRequestContextGetter(
-        base::ThreadTaskRunnerHandle::Get());
-  }
-
-  MOCK_METHOD0(GetName, const std::string&());
-  MOCK_METHOD1(
-      CreateInfoOperationPtr,
-      PrivetJSONOperation*(const PrivetJSONOperation::ResultCallback&));
-  MOCK_METHOD2(SwitchToHttps, void(uint16_t, const net::SHA256HashValue&));
-  MOCK_CONST_METHOD0(IsInHttpsMode, bool());
-  MOCK_CONST_METHOD0(GetHost, std::string());
-
-  void RefreshPrivetToken(
-      const PrivetURLFetcher::TokenCallback& callback) override {
-    FAIL();
-  }
-
-  scoped_ptr<PrivetJSONOperation> CreateInfoOperation(
-      const PrivetJSONOperation::ResultCallback& callback) override {
-    return make_scoped_ptr(CreateInfoOperationPtr(callback));
-  }
-
-  scoped_ptr<PrivetURLFetcher> CreateURLFetcher(
-      const GURL& url,
-      net::URLFetcher::RequestType request_type,
-      PrivetURLFetcher::Delegate* delegate) override {
-    return make_scoped_ptr(new PrivetURLFetcher(
-        url, request_type, request_context_.get(), delegate));
-  }
-
-  scoped_refptr<net::TestURLRequestContextGetter> request_context_;
-};
-
 }  // namespace
 
 class PrivetV3SessionTest : public testing::Test {
  public:
-  PrivetV3SessionTest() : fetcher_factory_(nullptr) {}
+  PrivetV3SessionTest()
+      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD),
+        fetcher_factory_(nullptr) {}
 
   void OnInitialized(Result result, const base::DictionaryValue& info) {
     info_.MergeDictionary(&info);
@@ -106,21 +73,21 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnablePrivetV3);
 
-    http_client_ = new StrictMock<MockPrivetHTTPClient>();
-    session_.reset(new PrivetV3Session(make_scoped_ptr(http_client_)));
+    scoped_refptr<net::TestURLRequestContextGetter> context_getter =
+        new net::TestURLRequestContextGetter(
+            content::BrowserThread::GetMessageLoopProxyForThread(
+                content::BrowserThread::IO));
+
+    session_.reset(
+        new PrivetV3Session(context_getter, net::HostPortPair("host", 80)));
 
     session_->on_post_data_ =
         base::Bind(&PrivetV3SessionTest::OnPostData, base::Unretained(this));
-
-    EXPECT_CALL(*http_client_, IsInHttpsMode()).WillRepeatedly(Return(false));
-    EXPECT_CALL(*http_client_, GetHost()).WillRepeatedly(Return("1.1.1.1"));
   }
 
-  base::MessageLoop loop_;
+  content::TestBrowserThreadBundle thread_bundle_;
   net::FakeURLFetcherFactory fetcher_factory_;
-  StrictMock<MockPrivetHTTPClient>* http_client_ = nullptr;
   base::DictionaryValue info_;
-  base::Closure quit_closure_;
   scoped_ptr<PrivetV3Session> session_;
 };
 
@@ -234,14 +201,6 @@
   ASSERT_EQ(sizeof(sha_fingerprint.data), fingerprint.size());
   memcpy(sha_fingerprint.data, fingerprint.data(), fingerprint.size());
 
-  EXPECT_CALL(*http_client_,
-              SwitchToHttps(443, Field(&net::SHA256HashValue::data,
-                                       ElementsAreArray(sha_fingerprint.data))))
-      .WillOnce(InvokeWithoutArgs([this]() {
-        EXPECT_CALL(*http_client_, IsInHttpsMode())
-            .WillRepeatedly(Return(true));
-      }));
-
   EXPECT_CALL(*this, OnCodeConfirmed(Result::STATUS_SUCCESS)).Times(1);
   EXPECT_CALL(*this, OnPostData(_))
       .WillOnce(Invoke(
@@ -291,7 +250,7 @@
         EXPECT_TRUE(hmac.Verify("testId", access_token));
 
         fetcher_factory_.SetFakeResponse(
-            GURL("http://host/privet/v3/auth"),
+            GURL("https://host/privet/v3/auth"),
             "{\"accessToken\":\"567\",\"tokenType\":\"testType\","
             "\"scope\":\"owner\"}",
             net::HTTP_OK, net::URLRequestStatus::SUCCESS);
@@ -315,8 +274,6 @@
       base::Bind(&PrivetV3SessionTest::OnInitialized, base::Unretained(this)));
   base::RunLoop().RunUntilIdle();
 
-  EXPECT_CALL(*http_client_, IsInHttpsMode()).WillRepeatedly(Return(false));
-
   EXPECT_CALL(*this, OnPairingStarted(Result::STATUS_SUCCESS)).Times(1);
   EXPECT_CALL(*this, OnPostData(_))
       .WillOnce(Invoke([this](const base::DictionaryValue& data) {
@@ -342,6 +299,9 @@
         std::string session_id;
         EXPECT_TRUE(data.GetString("sessionId", &session_id));
       }));
+
+  session_.reset();
+  base::RunLoop().RunUntilIdle();
 }
 
 // TODO(vitalybuka): replace PrivetHTTPClient with regular URL fetcher and
diff --git a/chrome/browser/extensions/installed_loader.cc b/chrome/browser/extensions/installed_loader.cc
index 8ee9a02..8e47da4 100644
--- a/chrome/browser/extensions/installed_loader.cc
+++ b/chrome/browser/extensions/installed_loader.cc
@@ -13,7 +13,6 @@
 #include "base/trace_event/trace_event.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/extensions/extension_action_manager.h"
 #include "chrome/browser/extensions/extension_error_reporter.h"
 #include "chrome/browser/extensions/extension_service.h"
 #include "chrome/browser/extensions/extension_util.h"
@@ -333,6 +332,7 @@
   int theme_count = 0;
   int page_action_count = 0;
   int browser_action_count = 0;
+  int no_action_count = 0;
   int disabled_for_permissions_count = 0;
   int non_webstore_ntp_override_count = 0;
   int incognito_allowed_count = 0;
@@ -342,8 +342,6 @@
   int eventless_event_pages_count = 0;
 
   const ExtensionSet& extensions = extension_registry_->enabled_extensions();
-  ExtensionActionManager* extension_action_manager =
-      ExtensionActionManager::Get(profile);
   for (ExtensionSet::const_iterator iter = extensions.begin();
        iter != extensions.end();
        ++iter) {
@@ -497,11 +495,16 @@
         break;
     }
 
-    if (extension_action_manager->GetPageAction(*extension))
+    // We check the manifest key (instead of the ExtensionActionManager) because
+    // we want to know how many extensions have a given type of action as part
+    // of their code, rather than as part of the extension action redesign
+    // (which gives each extension an action).
+    if (extension->manifest()->HasKey(manifest_keys::kPageAction))
       ++page_action_count;
-
-    if (extension_action_manager->GetBrowserAction(*extension))
+    else if (extension->manifest()->HasKey(manifest_keys::kBrowserAction))
       ++browser_action_count;
+    else
+      ++no_action_count;
 
     RecordCreationFlags(extension);
 
@@ -591,6 +594,8 @@
                            page_action_count);
   UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
                            browser_action_count);
+  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadNoExtensionAction",
+                           no_action_count);
   UMA_HISTOGRAM_COUNTS_100("Extensions.DisabledForPermissions",
                            disabled_for_permissions_count);
   UMA_HISTOGRAM_COUNTS_100("Extensions.NonWebStoreNewTabPageOverrides",
diff --git a/chrome/browser/local_discovery/endpoint_resolver.cc b/chrome/browser/local_discovery/endpoint_resolver.cc
new file mode 100644
index 0000000..ad5f7c0
--- /dev/null
+++ b/chrome/browser/local_discovery/endpoint_resolver.cc
@@ -0,0 +1,86 @@
+// Copyright 2015 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 "chrome/browser/local_discovery/endpoint_resolver.h"
+
+#include "base/command_line.h"
+#include "base/debug/dump_without_crashing.h"
+#include "chrome/browser/local_discovery/service_discovery_shared_client.h"
+#include "chrome/common/chrome_switches.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_util.h"
+
+namespace local_discovery {
+
+EndpointResolver::EndpointResolver() {
+  service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance();
+}
+
+EndpointResolver::~EndpointResolver() {}
+
+void EndpointResolver::Start(const std::string& service_name,
+                             const ResultCallback& callback) {
+  service_resolver_ = service_discovery_client_->CreateServiceResolver(
+      service_name, base::Bind(&EndpointResolver::ServiceResolveComplete,
+                               base::Unretained(this), callback));
+  service_resolver_->StartResolving();
+}
+
+void EndpointResolver::ServiceResolveComplete(
+    const ResultCallback& callback,
+    ServiceResolver::RequestStatus result,
+    const ServiceDescription& description) {
+  if (result != ServiceResolver::STATUS_SUCCESS)
+    return callback.Run(net::IPEndPoint());
+
+  Start(description.address, callback);
+}
+
+void EndpointResolver::Start(const net::HostPortPair& address,
+                             const ResultCallback& callback) {
+#if defined(OS_MACOSX)
+  net::IPAddressNumber ip_address;
+  if (!net::ParseIPLiteralToNumber(address.host(), &ip_address)) {
+    NOTREACHED() << address.ToString();
+    // Unexpected, but could be a reason for crbug.com/513505
+    base::debug::DumpWithoutCrashing();
+    return callback.Run(net::IPEndPoint());
+  }
+
+  // OSX already has IP there.
+  callback.Run(net::IPEndPoint(ip_address, address.port()));
+#else   // OS_MACOSX
+  net::AddressFamily address_family = net::ADDRESS_FAMILY_UNSPECIFIED;
+  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kPrivetIPv6Only)) {
+    address_family = net::ADDRESS_FAMILY_IPV6;
+  }
+
+  domain_resolver_ = service_discovery_client_->CreateLocalDomainResolver(
+      address.host(), address_family,
+      base::Bind(&EndpointResolver::DomainResolveComplete,
+                 base::Unretained(this), address.port(), callback));
+  domain_resolver_->Start();
+#endif  // OS_MACOSX
+}
+
+void EndpointResolver::DomainResolveComplete(
+    uint16 port,
+    const ResultCallback& callback,
+    bool success,
+    const net::IPAddressNumber& address_ipv4,
+    const net::IPAddressNumber& address_ipv6) {
+  if (!success)
+    return callback.Run(net::IPEndPoint());
+
+  net::IPAddressNumber address = address_ipv4;
+  if (address.empty())
+    address = address_ipv6;
+
+  DCHECK(!address.empty());
+
+  callback.Run(net::IPEndPoint(address, port));
+}
+
+}  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/endpoint_resolver.h b/chrome/browser/local_discovery/endpoint_resolver.h
new file mode 100644
index 0000000..687c15bb
--- /dev/null
+++ b/chrome/browser/local_discovery/endpoint_resolver.h
@@ -0,0 +1,56 @@
+// Copyright 2015 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.
+
+#ifndef CHROME_BROWSER_LOCAL_DISCOVERY_ENDPOINT_RESOLVER_H_
+#define CHROME_BROWSER_LOCAL_DISCOVERY_ENDPOINT_RESOLVER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/common/local_discovery/service_discovery_client.h"
+
+namespace net {
+class HostPortPair;
+class IPEndPoint;
+}
+
+namespace local_discovery {
+
+class ServiceDiscoverySharedClient;
+
+class EndpointResolver {
+ public:
+  using ResultCallback = base::Callback<void(const net::IPEndPoint& endpoint)>;
+
+  EndpointResolver();
+  ~EndpointResolver();
+
+  void Start(const std::string& service_name, const ResultCallback& callback);
+
+  void Start(const net::HostPortPair& address, const ResultCallback& callback);
+
+ private:
+  void ServiceResolveComplete(const ResultCallback& callback,
+                              ServiceResolver::RequestStatus result,
+                              const ServiceDescription& description);
+
+  void DomainResolveComplete(uint16 port,
+                             const ResultCallback& callback,
+                             bool success,
+                             const net::IPAddressNumber& address_ipv4,
+                             const net::IPAddressNumber& address_ipv6);
+
+ private:
+  scoped_refptr<ServiceDiscoverySharedClient> service_discovery_client_;
+  scoped_ptr<ServiceResolver> service_resolver_;
+  scoped_ptr<LocalDomainResolver> domain_resolver_;
+
+  DISALLOW_COPY_AND_ASSIGN(EndpointResolver);
+};
+
+}  // namespace local_discovery
+
+#endif  // CHROME_BROWSER_LOCAL_DISCOVERY_ENDPOINT_RESOLVER_H_
diff --git a/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.cc b/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.cc
index 8e2b2c6..684b606 100644
--- a/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.cc
+++ b/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.cc
@@ -4,13 +4,8 @@
 
 #include "chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h"
 
-#include "base/bind.h"
-#include "base/command_line.h"
-#include "base/strings/stringprintf.h"
+#include "chrome/browser/local_discovery/endpoint_resolver.h"
 #include "chrome/browser/local_discovery/privet_http_impl.h"
-#include "chrome/browser/local_discovery/service_discovery_shared_client.h"
-#include "chrome/common/chrome_switches.h"
-#include "net/base/net_util.h"
 
 namespace local_discovery {
 
@@ -32,9 +27,9 @@
 PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::ResolutionImpl(
     const std::string& service_name,
     net::URLRequestContextGetter* request_context)
-    : name_(service_name), request_context_(request_context) {
-  service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance();
-}
+    : name_(service_name),
+      request_context_(request_context),
+      endpoint_resolver_(new EndpointResolver()) {}
 
 PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::~ResolutionImpl() {
 }
@@ -46,65 +41,26 @@
 
 void PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::Start(
     const ResultCallback& callback) {
-  service_resolver_ = service_discovery_client_->CreateServiceResolver(
-      name_, base::Bind(&ResolutionImpl::ServiceResolveComplete,
-                        base::Unretained(this), callback));
-  service_resolver_->StartResolving();
-}
-
-void PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::ServiceResolveComplete(
-    const ResultCallback& callback,
-    ServiceResolver::RequestStatus result,
-    const ServiceDescription& description) {
-  if (result != ServiceResolver::STATUS_SUCCESS)
-    return callback.Run(scoped_ptr<PrivetHTTPClient>());
-
-  Start(description.address, callback);
+  endpoint_resolver_->Start(name_,
+                            base::Bind(&ResolutionImpl::ResolveComplete,
+                                       base::Unretained(this), callback));
 }
 
 void PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::Start(
     const net::HostPortPair& address,
     const ResultCallback& callback) {
-#if defined(OS_MACOSX)
-  net::IPAddressNumber ip_address;
-  DCHECK(net::ParseIPLiteralToNumber(address.host(), &ip_address));
-  // MAC already has IP there.
-  callback.Run(scoped_ptr<PrivetHTTPClient>(
-      new PrivetHTTPClientImpl(name_, address, request_context_.get())));
-#else  // OS_MACOSX
-  net::AddressFamily address_family = net::ADDRESS_FAMILY_UNSPECIFIED;
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kPrivetIPv6Only)) {
-    address_family = net::ADDRESS_FAMILY_IPV6;
-  }
-
-  domain_resolver_ = service_discovery_client_->CreateLocalDomainResolver(
-      address.host(), address_family,
-      base::Bind(&ResolutionImpl::DomainResolveComplete, base::Unretained(this),
-                 address.port(), callback));
-  domain_resolver_->Start();
-#endif  // OS_MACOSX
+  endpoint_resolver_->Start(address,
+                            base::Bind(&ResolutionImpl::ResolveComplete,
+                                       base::Unretained(this), callback));
 }
 
-void PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::DomainResolveComplete(
-    uint16 port,
+void PrivetHTTPAsynchronousFactoryImpl::ResolutionImpl::ResolveComplete(
     const ResultCallback& callback,
-    bool success,
-    const net::IPAddressNumber& address_ipv4,
-    const net::IPAddressNumber& address_ipv6) {
-  if (!success) {
-    callback.Run(scoped_ptr<PrivetHTTPClient>());
-    return;
-  }
+    const net::IPEndPoint& endpoint) {
+  if (endpoint.address().empty())
+    return callback.Run(scoped_ptr<PrivetHTTPClient>());
 
-  net::IPAddressNumber address = address_ipv4;
-  if (address.empty())
-    address = address_ipv6;
-
-  DCHECK(!address.empty());
-
-  net::HostPortPair new_address =
-      net::HostPortPair::FromIPEndPoint(net::IPEndPoint(address, port));
+  net::HostPortPair new_address = net::HostPortPair::FromIPEndPoint(endpoint);
   callback.Run(scoped_ptr<PrivetHTTPClient>(
       new PrivetHTTPClientImpl(name_, new_address, request_context_.get())));
 }
diff --git a/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h b/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h
index bc5448f..8681a27f 100644
--- a/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h
+++ b/chrome/browser/local_discovery/privet_http_asynchronous_factory_impl.h
@@ -5,13 +5,13 @@
 #ifndef CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_IMPL_H_
 #define CHROME_BROWSER_LOCAL_DISCOVERY_PRIVET_HTTP_ASYNCHRONOUS_FACTORY_IMPL_H_
 
+#include "base/macros.h"
 #include "chrome/browser/local_discovery/privet_http.h"
 #include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h"
-#include "chrome/common/local_discovery/service_discovery_client.h"
 
 namespace local_discovery {
 
-class ServiceDiscoverySharedClient;
+class EndpointResolver;
 
 class PrivetHTTPAsynchronousFactoryImpl : public PrivetHTTPAsynchronousFactory {
  public:
@@ -37,24 +37,18 @@
     const std::string& GetName() override;
 
    private:
-    void ServiceResolveComplete(const ResultCallback& callback,
-                                ServiceResolver::RequestStatus result,
-                                const ServiceDescription& description);
-
-    void DomainResolveComplete(uint16 port,
-                               const ResultCallback& callback,
-                               bool success,
-                               const net::IPAddressNumber& address_ipv4,
-                               const net::IPAddressNumber& address_ipv6);
-
+    void ResolveComplete(const ResultCallback& callback,
+                         const net::IPEndPoint& endpoint);
     std::string name_;
     scoped_refptr<net::URLRequestContextGetter> request_context_;
-    scoped_refptr<ServiceDiscoverySharedClient> service_discovery_client_;
-    scoped_ptr<ServiceResolver> service_resolver_;
-    scoped_ptr<LocalDomainResolver> domain_resolver_;
+    scoped_ptr<EndpointResolver> endpoint_resolver_;
+
+    DISALLOW_COPY_AND_ASSIGN(ResolutionImpl);
   };
 
   scoped_refptr<net::URLRequestContextGetter> request_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(PrivetHTTPAsynchronousFactoryImpl);
 };
 
 }  // namespace local_discovery
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.cc b/chrome/browser/local_discovery/privet_url_fetcher.cc
index 832bd43..6208e8d7 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher.cc
+++ b/chrome/browser/local_discovery/privet_url_fetcher.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 
 #include "base/bind.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/json/json_reader.h"
 #include "base/location.h"
 #include "base/memory/singleton.h"
@@ -211,6 +212,12 @@
 void PrivetURLFetcher::Start() {
   DCHECK_EQ(tries_, 0);  // We haven't called |Start()| yet.
 
+  if (!url_.is_valid()) {
+    // Not yet clear why it's possible. crbug.com/513505
+    base::debug::DumpWithoutCrashing();
+    return delegate_->OnError(this, UNKNOWN_ERROR);
+  }
+
   if (!send_empty_privet_token_ && !v3_mode_) {
     std::string privet_access_token;
     privet_access_token = GetPrivetAccessToken();
diff --git a/chrome/browser/local_discovery/privet_url_fetcher.h b/chrome/browser/local_discovery/privet_url_fetcher.h
index 20357915..6884633 100644
--- a/chrome/browser/local_discovery/privet_url_fetcher.h
+++ b/chrome/browser/local_discovery/privet_url_fetcher.h
@@ -103,8 +103,12 @@
   void SetUploadFilePath(const std::string& upload_content_type,
                          const base::FilePath& upload_file_path);
 
-  const GURL& url() const { return url_fetcher_->GetOriginalURL(); }
-  int response_code() const { return url_fetcher_->GetResponseCode(); }
+  const GURL& url() const {
+    return url_fetcher_ ? url_fetcher_->GetOriginalURL() : url_;
+  }
+  int response_code() const {
+    return url_fetcher_ ? url_fetcher_->GetResponseCode() : -1;
+  }
 
  private:
   void OnURLFetchCompleteParseData(const net::URLFetcher* source);
@@ -118,7 +122,7 @@
   void RequestTokenRefresh();
   void RefreshToken(const std::string& token);
 
-  GURL url_;
+  const GURL url_;
   net::URLFetcher::RequestType request_type_;
   scoped_refptr<net::URLRequestContextGetter> context_getter_;
   Delegate* delegate_;
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac.mm b/chrome/browser/local_discovery/service_discovery_client_mac.mm
index 4a09e3e..3c5fbd84 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac.mm
+++ b/chrome/browser/local_discovery/service_discovery_client_mac.mm
@@ -8,12 +8,14 @@
 #import <Foundation/Foundation.h>
 #import <net/if_dl.h>
 
+#include "base/debug/dump_without_crashing.h"
 #include "base/memory/singleton.h"
 #include "base/metrics/histogram.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/threading/thread.h"
 #include "net/base/ip_address_number.h"
+#include "net/base/ip_endpoint.h"
 
 using local_discovery::ServiceWatcherImplMac;
 using local_discovery::ServiceResolverImplMac;
@@ -334,33 +336,42 @@
 
 void ServiceResolverImplMac::NetServiceContainer::OnResolveUpdate(
     RequestStatus status) {
-  if (status == STATUS_SUCCESS) {
-    service_description_.service_name = service_name_;
-
-    for (NSData* address in [service_ addresses]) {
-      const void* bytes = [address bytes];
-      // TODO(justinlin): Handle IPv6 addresses?
-      if (static_cast<const sockaddr*>(bytes)->sa_family == AF_INET) {
-        const sockaddr_in* sock = static_cast<const sockaddr_in*>(bytes);
-        char addr[INET_ADDRSTRLEN];
-        inet_ntop(AF_INET, &sock->sin_addr, addr, INET_ADDRSTRLEN);
-        service_description_.address =
-            net::HostPortPair(addr, ntohs(sock->sin_port));
-        net::ParseIPLiteralToNumber(addr, &service_description_.ip_address);
-        break;
-      }
-    }
-
-    ParseTxtRecord([service_ TXTRecordData], &service_description_.metadata);
-
-    // TODO(justinlin): Implement last_seen.
-    service_description_.last_seen = base::Time::Now();
-    callback_runner_->PostTask(
-        FROM_HERE, base::Bind(callback_, status, service_description_));
-  } else {
+  if (status != STATUS_SUCCESS) {
     callback_runner_->PostTask(
         FROM_HERE, base::Bind(callback_, status, ServiceDescription()));
+    return;
   }
+
+  service_description_.service_name = service_name_;
+
+  for (NSData* address in [service_ addresses]) {
+    const void* bytes = [address bytes];
+    int length = [address length];
+    const sockaddr* socket = static_cast<const sockaddr*>(bytes);
+    net::IPEndPoint end_point;
+    if (end_point.FromSockAddr(socket, length)) {
+      service_description_.address =
+          net::HostPortPair::FromIPEndPoint(end_point);
+      break;
+    }
+  }
+
+  if (service_description_.address.host().empty()) {
+    NOTREACHED() << service_name_;
+    // Unexpected, but could be a reason for crbug.com/513505
+    base::debug::DumpWithoutCrashing();
+    callback_runner_->PostTask(
+        FROM_HERE,
+        base::Bind(callback_, STATUS_KNOWN_NONEXISTENT, ServiceDescription()));
+    return;
+  }
+
+  ParseTxtRecord([service_ TXTRecordData], &service_description_.metadata);
+
+  // TODO(justinlin): Implement last_seen.
+  service_description_.last_seen = base::Time::Now();
+  callback_runner_->PostTask(
+      FROM_HERE, base::Bind(callback_, status, service_description_));
 }
 
 void ServiceResolverImplMac::NetServiceContainer::SetServiceForTesting(
diff --git a/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm b/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
index 09c0451..dc0f20f 100644
--- a/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
+++ b/chrome/browser/local_discovery/service_discovery_client_mac_unittest.mm
@@ -11,29 +11,37 @@
 #include "chrome/browser/local_discovery/service_discovery_client_mac.h"
 #include "chrome/common/local_discovery/service_discovery_client.h"
 #include "content/public/test/test_browser_thread_bundle.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_util.h"
 #include "testing/gtest_mac.h"
 
 @interface TestNSNetService : NSNetService {
  @private
   NSData* data_;
+  NSArray* addresses_;
 }
-- (id) initWithData:(NSData *)data;
+- (id)initWithData:(NSData*)data;
+- (void)setAddresses:(NSArray*)addresses;
 @end
 
 @implementation TestNSNetService
 
--(id) initWithData:(NSData *)data {
+- (id)initWithData:(NSData*)data {
   if ((self = [super init])) {
     data_ = data;
   }
   return self;
 }
 
-- (NSArray *)addresses {
-  return [NSMutableArray array];
+- (void)setAddresses:(NSArray*)addresses {
+  addresses_ = addresses;
 }
 
-- (NSData *)TXTRecordData {
+- (NSArray*)addresses {
+  return addresses_;
+}
+
+- (NSData*)TXTRecordData {
   return data_;
 }
 
@@ -111,10 +119,21 @@
                  base::Unretained(this)));
 
   const uint8 record_bytes[] = { 2, 'a', 'b', 3, 'd', '=', 'e' };
-  base::scoped_nsobject<NSNetService> test_service(
-      [[TestNSNetService alloc] initWithData:
-          [[NSData alloc] initWithBytes:record_bytes
-                          length:arraysize(record_bytes)]]);
+  base::scoped_nsobject<TestNSNetService> test_service([[TestNSNetService alloc]
+      initWithData:[[NSData alloc] initWithBytes:record_bytes
+                                          length:arraysize(record_bytes)]]);
+
+  const std::string kIp = "2001:4860:4860::8844";
+  const uint16_t kPort = 4321;
+  net::IPAddressNumber ip_address;
+  ASSERT_TRUE(net::ParseIPLiteralToNumber(kIp, &ip_address));
+  net::IPEndPoint endpoint(ip_address, kPort);
+  net::SockaddrStorage storage;
+  ASSERT_TRUE(endpoint.ToSockAddr(storage.addr, &storage.addr_len));
+  NSData* discoveryHost =
+      [NSData dataWithBytes:storage.addr length:storage.addr_len];
+  NSArray* addresses = @[ discoveryHost ];
+  [test_service setAddresses:addresses];
 
   ServiceResolverImplMac* resolver_impl =
       static_cast<ServiceResolverImplMac*>(resolver.get());
@@ -128,6 +147,8 @@
 
   EXPECT_EQ(1, num_resolves_);
   EXPECT_EQ(2u, last_service_description_.metadata.size());
+  EXPECT_EQ(kIp, last_service_description_.address.host());
+  EXPECT_EQ(kPort, last_service_description_.address.port());
 }
 
 }  // namespace local_discovery
diff --git a/chrome/browser/media/android/router/media_router_android.cc b/chrome/browser/media/android/router/media_router_android.cc
index 02fcfb78..4b6e870 100644
--- a/chrome/browser/media/android/router/media_router_android.cc
+++ b/chrome/browser/media/android/router/media_router_android.cc
@@ -209,7 +209,7 @@
       env, java_media_router_.obj(), jroute_id.obj());
 }
 
-bool MediaRouterAndroid::HasLocalRoute() const {
+bool MediaRouterAndroid::HasLocalDisplayRoute() const {
   NOTIMPLEMENTED();
   return false;
 }
diff --git a/chrome/browser/media/android/router/media_router_android.h b/chrome/browser/media/android/router/media_router_android.h
index 610a22b..5bea573 100644
--- a/chrome/browser/media/android/router/media_router_android.h
+++ b/chrome/browser/media/android/router/media_router_android.h
@@ -51,7 +51,7 @@
   void AddIssue(const Issue& issue) override;
   void ClearIssue(const Issue::Id& issue_id) override;
   void OnPresentationSessionDetached(const MediaRoute::Id& route_id) override;
-  bool HasLocalRoute() const override;
+  bool HasLocalDisplayRoute() const override;
 
   // The methods called by the Java counterpart.
 
diff --git a/chrome/browser/media/router/local_media_routes_observer.h b/chrome/browser/media/router/local_media_routes_observer.h
index 3598ae66..0875413 100644
--- a/chrome/browser/media/router/local_media_routes_observer.h
+++ b/chrome/browser/media/router/local_media_routes_observer.h
@@ -11,15 +11,15 @@
 
 class MediaRouter;
 
-// Base class for observing whether local routes exist in the Media Router.
+// Base class for observing whether local displayable routes exist in the Media
+// Router.
 class LocalMediaRoutesObserver {
  public:
   explicit LocalMediaRoutesObserver(MediaRouter* router);
   virtual ~LocalMediaRoutesObserver();
 
-  // Called when a local route has been successfully created or if there has
-  // been an update to the list of routes.
-  virtual void OnHasLocalRouteUpdated(bool has_local_route) {}
+  // Called when |router_| now has, or no longer have, local display routes.
+  virtual void OnHasLocalDisplayRouteUpdated(bool has_local_route) {}
 
  private:
   MediaRouter* const router_;
diff --git a/chrome/browser/media/router/media_router.h b/chrome/browser/media/router/media_router.h
index 5836a9c3..ed6cf1e8 100644
--- a/chrome/browser/media/router/media_router.h
+++ b/chrome/browser/media/router/media_router.h
@@ -118,8 +118,9 @@
   virtual void OnPresentationSessionDetached(
       const MediaRoute::Id& route_id) = 0;
 
-  // Returns whether or not there is currently an active local route.
-  virtual bool HasLocalRoute() const = 0;
+  // Returns whether or not there is currently an active local displayable
+  // route.
+  virtual bool HasLocalDisplayRoute() const = 0;
 
  private:
   friend class IssuesObserver;
diff --git a/chrome/browser/media/router/media_router_mojo_impl.cc b/chrome/browser/media/router/media_router_mojo_impl.cc
index e7bc9d3..2e427c3 100644
--- a/chrome/browser/media/router/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/media_router_mojo_impl.cc
@@ -80,23 +80,23 @@
 
 void MediaRouterMojoImpl::MediaRouterMediaRoutesObserver::OnRoutesUpdated(
     const std::vector<media_router::MediaRoute>& routes) {
-  bool has_local_route =
+  bool has_local_display_route =
       std::find_if(routes.begin(), routes.end(),
                    [](const media_router::MediaRoute& route) {
-                      return route.is_local(); }) !=
-      routes.end();
+                     return route.is_local() && route.for_display();
+                   }) != routes.end();
 
-  // |this| will be deleted in UpdateHasLocalRoute() if |has_local_route| is
-  // false. Note that ObserverList supports removing an observer while
-  // iterating through it.
-  router_->UpdateHasLocalRoute(has_local_route);
+  // |this| will be deleted in UpdateHasLocalDisplayRoute() if
+  // |has_local_display_route| is false. Note that ObserverList supports
+  // removing an observer while iterating through it.
+  router_->UpdateHasLocalDisplayRoute(has_local_display_route);
 }
 
 MediaRouterMojoImpl::MediaRouterMojoImpl(
     extensions::EventPageTracker* event_page_tracker)
     : event_page_tracker_(event_page_tracker),
       instance_id_(base::GenerateGUID()),
-      has_local_route_(false),
+      has_local_display_route_(false),
       availability_(interfaces::MediaRouter::SINK_AVAILABILITY_UNAVAILABLE),
       wakeup_attempt_count_(0),
       weak_factory_(this) {
@@ -240,27 +240,30 @@
     route = media_route.To<scoped_ptr<MediaRoute>>();
     actual_presentation_id = presentation_id;
 
-    UpdateHasLocalRoute(true);
+    if (route->is_local() && route->for_display()) {
+      UpdateHasLocalDisplayRoute(true);
 
-    if (!routes_observer_)
-      routes_observer_.reset(new MediaRouterMediaRoutesObserver(this));
+      if (!routes_observer_)
+        routes_observer_.reset(new MediaRouterMediaRoutesObserver(this));
+    }
   }
 
   for (const MediaRouteResponseCallback& callback : callbacks)
     callback.Run(route.get(), actual_presentation_id, error);
 }
 
-void MediaRouterMojoImpl::UpdateHasLocalRoute(bool has_local_route) {
-  if (has_local_route_ == has_local_route)
+void MediaRouterMojoImpl::UpdateHasLocalDisplayRoute(
+    bool has_local_display_route) {
+  if (has_local_display_route_ == has_local_display_route)
     return;
 
-  has_local_route_ = has_local_route;
+  has_local_display_route_ = has_local_display_route;
 
-  if (!has_local_route_)
+  if (!has_local_display_route_)
     routes_observer_.reset();
 
   FOR_EACH_OBSERVER(LocalMediaRoutesObserver, local_routes_observers_,
-                    OnHasLocalRouteUpdated(has_local_route_));
+                    OnHasLocalDisplayRouteUpdated(has_local_display_route_));
 }
 
 void MediaRouterMojoImpl::CreateRoute(
@@ -375,7 +378,10 @@
   if (availability_ != interfaces::MediaRouter::SINK_AVAILABILITY_UNAVAILABLE) {
     RunOrDefer(base::Bind(&MediaRouterMojoImpl::DoStartObservingMediaSinks,
                           base::Unretained(this), source_id));
+  } else {
+    observer->OnSinksReceived(std::vector<MediaSink>());
   }
+
   return true;
 }
 
@@ -704,8 +710,8 @@
   media_route_provider_->OnPresentationSessionDetached(route_id);
 }
 
-bool MediaRouterMojoImpl::HasLocalRoute() const {
-  return has_local_route_;
+bool MediaRouterMojoImpl::HasLocalDisplayRoute() const {
+  return has_local_display_route_;
 }
 
 void MediaRouterMojoImpl::DoStartObservingMediaSinks(
diff --git a/chrome/browser/media/router/media_router_mojo_impl.h b/chrome/browser/media/router/media_router_mojo_impl.h
index 3e958f1..7f129a7 100644
--- a/chrome/browser/media/router/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/media_router_mojo_impl.h
@@ -85,7 +85,7 @@
   void AddIssue(const Issue& issue) override;
   void ClearIssue(const Issue::Id& issue_id) override;
   void OnPresentationSessionDetached(const MediaRoute::Id& route_id) override;
-  bool HasLocalRoute() const override;
+  bool HasLocalDisplayRoute() const override;
 
   const std::string& media_route_provider_extension_id() const {
     return media_route_provider_extension_id_;
@@ -109,6 +109,7 @@
   FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest,
                            RegisterAndUnregisterMediaRoutesObserver);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, HandleIssue);
+  FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoImplTest, HasLocalRoute);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoExtensionTest,
                            DeferredBindingAndSuspension);
   FRIEND_TEST_ALL_PREFIXES(MediaRouterMojoExtensionTest,
@@ -265,7 +266,7 @@
     interfaces::MediaRoutePtr media_route,
     const mojo::String& error_text);
 
-  void UpdateHasLocalRoute(bool has_local_route);
+  void UpdateHasLocalDisplayRoute(bool has_local_display_route);
 
   // Callback invoked by |event_page_tracker_| after an attempt to wake the
   // component extension. If |success| is false, the pending request queue is
@@ -338,8 +339,8 @@
   // therefore stale.
   std::string instance_id_;
 
-  // Set to true if there are routes started on this instance.
-  bool has_local_route_;
+  // Set to true if there are displayable routes started on this instance.
+  bool has_local_display_route_;
 
   // Observes local routes in order to notify LocalMediaRoutesObservers when
   // there are no more local routes.
diff --git a/chrome/browser/media/router/media_router_mojo_impl_unittest.cc b/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
index bb7b38f..e07f8801 100644
--- a/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
+++ b/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
@@ -31,6 +31,7 @@
 using testing::_;
 using testing::Eq;
 using testing::Invoke;
+using testing::IsEmpty;
 using testing::Mock;
 using testing::Not;
 using testing::Pointee;
@@ -174,6 +175,8 @@
   route->media_sink_id = kSinkId;
   route->media_route_id = kRouteId;
   route->description = kDescription;
+  route->is_local = true;
+  route->for_display = true;
 
   // Use a lambda function as an invocation target here to work around
   // a limitation with GMock::Invoke that prevents it from using move-only types
@@ -188,6 +191,9 @@
           const interfaces::MediaRouteProvider::CreateRouteCallback& cb) {
         cb.Run(route.Pass(), mojo::String());
       }));
+
+  // MediaRouterMojoImpl will start observing local displayable routes as a
+  // result of having one created.
   EXPECT_CALL(mock_media_route_provider_, StartObservingMediaRoutes());
 
   RouteResponseCallbackHandler handler;
@@ -230,6 +236,8 @@
   route->media_sink_id = kSinkId;
   route->media_route_id = kRouteId;
   route->description = kDescription;
+  route->is_local = true;
+  route->for_display = true;
 
   // Use a lambda function as an invocation target here to work around
   // a limitation with GMock::Invoke that prevents it from using move-only types
@@ -243,6 +251,9 @@
           const interfaces::MediaRouteProvider::JoinRouteCallback& cb) {
         cb.Run(route.Pass(), mojo::String());
       }));
+
+  // MediaRouterMojoImpl will start observing local displayable routes as a
+  // result of having one created.
   EXPECT_CALL(mock_media_route_provider_, StartObservingMediaRoutes());
 
   RouteResponseCallbackHandler handler;
@@ -337,28 +348,21 @@
       interfaces::MediaRouter::SINK_AVAILABILITY_AVAILABLE);
   MediaSource media_source(kSource);
 
-  MockMediaRouter mock_router;
   EXPECT_CALL(mock_media_route_provider_,
               StartObservingMediaSinks(mojo::String(kSource)))
       .Times(2);
   EXPECT_CALL(mock_media_route_provider_,
               StartObservingMediaSinks(mojo::String(kSource2)));
 
-  MediaSinksObserver* captured_observer;
-  EXPECT_CALL(mock_router, RegisterMediaSinksObserver(_))
-      .Times(3)
-      .WillRepeatedly(DoAll(SaveArg<0>(&captured_observer), Return(true)));
-
-  MockMediaSinksObserver sinks_observer(&mock_router, media_source);
-  EXPECT_EQ(&sinks_observer, captured_observer);
-  router()->RegisterMediaSinksObserver(&sinks_observer);
-  MockMediaSinksObserver extra_sinks_observer(&mock_router, media_source);
-  EXPECT_EQ(&extra_sinks_observer, captured_observer);
-  router()->RegisterMediaSinksObserver(&extra_sinks_observer);
-  MockMediaSinksObserver unrelated_sinks_observer(&mock_router,
+  MockMediaSinksObserver sinks_observer(router(), media_source);
+  EXPECT_TRUE(sinks_observer.Init());
+  MockMediaSinksObserver extra_sinks_observer(router(), media_source);
+  EXPECT_TRUE(extra_sinks_observer.Init());
+  MockMediaSinksObserver unrelated_sinks_observer(router(),
                                                   MediaSource(kSource2));
-  EXPECT_EQ(&unrelated_sinks_observer, captured_observer);
-  router()->RegisterMediaSinksObserver(&unrelated_sinks_observer);
+  EXPECT_TRUE(unrelated_sinks_observer.Init());
+
+  ProcessEventLoop();
 
   std::vector<MediaSink> expected_sinks;
   expected_sinks.push_back(
@@ -384,10 +388,6 @@
   media_router_proxy_->OnSinksReceived(media_source.id(), mojo_sinks.Pass());
   ProcessEventLoop();
 
-  EXPECT_CALL(mock_router, UnregisterMediaSinksObserver(&sinks_observer));
-  EXPECT_CALL(mock_router, UnregisterMediaSinksObserver(&extra_sinks_observer));
-  EXPECT_CALL(mock_router,
-              UnregisterMediaSinksObserver(&unrelated_sinks_observer));
   EXPECT_CALL(mock_media_route_provider_,
               StopObservingMediaSinks(mojo::String(kSource)));
   EXPECT_CALL(mock_media_route_provider_,
@@ -405,9 +405,13 @@
   MediaSource media_source(kSource);
   scoped_ptr<MockMediaSinksObserver> sinks_observer(
       new MockMediaSinksObserver(router(), media_source));
+  EXPECT_CALL(*sinks_observer, OnSinksReceived(IsEmpty()));
+  EXPECT_TRUE(sinks_observer->Init());
   MediaSource media_source2(kSource2);
   scoped_ptr<MockMediaSinksObserver> sinks_observer2(
       new MockMediaSinksObserver(router(), media_source2));
+  EXPECT_CALL(*sinks_observer2, OnSinksReceived(IsEmpty()));
+  EXPECT_TRUE(sinks_observer2->Init());
   EXPECT_CALL(mock_media_route_provider_,
               StartObservingMediaSinks(mojo::String(kSource)))
       .Times(0);
@@ -456,11 +460,15 @@
   router()->OnSinkAvailabilityUpdated(
       interfaces::MediaRouter::SINK_AVAILABILITY_UNAVAILABLE);
   MediaSource media_source(kSource);
-  scoped_ptr<MediaSinksObserver> sinks_observer =
-      make_scoped_ptr(new MockMediaSinksObserver(router(), media_source));
+  scoped_ptr<MockMediaSinksObserver> sinks_observer(
+      new MockMediaSinksObserver(router(), media_source));
+  EXPECT_CALL(*sinks_observer, OnSinksReceived(IsEmpty()));
+  EXPECT_TRUE(sinks_observer->Init());
   MediaSource media_source2(kSource2);
-  scoped_ptr<MediaSinksObserver> sinks_observer2 =
-      make_scoped_ptr(new MockMediaSinksObserver(router(), media_source2));
+  scoped_ptr<MockMediaSinksObserver> sinks_observer2(
+      new MockMediaSinksObserver(router(), media_source2));
+  EXPECT_CALL(*sinks_observer2, OnSinksReceived(IsEmpty()));
+  EXPECT_TRUE(sinks_observer2->Init());
   EXPECT_CALL(mock_media_route_provider_,
               StartObservingMediaSinks(mojo::String(kSource)))
       .Times(0);
@@ -755,6 +763,49 @@
   ProcessEventLoop();
 }
 
+TEST_F(MediaRouterMojoImplTest, HasLocalRoute) {
+  EXPECT_FALSE(router()->HasLocalDisplayRoute());
+  interfaces::MediaRoutePtr mojo_route1 = interfaces::MediaRoute::New();
+  mojo_route1->media_route_id = "routeId1";
+  mojo_route1->media_sink_id = "sinkId";
+  mojo_route1->is_local = false;
+  mojo_route1->for_display = false;
+  router()->RouteResponseReceived("presentationId1",
+                                  std::vector<MediaRouteResponseCallback>(),
+                                  mojo_route1.Pass(), "");
+  EXPECT_FALSE(router()->HasLocalDisplayRoute());
+
+  interfaces::MediaRoutePtr mojo_route2 = interfaces::MediaRoute::New();
+  mojo_route2->media_route_id = "routeId2";
+  mojo_route2->media_sink_id = "sinkId";
+  mojo_route2->is_local = false;
+  mojo_route2->for_display = true;
+  router()->RouteResponseReceived("presentationId2",
+                                  std::vector<MediaRouteResponseCallback>(),
+                                  mojo_route2.Pass(), "");
+  EXPECT_FALSE(router()->HasLocalDisplayRoute());
+
+  interfaces::MediaRoutePtr mojo_route3 = interfaces::MediaRoute::New();
+  mojo_route3->media_route_id = "routeId3";
+  mojo_route3->media_sink_id = "sinkId";
+  mojo_route3->is_local = true;
+  mojo_route3->for_display = false;
+  router()->RouteResponseReceived("presentationId3",
+                                  std::vector<MediaRouteResponseCallback>(),
+                                  mojo_route3.Pass(), "");
+  EXPECT_FALSE(router()->HasLocalDisplayRoute());
+
+  interfaces::MediaRoutePtr mojo_route4 = interfaces::MediaRoute::New();
+  mojo_route4->media_route_id = "routeId4";
+  mojo_route4->media_sink_id = "sinkId";
+  mojo_route4->is_local = true;
+  mojo_route4->for_display = true;
+  router()->RouteResponseReceived("presentationId4",
+                                  std::vector<MediaRouteResponseCallback>(),
+                                  mojo_route4.Pass(), "");
+  EXPECT_TRUE(router()->HasLocalDisplayRoute());
+}
+
 TEST_F(MediaRouterMojoImplTest, QueuedWhileAsleep) {
   EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id()))
       .Times(2)
diff --git a/chrome/browser/media/router/media_sinks_observer.cc b/chrome/browser/media/router/media_sinks_observer.cc
index ea57e38..1eecabcd 100644
--- a/chrome/browser/media/router/media_sinks_observer.cc
+++ b/chrome/browser/media/router/media_sinks_observer.cc
@@ -11,13 +11,21 @@
 
 MediaSinksObserver::MediaSinksObserver(MediaRouter* router,
                                        const MediaSource& source)
-    : source_(source), router_(router) {
+    : source_(source), router_(router), initialized_(false) {
   DCHECK(router_);
-  is_active_ = router_->RegisterMediaSinksObserver(this);
 }
 
 MediaSinksObserver::~MediaSinksObserver() {
-  router_->UnregisterMediaSinksObserver(this);
+  if (initialized_)
+    router_->UnregisterMediaSinksObserver(this);
+}
+
+bool MediaSinksObserver::Init() {
+  if (initialized_)
+    return true;
+
+  initialized_ = router_->RegisterMediaSinksObserver(this);
+  return initialized_;
 }
 
 }  // namespace media_router
diff --git a/chrome/browser/media/router/media_sinks_observer.h b/chrome/browser/media/router/media_sinks_observer.h
index 95c137c..192bede 100644
--- a/chrome/browser/media/router/media_sinks_observer.h
+++ b/chrome/browser/media/router/media_sinks_observer.h
@@ -26,6 +26,11 @@
   MediaSinksObserver(MediaRouter* router, const MediaSource& source);
   virtual ~MediaSinksObserver();
 
+  // Registers with MediaRouter to start observing. Must be called before the
+  // observer will start receiving updates. Returns |true| if the observer is
+  // initialized. This method is no-op if the observer is already initialized.
+  bool Init();
+
   // This function is invoked when the list of sinks compatible
   // with |source_| has been updated.
   // Implementations may not perform operations that modify the Media Router's
@@ -35,12 +40,10 @@
 
   const MediaSource& source() const { return source_; }
 
-  bool is_active() const { return is_active_; }
-
  private:
   const MediaSource source_;
   MediaRouter* router_;
-  bool is_active_;
+  bool initialized_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaSinksObserver);
 };
diff --git a/chrome/browser/media/router/mock_media_router.h b/chrome/browser/media/router/mock_media_router.h
index 01fa7b5..10ac636f9 100644
--- a/chrome/browser/media/router/mock_media_router.h
+++ b/chrome/browser/media/router/mock_media_router.h
@@ -54,7 +54,7 @@
   MOCK_METHOD1(ClearIssue, void(const Issue::Id& issue_id));
   MOCK_METHOD1(OnPresentationSessionDetached,
                void(const MediaRoute::Id& route_id));
-  MOCK_CONST_METHOD0(HasLocalRoute, bool());
+  MOCK_CONST_METHOD0(HasLocalDisplayRoute, bool());
   MOCK_METHOD1(RegisterIssuesObserver, void(IssuesObserver* observer));
   MOCK_METHOD1(UnregisterIssuesObserver, void(IssuesObserver* observer));
   MOCK_METHOD1(RegisterMediaSinksObserver, bool(MediaSinksObserver* observer));
diff --git a/chrome/browser/media/router/presentation_media_sinks_observer_unittest.cc b/chrome/browser/media/router/presentation_media_sinks_observer_unittest.cc
index 164d8c7f..bbfa13b 100644
--- a/chrome/browser/media/router/presentation_media_sinks_observer_unittest.cc
+++ b/chrome/browser/media/router/presentation_media_sinks_observer_unittest.cc
@@ -25,10 +25,11 @@
   ~PresentationMediaSinksObserverTest() override {}
 
   void SetUp() override {
-    EXPECT_CALL(router_, RegisterMediaSinksObserver(_)).Times(1);
+    EXPECT_CALL(router_, RegisterMediaSinksObserver(_)).WillOnce(Return(true));
     observer_.reset(new PresentationMediaSinksObserver(
         &router_, &listener_,
         MediaSourceForPresentationUrl("http://example.com/presentation.html")));
+    EXPECT_TRUE(observer_->Init());
   }
 
   void TearDown() override {
diff --git a/chrome/browser/media/router/presentation_service_delegate_impl.cc b/chrome/browser/media/router/presentation_service_delegate_impl.cc
index d2228e53..bc145d2 100644
--- a/chrome/browser/media/router/presentation_service_delegate_impl.cc
+++ b/chrome/browser/media/router/presentation_service_delegate_impl.cc
@@ -171,7 +171,7 @@
   sinks_observer_.reset(
       new PresentationMediaSinksObserver(router_, listener, source));
 
-  if (!sinks_observer_->is_active()) {
+  if (!sinks_observer_->Init()) {
     sinks_observer_.reset();
     listener->OnScreenAvailabilityNotSupported();
     return false;
diff --git a/chrome/browser/notifications/message_center_notification_manager.cc b/chrome/browser/notifications/message_center_notification_manager.cc
index eb19cd6..9ac4fc3 100644
--- a/chrome/browser/notifications/message_center_notification_manager.cc
+++ b/chrome/browser/notifications/message_center_notification_manager.cc
@@ -53,12 +53,14 @@
   message_center_->SetNotifierSettingsProvider(settings_provider_.get());
 
 #if defined(OS_CHROMEOS)
-  blockers_.push_back(
-      new LoginStateNotificationBlockerChromeOS(message_center));
+  blockers_.push_back(make_scoped_ptr(
+      new LoginStateNotificationBlockerChromeOS(message_center)));
 #else
-  blockers_.push_back(new ScreenLockNotificationBlocker(message_center));
+  blockers_.push_back(make_scoped_ptr(
+      new ScreenLockNotificationBlocker(message_center)));
 #endif
-  blockers_.push_back(new FullscreenNotificationBlocker(message_center));
+  blockers_.push_back(make_scoped_ptr(
+      new FullscreenNotificationBlocker(message_center)));
 
 #if defined(OS_WIN) || defined(OS_MACOSX) \
   || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
diff --git a/chrome/browser/notifications/message_center_notification_manager.h b/chrome/browser/notifications/message_center_notification_manager.h
index 9951465..c3a1cac 100644
--- a/chrome/browser/notifications/message_center_notification_manager.h
+++ b/chrome/browser/notifications/message_center_notification_manager.h
@@ -7,10 +7,10 @@
 
 #include <map>
 #include <string>
+#include <vector>
 
 #include "base/gtest_prod_util.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
@@ -110,7 +110,7 @@
   scoped_ptr<message_center::NotifierSettingsProvider> settings_provider_;
 
   // To own the blockers.
-  ScopedVector<message_center::NotificationBlocker> blockers_;
+  std::vector<scoped_ptr<message_center::NotificationBlocker>> blockers_;
 
   NotificationSystemObserver system_observer_;
 
diff --git a/chrome/browser/notifications/message_center_settings_controller.cc b/chrome/browser/notifications/message_center_settings_controller.cc
index 43d5665..da7fe54 100644
--- a/chrome/browser/notifications/message_center_settings_controller.cc
+++ b/chrome/browser/notifications/message_center_settings_controller.cc
@@ -484,13 +484,16 @@
   Profile* profile =
       chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
   DCHECK(profile);
-  notifier_groups_.push_back(
+
+  scoped_ptr<message_center::ProfileNotifierGroup> group(
       new message_center::ProfileNotifierGroup(gfx::Image(user->GetImage()),
                                                user->GetDisplayName(),
                                                user->GetDisplayName(),
                                                0,
                                                profile));
 
+  notifier_groups_.push_back(group.Pass());
+
   FOR_EACH_OBSERVER(message_center::NotifierSettingsObserver,
                     observers_,
                     NotifierGroupChanged());
@@ -531,7 +534,8 @@
     if (chromeos::ProfileHelper::IsSigninProfile(group->profile()))
       continue;
 #endif
-    notifier_groups_.push_back(group.release());
+
+    notifier_groups_.push_back(group.Pass());
   }
 
 #if defined(OS_CHROMEOS)
diff --git a/chrome/browser/notifications/message_center_settings_controller.h b/chrome/browser/notifications/message_center_settings_controller.h
index 6d81bbf..5ada1a3 100644
--- a/chrome/browser/notifications/message_center_settings_controller.h
+++ b/chrome/browser/notifications/message_center_settings_controller.h
@@ -10,7 +10,6 @@
 
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
 #include "chrome/browser/extensions/app_icon_loader.h"
@@ -127,7 +126,9 @@
 
   // The list of all configurable notifier groups. This is each profile that is
   // loaded (and in the ProfileInfoCache - so no incognito profiles go here).
-  ScopedVector<message_center::ProfileNotifierGroup> notifier_groups_;
+  std::vector<scoped_ptr<message_center::ProfileNotifierGroup>>
+      notifier_groups_;
+
   size_t current_notifier_group_;
 
   content::NotificationRegistrar registrar_;
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc
index 6a5db5e1..427a811 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.cc
+++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -62,6 +62,10 @@
 
 namespace {
 
+// Invalid id for a renderer process. Used in cases where we need to check for
+// permission without having an associated renderer process yet.
+const int kInvalidRenderProcessId = -1;
+
 // Callback to provide when deleting the data associated with persistent Web
 // Notifications from the notification database.
 void OnPersistentNotificationDataDeleted(bool success) {
@@ -100,8 +104,20 @@
     BrowserContext* browser_context,
     int64_t persistent_notification_id,
     const GURL& origin,
-    int action_index) const {
+    int action_index) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  blink::WebNotificationPermission permission =
+      CheckPermissionOnUIThread(browser_context, origin,
+                                kInvalidRenderProcessId);
+
+  // TODO(peter): Change this to a CHECK() when Issue 555572 is resolved.
+  // Also change this method to be const again.
+  if (permission != blink::WebNotificationPermissionAllowed) {
+    content::RecordAction(base::UserMetricsAction(
+        "Notifications.Persistent.ClickedWithoutPermission"));
+    return;
+  }
+
   content::RecordAction(
       base::UserMetricsAction("Notifications.Persistent.Clicked"));
 
diff --git a/chrome/browser/notifications/platform_notification_service_impl.h b/chrome/browser/notifications/platform_notification_service_impl.h
index 5a1ff235..e7f9ab6 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.h
+++ b/chrome/browser/notifications/platform_notification_service_impl.h
@@ -45,7 +45,7 @@
       content::BrowserContext* browser_context,
       int64_t persistent_notification_id,
       const GURL& origin,
-      int action_index) const;
+      int action_index);
 
   // To be called when a persistent notification has been closed. The data
   // associated with the notification has to be pruned from the database in this
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observers_unittest.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observers_unittest.cc
index e8557d44..e6716ea 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observers_unittest.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observers_unittest.cc
@@ -18,6 +18,16 @@
 
 }  // namespace
 
+class TestPageLoadMetricsEmbedderInterface
+    : public page_load_metrics::PageLoadMetricsEmbedderInterface {
+ public:
+  TestPageLoadMetricsEmbedderInterface() {}
+  rappor::RapporService* GetRapporService() override { return nullptr; }
+  bool IsPrerendering(content::WebContents* web_contents) override {
+    return false;
+  }
+};
+
 class TestFromGWSPageLoadMetricsObserver
     : public FromGWSPageLoadMetricsObserver {
  public:
@@ -46,7 +56,8 @@
     NavigateAndCommit(GURL("http://www.google.com"));
     observer_ =
         make_scoped_ptr(new page_load_metrics::MetricsWebContentsObserver(
-            web_contents(), nullptr));
+            web_contents(),
+            make_scoped_ptr(new TestPageLoadMetricsEmbedderInterface())));
     observer_->WasShown();
 
     // Add PageLoadMetricsObservers here.
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index 88858936..1f92497 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -4,8 +4,9 @@
 
 #include "chrome/browser/page_load_metrics/page_load_metrics_initialize.h"
 
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h"
-#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
+#include "chrome/browser/prerender/prerender_contents.h"
 #include "components/rappor/rappor_service.h"
 #include "content/public/browser/web_contents.h"
 
@@ -25,11 +26,23 @@
 namespace chrome {
 
 void InitializePageLoadMetricsForWebContents(
-    content::WebContents* web_contents,
-    rappor::RapporService* rappor_service) {
+    content::WebContents* web_contents) {
   RegisterPageLoadMetricsObservers(
       page_load_metrics::MetricsWebContentsObserver::CreateForWebContents(
-          web_contents, rappor_service));
+          web_contents,
+          make_scoped_ptr(new PageLoadMetricsEmbedderInterfaceImpl())));
+}
+
+PageLoadMetricsEmbedderInterfaceImpl::~PageLoadMetricsEmbedderInterfaceImpl() {}
+
+rappor::RapporService*
+PageLoadMetricsEmbedderInterfaceImpl::GetRapporService() {
+  return g_browser_process->rappor_service();
+}
+
+bool PageLoadMetricsEmbedderInterfaceImpl::IsPrerendering(
+    content::WebContents* web_contents) {
+  return prerender::PrerenderContents::FromWebContents(web_contents) != nullptr;
 }
 
 }  // namespace chrome
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.h b/chrome/browser/page_load_metrics/page_load_metrics_initialize.h
index b0f5c0d..f9a78ca 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_INITIALIZE_H_
 #define CHROME_BROWSER_PAGE_LOAD_METRICS_PAGE_LOAD_METRICS_INITIALIZE_H_
 
+#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
+
 namespace content {
 class WebContents;
 }
@@ -16,8 +18,16 @@
 namespace chrome {
 
 void InitializePageLoadMetricsForWebContents(
-    content::WebContents* web_contents,
-    rappor::RapporService* rappor_service);
+    content::WebContents* web_contents);
+
+class PageLoadMetricsEmbedderInterfaceImpl
+    : public page_load_metrics::PageLoadMetricsEmbedderInterface {
+ public:
+  // PageLoadMetricsEmbedderInterface:
+  ~PageLoadMetricsEmbedderInterfaceImpl() override;
+  rappor::RapporService* GetRapporService() override;
+  bool IsPrerendering(content::WebContents* web_contents) override;
+};
 
 }  // namespace chrome
 
diff --git a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
index 5618c7fc..6cf146e8 100644
--- a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
+++ b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
@@ -31,6 +31,7 @@
       "matches": [ "<all_urls>" ],
       "exclude_globs": [
           "chrome-extension://mndnfokpggljbaajbnioimlmbfngpief/cvox2/background/background.html",
+          "chrome-extension://mndnfokpggljbaajbnioimlmbfngpief/cvox2/background/panel.html",
           "chrome://md-settings*",
           "chrome://downloads*",
           "chrome://oobe/login*",
diff --git a/chrome/browser/resources/chromeos/chromevox/testing/test_msgs.js b/chrome/browser/resources/chromeos/chromevox/testing/test_msgs.js
index e4dd01d..969dd04 100644
--- a/chrome/browser/resources/chromeos/chromevox/testing/test_msgs.js
+++ b/chrome/browser/resources/chromeos/chromevox/testing/test_msgs.js
@@ -47,6 +47,14 @@
   }
 
   var messageString = message.message;
+  var placeholders = message.placeholders;
+  if (placeholders) {
+    for (name in placeholders) {
+      messageString = messageString.replace(
+          '$' + name + '$',
+          placeholders[name].content);
+    }
+  }
   if (opt_subs) {
     // Unshift a null to make opt_subs and message.placeholders line up.
     for (var i = 0; i < opt_subs.length; i++) {
diff --git a/chrome/browser/resources/chromeos/login/accessibility_menu.css b/chrome/browser/resources/chromeos/login/accessibility_menu.css
index cb8350a..d291f7c 100644
--- a/chrome/browser/resources/chromeos/login/accessibility_menu.css
+++ b/chrome/browser/resources/chromeos/login/accessibility_menu.css
@@ -8,6 +8,7 @@
   -webkit-padding-start: 25px;
   padding-bottom: 25px;
   padding-top: 15px;
+  z-index: 1;
 }
 
 .checkboxrow {
diff --git a/chrome/browser/resources/chromeos/login/header_bar.js b/chrome/browser/resources/chromeos/login/header_bar.js
index 337d3f5..d9668e1 100644
--- a/chrome/browser/resources/chromeos/login/header_bar.js
+++ b/chrome/browser/resources/chromeos/login/header_bar.js
@@ -289,12 +289,8 @@
      */
     updateUI_: function() {
       var gaiaIsActive = (this.signinUIState_ == SIGNIN_UI_STATE.GAIA_SIGNIN);
-      var gaiaIsActiveWithBackButton =
-          gaiaIsActive && $('gaia-navigation').backVisible;
       var enrollmentIsActive =
           (this.signinUIState_ == SIGNIN_UI_STATE.ENROLLMENT);
-      var enrollmentIsActiveWithBackButton =
-          enrollmentIsActive && $('oauth-enroll-navigation').backVisible;
       var accountPickerIsActive =
           (this.signinUIState_ == SIGNIN_UI_STATE.ACCOUNT_PICKER);
       var supervisedUserCreationDialogIsActive =
@@ -333,9 +329,9 @@
           wrongHWIDWarningIsActive ||
           isSamlPasswordConfirm ||
           isMultiProfilesUI ||
-          (gaiaIsActive && $('gaia-signin').cancelable) ||
-          enrollmentIsActiveWithBackButton ||
-          gaiaIsActiveWithBackButton;
+          (gaiaIsActive && $('gaia-signin').closable) ||
+          (enrollmentIsActive && !$('oauth-enrollment').isAtTheBeginning()) ||
+          (gaiaIsActive && !$('gaia-signin').isAtTheBeginning());
       $('restart-header-bar-item').hidden = !this.showReboot_;
       $('shutdown-header-bar-item').hidden = !this.showShutdown_;
       $('sign-out-user-item').hidden = !isLockScreen;
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.css b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.css
index 1f2b525..9ef604d 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.css
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.css
@@ -10,7 +10,7 @@
 }
 
 #oauth-enrollment.saml {
-  padding-top: 47px;
+  padding-top: 44px;
   width: 562px;
 }
 
@@ -77,12 +77,15 @@
 }
 
 #oauth-saml-notice-container {
-  -webkit-margin-start: 19px;
+  align-items: center;
+  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.17);
+  display: flex;
+  height: 44px;
+  justify-content: center;
   left: 0;
   position: absolute;
   right: 0;
-  text-align: start;
-  top: 15px;
+  top: 0;
 }
 
 #oauth-enrollment:not(.saml) #oauth-saml-notice-container {
@@ -92,7 +95,6 @@
 #oauth-saml-notice-message {
   color: rgb(106, 106, 106);
   font-size: 13px;
-  margin: 0 auto;
 }
 
 #oauth-enroll-attribute-prompt-message {
diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
index a8f4e2e7..ab340a07 100644
--- a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
+++ b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js
@@ -57,6 +57,13 @@
      */
     navigation_: undefined,
 
+    /**
+     * Value contained in the last received 'backButton' event.
+     * @type {boolean}
+     * @private
+     */
+    lastBackMessageValue_: false,
+
     /** @override */
     decorate: function() {
       this.navigation_ = $('oauth-enroll-navigation');
@@ -93,18 +100,19 @@
               $('oauth-saml-notice-message').textContent =
                   loadTimeData.getStringF('samlNotice',
                                           this.authenticator_.authDomain);
-              this.navigation_.backVisible = false;
             }
             this.classList.toggle('saml', isSAML);
             if (Oobe.getInstance().currentScreen == this)
               Oobe.getInstance().updateScreenSize(this);
+            this.lastBackMessageValue_ = false;
+            this.updateControlsState();
           }).bind(this));
 
       this.authenticator_.addEventListener('backButton',
           (function(e) {
-            this.navigation_.backVisible = !!e.detail;
+            this.lastBackMessageValue_ = !!e.detail;
             $('oauth-enroll-auth-view').focus();
-            $('login-header-bar').updateUI_();
+            this.updateControlsState();
           }).bind(this));
 
       this.authenticator_.insecureContentBlockedCallback =
@@ -241,12 +249,6 @@
       this.classList.toggle('oauth-enroll-state-' + this.currentStep_, false);
       this.classList.toggle('oauth-enroll-state-' + step, true);
 
-      this.navigation_.backVisible = false;
-      this.navigation_.closeVisible = this.isManualEnrollment_ &&
-          (step == STEP_SIGNIN || step == STEP_ERROR);
-      this.navigation_.refreshVisible =
-          !this.isManualEnrollment_ && step == STEP_SIGNIN;
-
       if (step == STEP_SIGNIN) {
         $('oauth-enroll-auth-view').focus();
       } else if (step == STEP_ERROR) {
@@ -258,7 +260,10 @@
       } else if (step == STEP_ATTRIBUTE_PROMPT_ERROR) {
         $('oauth-enroll-attribute-prompt-error-card').submitButton.focus();
       }
+
       this.currentStep_ = step;
+      this.lastBackMessageValue_ = false;
+      this.updateControlsState();
     },
 
     /**
@@ -279,7 +284,9 @@
     },
 
     doReload: function() {
+      this.lastBackMessageValue_ = false;
       this.authenticator_.reload();
+      this.updateControlsState();
     },
 
     /**
@@ -307,6 +314,30 @@
       chrome.send('oauthEnrollAttributes',
                   [$('oauth-enroll-asset-id').value,
                    $('oauth-enroll-location').value]);
+    },
+
+    /**
+     * Returns true if we are at the begging of enrollment flow (i.e. the email
+     * page).
+     *
+     * @type {boolean}
+     */
+    isAtTheBeginning: function() {
+      return !this.navigation_.backVisible && this.currentStep_ == STEP_SIGNIN;
+    },
+
+    /**
+     * Updates visibility of navigation buttons.
+     */
+    updateControlsState: function() {
+      this.navigation_.backVisible = this.currentStep_ == STEP_SIGNIN &&
+                                     this.lastBackMessageValue_;
+      this.navigation_.refreshVisible = this.isAtTheBeginning() &&
+                                        !this.isManualEnrollment_;
+      this.navigation_.closeVisible = (this.currentStep_ == STEP_SIGNIN ||
+                                       this.currentStep_ == STEP_ERROR) &&
+                                      !this.navigation_.refreshVisible;
+      $('login-header-bar').updateUI_();
     }
   };
 });
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.css b/chrome/browser/resources/chromeos/login/screen_gaia_signin.css
index 06a5616..4d60218 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.css
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.css
@@ -9,7 +9,7 @@
 }
 
 #gaia-signin.full-width {
-  padding: 47px 0 0;
+  padding: 44px 0 0;
   width: 562px;
 }
 
@@ -55,19 +55,20 @@
 }
 
 #saml-notice-container {
-  -webkit-margin-start: 19px;
+  align-items: center;
+  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.17);
+  display: flex;
+  height: 44px;
+  justify-content: center;
   left: 0;
   position: absolute;
   right: 0;
-  text-align: center;
-  text-align: start;
-  top: 15px;
+  top: 0;
 }
 
 #saml-notice-message {
   color: rgb(106, 106, 106);
   font-size: 13px;
-  margin: 0 auto;
 }
 
 #gaia-whitelist-error {
diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
index 8d4c4ca5..433e01c3 100644
--- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
+++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js
@@ -32,7 +32,7 @@
       'loadAuthExtension',
       'doReload',
       'monitorOfflineIdle',
-      'updateCancelButtonState',
+      'updateControlsState',
       'showWhitelistCheckFailedError',
     ],
 
@@ -87,18 +87,59 @@
     showViewProcessed_: undefined,
 
     /**
-     * Whether user can cancel Gaia screen.
+     * Whether we've processed 'authCompleted' message.
      * @type {boolean}
      * @private
      */
-    cancelable_: false,
-    get cancelable() {
-      // TODO(dzhioev): add cancel and refresh buttons hiding logic here.
-      // http://crbug.com/484514
-      return this.cancelable_;
+    authCompleted_: false,
+
+    /**
+     * Value contained in the last received 'backButton' event.
+     * @type {boolean}
+     * @private
+     */
+    lastBackMessageValue_: false,
+
+    /**
+     * Whether the dialog could be closed.
+     * @type {boolean}
+     */
+    get closable() {
+      return !!$('pod-row').pods.length || this.isLocal;
     },
-    set cancelable(value) {
-      this.cancelable_ = value;
+
+    /**
+     * Returns true if GAIA is at the begging of flow (i.e. the email page).
+     * @type {boolean}
+     */
+    isAtTheBeginning: function() {
+      return !this.navigation_.backVisible &&
+             !this.isSAML() &&
+             !this.classList.contains('whitelist-error') &&
+             !this.authCompleted_;
+    },
+
+    /**
+     * Updates visibility of navigation buttons.
+     */
+    updateControlsState: function() {
+      var isWhitelistError = this.classList.contains('whitelist-error');
+
+      this.navigation_.backVisible =
+        this.lastBackMessageValue_ &&
+        !isWhitelistError &&
+        !this.authCompleted_ &&
+        !this.loading &&
+        !this.isSAML();
+
+      this.navigation_.refreshVisible =
+        !this.closable && this.isAtTheBeginning();
+
+      this.navigation_.closeVisible =
+        !this.navigation_.refreshVisible &&
+        !isWhitelistError &&
+        !this.authCompleted;
+
       $('login-header-bar').updateUI_();
     },
 
@@ -190,6 +231,9 @@
       this.navigation_.addEventListener('close', function() {
         this.cancel();
       }.bind(this));
+      this.navigation_.addEventListener('refresh', function() {
+        this.cancel();
+      }.bind(this));
 
       $('gaia-whitelist-error').addEventListener('buttonclick', function() {
          this.showWhitelistCheckFailedError(false);
@@ -307,6 +351,7 @@
       this.getSigninFrame_().hidden = show;
       this.classList.toggle('loading', show);
       $('signin-frame').classList.remove('show');
+      this.updateControlsState();
     },
 
     /**
@@ -404,14 +449,14 @@
         chrome.send('loginVisible', ['gaia-loading']);
       });
 
-      this.navigation_.disabled = false;
-      this.navigation_.backVisible = false;
-
       this.classList.toggle('loading', this.loading);
 
       // Button header is always visible when sign in is presented.
       // Header is hidden once GAIA reports on successful sign in.
       Oobe.getInstance().headerHidden = false;
+
+      this.lastBackMessageValue_ = false;
+      this.updateControlsState();
     },
 
     getSigninFrame_: function() {
@@ -443,6 +488,8 @@
     loadAuthExtension: function(data) {
       this.isLocal = data.isLocal;
       this.email = '';
+      this.authCompleted_ = false;
+      this.lastBackMessageValue_ = false;
 
       // Reset SAML
       this.classList.toggle('full-width', false);
@@ -484,11 +531,10 @@
           this.loadOffline(params);
           this.onAuthReady_();
         } else {
-          this.gaiaAuthHost_.load(authMode,
-                                  params,
-                                  this.onAuthCompleted_.bind(this));
+          this.gaiaAuthHost_.load(authMode, params);
         }
       }
+      this.updateControlsState();
     },
 
     /**
@@ -502,7 +548,7 @@
       $('login-header-bar').showGuestButton = data.guestSignin;
 
       this.isShowUsers_ = data.isShowUsers;
-      this.updateCancelButtonState();
+      this.updateControlsState();
 
       this.isEnrollingConsumerManagement_ = data.isEnrollingConsumerManagement;
 
@@ -512,16 +558,6 @@
     },
 
     /**
-     * Updates [Cancel] button state. Allow cancellation of screen only when
-     * user pods can be displayed.
-     */
-    updateCancelButtonState: function() {
-      this.cancelable = this.isLocal ||
-                        (this.isShowUsers_ && $('pod-row').pods.length);
-      this.navigation_.closeVisible = this.cancelable;
-    },
-
-    /**
      * Whether the current auth flow is SAML.
      */
     isSAML: function() {
@@ -547,13 +583,11 @@
       this.classList.toggle('full-width', isSAML);
       $('saml-notice-container').hidden = !isSAML;
 
-      if (isSAML)
-        this.navigation_.backVisible = false;
-
       if (Oobe.getInstance().currentScreen === this) {
         Oobe.getInstance().updateScreenSize(this);
-        this.navigation_.closeVisible = isSAML || this.cancelable;
       }
+
+      this.updateControlsState();
     },
 
     /**
@@ -591,9 +625,9 @@
      * @private
      */
     onBackButton_: function(e) {
-      this.navigation_.backVisible = !!e.detail;
-      $('login-header-bar').updateUI_();
       this.getSigninFrame_().focus();
+      this.lastBackMessageValue_ = !!e.detail;
+      this.updateControlsState();
     },
 
     /**
@@ -753,13 +787,13 @@
 
       this.loading = true;
 
-      this.navigation_.backVisible = false;
-      this.navigation_.closeVisible = false;
-
       // Now that we're in logged in state header should be hidden.
       Oobe.getInstance().headerHidden = true;
       // Clear any error messages that were shown before login.
       Oobe.clearErrors();
+
+      this.authCompleted_ = true;
+      this.updateControlsState();
     },
 
     /**
@@ -819,6 +853,9 @@
       this.gaiaAuthHost_.reload();
       this.loading = true;
       this.startLoadingTimer_();
+      this.lastBackMessageValue_ = false;
+      this.authCompleted_ = false;
+      this.updateControlsState();
     },
 
     /**
@@ -847,20 +884,13 @@
      * Called when user canceled signin.
      */
     cancel: function() {
-      if (!this.cancelable) {
-        // In OOBE signin screen, cancel is not allowed because there is
-        // no other screen to show. If user is in middle of a saml flow,
-        // reset signin screen to get out of the saml flow.
-        if (this.isSAML())
-          Oobe.resetSigninUI(true);
-
+      if (!this.navigation_.refreshVisible && !this.navigation_.closeVisible)
         return;
-      }
 
-      $('offline-gaia').switchToEmailCard();
-
-      this.classList.remove('whitelist-error');
-      Oobe.showUserPods();
+      if (this.closable)
+        Oobe.showUserPods();
+      else
+        Oobe.resetSigninUI(true);
     },
 
     /**
@@ -915,6 +945,8 @@
 
       if (!show)
         Oobe.showSigninUI();
+
+      this.updateControlsState();
     }
   };
 });
diff --git a/chrome/browser/resources/md_extensions/manager.css b/chrome/browser/resources/md_extensions/manager.css
index ca6fc3c..a5f689f7 100644
--- a/chrome/browser/resources/md_extensions/manager.css
+++ b/chrome/browser/resources/md_extensions/manager.css
@@ -12,14 +12,18 @@
   };
 }
 
-extensions-item {
-  display: inline-block;
-  margin-top: 20px;
-}
-
-#item-list {
+#items {
   -webkit-margin-start: 30px;
   overflow-y: auto;
+  padding-bottom: 30px;
+}
+
+#items h2 {
+  color: #5a5a5a;
+  font-size: 1.1em;
+  font-weight: normal;
+  margin-bottom: 0;
+  margin-top: 30px;
 }
 
 extensions-item {
diff --git a/chrome/browser/resources/md_extensions/manager.html b/chrome/browser/resources/md_extensions/manager.html
index c991723..bfcb918 100644
--- a/chrome/browser/resources/md_extensions/manager.html
+++ b/chrome/browser/resources/md_extensions/manager.html
@@ -12,7 +12,14 @@
       <extensions-toolbar class="paper-header" id="toolbar">
       </extensions-toolbar>
       <extensions-sidebar></extensions-sidebar>
-      <div id="item-list"></div>
+      <div id="items">
+        <h2 id="extensions-header" i18n-content="sidebarExtensions"></h2>
+        <div id="extensions-list"></div>
+        <h2 id="apps-header" i18n-content="sidebarApps"></h2>
+        <div id="apps-list"></div>
+        <h2 id="websites-header" i18n-content="sidebarWebsites"></h2>
+        <div id="websites-list"></div>
+      </div>
     </paper-header-panel>
   </template>
   <link rel="import" type="css" href="chrome://extensions/manager.css">
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js
index 3ff4a3b..f7f94d8 100644
--- a/chrome/browser/resources/md_extensions/manager.js
+++ b/chrome/browser/resources/md_extensions/manager.js
@@ -15,6 +15,7 @@
     ready: function() {
       this.sidebar = this.$$('extensions-sidebar');
       extensions.Service.getInstance().managerReady(this);
+      this.sidebar.setScrollDelegate(new ScrollHelper(this));
     },
 
     /**
@@ -26,8 +27,28 @@
      *     not present, the item is appended to the end of the list.
      */
     addItem: function(extension, delegate, opt_index) {
+      var listId;
+      var ExtensionType = chrome.developerPrivate.ExtensionType;
+      switch (extension.type) {
+        case ExtensionType.HOSTED_APP:
+        case ExtensionType.LEGACY_PACKAGED_APP:
+          listId = 'websites-list';
+          break;
+        case ExtensionType.PLATFORM_APP:
+          listId = 'apps-list';
+          break;
+        case ExtensionType.EXTENSION:
+        case ExtensionType.SHARED_MODULE:
+          listId = 'extensions-list';
+          break;
+        case ExtensionType.THEME:
+          assertNotReached(
+              'Don\'t send themes to the chrome://extensions page');
+          break;
+      }
+      assert(listId);
       var extensionItem = new extensions.Item(extension, delegate);
-      var itemList = this.$['item-list'];
+      var itemList = this.$[listId];
       var refNode = opt_index !== undefined ?
           itemList.children[opt_index] : undefined;
       itemList.insertBefore(extensionItem, refNode);
@@ -60,5 +81,34 @@
      },
   });
 
+  /**
+   * @param {extensions.Manager} manager
+   * @constructor
+   * @implements {extensions.SidebarScrollDelegate}
+   */
+  function ScrollHelper(manager) {
+    this.items_ = manager.$.items;
+  }
+
+  ScrollHelper.prototype = {
+    /** @override */
+    scrollToExtensions: function() {
+      this.items_.scrollTop =
+          this.items_.querySelector('#extensions-header').offsetTop;
+    },
+
+    /** @override */
+    scrollToApps: function() {
+      this.items_.scrollTop =
+          this.items_.querySelector('#apps-header').offsetTop;
+    },
+
+    /** @override */
+    scrollToWebsites: function() {
+      this.items_.scrollTop =
+          this.items_.querySelector('#websites-header').offsetTop;
+    },
+  };
+
   return {Manager: Manager};
 });
diff --git a/chrome/browser/resources/md_extensions/sidebar.html b/chrome/browser/resources/md_extensions/sidebar.html
index 1f1b5b2..4a8c173 100644
--- a/chrome/browser/resources/md_extensions/sidebar.html
+++ b/chrome/browser/resources/md_extensions/sidebar.html
@@ -9,15 +9,18 @@
 <dom-module id="extensions-sidebar">
   <template>
     <paper-menu id="section-menu">
-      <paper-item class="section-menu-item" id="sections-extensions">
+      <paper-item class="section-menu-item" id="sections-extensions"
+          on-tap="onExtensionsTap_">
         <iron-icon icon="extension"></iron-icon>
         <span i18n-content="sidebarExtensions"></span>
       </paper-item>
-      <paper-item class="section-menu-item" id="sections-apps">
+      <paper-item class="section-menu-item" id="sections-apps"
+          on-tap="onAppsTap_">
         <iron-icon icon="apps"></iron-icon>
         <span i18n-content="sidebarApps"></span>
       </paper-item>
-      <paper-item class="section-menu-item" id="sections-websites">
+      <paper-item class="section-menu-item" id="sections-websites"
+          on-tap="onWebsitesTap_">
         <iron-icon icon="cloud"></iron-icon>
         <span i18n-content="sidebarWebsites"></span>
       </paper-item>
diff --git a/chrome/browser/resources/md_extensions/sidebar.js b/chrome/browser/resources/md_extensions/sidebar.js
index 6aebb54..47c68a7 100644
--- a/chrome/browser/resources/md_extensions/sidebar.js
+++ b/chrome/browser/resources/md_extensions/sidebar.js
@@ -23,6 +23,20 @@
     updateAllExtensions: assertNotReached,
   };
 
+  /** @interface */
+  var SidebarScrollDelegate = function() {};
+
+  SidebarScrollDelegate.prototype = {
+    /** Scrolls to the extensions section. */
+    scrollToExtensions: assertNotReached,
+
+    /** Scrolls to the apps section. */
+    scrollToApps: assertNotReached,
+
+    /** Scrolls to the websites section. */
+    scrollToWebsites: assertNotReached,
+  };
+
   var Sidebar = Polymer({
     is: 'extensions-sidebar',
 
@@ -39,22 +53,48 @@
 
     /** @param {extensions.SidebarDelegate} delegate */
     setDelegate: function(delegate) {
+      /** @private {extensions.SidebarDelegate} */
       this.delegate_ = delegate;
     },
 
+    /** @param {extensions.SidebarScrollDelegate} scrollDelegate */
+    setScrollDelegate: function(scrollDelegate) {
+      /** @private {extensions.SidebarScrollDelegate} */
+      this.scrollDelegate_ = scrollDelegate;
+    },
+
+    /** @private */
+    onExtensionsTap_: function() {
+      this.scrollDelegate_.scrollToExtensions();
+    },
+
+    /** @private */
+    onAppsTap_: function() {
+      this.scrollDelegate_.scrollToApps();
+    },
+
+    /** @private */
+    onWebsitesTap_: function() {
+      this.scrollDelegate_.scrollToWebsites();
+    },
+
+    /** @private */
     onDevModeChange_: function() {
       this.delegate_.setProfileInDevMode(
           this.$['developer-mode-checkbox'].checked);
     },
 
+    /** @private */
     onLoadUnpackedTap_: function() {
       this.delegate_.loadUnpacked();
     },
 
+    /** @private */
     onPackTap_: function() {
       this.delegate_.packExtension();
     },
 
+    /** @private */
     onUpdateNowTap_: function() {
       this.delegate_.updateAllExtensions();
     },
@@ -63,6 +103,7 @@
   return {
     Sidebar: Sidebar,
     SidebarDelegate: SidebarDelegate,
+    SidebarScrollDelegate: SidebarScrollDelegate,
   };
 });
 
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css
index 05f4f29..6bf24425 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css
@@ -2,6 +2,10 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file. */
 
+:root {
+  --container-header-height: 52px;
+}
+
 .active-sink {
   color: rgb(33, 150, 243);
 }
@@ -19,12 +23,19 @@
   padding-top: 4px;
 }
 
+#container-header {
+  position: fixed;
+  width: 100%;
+  z-index: 1;
+}
+
 #device-missing {
   align-items: center;
   background-color: white;
   display: flex;
   height: 120px;
   justify-content: center;
+  margin-top: var(--container-header-height);
 }
 
 #device-missing a {
@@ -33,6 +44,7 @@
 }
 
 #issue-banner {
+  margin-top: var(--container-header-height);
   width: 100%;
   z-index: 1;
 }
@@ -58,6 +70,7 @@
 paper-menu {
   -webkit-user-select: none;
   color: rgba(0, 0, 0, 0.87);
+  margin-top: var(--container-header-height);
   overflow-x: hidden;
   overflow-y: auto;
   padding-bottom: 12px;
@@ -87,10 +100,6 @@
   font-weight: normal;
 }
 
-#sink-list {
-  max-height: 320px;
-}
-
 .sink-text {
   -webkit-padding-end: 26px;
   line-height: normal;
@@ -99,3 +108,7 @@
   white-space: nowrap;
   width: 250px;
 }
+
+#route-details {
+  margin-top: var(--container-header-height);
+}
\ No newline at end of file
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
index a19e319..0015d83 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.html
@@ -30,7 +30,7 @@
     <paper-menu id="cast-mode-list"
         hidden$="[[computeCastModeHidden_(currentView_)]]">
       <template is="dom-repeat" id="defaultCastModeList"
-          items="[[computeDefaultCastModeList_(castModeList_)]]">
+          items="[[computeDefaultCastModeList_(castModeList)]]">
         <paper-item on-click="onCastModeClick_">
           <iron-icon class="cast-mode-icon"
               icon="[[computeCastModeIcon_(item)]]">
@@ -39,11 +39,11 @@
         </paper-item>
       </template>
       <div id="share-screen-text"
-          hidden$="[[computeShareScreenSubheadingHidden_(castModeList_)]]">
+          hidden$="[[computeShareScreenSubheadingHidden_(castModeList)]]">
         <span>[[shareYourScreenSubheadingText_]]</span>
       </div>
       <template is="dom-repeat" id="nonDefaultCastModeList"
-          items="[[computeNonDefaultCastModeList_(castModeList_)]]">
+          items="[[computeNonDefaultCastModeList_(castModeList)]]">
         <paper-item on-click="onCastModeClick_">
           <iron-icon class="cast-mode-icon"
               icon="[[computeCastModeIcon_(item)]]">
@@ -69,7 +69,7 @@
         </a>
       </div>
       <paper-menu id="sink-list"
-          hidden$="[[computeSinkListHidden_(currentView_, issue)]]">
+          hidden$="[[computeSinkListHidden_(sinksToShow_)]]">
         <template is="dom-repeat" id="sinkList" items="[[sinksToShow_]]">
           <paper-item class="sink" on-click="onSinkClick_">
             <div class="sink-content">
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
index aa86c5cb..b655cfe 100644
--- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
+++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
@@ -20,9 +20,9 @@
 
     /**
      * The list of CastModes to show.
-     * @private {!Array<!media_router.CastMode>}
+     * @type {!Array<!media_router.CastMode>}
      */
-    castModeList_: {
+    castModeList: {
       type: Array,
       value: [],
       observer: 'checkCurrentCastMode_',
@@ -162,7 +162,7 @@
     },
 
     /**
-     * The value of the selected cast mode in |castModeList_|.
+     * The value of the selected cast mode in |castModeList|.
      * @private {number}
      */
     selectedCastModeValue_: {
@@ -243,9 +243,9 @@
    * cast mode to the first available cast mode on the list.
    */
   checkCurrentCastMode_: function() {
-    if (this.castModeList_.length > 0 &&
+    if (this.castModeList.length > 0 &&
         !this.findCastModeByType_(this.selectedCastModeValue_)) {
-      this.setSelectedCastMode_(this.castModeList_[0]);
+      this.setSelectedCastMode_(this.castModeList[0]);
     }
   },
 
@@ -504,7 +504,7 @@
    *     castModeList, or undefined if not found.
    */
   findCastModeByType_: function(castModeType) {
-    return this.castModeList_.find(function(element, index, array) {
+    return this.castModeList.find(function(element, index, array) {
       return element.type == castModeType;
     });
   },
@@ -518,7 +518,7 @@
    *     opened.
    */
   initializeCastModes: function(availableCastModes, initialCastModeType) {
-    this.castModeList_ = availableCastModes;
+    this.castModeList = availableCastModes;
     var castMode = this.findCastModeByType_(initialCastModeType);
     if (!castMode)
       return;
@@ -692,16 +692,28 @@
   /**
    * Rebuilds the list of sinks to be shown for the current cast mode.
    * A sink should be shown if it is compatible with the current cast mode, or
-   * if the sink is associated with a route.
+   * if the sink is associated with a route.  The resulting list is sorted by
+   * name.
    */
   rebuildSinksToShow_: function() {
     var sinksToShow = [];
-    this.allSinks.forEach(function(element, index, array) {
+    this.allSinks.forEach(function(element) {
       if (element.castModes.indexOf(this.selectedCastModeValue_) != -1 ||
           this.sinkToRouteMap_[element.id]) {
         sinksToShow.push(element);
       }
     }, this);
+
+    // Sort the |sinksToShow| by name.  If any two devices have the same name,
+    // use their IDs to stabilize the ordering.
+    sinksToShow.sort(function(a, b) {
+      var ordering = a.name.localeCompare(b.name);
+      if (ordering != 0) {
+        return ordering;
+      }
+      return (a.id < b.id) ? -1 : ((a.id == b.id) ? 0 : 1);
+    });
+
     this.sinksToShow_ = sinksToShow;
   },
 
diff --git a/chrome/browser/resources/options/browser_options.css b/chrome/browser/resources/options/browser_options.css
index b9e718d6..bc6f017 100644
--- a/chrome/browser/resources/options/browser_options.css
+++ b/chrome/browser/resources/options/browser_options.css
@@ -42,6 +42,7 @@
 
 #account-picture {
   height: 56px;
+  object-fit: cover;
   vertical-align: middle;
   width: 56px;
 }
diff --git a/chrome/browser/resources/settings/advanced_page/advanced_page.html b/chrome/browser/resources/settings/advanced_page/advanced_page.html
index 008a1f7..d57aa53f 100644
--- a/chrome/browser/resources/settings/advanced_page/advanced_page.html
+++ b/chrome/browser/resources/settings/advanced_page/advanced_page.html
@@ -81,5 +81,5 @@
     </settings-section>
 </if>
   </template>
-  <script src="advanced_page.js"></script>
+  <script src="chrome://md-settings/advanced_page/advanced_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css
index df0c564..ba920d0 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.css
@@ -5,3 +5,24 @@
 iron-icon {
   -webkit-margin-end: 10px;
 }
+
+#deviceList {
+  border: lightgrey solid 1px;
+  margin: 10px 0;
+  max-height: 400px;
+  padding: 10px;
+}
+
+div.iron-selected,
+div.device:hover {
+  background-color: lightgrey;
+}
+
+div.device:not(:hover) .hover-only {
+  visibility: hidden;
+}
+
+span.name[connected],
+span.name[connecting] {
+  font-weight: bold;
+}
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
index 4c093d5a..966ba25 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.html
@@ -1,8 +1,13 @@
 <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/device-icons.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html">
+<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html">
 <link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_collapse/cr_collapse.html">
+<link rel="import" href="chrome://resources/html/i18n_behavior.html">
 <link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html">
 
 <dom-module id="settings-bluetooth-page">
@@ -12,12 +17,47 @@
     <settings-animated-pages id="pages" current-route="{{currentRoute}}"
         section="bluetooth">
       <neon-animatable id="main">
-        <div class="layout horizontal center">
-          <iron-icon icon="device:bluetooth"></iron-icon>
-          <span class="flex" i18n-content="enableBluetooth"></span>
-          <paper-toggle-button checked="{{bluetoothEnabled}}"
-              on-change="onBluetoothEnabledChange_">
-          </paper-toggle-button>
+        <div class="layout vertical">
+          <div class="layout horizontal center">
+            <iron-icon icon="device:bluetooth"></iron-icon>
+            <span class="flex" i18n-content="bluetoothEnable"></span>
+            <paper-toggle-button checked="{{bluetoothEnabled}}"
+                on-change="onBluetoothEnabledChange_">
+            </paper-toggle-button>
+          </div>
+          <cr-collapse opened="[[bluetoothEnabled]]">
+            <div id="deviceList" class="layout vertical flex">
+              <span hidden$="[[haveDevices_(deviceList)]]"
+                  i18n-content="bluetoothNoDevices">
+              </span>
+              <iron-selector selected="{{selectedDevice}}">
+                <template is="dom-repeat" items="[[deviceList]]">
+                  <div class="device layout horizontal center"
+                      hidden$="[[!showDeviceInList_(item)]]">
+                    <span class="name flex"
+                        connected$=[[item.connected]]
+                        connecting$=[[item.connecting]]>
+                      [[getDeviceText_(item)]]
+                    </span>
+                    <paper-icon-button class="hover-only"
+                        icon="clear" address$=[[item.address]]
+                        on-tap="onRemoveTap_">
+                    </paper-icon-button>
+                  </div>
+                </template>
+              </iron-selector>
+            </div>
+          </cr-collapse>
+          <div class="layout horizontal end-justified"
+              hidden$="[[!bluetoothEnabled]]">
+            <paper-button id="connect" i18n-content="bluetoothConnect"
+                disabled="[[!haveSelectedDevice_(selectedDevice)]]"
+                on-tap="onConnectTap_">
+            </paper-button>
+            <paper-button id="addDevice" i18n-content="bluetoothAddDevice"
+                on-tap="onAddDeviceTap_">
+            </paper-button>
+          </div>
         </div>
       </neon-animatable>
     </settings-animated-pages>
diff --git a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
index 6328c0ae..972e3c9 100644
--- a/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
+++ b/chrome/browser/resources/settings/bluetooth_page/bluetooth_page.js
@@ -20,6 +20,10 @@
 Polymer({
   is: 'settings-bluetooth-page',
 
+  behaviors: [
+    I18nBehavior,
+  ],
+
   properties: {
     /** The current active route. */
     currentRoute: {
@@ -28,15 +32,39 @@
     },
 
     /** Whether bluetooth is enabled. */
-    bluetoothEnabled: Boolean,
+    bluetoothEnabled: {type: Boolean, value: false},
+
+    /**
+     * The ordered list of bluetooth devices.
+     * @type {!Array<!chrome.bluetooth.Device>}
+     */
+    deviceList: {type: Array, value: function() { return []; }},
+
+    /** The index of the selected device or -1 if none. */
+    selectedDevice: {type: Number, value: -1}
   },
 
   /**
    * Listener for chrome.bluetooth.onAdapterStateChanged events.
-   * @type {function(!chrome.bluetooth.AdapterState)}
+   * @type {function(!chrome.bluetooth.AdapterState)|undefined}
    * @private
    */
-  bluetoothAdapterStateChangedListener_: function() {},
+  bluetoothAdapterStateChangedListener_: undefined,
+
+  /**
+   * Listener for chrome.bluetooth.onBluetoothDeviceAdded/Changed events.
+   * @type {function(!chrome.bluetooth.Device)|undefined}
+   * @private
+   */
+  bluetoothDeviceUpdatedListener_: undefined,
+
+  /**
+   * Listener for chrome.bluetooth.onBluetoothDeviceRemoved events.
+   * @type {function(!chrome.bluetooth.Device)|undefined}
+   * @private
+   */
+  bluetoothDeviceRemovedListener_: undefined,
+
 
   /** @override */
   attached: function() {
@@ -45,12 +73,54 @@
     chrome.bluetooth.onAdapterStateChanged.addListener(
         this.bluetoothAdapterStateChangedListener_);
 
+    this.bluetoothDeviceUpdatedListener_ =
+        this.onBluetoothDeviceUpdated_.bind(this);
+    chrome.bluetooth.onDeviceAdded.addListener(
+        this.bluetoothDeviceUpdatedListener_);
+    chrome.bluetooth.onDeviceChanged.addListener(
+        this.bluetoothDeviceUpdatedListener_);
+
+    this.bluetoothDeviceRemovedListener_ =
+        this.onBluetoothDeviceRemoved_.bind(this);
+    chrome.bluetooth.onDeviceRemoved.addListener(
+        this.bluetoothDeviceRemovedListener_);
+
+    // Request the inital adapter state.
+    chrome.bluetooth.getAdapterState(
+        this.bluetoothAdapterStateChangedListener_);
   },
 
   /** @override */
   detached: function() {
-    chrome.bluetooth.onAdapterStateChanged.removeListener(
-        this.bluetoothAdapterStateChangedListener_);
+    if (this.bluetoothAdapterStateChangedListener_) {
+      chrome.bluetooth.onAdapterStateChanged.removeListener(
+          this.bluetoothAdapterStateChangedListener_);
+    }
+    if (this.bluetoothDeviceUpdatedListener_) {
+      chrome.bluetooth.onDeviceAdded.removeListener(
+          this.bluetoothDeviceUpdatedListener_);
+      chrome.bluetooth.onDeviceChanged.removeListener(
+          this.bluetoothDeviceUpdatedListener_);
+    }
+    if (this.bluetoothDeviceRemovedListener_) {
+      chrome.bluetooth.onDeviceRemoved.removeListener(
+          this.bluetoothDeviceRemovedListener_);
+    }
+  },
+
+  /**
+   * If bluetooth is enabled, request the complete list of devices and update
+   * |deviceList|.
+   * @private
+   */
+  updateDeviceList_: function() {
+    if (!this.bluetoothEnabled) {
+      this.deviceList = [];
+      return;
+    }
+    chrome.bluetooth.getDevices(function(devices) {
+      this.deviceList = devices;
+    }.bind(this));
   },
 
   /**
@@ -62,7 +132,8 @@
         {powered: this.bluetoothEnabled}, function() {
           if (chrome.runtime.lastError) {
             console.error(
-                'Error enabling bluetooth:', chrome.runtime.lastError.message);
+                'Error enabling bluetooth: ' +
+                chrome.runtime.lastError.message);
           }
         });
   },
@@ -74,5 +145,132 @@
    */
   onBluetoothAdapterStateChanged_: function(state) {
     this.bluetoothEnabled = state.powered;
+    this.updateDeviceList_();
   },
+
+  /**
+   * Process bluetooth.onDeviceAdded and onDeviceChanged events.
+   * @param {!chrome.bluetooth.Device} device
+   * @private
+   */
+  onBluetoothDeviceUpdated_: function(device) {
+    if (!device)
+      return;
+    var address = device.address;
+    var index = this.getDeviceIndex_(address);
+    if (index >= 0) {
+      this.set('deviceList.' + index, device);
+      return;
+    }
+    this.push('deviceList', device);
+  },
+
+  /**
+   * Process bluetooth.onDeviceRemoved events.
+   * @param {!chrome.bluetooth.Device} device
+   * @private
+   */
+  onBluetoothDeviceRemoved_: function(device) {
+    var address = device.address;
+    var index = this.getDeviceIndex_(address);
+    if (index < 0)
+      return;
+    this.splice('deviceList', index, 1);
+  },
+
+  /**
+   * @param {string} address
+   * @return {number} The index of the device associated with |address| or -1.
+   * @private
+   */
+  getDeviceIndex_: function(address) {
+    var len = this.deviceList.length;
+    for (var i = 0; i < len; ++i) {
+      if (this.deviceList[i].address == address)
+        return i;
+    }
+    return -1;
+  },
+
+  /**
+   * @param {!chrome.bluetooth.Device} device
+   * @return {string} The text to display for |device| in the device list.
+   * @private
+   */
+  getDeviceText_: function(device) {
+    if (device.connecting)
+      return this.i18n('bluetoothConnecting', device.name);
+    return device.name || device.address;
+  },
+
+  /**
+   * @param {!chrome.bluetooth.Device} device
+   * @return {boolean} True if |device| should be shown in the device list.
+   * @private
+   */
+  showDeviceInList_: function(device) {
+    return !!device.paired || !!device.connected || !!device.connecting;
+  },
+
+  /**
+   * @param {!Array<!chrome.bluetooth.Device>} deviceList
+   * @return {boolean} True if deviceList is not empty.
+   * @private
+   */
+  haveDevices_: function(deviceList) { return !!deviceList.length; },
+
+  /**
+   * @param {number} selectedDevice
+   * @return {boolean} True if a device is selected.
+   * @private
+   */
+  haveSelectedDevice_: function(selectedDevice) { return selectedDevice >= 0; },
+
+  /** @private */
+  onConnectTap_: function() {
+    if (this.selectedDevice < 0)
+      return;
+    var device = this.deviceList[this.selectedDevice];
+    if (!device)
+      return;
+    chrome.bluetoothPrivate.connect(device.address, function(result) {
+      if (chrome.runtime.lastError) {
+        console.error(
+            'Error connecting to: ' + device.address +
+            chrome.runtime.lastError.message);
+      }
+    });
+  },
+
+  /**
+   * @param {!Event} event
+   * @private
+   */
+  onRemoveTap_: function(event) {
+    var address = event.target.address;
+    var index = this.getDeviceIndex_(address);
+    if (index < 0)
+      return;
+    var device = this.deviceList[index];
+    if (device.connected) {
+      chrome.bluetoothPrivate.disconnectAll(address, function() {
+        if (chrome.runtime.lastError) {
+          console.error(
+              'Error disconnecting devce: ' + device.name + ': ' +
+              chrome.runtime.lastError.message);
+        }
+      });
+    } else {
+      chrome.bluetoothPrivate.forgetDevice(address, function() {
+        if (chrome.runtime.lastError) {
+          console.error(
+              'Error forgetting devce: ' + device.name + ': ' +
+                  chrome.runtime.lastError.message);
+        }
+      });
+    }
+  },
+
+  /** @private */
+  onAddDeviceTap_: function() {}
 });
diff --git a/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp b/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp
index cc915ac..f16a028 100644
--- a/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp
+++ b/chrome/browser/resources/settings/bluetooth_page/compiled_resources.gyp
@@ -9,6 +9,7 @@
         'depends': [
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:assert',
           '../../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data',
+          '../../../../../ui/webui/resources/js/i18n_behavior.js',
           '../settings_page/settings_animated_pages.js'
         ],
         'externs': [
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.html b/chrome/browser/resources/settings/reset_page/reset_page.html
index 65c33fc..af08139 100644
--- a/chrome/browser/resources/settings/reset_page/reset_page.html
+++ b/chrome/browser/resources/settings/reset_page/reset_page.html
@@ -20,5 +20,5 @@
     </div>
 </if>
   </template>
-  <script src="reset_page.js"></script>
+  <script src="chrome://md-settings/reset_page/reset_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/reset_page/reset_page.js b/chrome/browser/resources/settings/reset_page/reset_page.js
index 0142717..4a8e66c 100644
--- a/chrome/browser/resources/settings/reset_page/reset_page.js
+++ b/chrome/browser/resources/settings/reset_page/reset_page.js
@@ -24,7 +24,7 @@
   properties: {
     allowPowerwash_: {
       type: Boolean,
-      value: loadTimeData.getBoolean('allowPowerwash')
+      value: cr.isChromeOS ? loadTimeData.getBoolean('allowPowerwash') : false
     },
   },
 
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html
index 26ab4a6c..907ae18 100644
--- a/chrome/browser/resources/settings/settings_menu/settings_menu.html
+++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -68,10 +68,12 @@
             <iron-icon icon="lock" item-icon></iron-icon>
             <span i18n-content="privacyPageTitle"></span>
           </paper-icon-item>
+<if expr="chromeos">
           <paper-icon-item>
             <iron-icon icon="device:bluetooth" item-icon></iron-icon>
             <span i18n-content="bluetoothPageTitle"></span>
           </paper-icon-item>
+</if>
           <paper-icon-item>
             <iron-icon icon="file-download" item-icon></iron-icon>
             <span i18n-content="downloadsPageTitle"></span>
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 1e16817..4d9c1c3 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -231,7 +231,8 @@
                  type="chrome_html" />
       <structure name="IDR_SETTINGS_RESET_PAGE_HTML"
                  file="reset_page/reset_page.html"
-                 type="chrome_html" />
+                 type="chrome_html"
+                 flattenhtml="true" />
       <structure name="IDR_SETTINGS_RESET_PAGE_JS"
                  file="reset_page/reset_page.js"
                  type="chrome_html" />
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index 348750e..f9c62c3 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -573,6 +573,7 @@
     } else {
       DVLOG(1) << "Zip analysis failed for " << item_->GetFullPath().value();
     }
+    UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileSuccess", results.success);
     UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasExecutable",
                           archived_executable_);
     UMA_HISTOGRAM_BOOLEAN("SBClientDownload.ZipFileHasArchiveButNoExecutable",
diff --git a/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc b/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc
index 7c666c7..d367cd8 100644
--- a/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/platform_state_store.cc
@@ -42,15 +42,13 @@
     const base::DictionaryValue& keys_and_digests,
     RepeatedPtrField<StateStoreData::Incidents::KeyDigestMapFieldEntry>*
         key_digest_pairs) {
+  std::string digest_value;
   for (base::DictionaryValue::Iterator iter(keys_and_digests); !iter.IsAtEnd();
        iter.Advance()) {
-    const base::StringValue* digest_value = nullptr;
-    if (!iter.value().GetAsString(&digest_value)) {
-      NOTREACHED();
-      continue;
-    }
     uint32_t digest = 0;
-    if (!base::StringToUint(digest_value->GetString(), &digest)) {
+    if (iter.value().GetType() != base::Value::TYPE_STRING ||
+        !iter.value().GetAsString(&digest_value) ||
+        !base::StringToUint(digest_value, &digest)) {
       NOTREACHED();
       continue;
     }
diff --git a/chrome/browser/safe_browsing/incident_reporting/platform_state_store_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/platform_state_store_unittest.cc
index 9ee1faa..03eef13a 100644
--- a/chrome/browser/safe_browsing/incident_reporting/platform_state_store_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/platform_state_store_unittest.cc
@@ -6,6 +6,8 @@
 
 #if defined(USE_PLATFORM_STATE_STORE)
 
+#include "base/json/json_reader.h"
+#include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -26,19 +28,20 @@
 
 // Returns a dict with some sample data in it.
 scoped_ptr<base::DictionaryValue> CreateTestIncidentsSentPref() {
-  scoped_ptr<base::DictionaryValue> incidents_sent(new base::DictionaryValue);
+  static const char kData[] =
+      "{"
+      "\"2\":{\"spam\":\"1234\",\"blorf\":\"5\"},"
+      "\"0\":{\"whaa\":\"0\",\"wha?\":\"9876\"}"
+      "}";
+  base::JSONReader reader;
 
-  scoped_ptr<base::DictionaryValue> type_dict(new base::DictionaryValue);
-  type_dict->SetStringWithoutPathExpansion("spam", "1234");
-  type_dict->SetStringWithoutPathExpansion("blorf", "5");
-  incidents_sent->SetWithoutPathExpansion("2", type_dict.release());
-
-  type_dict.reset(new base::DictionaryValue);
-  type_dict->SetStringWithoutPathExpansion("whaa", "0");
-  type_dict->SetStringWithoutPathExpansion("wha?", "9876");
-  incidents_sent->SetWithoutPathExpansion("0", type_dict.release());
-
-  return incidents_sent.Pass();
+  scoped_ptr<base::Value> root(reader.Read(kData));
+  EXPECT_TRUE(root);
+  base::DictionaryValue* incidents_sent = nullptr;
+  EXPECT_TRUE(root->GetAsDictionary(&incidents_sent));
+  // Relinquish ownership to |incidents_sent|.
+  ignore_result(root.release());
+  return make_scoped_ptr(incidents_sent);
 }
 
 }  // namespace
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.cc b/chrome/browser/safe_browsing/srt_fetcher_win.cc
index 3472124..bd063aa 100644
--- a/chrome/browser/safe_browsing/srt_fetcher_win.cc
+++ b/chrome/browser/safe_browsing/srt_fetcher_win.cc
@@ -16,6 +16,7 @@
 #include "base/prefs/pref_service.h"
 #include "base/process/launch.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
 #include "base/threading/thread_checker.h"
@@ -48,6 +49,7 @@
 
 const wchar_t kSoftwareRemovalToolRegistryKey[] =
     L"Software\\Google\\Software Removal Tool";
+
 const wchar_t kEndTimeValueName[] = L"EndTime";
 const wchar_t kStartTimeValueName[] = L"StartTime";
 
@@ -72,11 +74,13 @@
 ReporterLauncher g_reporter_launcher_;
 PromptTrigger g_prompt_trigger_;
 
+const wchar_t kScanTimesSubKey[] = L"ScanTimes";
 const wchar_t kFoundUwsValueName[] = L"FoundUws";
 
 const char kFoundUwsMetricName[] = "SoftwareReporter.FoundUwS";
 const char kFoundUwsReadErrorMetricName[] =
     "SoftwareReporter.FoundUwSReadError";
+const char kScanTimesMetricName[] = "SoftwareReporter.UwSScanTimes";
 
 void DisplaySRTPrompt(const base::FilePath& download_path) {
   // Find the last active browser, which may be NULL, in which case we won't
@@ -294,8 +298,12 @@
     return;
   }
 
-  if (!incoming_seed.empty())
+  if (!incoming_seed.empty() && incoming_seed != old_seed) {
     prefs->SetString(prefs::kSwReporterPromptSeed, incoming_seed);
+    // Forget about pending prompts if prompt seed has changed.
+    if (local_state)
+      local_state->SetBoolean(prefs::kSwReporterPendingPrompt, false);
+  }
   prefs->SetString(prefs::kSwReporterPromptVersion, reporter_version);
 
   // Download the SRT.
@@ -362,6 +370,46 @@
   }
 }
 
+// Report the UwS scan times of the software reporter tool via UMA.
+void ReportSwReporterScanTimes() {
+  base::string16 scan_times_key_path = base::StringPrintf(
+      L"%ls\\%ls", kSoftwareRemovalToolRegistryKey, kScanTimesSubKey);
+  base::win::RegKey scan_times_key(HKEY_CURRENT_USER,
+                                   scan_times_key_path.c_str(), KEY_ALL_ACCESS);
+  if (!scan_times_key.Valid())
+    return;
+
+  base::string16 value_name;
+  int uws_id = 0;
+  int64 raw_scan_time = 0;
+  int num_scan_times = scan_times_key.GetValueCount();
+  for (int i = 0; i < num_scan_times; ++i) {
+    if (scan_times_key.GetValueNameAt(i, &value_name) == ERROR_SUCCESS &&
+        base::StringToInt(value_name, &uws_id) &&
+        scan_times_key.ReadInt64(value_name.c_str(), &raw_scan_time) ==
+            ERROR_SUCCESS) {
+      base::TimeDelta scan_time =
+          base::TimeDelta::FromInternalValue(raw_scan_time);
+      base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
+          kScanTimesMetricName, base::HistogramBase::kUmaTargetedHistogramFlag);
+      if (histogram) {
+        // We report the number of seconds plus one because it can take less
+        // than one second to scan some UwS and the count passed to |AddCount|
+        // must be at least one.
+        histogram->AddCount(uws_id, scan_time.InSeconds() + 1);
+      }
+    }
+  }
+  // Clean up by deleting the scan times key, which is a subkey of the main
+  // reporter key.
+  scan_times_key.Close();
+  base::win::RegKey reporter_key(HKEY_CURRENT_USER,
+                                 kSoftwareRemovalToolRegistryKey,
+                                 KEY_ENUMERATE_SUB_KEYS);
+  if (reporter_key.Valid())
+    reporter_key.DeleteKey(kScanTimesSubKey);
+}
+
 // This class tries to run the reporter and reacts to its exit code. It
 // schedules subsequent runs as needed, or retries as soon as a browser is
 // available when none is on first try.
@@ -434,6 +482,7 @@
                             base::Time::Now().ToInternalValue());
     }
     ReportSwReporterRuntime(reporter_running_time);
+    ReportSwReporterScanTimes();
 
     if (!IsInSRTPromptFieldTrialGroups()) {
       // Knowing about disabled field trial is more important than reporter not
diff --git a/chrome/browser/sessions/session_restore_android.cc b/chrome/browser/sessions/session_restore_android.cc
index 5bce046..ea2fec6 100644
--- a/chrome/browser/sessions/session_restore_android.cc
+++ b/chrome/browser/sessions/session_restore_android.cc
@@ -6,7 +6,6 @@
 
 #include <vector>
 
-#include "base/memory/scoped_vector.h"
 #include "chrome/browser/android/tab_android.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/android/tab_model/tab_model.h"
@@ -31,7 +30,7 @@
   Profile* profile = Profile::FromBrowserContext(context);
   TabModel* tab_model = TabModelList::GetTabModelForWebContents(web_contents);
   DCHECK(tab_model);
-  ScopedVector<content::NavigationEntry> scoped_entries =
+  std::vector<scoped_ptr<content::NavigationEntry>> entries =
       sessions::ContentSerializedNavigationBuilder::ToNavigationEntries(
           session_tab.navigations, profile);
   content::WebContents* new_web_contents = content::WebContents::Create(
@@ -40,7 +39,7 @@
   new_web_contents->GetController().Restore(
       selected_index,
       content::NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
-      &scoped_entries);
+      &entries);
 
   TabAndroid* current_tab = TabAndroid::FromWebContents(web_contents);
   DCHECK(current_tab);
diff --git a/chrome/browser/shell_integration_win_unittest.cc b/chrome/browser/shell_integration_win_unittest.cc
index ffe0db8..4bf9893 100644
--- a/chrome/browser/shell_integration_win_unittest.cc
+++ b/chrome/browser/shell_integration_win_unittest.cc
@@ -141,7 +141,7 @@
 
     // Shortcut 4 is like shortcut 1, but it's appid is of the same size as the
     // expected appid.
-    base::string16 same_size_as_chrome_app_id(L'1', chrome_app_id_.size());
+    base::string16 same_size_as_chrome_app_id(chrome_app_id_.size(), L'1');
     temp_properties.set_target(chrome_exe_);
     temp_properties.set_app_id(same_size_as_chrome_app_id);
     ASSERT_NO_FATAL_FAILURE(
diff --git a/chrome/browser/sync/abstract_profile_sync_service_test.cc b/chrome/browser/sync/abstract_profile_sync_service_test.cc
index c57ccd9f..d9fa08a0 100644
--- a/chrome/browser/sync/abstract_profile_sync_service_test.cc
+++ b/chrome/browser/sync/abstract_profile_sync_service_test.cc
@@ -42,11 +42,10 @@
 }
 
 AbstractProfileSyncServiceTest::AbstractProfileSyncServiceTest()
+    // Purposefully do not use a real FILE thread, see crbug/550013.
     : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD |
-                     content::TestBrowserThreadBundle::REAL_FILE_THREAD |
                      content::TestBrowserThreadBundle::REAL_IO_THREAD),
-      sync_service_(NULL) {
-}
+      sync_service_(NULL) {}
 
 AbstractProfileSyncServiceTest::~AbstractProfileSyncServiceTest() {}
 
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl.cc b/chrome/browser/sync/profile_sync_components_factory_impl.cc
index 5a3d501..a482550c 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl.cc
@@ -109,7 +109,11 @@
 
 syncer::ModelTypeSet GetEnabledTypesFromCommandLine(
     const base::CommandLine& command_line) {
-  return syncer::ModelTypeSet();
+  syncer::ModelTypeSet enabled_types;
+  if (command_line.HasSwitch(autofill::switches::kEnableWalletMetadataSync))
+    enabled_types.Put(syncer::AUTOFILL_WALLET_METADATA);
+
+  return enabled_types;
 }
 
 }  // namespace
@@ -187,10 +191,10 @@
             syncer::AUTOFILL_WALLET_DATA));
   }
 
-  // Wallet metadata sync depends on Wallet data sync. Register if Wallet data
-  // is syncing and metadata sync is not explicitly disabled.
-  if (!wallet_disabled &&
-      !disabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) {
+  // Wallet metadata sync depends on Wallet data sync and is disabled by
+  // default. Register if Wallet data is syncing and metadata sync is explicitly
+  // enabled.
+  if (!wallet_disabled && enabled_types.Has(syncer::AUTOFILL_WALLET_METADATA)) {
     sync_service->RegisterDataTypeController(
         new browser_sync::AutofillWalletDataTypeController(
             ui_thread, db_thread, error_callback, sync_client,
diff --git a/chrome/browser/sync/profile_sync_components_factory_impl_unittest.cc b/chrome/browser/sync/profile_sync_components_factory_impl_unittest.cc
index e613633..a2f2f1f 100644
--- a/chrome/browser/sync/profile_sync_components_factory_impl_unittest.cc
+++ b/chrome/browser/sync/profile_sync_components_factory_impl_unittest.cc
@@ -54,7 +54,6 @@
     datatypes.push_back(syncer::AUTOFILL);
     datatypes.push_back(syncer::AUTOFILL_PROFILE);
     datatypes.push_back(syncer::AUTOFILL_WALLET_DATA);
-    datatypes.push_back(syncer::AUTOFILL_WALLET_METADATA);
     datatypes.push_back(syncer::BOOKMARKS);
     datatypes.push_back(syncer::DEVICE_INFO);
 #if defined(OS_LINUX) || defined(OS_WIN) || defined(OS_CHROMEOS)
diff --git a/chrome/browser/sync/profile_sync_service_startup_unittest.cc b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
index 4d4fbe6d..03160fd3 100644
--- a/chrome/browser/sync/profile_sync_service_startup_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_startup_unittest.cc
@@ -107,8 +107,8 @@
 class ProfileSyncServiceStartupTest : public testing::Test {
  public:
   ProfileSyncServiceStartupTest()
+      // Purposefully do not use a real FILE thread, see crbug/550013.
       : thread_bundle_(content::TestBrowserThreadBundle::REAL_DB_THREAD |
-                       content::TestBrowserThreadBundle::REAL_FILE_THREAD |
                        content::TestBrowserThreadBundle::REAL_IO_THREAD),
         profile_manager_(TestingBrowserProcess::GetGlobal()),
         sync_(NULL) {}
@@ -255,8 +255,7 @@
   }
 };
 
-// http://crbug.com/550013
-TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartFirstTime) {
+TEST_F(ProfileSyncServiceStartupTest, StartFirstTime) {
   // We've never completed startup.
   profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncHasSetupCompleted);
   CreateSyncService();
@@ -374,13 +373,7 @@
   EXPECT_TRUE(sync_->IsSyncActive());
 }
 
-#if defined(OS_WIN)
-// http://crbug.com/396402
-#define MAYBE_StartCrosNoCredentials DISABLED_StartCrosNoCredentials
-#else
-#define MAYBE_StartCrosNoCredentials StartCrosNoCredentials
-#endif
-TEST_F(ProfileSyncServiceStartupCrosTest, MAYBE_StartCrosNoCredentials) {
+TEST_F(ProfileSyncServiceStartupCrosTest, StartCrosNoCredentials) {
   EXPECT_CALL(*GetSyncApiComponentFactoryMock(),
               CreateDataTypeManager(_, _, _, _, _))
       .Times(0);
@@ -399,8 +392,7 @@
   EXPECT_FALSE(sync_->IsSyncActive());
 }
 
-// http://crbug.com/550013
-TEST_F(ProfileSyncServiceStartupCrosTest, DISABLED_StartFirstTime) {
+TEST_F(ProfileSyncServiceStartupCrosTest, StartFirstTime) {
   SetUpSyncBackendHost();
   DataTypeManagerMock* data_type_manager = SetUpDataTypeManager();
   profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncHasSetupCompleted);
@@ -417,13 +409,7 @@
   EXPECT_TRUE(sync_->IsSyncActive());
 }
 
-#if defined(OS_WIN)
-// http://crbug.com/396402
-#define MAYBE_StartNormal DISABLED_StartNormal
-#else
-#define MAYBE_StartNormal StartNormal
-#endif
-TEST_F(ProfileSyncServiceStartupTest, MAYBE_StartNormal) {
+TEST_F(ProfileSyncServiceStartupTest, StartNormal) {
   // Pre load the tokens
   CreateSyncService();
   std::string account_id =
@@ -445,8 +431,7 @@
 // Test that we can recover from a case where a bug in the code resulted in
 // OnUserChoseDatatypes not being properly called and datatype preferences
 // therefore being left unset.
-// http://crbug.com/550013
-TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartRecoverDatatypePrefs) {
+TEST_F(ProfileSyncServiceStartupTest, StartRecoverDatatypePrefs) {
   // Clear the datatype preference fields (simulating bug 154940).
   profile_->GetPrefs()->ClearPref(
       sync_driver::prefs::kSyncKeepEverythingSynced);
@@ -479,13 +464,7 @@
 
 // Verify that the recovery of datatype preferences doesn't overwrite a valid
 // case where only bookmarks are enabled.
-#if defined(OS_WIN)
-// http://crbug.com/396402
-#define MAYBE_StartDontRecoverDatatypePrefs DISABLED_StartDontRecoverDatatypePrefs
-#else
-#define MAYBE_StartDontRecoverDatatypePrefs StartDontRecoverDatatypePrefs
-#endif
-TEST_F(ProfileSyncServiceStartupTest, MAYBE_StartDontRecoverDatatypePrefs) {
+TEST_F(ProfileSyncServiceStartupTest, StartDontRecoverDatatypePrefs) {
   // Explicitly set Keep Everything Synced to false and have only bookmarks
   // enabled.
   profile_->GetPrefs()->SetBoolean(
@@ -510,13 +489,7 @@
       sync_driver::prefs::kSyncKeepEverythingSynced));
 }
 
-#if defined(OS_WIN)
-// http://crbug.com/396402
-#define MAYBE_ManagedStartup DISABLED_ManagedStartup
-#else
-#define MAYBE_ManagedStartup ManagedStartup
-#endif
-TEST_F(ProfileSyncServiceStartupTest, MAYBE_ManagedStartup) {
+TEST_F(ProfileSyncServiceStartupTest, ManagedStartup) {
   // Service should not be started by Initialize() since it's managed.
   profile_->GetPrefs()->SetString(prefs::kGoogleServicesAccountId,
                                   kEmail);
@@ -532,8 +505,7 @@
   sync_->Initialize();
 }
 
-// http://crbug.com/550013
-TEST_F(ProfileSyncServiceStartupTest, DISABLED_SwitchManaged) {
+TEST_F(ProfileSyncServiceStartupTest, SwitchManaged) {
   CreateSyncService();
   std::string account_id =
       SimulateTestUserSignin(profile_, fake_signin(), sync_);
@@ -563,8 +535,7 @@
   profile_->GetPrefs()->ClearPref(sync_driver::prefs::kSyncManaged);
 }
 
-// http://crbug.com/550013
-TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartFailure) {
+TEST_F(ProfileSyncServiceStartupTest, StartFailure) {
   CreateSyncService();
   std::string account_id =
       SimulateTestUserSignin(profile_, fake_signin(), sync_);
@@ -590,8 +561,7 @@
   EXPECT_TRUE(sync_->HasUnrecoverableError());
 }
 
-// http://crbug.com/550013
-TEST_F(ProfileSyncServiceStartupTest, DISABLED_StartDownloadFailed) {
+TEST_F(ProfileSyncServiceStartupTest, StartDownloadFailed) {
   // Pre load the tokens
   CreateSyncService();
   std::string account_id =
diff --git a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
index e238961..540595a 100644
--- a/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
+++ b/chrome/browser/sync/profile_sync_service_typed_url_unittest.cc
@@ -377,7 +377,8 @@
                                 favicon_urls));
   }
 
-  static bool URLsEqual(history::URLRow& lhs, history::URLRow& rhs) {
+  static bool URLsEqual(const history::URLRow& lhs,
+                        const history::URLRow& rhs) {
     // Only verify the fields we explicitly sync (i.e. don't verify typed_count
     // or visit_count because we rely on the history DB to manage those values
     // and they are left unchanged by HistoryBackendMock).
@@ -429,7 +430,7 @@
   }
 }
 
-} // namespace
+}  // namespace
 
 TEST_F(ProfileSyncServiceTypedUrlTest, EmptyNativeEmptySync) {
   EXPECT_CALL((*history_backend_.get()), GetAllTypedURLs(_)).
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index 69619dd..0cfc95fb 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -137,7 +137,7 @@
       syncer::AUTOFILL_WALLET_DATA));
   // TODO(pvalenzuela): Assert that the local root node for AUTOFILL_WALLET_DATA
   // exists.
-  ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
+  ASSERT_FALSE(GetClient(0)->service()->GetActiveDataTypes().Has(
       syncer::AUTOFILL_WALLET_METADATA));
 }
 
@@ -157,7 +157,7 @@
   ASSERT_TRUE(SetupSync()) << "SetupSync() failed";
   ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
       syncer::AUTOFILL_WALLET_DATA));
-  ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
+  ASSERT_FALSE(GetClient(0)->service()->GetActiveDataTypes().Has(
       syncer::AUTOFILL_WALLET_METADATA));
 }
 
@@ -185,7 +185,7 @@
   ASSERT_FALSE(enabled_checker.TimedOut());
   ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
       syncer::AUTOFILL_WALLET_DATA));
-  ASSERT_TRUE(GetClient(0)->service()->GetActiveDataTypes().Has(
+  ASSERT_FALSE(GetClient(0)->service()->GetActiveDataTypes().Has(
       syncer::AUTOFILL_WALLET_METADATA));
 
   // Then disable the experiment.
diff --git a/chrome/browser/thumbnails/simple_thumbnail_crop.cc b/chrome/browser/thumbnails/simple_thumbnail_crop.cc
index 5af2ae9e..92bc0b4a 100644
--- a/chrome/browser/thumbnails/simple_thumbnail_crop.cc
+++ b/chrome/browser/thumbnails/simple_thumbnail_crop.cc
@@ -45,7 +45,7 @@
   if (bitmap.isNull() || bitmap.empty())
     return;
 
-  ClipResult clip_result;
+  ClipResult clip_result = context->clip_result();
   SkBitmap thumbnail = CreateThumbnail(
       bitmap,
       ComputeTargetSizeAtMaximumScale(target_size_),
diff --git a/chrome/browser/tracing/OWNERS b/chrome/browser/tracing/OWNERS
index 73bcad3..a7ae202 100644
--- a/chrome/browser/tracing/OWNERS
+++ b/chrome/browser/tracing/OWNERS
@@ -1,3 +1,4 @@
-nduca@chromium.org
 dsinclair@chromium.org
+nduca@chromium.org
+oysteine@chromium.org
 simonhatch@chromium.org
diff --git a/chrome/browser/translate/chrome_translate_client.cc b/chrome/browser/translate/chrome_translate_client.cc
index af7de8e..cf3a9606 100644
--- a/chrome/browser/translate/chrome_translate_client.cc
+++ b/chrome/browser/translate/chrome_translate_client.cc
@@ -164,8 +164,8 @@
 
 void ChromeTranslateClient::ShowTranslateUI(
     translate::TranslateStep step,
-    const std::string source_language,
-    const std::string target_language,
+    const std::string& source_language,
+    const std::string& target_language,
     translate::TranslateErrors::Type error_type,
     bool triggered_from_menu) {
   DCHECK(web_contents());
diff --git a/chrome/browser/translate/chrome_translate_client.h b/chrome/browser/translate/chrome_translate_client.h
index 841ed894..e658849 100644
--- a/chrome/browser/translate/chrome_translate_client.h
+++ b/chrome/browser/translate/chrome_translate_client.h
@@ -89,8 +89,8 @@
       scoped_ptr<translate::TranslateInfoBarDelegate> delegate) const override;
 #endif
   void ShowTranslateUI(translate::TranslateStep step,
-                       const std::string source_language,
-                       const std::string target_language,
+                       const std::string& source_language,
+                       const std::string& target_language,
                        translate::TranslateErrors::Type error_type,
                        bool triggered_from_menu) override;
   bool IsTranslatableURL(const GURL& url) override;
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 56d0947..54f16d1 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -389,6 +389,7 @@
     deps += [
       "//chrome/browser/metro_utils",
       "//chrome/installer/util:strings",
+      "//components/search_engines",
       "//google_update",
       "//third_party/wtl",
       "//third_party/iaccessible2",
diff --git a/chrome/browser/ui/browser_tabrestore.cc b/chrome/browser/ui/browser_tabrestore.cc
index 5943f38..ba24ec0 100644
--- a/chrome/browser/ui/browser_tabrestore.cc
+++ b/chrome/browser/ui/browser_tabrestore.cc
@@ -4,7 +4,6 @@
 
 #include "chrome/browser/ui/browser_tabrestore.h"
 
-#include "base/memory/scoped_vector.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/sessions/session_service.h"
@@ -72,14 +71,14 @@
   extensions::TabHelper::CreateForWebContents(web_contents);
   extensions::TabHelper::FromWebContents(web_contents)->
       SetExtensionAppById(extension_app_id);
-  ScopedVector<NavigationEntry> scoped_entries =
+  std::vector<scoped_ptr<NavigationEntry>> entries =
       ContentSerializedNavigationBuilder::ToNavigationEntries(
           navigations, browser->profile());
   web_contents->SetUserAgentOverride(user_agent_override);
   web_contents->GetController().Restore(
       selected_navigation, GetRestoreType(browser, from_last_session),
-      &scoped_entries);
-  DCHECK_EQ(0u, scoped_entries.size());
+      &entries);
+  DCHECK_EQ(0u, entries.size());
 
   return web_contents;
 }
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h
index 4904493..703d12e4 100644
--- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h
+++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.h
@@ -36,6 +36,9 @@
   // Display the identity status (e.g. verified, not verified).
   NSTextField* identityStatusField_;
 
+  // The link button for opening the DevTools Security panel for details.
+  NSButton* securityDetailsButton_;
+
   // The main content view for the Permissions tab.
   NSView* permissionsTabContentView_;
 
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
index de25d116..33117f2 100644
--- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
+++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller.mm
@@ -13,6 +13,8 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/sys_string_conversions.h"
 #import "chrome/browser/certificate_viewer.h"
+#include "chrome/browser/devtools/devtools_toggle_action.h"
+#include "chrome/browser/devtools/devtools_window.h"
 #include "chrome/browser/infobars/infobar_service.h"
 #include "chrome/browser/ui/browser_dialogs.h"
 #import "chrome/browser/ui/cocoa/browser_window_controller.h"
@@ -443,6 +445,15 @@
                                   bold:NO
                                 toView:contentView_
                                atPoint:controlOrigin];
+  controlOrigin.y +=
+      NSHeight([identityStatusField_ frame]) + kConnectionHeadlineSpacing;
+
+  NSString* securityDetailsButtonText =
+      l10n_util::GetNSString(IDS_WEBSITE_SETTINGS_DETAILS_LINK);
+  securityDetailsButton_ = [self addLinkButtonWithText:securityDetailsButtonText
+                                                toView:contentView_];
+  [securityDetailsButton_ setTarget:self];
+  [securityDetailsButton_ setAction:@selector(showSecurityPanel:)];
 
   // Create the tab view and its two tabs.
 
@@ -560,9 +571,20 @@
       NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK, false));
 }
 
+// Handler for the site settings button below the list of permissions.
+- (void)showSecurityPanel:(id)sender {
+  DCHECK(webContents_);
+  DCHECK(presenter_);
+  presenter_->RecordWebsiteSettingsAction(
+      WebsiteSettings::WEBSITE_SETTINGS_SECURITY_DETAILS_OPENED);
+  DevToolsWindow::OpenDevToolsWindow(webContents_,
+                                     DevToolsToggleAction::ShowSecurityPanel());
+}
+
 // Handler for the link button to show certificate information.
 - (void)showCertificateInfo:(id)sender {
   DCHECK(certificateId_);
+  DCHECK(presenter_);
   presenter_->RecordWebsiteSettingsAction(
       WebsiteSettings::WEBSITE_SETTINGS_CERTIFICATE_DIALOG_OPENED);
   ShowCertificateViewerByID(webContents_, [self parentWindow], certificateId_);
@@ -675,6 +697,10 @@
   CGFloat yPos = NSMaxY([identityField_ frame]) + kConnectionHeadlineSpacing;
   yPos = [self setYPositionOfView:identityStatusField_ to:yPos];
 
+  [siteSettingsButton_ setFrameOrigin:NSMakePoint(kFramePadding, yPos)];
+  yPos = NSMaxY([identityStatusField_ frame]) + kConnectionHeadlineSpacing;
+  yPos = [self setYPositionOfView:securityDetailsButton_ to:yPos];
+
   // Lay out the Permissions tab.
 
   yPos = [self setYPositionOfView:cookiesView_ to:kFramePadding];
@@ -728,7 +754,10 @@
 
   // Adjust the tab view size and place it below the identity status.
 
-  yPos = NSMaxY([identityStatusField_ frame]) + kTabStripTopSpacing;
+  yPos = NSMaxY([identityStatusField_ frame]) + kVerticalSpacing;
+  yPos = [self setYPositionOfView:segmentedControl_ to:yPos];
+
+  yPos = NSMaxY([securityDetailsButton_ frame]) + kTabStripTopSpacing;
   yPos = [self setYPositionOfView:segmentedControl_ to:yPos];
 
   CGFloat connectionTabHeight = NSMaxY([helpButton_ frame]) + kVerticalSpacing;
diff --git a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
index 627c937..6b6fa00 100644
--- a/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/website_settings/website_settings_bubble_controller_unittest.mm
@@ -176,9 +176,15 @@
     EXPECT_EQ(1U, [window_subviews count]);
     NSArray* subviews = [[window_subviews lastObject] subviews];
 
-    // Expect 4 views: the identity, identity status, the segmented control
-    // (which implements the tab strip), and the tab view.
-    EXPECT_EQ(4U, [subviews count]);
+    /**
+     *Expect 4 views:
+     * - the identity
+     * - identity status
+     * - security details link
+     * -  segmented control (which implements the tab strip),
+     * - and the tab view.
+     */
+    EXPECT_EQ(5U, [subviews count]);
 
     bool desired_result = match_type == TEXT_EQUAL;
 
diff --git a/chrome/browser/ui/passwords/manage_passwords_test.h b/chrome/browser/ui/passwords/manage_passwords_test.h
index 5f82d34..aee3613 100644
--- a/chrome/browser/ui/passwords/manage_passwords_test.h
+++ b/chrome/browser/ui/passwords/manage_passwords_test.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_UI_PASSWORDS_MANAGE_PASSWORDS_TEST_H_
 
 #include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
 #include "base/metrics/histogram_samples.h"
 #include "base/test/histogram_tester.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/ui/passwords/password_manager_presenter.cc b/chrome/browser/ui/passwords/password_manager_presenter.cc
index ec667047..5769971 100644
--- a/chrome/browser/ui/passwords/password_manager_presenter.cc
+++ b/chrome/browser/ui/passwords/password_manager_presenter.cc
@@ -131,7 +131,7 @@
 }
 
 void PasswordManagerPresenter::RequestShowPassword(size_t index) {
-#if !defined(OS_ANDROID) // This is never called on Android.
+#if !defined(OS_ANDROID)  // This is never called on Android.
   if (index >= password_list_.size()) {
     // |index| out of bounds might come from a compromised renderer, don't let
     // it crash the browser. http://crbug.com/362054
diff --git a/chrome/browser/ui/passwords/password_ui_view.h b/chrome/browser/ui/passwords/password_ui_view.h
index 3bc7732..92f1b2c 100644
--- a/chrome/browser/ui/passwords/password_ui_view.h
+++ b/chrome/browser/ui/passwords/password_ui_view.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_UI_PASSWORDS_PASSWORD_UI_VIEW_H_
 #define CHROME_BROWSER_UI_PASSWORDS_PASSWORD_UI_VIEW_H_
 
+#include <string>
+
 #include "base/memory/scoped_vector.h"
 #include "ui/gfx/native_widget_types.h"
 
diff --git a/chrome/browser/ui/startup/startup_browser_creator.cc b/chrome/browser/ui/startup/startup_browser_creator.cc
index 0eba5e7..9e9daf6 100644
--- a/chrome/browser/ui/startup/startup_browser_creator.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator.cc
@@ -92,6 +92,8 @@
 
 #if defined(OS_WIN)
 #include "chrome/browser/metrics/jumplist_metrics_win.h"
+#include "components/search_engines/detect_desktop_search_win.h"
+#include "components/search_engines/search_engines_switches.h"
 #endif
 
 #if defined(ENABLE_PRINT_PREVIEW)
@@ -549,6 +551,26 @@
     // Allow it until this bug is fixed.
     //  http://code.google.com/p/chromium/issues/detail?id=60641
     GURL url = GURL(param.MaybeAsASCII());
+
+#if defined(OS_WIN)
+    if (command_line.HasSwitch(
+            switches::kUseDefaultSearchProviderForDesktopSearch)) {
+      TemplateURLService* template_url_service =
+          TemplateURLServiceFactory::GetForProfile(profile);
+      DCHECK(template_url_service);
+      base::string16 search_terms;
+      if (DetectWindowsDesktopSearch(
+              url, template_url_service->search_terms_data(), &search_terms)) {
+        GURL search_url(GetDefaultSearchURLForSearchTerms(template_url_service,
+                                                          search_terms));
+        if (search_url.is_valid()) {
+          urls.push_back(search_url);
+          continue;
+        }
+      }
+    }
+#endif  // defined(OS_WIN)
+
     // http://crbug.com/371030: Only use URLFixerUpper if we don't have a valid
     // URL, otherwise we will look in the current directory for a file named
     // 'about' if the browser was started with a about:foo argument.
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 9e5bfe7..680f94f 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -496,14 +496,9 @@
     bool process_startup,
     const std::vector<GURL>& urls_to_open,
     chrome::HostDesktopType desktop_type) {
-  // If we're starting up in "background mode" (no open browser window) then
-  // don't open any browser windows, unless kAutoLaunchAtStartup is also
-  // specified.
-  if (process_startup &&
-      command_line_.HasSwitch(switches::kNoStartupWindow) &&
-      !command_line_.HasSwitch(switches::kAutoLaunchAtStartup)) {
+  // Don't open any browser windows if we're starting up in "background mode".
+  if (process_startup && command_line_.HasSwitch(switches::kNoStartupWindow))
     return;
-  }
 
   // Determine whether or not this launch must include the welcome page.
   InitializeWelcomeRunType(urls_to_open);
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index 8ebb1e9..0433956 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -50,6 +50,7 @@
 #include "content/public/browser/web_contents.h"
 
 #if defined(OS_ANDROID)
+#include "chrome/browser/android/data_usage/data_use_tab_helper.h"
 #include "chrome/browser/android/voice_search_tab_helper.h"
 #include "chrome/browser/android/webapps/single_tab_mode_tab_helper.h"
 #include "chrome/browser/ui/android/context_menu_helper.h"
@@ -164,11 +165,7 @@
   ManagePasswordsUIController::CreateForWebContents(web_contents);
   NavigationCorrectionTabObserver::CreateForWebContents(web_contents);
   NavigationMetricsRecorder::CreateForWebContents(web_contents);
-  // rappor_service will either be null or share a lifetime with the
-  // BrowserProcess g_browser_process. The above ensures rappor_service() will
-  // survive as long as the web_contents will survive.
-  chrome::InitializePageLoadMetricsForWebContents(
-      web_contents, g_browser_process->rappor_service());
+  chrome::InitializePageLoadMetricsForWebContents(web_contents);
   PopupBlockerTabHelper::CreateForWebContents(web_contents);
   PrefsTabHelper::CreateForWebContents(web_contents);
   prerender::PrerenderTabHelper::CreateForWebContents(web_contents);
@@ -184,6 +181,7 @@
 
 #if defined(OS_ANDROID)
   ContextMenuHelper::CreateForWebContents(web_contents);
+  DataUseTabHelper::CreateForWebContents(web_contents);
   SingleTabModeTabHelper::CreateForWebContents(web_contents);
   VoiceSearchTabHelper::CreateForWebContents(web_contents);
   WindowAndroidHelper::CreateForWebContents(web_contents);
diff --git a/chrome/browser/ui/toolbar/media_router_action.cc b/chrome/browser/ui/toolbar/media_router_action.cc
index 2b9f59b..2fbdbe7 100644
--- a/chrome/browser/ui/toolbar/media_router_action.cc
+++ b/chrome/browser/ui/toolbar/media_router_action.cc
@@ -50,7 +50,7 @@
           ui::ResourceBundle::GetSharedInstance()
               .GetImageNamed(IDR_MEDIA_ROUTER_WARNING_ICON)),
       current_icon_(&media_router_idle_icon_),
-      has_local_route_(false),
+      has_local_display_route_(false),
       delegate_(nullptr),
       browser_(browser),
       platform_delegate_(MediaRouterActionPlatformDelegate::Create(browser)),
@@ -61,7 +61,8 @@
   tab_strip_model_observer_.Add(browser_->tab_strip_model());
 
   RegisterObserver();
-  OnHasLocalRouteUpdated(GetMediaRouter(browser)->HasLocalRoute());
+  OnHasLocalDisplayRouteUpdated(
+      GetMediaRouter(browser)->HasLocalDisplayRoute());
 }
 
 MediaRouterAction::~MediaRouterAction() {
@@ -158,8 +159,9 @@
   MaybeUpdateIcon();
 }
 
-void MediaRouterAction::OnHasLocalRouteUpdated(bool has_local_route) {
-  has_local_route_ = has_local_route;
+void MediaRouterAction::OnHasLocalDisplayRouteUpdated(
+    bool has_local_display_route) {
+  has_local_display_route_ = has_local_display_route;
   MaybeUpdateIcon();
 }
 
@@ -237,6 +239,6 @@
       return &media_router_warning_icon_;
   }
 
-  return has_local_route_ ?
-      &media_router_active_icon_ : &media_router_idle_icon_;
+  return has_local_display_route_ ? &media_router_active_icon_
+                                  : &media_router_idle_icon_;
 }
diff --git a/chrome/browser/ui/toolbar/media_router_action.h b/chrome/browser/ui/toolbar/media_router_action.h
index ba35300..f7797c0b 100644
--- a/chrome/browser/ui/toolbar/media_router_action.h
+++ b/chrome/browser/ui/toolbar/media_router_action.h
@@ -54,7 +54,7 @@
   void OnIssueUpdated(const media_router::Issue* issue) override;
 
   // media_router::LocalMediaRoutesObserver:
-  void OnHasLocalRouteUpdated(bool has_local_route) override;
+  void OnHasLocalDisplayRouteUpdated(bool has_local_display_route) override;
 
   // ToolbarStripModelObserver:
   void ActiveTabChanged(content::WebContents* old_contents,
@@ -103,8 +103,8 @@
   // in OnIssueUpdated(), which is called by the IssueManager.
   scoped_ptr<media_router::Issue> issue_;
 
-  // Whether a local active route exists.
-  bool has_local_route_;
+  // Whether a local displayable active route exists.
+  bool has_local_display_route_;
 
   ToolbarActionViewDelegate* delegate_;
 
diff --git a/chrome/browser/ui/toolbar/media_router_action_unittest.cc b/chrome/browser/ui/toolbar/media_router_action_unittest.cc
index d558ee7a..579e983 100644
--- a/chrome/browser/ui/toolbar/media_router_action_unittest.cc
+++ b/chrome/browser/ui/toolbar/media_router_action_unittest.cc
@@ -195,12 +195,12 @@
       idle_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
   // Update |current_icon_| since there is a local route.
-  action()->OnHasLocalRouteUpdated(true);
+  action()->OnHasLocalDisplayRouteUpdated(true);
   EXPECT_TRUE(gfx::test::AreImagesEqual(
       active_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
   // Update |current_icon_| since there are no local routes.
-  action()->OnHasLocalRouteUpdated(false);
+  action()->OnHasLocalDisplayRouteUpdated(false);
   EXPECT_TRUE(gfx::test::AreImagesEqual(
       idle_icon(), action()->GetIcon(nullptr, gfx::Size())));
 }
@@ -218,12 +218,12 @@
       idle_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
   // Non-local routes also do not have an effect on |current_icon_|.
-  action()->OnHasLocalRouteUpdated(false);
+  action()->OnHasLocalDisplayRouteUpdated(false);
   EXPECT_TRUE(gfx::test::AreImagesEqual(
       idle_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
   // Update |current_icon_| since there is a local route.
-  action()->OnHasLocalRouteUpdated(true);
+  action()->OnHasLocalDisplayRouteUpdated(true);
   EXPECT_TRUE(gfx::test::AreImagesEqual(
       active_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
@@ -234,7 +234,7 @@
       warning_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
   // Closing a local route makes no difference to |current_icon_|.
-  action()->OnHasLocalRouteUpdated(false);
+  action()->OnHasLocalDisplayRouteUpdated(false);
   EXPECT_TRUE(gfx::test::AreImagesEqual(
       warning_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
@@ -244,7 +244,7 @@
       error_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
   // Fatal issues still take precedent over local routes.
-  action()->OnHasLocalRouteUpdated(true);
+  action()->OnHasLocalDisplayRouteUpdated(true);
   EXPECT_TRUE(gfx::test::AreImagesEqual(
       error_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
@@ -255,7 +255,7 @@
       active_icon(), action()->GetIcon(nullptr, gfx::Size())));
 
   // Update |current_icon_| when the local route is closed.
-  action()->OnHasLocalRouteUpdated(false);
+  action()->OnHasLocalDisplayRouteUpdated(false);
   EXPECT_TRUE(gfx::test::AreImagesEqual(
       idle_icon(), action()->GetIcon(nullptr, gfx::Size())));
 }
diff --git a/chrome/browser/ui/views/layout_constants.cc b/chrome/browser/ui/views/layout_constants.cc
index c291e7a..de59375 100644
--- a/chrome/browser/ui/views/layout_constants.cc
+++ b/chrome/browser/ui/views/layout_constants.cc
@@ -9,8 +9,7 @@
 
 int GetLayoutConstant(LayoutConstant constant) {
   const int kFindBarVerticalOffset[] = {1, 6, 6};
-  // The -1 means the label and the icon will overlap by a pixel.
-  const int kIconLabelViewInternalPadding[] = {3, -1, -1};
+  const int kIconLabelViewInternalPadding[] = {3, 2, 2};
   const int kIconLabelViewTrailingPadding[] = {2, 8, 8};
   const int kLocationBarBorderThickness[] = {2, 1, 1};
   const int kLocationBarBubbleHorizontalPadding[] = {1, 4, 4};
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index ca74f171..41462f9 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -86,6 +86,13 @@
   return 1.0;
 }
 
+int IconLabelBubbleView::GetImageAndPaddingWidth() const {
+  const int image_width = image_->GetPreferredSize().width();
+  return image_width
+             ? image_width + GetLayoutConstant(ICON_LABEL_VIEW_INTERNAL_PADDING)
+             : 0;
+}
+
 gfx::Size IconLabelBubbleView::GetPreferredSize() const {
   // Height will be ignored by the LocationBarView.
   return GetSizeForLabelWidth(label_->GetPreferredSize().width());
@@ -102,9 +109,7 @@
                              GetBubbleOuterPadding(icon_has_enough_padding)),
                     0, image_->GetPreferredSize().width(), height());
 
-  const int padding = GetLayoutConstant(ICON_LABEL_VIEW_INTERNAL_PADDING);
-  int pre_label_width =
-      GetBubbleOuterPadding(true) + (image_width ? (image_width + padding) : 0);
+  int pre_label_width = GetBubbleOuterPadding(true) + GetImageAndPaddingWidth();
   label_->SetBounds(pre_label_width, 0,
                     width() - pre_label_width - GetBubbleOuterPadding(false),
                     height());
@@ -126,12 +131,9 @@
 gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int width) const {
   gfx::Size size(image_->GetPreferredSize());
   if (ShouldShowBackground()) {
-    const int image_width = image_->GetPreferredSize().width();
-    const int padding = GetLayoutConstant(ICON_LABEL_VIEW_INTERNAL_PADDING);
-    const int non_label_width =
-        GetBubbleOuterPadding(true) +
-        (image_width ? (image_width + padding) : 0) +
-        GetBubbleOuterPadding(false);
+    const int non_label_width = GetBubbleOuterPadding(true) +
+                                GetImageAndPaddingWidth() +
+                                GetBubbleOuterPadding(false);
     size = gfx::Size(WidthMultiplier() * (width + non_label_width), 0);
     if (!ui::MaterialDesignController::IsModeMaterial())
       size.SetToMax(background_painter_->GetMinimumSize());
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index 7978cf9..72f0e4a 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -68,6 +68,10 @@
   // full-width view and can be used to animate the width of the view.
   virtual double WidthMultiplier() const;
 
+  // Returns the amount of horizontal space needed to draw the image and its
+  // padding before the label.
+  virtual int GetImageAndPaddingWidth() const;
+
   // views::View:
   gfx::Size GetPreferredSize() const override;
   void Layout() override;
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
index 15eea50..d5bf2dd 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.cc
@@ -110,3 +110,14 @@
 const char* SelectedKeywordView::GetClassName() const {
   return "SelectedKeywordView";
 }
+
+int SelectedKeywordView::GetImageAndPaddingWidth() const {
+  int width = IconLabelBubbleView::GetImageAndPaddingWidth();
+  // Squeeze the icon and label closer to account for intrinsic padding in the
+  // icon.
+  if (ui::MaterialDesignController::IsModeMaterial() && width > 0)
+    width -= 3;
+
+  DCHECK_GT(width, 0);
+  return width;
+}
diff --git a/chrome/browser/ui/views/location_bar/selected_keyword_view.h b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
index 3db92b3..e85f819 100644
--- a/chrome/browser/ui/views/location_bar/selected_keyword_view.h
+++ b/chrome/browser/ui/views/location_bar/selected_keyword_view.h
@@ -46,6 +46,7 @@
  private:
   // IconLabelBubbleView:
   const char* GetClassName() const override;
+  int GetImageAndPaddingWidth() const override;
 
   // The keyword we're showing. If empty, no keyword is selected.
   // NOTE: we don't cache the TemplateURL as it is possible for it to get
diff --git a/chrome/browser/ui/website_settings/website_settings.h b/chrome/browser/ui/website_settings/website_settings.h
index c6b0d669..2b5524c 100644
--- a/chrome/browser/ui/website_settings/website_settings.h
+++ b/chrome/browser/ui/website_settings/website_settings.h
@@ -88,6 +88,7 @@
     // WEBSITE_SETTINGS_TRANSPARENCY_VIEWER_OPENED = 7,
     WEBSITE_SETTINGS_CONNECTION_HELP_OPENED = 8,
     WEBSITE_SETTINGS_SITE_SETTINGS_OPENED = 9,
+    WEBSITE_SETTINGS_SECURITY_DETAILS_OPENED = 10,
     WEBSITE_SETTINGS_COUNT
   };
 
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
index 0822a72..dd9188c 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.cc
@@ -82,6 +82,16 @@
       test_data_dir_.AppendASCII("packaged_app")));
 }
 
+void ExtensionSettingsUIBrowserTest::InstallHostedApp() {
+  EXPECT_TRUE(InstallUnpackedExtension(
+      test_data_dir_.AppendASCII("hosted_app")));
+}
+
+void ExtensionSettingsUIBrowserTest::InstallPlatformApp() {
+  EXPECT_TRUE(InstallUnpackedExtension(
+      test_data_dir_.AppendASCII("platform_apps").AppendASCII("minimal")));
+}
+
 void ExtensionSettingsUIBrowserTest::AddManagedPolicyProvider() {
   auto* extension_service = extensions::ExtensionSystem::Get(GetProfile());
   extension_service->management_policy()->RegisterProvider(&policy_provider_);
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
index 71ee675..f04fd35 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
+++ b/chrome/browser/ui/webui/extensions/extension_settings_browsertest.h
@@ -39,6 +39,10 @@
 
   void InstallPackagedApp();
 
+  void InstallHostedApp();
+
+  void InstallPlatformApp();
+
   void AddManagedPolicyProvider();
 
   void SetAutoConfirmUninstall();
diff --git a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
index d81c695..797261c 100644
--- a/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_dialog_controller_impl.cc
@@ -34,10 +34,12 @@
 using ui::WebDialogDelegate;
 
 namespace {
+#if defined(OS_MACOSX)
+const int kFixedHeight = 265;
+#else
 const int kMaxHeight = 400;
-#if !defined(OS_MACOSX)
 const int kMinHeight = 80;
-#endif  // !defined(OS_MACOSX)
+#endif
 const int kWidth = 340;
 }
 
@@ -104,7 +106,7 @@
   DCHECK(size);
   // TODO(apacible): Remove after autoresizing is implemented for OSX.
 #if defined(OS_MACOSX)
-  *size = gfx::Size(kWidth, kMaxHeight);
+  *size = gfx::Size(kWidth, kFixedHeight);
 #else
   // size is not used because the dialog is auto-resizeable.
   *size = gfx::Size();
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.cc b/chrome/browser/ui/webui/media_router/media_router_ui.cc
index bd52e04..b66fb77 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.cc
@@ -32,6 +32,8 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/constants.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/web_dialogs/web_dialog_delegate.h"
@@ -44,30 +46,35 @@
 const int kCreateRouteTimeoutSeconds = 20;
 
 std::string GetHostFromURL(const GURL& gurl) {
-  if (gurl.is_empty())
-    return std::string();
+  if (gurl.is_empty()) return std::string();
   std::string host = gurl.host();
   if (base::StartsWith(host, "www.", base::CompareCase::INSENSITIVE_ASCII))
     host = host.substr(4);
   return host;
 }
 
-std::string GetTruncatedHostFromURL(const GURL& gurl) {
-  std::string host = GetHostFromURL(gurl);
-
+std::string TruncateHost(const std::string& host) {
   const std::string truncated =
       net::registry_controlled_domains::GetDomainAndRegistry(
-          host,
-          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+          host, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
   // The truncation will be empty in some scenarios (e.g. host is
   // simply an IP address). Fail gracefully.
-  if (truncated.empty())
-    return host;
-  return truncated;
+  return truncated.empty() ? host : truncated;
 }
 
 }  // namespace
 
+// static
+std::string MediaRouterUI::GetExtensionName(
+    const GURL& gurl, extensions::ExtensionRegistry* registry) {
+  if (gurl.is_empty() || !registry) return std::string();
+
+  const extensions::Extension* extension =
+      registry->enabled_extensions().GetExtensionOrAppByURL(gurl);
+
+  return extension ? extension->name() : std::string();
+}
+
 // This class calls to refresh the UI when the highest priority issue is
 // updated.
 class MediaRouterUI::UIIssuesObserver : public IssuesObserver {
@@ -90,8 +97,7 @@
 };
 
 MediaRouterUI::UIMediaRoutesObserver::UIMediaRoutesObserver(
-    MediaRouter* router,
-    const RoutesUpdatedCallback& callback)
+    MediaRouter* router, const RoutesUpdatedCallback& callback)
     : MediaRoutesObserver(router), callback_(callback) {
   DCHECK(!callback_.is_null());
 }
@@ -107,8 +113,8 @@
       for (const MediaRoute& existing_route : routes_for_display) {
         if (existing_route.media_sink_id() == route.media_sink_id()) {
           DVLOG(2) << "Received another route for display with the same sink"
-                   << " id as an existing route. "
-                   << route.media_route_id() << " has the same sink id as "
+                   << " id as an existing route. " << route.media_route_id()
+                   << " has the same sink id as "
                    << existing_route.media_sink_id() << ".";
         }
       }
@@ -157,11 +163,9 @@
 }
 
 MediaRouterUI::~MediaRouterUI() {
-  if (issues_observer_)
-    issues_observer_->UnregisterObserver();
+  if (issues_observer_) issues_observer_->UnregisterObserver();
 
-  if (query_result_manager_.get())
-    query_result_manager_->RemoveObserver(this);
+  if (query_result_manager_.get()) query_result_manager_->RemoveObserver(this);
   if (presentation_service_delegate_.get())
     presentation_service_delegate_->RemoveDefaultPresentationRequestObserver(
         this);
@@ -217,13 +221,13 @@
   query_result_manager_->AddObserver(this);
 
   // These modes are always available.
-  query_result_manager_->StartSinksQuery(
-      MediaCastMode::DESKTOP_MIRROR, MediaSourceForDesktop());
+  query_result_manager_->StartSinksQuery(MediaCastMode::DESKTOP_MIRROR,
+                                         MediaSourceForDesktop());
   initiator_ = initiator;
   MediaSource mirroring_source(
       MediaSourceForTab(SessionTabHelper::IdForTab(initiator)));
-  query_result_manager_->StartSinksQuery(
-      MediaCastMode::TAB_MIRROR, mirroring_source);
+  query_result_manager_->StartSinksQuery(MediaCastMode::TAB_MIRROR,
+                                         mirroring_source);
   UpdateCastModes();
 }
 
@@ -245,8 +249,7 @@
   // Gets updated cast modes from |query_result_manager_| and forwards it to UI.
   query_result_manager_->GetSupportedCastModes(&cast_modes_);
   if (ui_initialized_) {
-    handler_->UpdateCastModes(
-        cast_modes_, GetHostFromURL(GetFrameURL()));
+    handler_->UpdateCastModes(cast_modes_, GetPresentationRequestSourceName());
   }
 }
 
@@ -315,10 +318,9 @@
   // treat subsequent route requests from a Presentation API-initiated dialogs
   // as browser-initiated.
   std::vector<MediaRouteResponseCallback> route_response_callbacks;
-  route_response_callbacks.push_back(
-      base::Bind(&MediaRouterUI::OnRouteResponseReceived,
-                 weak_factory_.GetWeakPtr(), current_route_request_id_,
-                 sink_id));
+  route_response_callbacks.push_back(base::Bind(
+      &MediaRouterUI::OnRouteResponseReceived, weak_factory_.GetWeakPtr(),
+      current_route_request_id_, sink_id));
   if (requesting_route_for_default_source_) {
     if (create_session_request_) {
       // |create_session_request_| will be nullptr after this call, as the
@@ -335,11 +337,10 @@
 
   // Start the timer.
   route_creation_timer_.Start(
-      FROM_HERE, base::TimeDelta::FromSeconds(kCreateRouteTimeoutSeconds),
-      this, &MediaRouterUI::RouteCreationTimeout);
+      FROM_HERE, base::TimeDelta::FromSeconds(kCreateRouteTimeoutSeconds), this,
+      &MediaRouterUI::RouteCreationTimeout);
 
-  router_->CreateRoute(source.id(), sink_id, origin,
-                       initiator_,
+  router_->CreateRoute(source.id(), sink_id, origin, initiator_,
                        route_response_callbacks);
   return true;
 }
@@ -348,9 +349,7 @@
   router_->CloseRoute(route_id);
 }
 
-void MediaRouterUI::AddIssue(const Issue& issue) {
-  router_->AddIssue(issue);
-}
+void MediaRouterUI::AddIssue(const Issue& issue) { router_->AddIssue(issue); }
 
 void MediaRouterUI::ClearIssue(const std::string& issue_id) {
   router_->ClearIssue(issue_id);
@@ -359,19 +358,16 @@
 void MediaRouterUI::OnResultsUpdated(
     const std::vector<MediaSinkWithCastModes>& sinks) {
   sinks_ = sinks;
-  if (ui_initialized_)
-    handler_->UpdateSinks(sinks_);
+  if (ui_initialized_) handler_->UpdateSinks(sinks_);
 }
 
 void MediaRouterUI::SetIssue(const Issue* issue) {
-  if (ui_initialized_)
-    handler_->UpdateIssue(issue);
+  if (ui_initialized_) handler_->UpdateIssue(issue);
 }
 
 void MediaRouterUI::OnRoutesUpdated(const std::vector<MediaRoute>& routes) {
   routes_ = routes;
-  if (ui_initialized_)
-    handler_->UpdateRoutes(routes_);
+  if (ui_initialized_) handler_->UpdateRoutes(routes_);
 }
 
 void MediaRouterUI::OnRouteResponseReceived(const int route_request_id,
@@ -381,8 +377,7 @@
                                             const std::string& error) {
   DVLOG(1) << "OnRouteResponseReceived";
   // If we receive a new route that we aren't expecting, do nothing.
-  if (route_request_id != current_route_request_id_)
-    return;
+  if (route_request_id != current_route_request_id_) return;
 
   if (!route) {
     // The provider will handle sending an issue for a failed route request.
@@ -399,32 +394,43 @@
   requesting_route_for_default_source_ = false;
   current_route_request_id_ = -1;
 
-  base::string16 host = base::UTF8ToUTF16(GetTruncatedHostFromURL(
-      GetFrameURL()));
+  base::string16 host =
+      base::UTF8ToUTF16(GetTruncatedPresentationRequestSourceName());
 
   // TODO(apacible): Update error messages based on current cast mode
   // (e.g. desktop).
-  std::string issue_title = host.empty() ?
-      l10n_util::GetStringUTF8(
-          IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_TIMEOUT_FOR_TAB) :
-      l10n_util::GetStringFUTF8(IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_TIMEOUT,
-                                host);
+  std::string issue_title =
+      host.empty() ? l10n_util::GetStringUTF8(
+                         IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_TIMEOUT_FOR_TAB)
+                   : l10n_util::GetStringFUTF8(
+                         IDS_MEDIA_ROUTER_ISSUE_CREATE_ROUTE_TIMEOUT, host);
 
   Issue issue(issue_title, std::string(),
-      IssueAction(IssueAction::TYPE_DISMISS),
-      std::vector<IssueAction>(), std::string(), Issue::NOTIFICATION,
-      false, std::string());
+              IssueAction(IssueAction::TYPE_DISMISS),
+              std::vector<IssueAction>(), std::string(), Issue::NOTIFICATION,
+              false, std::string());
   AddIssue(issue);
   handler_->NotifyRouteCreationTimeout();
 }
 
 GURL MediaRouterUI::GetFrameURL() const {
-  return presentation_request_ ? presentation_request_->frame_url() :
-      GURL();
+  return presentation_request_ ? presentation_request_->frame_url() : GURL();
 }
 
-std::string MediaRouterUI::GetFrameURLHost() const {
-  return GetHostFromURL(GetFrameURL());
+std::string MediaRouterUI::GetPresentationRequestSourceName() const {
+  GURL gurl = GetFrameURL();
+  return gurl.SchemeIs(extensions::kExtensionScheme)
+             ? GetExtensionName(gurl, extensions::ExtensionRegistry::Get(
+                                          Profile::FromWebUI(web_ui())))
+             : GetHostFromURL(gurl);
+}
+
+std::string MediaRouterUI::GetTruncatedPresentationRequestSourceName() const {
+  GURL gurl = GetFrameURL();
+  return gurl.SchemeIs(extensions::kExtensionScheme)
+             ? GetExtensionName(gurl, extensions::ExtensionRegistry::Get(
+                                          Profile::FromWebUI(web_ui())))
+             : TruncateHost(GetHostFromURL(gurl));
 }
 
 const std::string& MediaRouterUI::GetRouteProviderExtensionId() const {
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui.h b/chrome/browser/ui/webui/media_router/media_router_ui.h
index f18ce31..958b5bb7b 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui.h
+++ b/chrome/browser/ui/webui/media_router/media_router_ui.h
@@ -27,6 +27,10 @@
 class WebContents;
 }  // namespace content
 
+namespace extensions {
+class ExtensionRegistry;
+}  // namespace extensions
+
 namespace media_router {
 
 class IssuesObserver;
@@ -104,7 +108,8 @@
   void ClearIssue(const Issue::Id& issue_id);
 
   // Returns the hostname of the default source's parent frame URL.
-  std::string GetFrameURLHost() const;
+  std::string GetPresentationRequestSourceName() const;
+  std::string GetTruncatedPresentationRequestSourceName() const;
   bool HasPendingRouteRequest() const {
     return current_route_request_id_ != -1;
   }
@@ -119,6 +124,11 @@
  private:
   FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
                            UIMediaRoutesObserverFiltersNonDisplayRoutes);
+  FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest, GetExtensionNameExtensionPresent);
+  FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
+                           GetExtensionNameEmptyWhenNotInstalled);
+  FRIEND_TEST_ALL_PREFIXES(MediaRouterUITest,
+                           GetExtensionNameEmptyWhenNotExtensionURL);
 
   class UIIssuesObserver;
   class UIMediaRoutesObserver : public MediaRoutesObserver {
@@ -139,6 +149,9 @@
     DISALLOW_COPY_AND_ASSIGN(UIMediaRoutesObserver);
   };
 
+  static std::string GetExtensionName(const GURL& url,
+                                      extensions::ExtensionRegistry* registry);
+
   // QueryResultManager::Observer
   void OnResultsUpdated(
       const std::vector<MediaSinkWithCastModes>& sinks) override;
diff --git a/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc b/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
index 44bb9d0e..3b4ff917 100644
--- a/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_ui_unittest.cc
@@ -6,6 +6,11 @@
 #include "chrome/browser/media/router/media_route.h"
 #include "chrome/browser/media/router/mock_media_router.h"
 #include "chrome/browser/ui/webui/media_router/media_router_ui.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_builder.h"
+#include "extensions/common/test_util.h"
+#include "extensions/common/value_builder.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -55,4 +60,37 @@
   observer.reset();
 }
 
+TEST_F(MediaRouterUITest, GetExtensionNameExtensionPresent) {
+  std::string id = "extensionid";
+  GURL url = GURL("chrome-extension://" + id);
+  scoped_ptr<extensions::ExtensionRegistry> registry =
+      make_scoped_ptr(new extensions::ExtensionRegistry(nullptr));
+  scoped_refptr<extensions::Extension> app =
+      extensions::test_util::BuildApp(extensions::ExtensionBuilder().Pass())
+          .MergeManifest(
+              extensions::DictionaryBuilder().Set("name", "test app name"))
+          .SetID(id)
+          .Build();
+
+  ASSERT_TRUE(registry->AddEnabled(app));
+  EXPECT_EQ("test app name",
+            MediaRouterUI::GetExtensionName(url, registry.get()));
+}
+
+TEST_F(MediaRouterUITest, GetExtensionNameEmptyWhenNotInstalled) {
+  std::string id = "extensionid";
+  GURL url = GURL("chrome-extension://" + id);
+  scoped_ptr<extensions::ExtensionRegistry> registry =
+      make_scoped_ptr(new extensions::ExtensionRegistry(nullptr));
+
+  EXPECT_EQ("", MediaRouterUI::GetExtensionName(url, registry.get()));
+}
+
+TEST_F(MediaRouterUITest, GetExtensionNameEmptyWhenNotExtensionURL) {
+  GURL url = GURL("https://www.google.com");
+  scoped_ptr<extensions::ExtensionRegistry> registry =
+      make_scoped_ptr(new extensions::ExtensionRegistry(nullptr));
+
+  EXPECT_EQ("", MediaRouterUI::GetExtensionName(url, registry.get()));
+}
 }  // namespace media_router
diff --git a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
index 9c9092ec..4c911f9 100644
--- a/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
+++ b/chrome/browser/ui/webui/media_router/media_router_webui_message_handler.cc
@@ -276,7 +276,8 @@
 
   const std::set<MediaCastMode> cast_modes = media_router_ui_->cast_modes();
   scoped_ptr<base::ListValue> cast_modes_list(
-      CastModesToValue(cast_modes, media_router_ui_->GetFrameURLHost()));
+      CastModesToValue(cast_modes,
+                       media_router_ui_->GetPresentationRequestSourceName()));
   initial_data.Set("castModes", cast_modes_list.release());
   if (!cast_modes.empty()) {
     initial_data.SetInteger("initialCastModeType",
diff --git a/chrome/browser/ui/webui/media_router/query_result_manager.cc b/chrome/browser/ui/webui/media_router/query_result_manager.cc
index f7d4588..43547bb 100644
--- a/chrome/browser/ui/webui/media_router/query_result_manager.cc
+++ b/chrome/browser/ui/webui/media_router/query_result_manager.cc
@@ -87,6 +87,7 @@
 
   linked_ptr<CastModeMediaSinksObserver> observer(
       new CastModeMediaSinksObserver(cast_mode, source, router_, this));
+  observer->Init();
   auto result = sinks_observers_.insert(std::make_pair(cast_mode, observer));
   DCHECK(result.second);
   NotifyOnResultsUpdated();
diff --git a/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc b/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc
index ca98ba5..0483852 100644
--- a/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc
+++ b/chrome/browser/ui/webui/media_router/query_result_manager_unittest.cc
@@ -40,7 +40,8 @@
   }
 
   void DiscoverSinks(MediaCastMode cast_mode, const MediaSource& source) {
-    EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)).Times(1);
+    EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_))
+        .WillOnce(Return(true));
     EXPECT_CALL(mock_observer_, OnResultsUpdated(_)).Times(1);
     query_result_manager_.StartSinksQuery(cast_mode, source);
   }
@@ -93,7 +94,8 @@
   EXPECT_TRUE(actual_source.Empty());
 
   MediaSource source(MediaSourceForPresentationUrl("http://fooUrl"));
-  EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)).Times(1);
+  EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_))
+      .WillOnce(Return(true));
   query_result_manager_.StartSinksQuery(MediaCastMode::DEFAULT, source);
 
   query_result_manager_.GetSupportedCastModes(&cast_modes);
@@ -106,7 +108,8 @@
   // Register a different source for the same cast mode.
   MediaSource another_source(MediaSourceForPresentationUrl("http://barUrl"));
   EXPECT_CALL(mock_router_, UnregisterMediaSinksObserver(_)).Times(1);
-  EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)).Times(1);
+  EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_))
+      .WillOnce(Return(true));
   query_result_manager_.StartSinksQuery(
       MediaCastMode::DEFAULT, another_source);
 
@@ -204,7 +207,8 @@
   expected_sinks.back().cast_modes.insert(MediaCastMode::TAB_MIRROR);
 
   EXPECT_CALL(mock_router_, UnregisterMediaSinksObserver(_)).Times(1);
-  EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_)).Times(1);
+  EXPECT_CALL(mock_router_, RegisterMediaSinksObserver(_))
+      .WillOnce(Return(true));
   EXPECT_CALL(mock_observer_,
               OnResultsUpdated(VectorEquals(expected_sinks))).Times(1);
   query_result_manager_.StartSinksQuery(
diff --git a/chrome/browser/ui/webui/options/clear_browser_data_handler.cc b/chrome/browser/ui/webui/options/clear_browser_data_handler.cc
index bcd8569..b14ec95 100644
--- a/chrome/browser/ui/webui/options/clear_browser_data_handler.cc
+++ b/chrome/browser/ui/webui/options/clear_browser_data_handler.cc
@@ -59,6 +59,17 @@
   return true;
 }
 
+// A helper function to display the size of cache in units of MB or higher.
+// We need this, as 1 MB is the lowest nonzero cache size displayed by the
+// counter.
+base::string16 FormatBytesMBOrHigher(BrowsingDataCounter::ResultInt bytes) {
+  if (ui::GetByteDisplayUnits(bytes) >= ui::DataUnits::DATA_UNITS_MEBIBYTE)
+    return ui::FormatBytes(bytes);
+
+  return ui::FormatBytesWithUnits(
+      bytes, ui::DataUnits::DATA_UNITS_MEBIBYTE, true);
+}
+
 }  // namespace
 
 namespace options {
@@ -170,15 +181,13 @@
     // a subset of cache (i.e. a finite time interval), and almost zero (< 1MB).
     static const int kBytesInAMegabyte = 1024 * 1024;
     if (cache_size_bytes >= kBytesInAMegabyte) {
-      base::string16 formatted_size = ui::FormatBytes(cache_size_bytes);
+      base::string16 formatted_size = FormatBytesMBOrHigher(cache_size_bytes);
       text = time_period == BrowsingDataRemover::EVERYTHING
           ? formatted_size
           : l10n_util::GetStringFUTF16(IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE,
                                        formatted_size);
     } else {
-      base::string16 formatted_size = ui::FormatBytes(kBytesInAMegabyte);
-      text = l10n_util::GetStringFUTF16(IDS_DEL_CACHE_COUNTER_UPPER_ESTIMATE,
-                                        formatted_size);
+      text = l10n_util::GetStringUTF16(IDS_DEL_CACHE_COUNTER_ALMOST_EMPTY);
     }
 
   } else if (pref_name == prefs::kDeleteBrowsingHistory) {
diff --git a/chrome/browser/ui/webui/options/password_manager_handler.cc b/chrome/browser/ui/webui/options/password_manager_handler.cc
index 9f77081..216a008 100644
--- a/chrome/browser/ui/webui/options/password_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/password_manager_handler.cc
@@ -51,17 +51,17 @@
 
 // Copies from |form| to |entry| the origin, shown origin and whether the
 // origin is secure or not.
-void copyOriginInfoOfPasswordForm(const autofill::PasswordForm* form,
+void CopyOriginInfoOfPasswordForm(const autofill::PasswordForm& form,
                                   const std::string& languages,
-                                  scoped_ptr<base::DictionaryValue>& entry) {
+                                  base::DictionaryValue* entry) {
   entry->SetString(
       kOriginField,
       url_formatter::FormatUrl(
-          form->origin, languages, url_formatter::kFormatUrlOmitNothing,
+          form.origin, languages, url_formatter::kFormatUrlOmitNothing,
           net::UnescapeRule::SPACES, nullptr, nullptr, nullptr));
   entry->SetString(kShownUrlField,
-                   password_manager::GetShownOrigin(form->origin, languages));
-  entry->SetBoolean(kIsSecureField, content::IsOriginSecure(form->origin));
+                   password_manager::GetShownOrigin(form, languages));
+  entry->SetBoolean(kIsSecureField, content::IsOriginSecure(form.origin));
 }
 
 }  // namespace
@@ -223,7 +223,7 @@
   base::string16 placeholder(base::ASCIIToUTF16("        "));
   for (const autofill::PasswordForm* saved_password : password_list) {
     scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
-    copyOriginInfoOfPasswordForm(saved_password, languages_, entry);
+    CopyOriginInfoOfPasswordForm(*saved_password, languages_, entry.get());
 
     entry->SetString(kUsernameField, saved_password->username_value);
     if (show_passwords) {
@@ -254,7 +254,7 @@
   base::ListValue entries;
   for (const autofill::PasswordForm* exception : password_exception_list) {
     scoped_ptr<base::DictionaryValue> entry(new base::DictionaryValue);
-    copyOriginInfoOfPasswordForm(exception, languages_, entry);
+    CopyOriginInfoOfPasswordForm(*exception, languages_, entry.get());
     entries.Append(entry.release());
   }
 
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 1f5b503..88a7be4 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -126,7 +126,15 @@
   html_source->AddLocalizedString(
       "bluetoothPageTitle", IDS_SETTINGS_BLUETOOTH);
   html_source->AddLocalizedString(
-      "enableBluetooth", IDS_SETTINGS_BLUETOOTH_ENABLE);
+      "bluetoothEnable", IDS_SETTINGS_BLUETOOTH_ENABLE);
+  html_source->AddLocalizedString(
+      "bluetoothConnect", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECT);
+  html_source->AddLocalizedString(
+      "bluetoothAddDevice", IDS_OPTIONS_SETTINGS_ADD_BLUETOOTH_DEVICE);
+  html_source->AddLocalizedString(
+      "bluetoothNoDevices", IDS_OPTIONS_SETTINGS_BLUETOOTH_NO_DEVICES);
+  html_source->AddLocalizedString(
+      "bluetoothConnecting", IDS_OPTIONS_SETTINGS_BLUETOOTH_CONNECTING);
 }
 #endif
 
diff --git a/chrome/browser/ui/webui/settings/settings_advanced_browsertest.js b/chrome/browser/ui/webui/settings/settings_advanced_browsertest.js
new file mode 100644
index 0000000..9241774
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/settings_advanced_browsertest.js
@@ -0,0 +1,28 @@
+// Copyright 2015 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.
+
+/**
+ * @extends {testing.Test}
+ * @constructor
+ */
+function SettingsAdvancedBrowserTest() {}
+
+SettingsAdvancedBrowserTest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://md-settings/advanced',
+
+  /**
+   * TODO(dpapad): Fix accessibility issues and enable checks.
+   * @override
+   */
+  runAccessibilityChecks: false,
+};
+
+TEST_F('SettingsAdvancedBrowserTest', 'NoConsoleErrors', function() {
+  assertEquals(this.browsePreload, document.location.href);
+  // Nothing else to assert here. If there are errors in the console the test
+  // will automatically fail.
+});
diff --git a/chrome/browser/ui/webui/settings/settings_basic_browsertest.js b/chrome/browser/ui/webui/settings/settings_basic_browsertest.js
new file mode 100644
index 0000000..f38bf11
--- /dev/null
+++ b/chrome/browser/ui/webui/settings/settings_basic_browsertest.js
@@ -0,0 +1,28 @@
+// Copyright 2015 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.
+
+/**
+ * @extends {testing.Test}
+ * @constructor
+ */
+function SettingsBasicBrowserTest() {}
+
+SettingsBasicBrowserTest.prototype = {
+  __proto__: testing.Test.prototype,
+
+  /** @override */
+  browsePreload: 'chrome://md-settings/',
+
+  /**
+   * TODO(dpapad): Fix accessibility issues and enable checks.
+   * @override
+   */
+  runAccessibilityChecks: false,
+};
+
+TEST_F('SettingsBasicBrowserTest', 'NoConsoleErrors', function() {
+  assertEquals(this.browsePreload, document.location.href);
+  // Nothing else to assert here. If there are errors in the console the test
+  // will automatically fail.
+});
diff --git a/chrome/chrome.isolate b/chrome/chrome.isolate
index 3311f06f9..90b3c48 100644
--- a/chrome/chrome.isolate
+++ b/chrome/chrome.isolate
@@ -110,13 +110,6 @@
         ],
       },
     }],
-    ['OS=="win" and component=="shared_library" and (CONFIGURATION_NAME=="Debug" or CONFIGURATION_NAME=="Debug_x64")', {
-      'variables': {
-        'files': [
-          '<(PRODUCT_DIR)/crcrypto.dll',
-        ],
-      },
-    }],
     ['OS=="win" and component=="static_library"', {
       'variables': {
         'files': [
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index cfefb0b..d126685 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -68,8 +68,6 @@
       'browser/android/compositor/layer/crushed_sprite_layer.cc',
       'browser/android/compositor/layer/crushed_sprite_layer.h',
       'browser/android/compositor/layer/layer.h',
-      'browser/android/compositor/layer/reader_mode_layer.cc',
-      'browser/android/compositor/layer/reader_mode_layer.h',
       'browser/android/compositor/layer/tab_handle_layer.cc',
       'browser/android/compositor/layer/tab_handle_layer.h',
       'browser/android/compositor/layer/tab_layer.cc',
@@ -82,8 +80,6 @@
       'browser/android/compositor/layer_title_cache.h',
       'browser/android/compositor/scene_layer/contextual_search_scene_layer.cc',
       'browser/android/compositor/scene_layer/contextual_search_scene_layer.h',
-      'browser/android/compositor/scene_layer/reader_mode_scene_layer.cc',
-      'browser/android/compositor/scene_layer/reader_mode_scene_layer.h',
       'browser/android/compositor/scene_layer/scene_layer.cc',
       'browser/android/compositor/scene_layer/scene_layer.h',
       'browser/android/compositor/scene_layer/static_tab_scene_layer.cc',
@@ -108,6 +104,12 @@
       'browser/android/cookies/cookies_fetcher.h',
       'browser/android/data_usage/data_use_tab_model.cc',
       'browser/android/data_usage/data_use_tab_model.h',
+      'browser/android/data_usage/data_use_tab_helper.cc',
+      'browser/android/data_usage/data_use_tab_helper.h',
+      'browser/android/data_usage/data_use_ui_tab_model.cc',
+      'browser/android/data_usage/data_use_ui_tab_model.h',
+      'browser/android/data_usage/data_use_ui_tab_model_factory.cc',
+      'browser/android/data_usage/data_use_ui_tab_model_factory.h',
       'browser/android/data_usage/external_data_use_observer.cc',
       'browser/android/data_usage/external_data_use_observer.h',
       'browser/android/data_usage/tab_data_use_entry.cc',
@@ -295,7 +297,7 @@
       'browser/background_sync/background_sync_controller_factory.cc',
       'browser/background_sync/background_sync_controller_factory.h',
       'browser/background_sync/background_sync_controller_impl.cc',
-      'browser/background_sync/background_sync_controller_implh.h',
+      'browser/background_sync/background_sync_controller_impl.h',
       'browser/bad_message.cc',
       'browser/bad_message.h',
       'browser/banners/app_banner_data_fetcher.cc',
@@ -1790,7 +1792,6 @@
       'android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java',
       'android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java',
       'android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ContextualSearchSceneLayer.java',
-      'android/java/src/org/chromium/chrome/browser/compositor/scene_layer/ReaderModeSceneLayer.java',
       'android/java/src/org/chromium/chrome/browser/compositor/scene_layer/SceneLayer.java',
       'android/java/src/org/chromium/chrome/browser/compositor/scene_layer/StaticTabSceneLayer.java',
       'android/java/src/org/chromium/chrome/browser/compositor/scene_layer/TabListSceneLayer.java',
@@ -2633,6 +2634,8 @@
       'browser/local_discovery/cloud_print_printer_list.h',
       'browser/local_discovery/device_description.cc',
       'browser/local_discovery/device_description.h',
+      'browser/local_discovery/endpoint_resolver.cc',
+      'browser/local_discovery/endpoint_resolver.h',
       'browser/local_discovery/gcd_api_flow.cc',
       'browser/local_discovery/gcd_api_flow.h',
       'browser/local_discovery/gcd_api_flow_impl.cc',
diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi
index 6214571..dd4fe6e 100644
--- a/chrome/chrome_browser_chromeos.gypi
+++ b/chrome/chrome_browser_chromeos.gypi
@@ -13,6 +13,8 @@
         'browser/chromeos/accessibility/accessibility_manager.h',
         'browser/chromeos/accessibility/accessibility_util.cc',
         'browser/chromeos/accessibility/accessibility_util.h',
+        'browser/chromeos/accessibility/chromevox_panel.cc',
+        'browser/chromeos/accessibility/chromevox_panel.h',
         'browser/chromeos/accessibility/magnification_manager.cc',
         'browser/chromeos/accessibility/magnification_manager.h',
         'browser/chromeos/accessibility/spoken_feedback_event_rewriter.cc',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index d804fe16..4032b4e 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -3111,6 +3111,7 @@
             'installer_util_strings',
             'metro_utils',
             '../components/components.gyp:browser_watcher',
+            '../components/components.gyp:search_engines',
             '../google_update/google_update.gyp:google_update',
             '../third_party/iaccessible2/iaccessible2.gyp:iaccessible2',
             '../third_party/isimpledom/isimpledom.gyp:isimpledom',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 76982f5..3f17de3 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -106,6 +106,7 @@
       'browser/devtools/devtools_window_testing.cc',
       'browser/devtools/devtools_window_testing.h',
       'browser/do_not_track_browsertest.cc',
+      'browser/dom_distiller/distillable_page_utils_browsertest.cc',
       'browser/dom_distiller/dom_distiller_viewer_source_browsertest.cc',
       'browser/dom_distiller/tab_utils_browsertest.cc',
       'browser/download/download_browsertest.cc',
@@ -952,6 +953,8 @@
       'browser/ui/webui/options/settings_app_browsertest.js',
       'browser/ui/webui/options/settings_format_browsertest.js',
       'browser/ui/webui/options/startup_page_list_browsertest.js',
+      'browser/ui/webui/settings/settings_advanced_browsertest.js',
+      'browser/ui/webui/settings/settings_basic_browsertest.js',
       'browser/ui/webui/sync_internals_browsertest.js',
       'browser/ui/webui/sync_setup_browsertest.js',
       'test/data/chromeos/oobe_webui_browsertest.js',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index ac8f3b4..dc77a37 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -14,6 +14,7 @@
       'browser/android/bookmarks/partner_bookmarks_shim_unittest.cc',
       'browser/android/contextualsearch/contextual_search_delegate_unittest.cc',
       'browser/android/data_usage/data_use_tab_model_unittest.cc',
+      'browser/android/data_usage/data_use_ui_tab_model_unittest.cc',
       'browser/android/data_usage/external_data_use_observer_unittest.cc',
       'browser/android/data_usage/tab_data_use_entry_unittest.cc',
       'browser/android/history_report/delta_file_backend_leveldb_unittest.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 95b197a0..c02bacc 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -105,10 +105,6 @@
 // Whitelist for Negotiate Auth servers
 const char kAuthServerWhitelist[]           = "auth-server-whitelist";
 
-// A flag that is used to tell Chrome that it was launched automatically at
-// computer startup and not by some user action.
-const char kAutoLaunchAtStartup[]           = "auto-launch-at-startup";
-
 // This flag makes Chrome auto-select the provided choice when an extension asks
 // permission to start desktop capture. Should only be used for tests. For
 // instance, --auto-select-desktop-capture-source="Entire screen" will
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index c8638a9..4dbc24a 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -42,7 +42,6 @@
 extern const char kAppModeOAuth2Token[];
 extern const char kAuthExtensionPath[];
 extern const char kAuthServerWhitelist[];
-extern const char kAutoLaunchAtStartup[];
 extern const char kAutoSelectDesktopCaptureSource[];
 extern const char kBypassAppBannerEngagementChecks[];
 extern const char kCertificateTransparencyLog[];
diff --git a/chrome/common/extensions/api/file_system_provider.idl b/chrome/common/extensions/api/file_system_provider.idl
index 1eacb25..1908c18 100644
--- a/chrome/common/extensions/api/file_system_provider.idl
+++ b/chrome/common/extensions/api/file_system_provider.idl
@@ -485,7 +485,7 @@
   [nocompile] callback MetadataCallback = void(EntryMetadata metadata);
 
   // Success callback for the $(ref:onGetActionsRequested) event.
-  [nocompile, nodoc] callback ActionsCallback = void(Action[] actions);
+  [nocompile] callback ActionsCallback = void(Action[] actions);
 
   // Success callback for the $(ref:onReadDirectoryRequested) event. If more
   // entries will be returned, then <code>hasMore</code> must be true, and it
@@ -596,7 +596,7 @@
     // should be returned. The actions must be returned with the
     // <code>successCallback</code> call. In case of an error,
     // <code>errorCallback</code> must be called.
-    [maxListeners=1, nodoc] static void onGetActionsRequested(
+    [maxListeners=1] static void onGetActionsRequested(
         GetActionsRequestedOptions options,
         ActionsCallback successCallback,
         ProviderErrorCallback errorCallback);
@@ -735,7 +735,7 @@
     // Raised when executing an action for a set of files or directories is\
     // requested. After the action is completed, <code>successCallback</code>
     // must be called. On error, <code>errorCallback</code> must be called.
-    [maxListeners=1, nodoc] static void onExecuteActionRequested(
+    [maxListeners=1] static void onExecuteActionRequested(
       ExecuteActionRequestedOptions options,
       ProviderSuccessCallback successCallback,
       ProviderErrorCallback errorCallback);
diff --git a/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc b/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc
index c99b006..061bda4 100644
--- a/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc
+++ b/chrome/common/extensions/features/chrome_channel_feature_filter_unittest.cc
@@ -237,7 +237,7 @@
           .Set("extension_types", ListBuilder().Append("extension"))
           .Build());
   simple_feature->Parse(rule.get());
-  features->push_back(simple_feature.release());
+  features->push_back(simple_feature.Pass());
 
   // Rule: "legacy_packaged_app", channel stable.
   simple_feature.reset(CreateFeature<SimpleFeature>());
@@ -247,7 +247,7 @@
           .Set("extension_types", ListBuilder().Append("legacy_packaged_app"))
           .Build();
   simple_feature->Parse(rule.get());
-  features->push_back(simple_feature.release());
+  features->push_back(simple_feature.Pass());
 
   scoped_ptr<ComplexFeature> feature(new ComplexFeature(features.Pass()));
 
diff --git a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
index fc388e0..66a4f20 100644
--- a/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
+++ b/chrome/common/extensions/permissions/chrome_permission_message_rules.cc
@@ -217,14 +217,9 @@
       const PermissionIDSet& permissions) const {
     DCHECK(permissions.size() > 1);
     // Put all the individual items into submessages.
-    std::vector<base::string16> submessages;
-    std::vector<base::string16> devices =
+    std::vector<base::string16> submessages =
         permissions.GetAllPermissionsWithID(APIPermission::kUsbDevice)
             .GetAllPermissionParameters();
-    for (const base::string16& device : devices) {
-      submessages.push_back(l10n_util::GetStringFUTF16(
-          IDS_EXTENSION_PROMPT_WARNING_USB_DEVICE_LIST_ITEM, device));
-    }
     std::vector<base::string16> vendors =
         permissions.GetAllPermissionsWithID(
                        APIPermission::kUsbDeviceUnknownProduct)
diff --git a/chrome/installer/installer_tools.gyp b/chrome/installer/installer_tools.gyp
index c926caf..e30bce4 100644
--- a/chrome/installer/installer_tools.gyp
+++ b/chrome/installer/installer_tools.gyp
@@ -3,36 +3,10 @@
 # found in the LICENSE file.
 
 {
-  'variables': {
-    'version_py': '<(DEPTH)/build/util/version.py',
-    'version_path': '<(DEPTH)/chrome/VERSION',
-    'lastchange_path': '<(DEPTH)/build/util/LASTCHANGE',
-    'branding_dir': '<(DEPTH)/chrome/app/theme/<(branding_path_component)',
-    'msvs_use_common_release': 0,
-    'msvs_use_common_linker_extras': 0,
-  },
   'conditions': [
     ['OS=="win"', {
       'targets': [
         {
-          'target_name': 'validate_installation',
-          'type': 'executable',
-          'dependencies': [
-            '<(DEPTH)/base/base.gyp:base',
-            '<(DEPTH)/chrome/chrome.gyp:installer_util',
-            '<(DEPTH)/chrome/chrome.gyp:installer_util_strings',
-            '<(DEPTH)/chrome/common_constants.gyp:common_constants',
-          ],
-          'include_dirs': [
-            '<(DEPTH)',
-          ],
-          'sources': [
-            'tools/validate_installation.rc',
-            'tools/validate_installation_main.cc',
-            'tools/validate_installation_resource.h',
-          ],
-        },
-        {
           # A target that is outdated if any of the mini_installer test sources
           # are modified.
           'target_name': 'test_installer_sentinel',
diff --git a/chrome/installer/linux/flock_make_package.py b/chrome/installer/linux/flock_make_package.py
index 8dfc0899..839fc40 100644
--- a/chrome/installer/linux/flock_make_package.py
+++ b/chrome/installer/linux/flock_make_package.py
@@ -18,4 +18,4 @@
 if len(sys.argv) < 3:
   print "Incorrect args."
   sys.exit(1)
-subprocess.call(["flock", "--", sys.argv[1], "bash"] + sys.argv[2:])
+sys.exit(subprocess.call(["flock", "--", sys.argv[1], "bash"] + sys.argv[2:]))
diff --git a/chrome/installer/linux/rpm/expected_deps_x86_64 b/chrome/installer/linux/rpm/expected_deps_x86_64
index c6caba5..170aeb22 100644
--- a/chrome/installer/linux/rpm/expected_deps_x86_64
+++ b/chrome/installer/linux/rpm/expected_deps_x86_64
@@ -13,6 +13,7 @@
 libc.so.6(GLIBC_2.4)(64bit)
 libc.so.6(GLIBC_2.6)(64bit)
 libc.so.6(GLIBC_2.7)(64bit)
+libc.so.6(GLIBC_2.9)(64bit)
 libcups.so.2()(64bit)
 libdbus-1.so.3()(64bit)
 libdl.so.2()(64bit)
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 9584b01..3bd2a05 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -26,7 +26,6 @@
 #include "chrome/installer/setup/setup_constants.h"
 #include "chrome/installer/setup/setup_util.h"
 #include "chrome/installer/setup/update_active_setup_version_work_item.h"
-#include "chrome/installer/util/auto_launch_util.h"
 #include "chrome/installer/util/beacons.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/create_reg_key_work_item.h"
@@ -284,7 +283,7 @@
         "      ShowNameOnSquare150x150Logo='on'\r\n"
         "      Square150x150Logo='%ls\\Logo.png'\r\n"
         "      Square70x70Logo='%ls\\SmallLogo.png'\r\n"
-        "      ForegroundText='light'>\r\n"
+        "      ForegroundText='light'\r\n"
         "      BackgroundColor='#323232'/>\r\n"
         "</Application>\r\n";
 
@@ -375,20 +374,21 @@
 
   if (!do_not_create_desktop_shortcut ||
       shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) {
+    const base::string16 alternate_shortcut_name =
+        dist->GetShortcutName(BrowserDistribution::SHORTCUT_CHROME_ALTERNATE);
+
     ShellUtil::ShortcutProperties desktop_properties(base_properties);
-    if (alternate_desktop_shortcut) {
-      desktop_properties.set_shortcut_name(
-          dist->GetShortcutName(
-              BrowserDistribution::SHORTCUT_CHROME_ALTERNATE));
-    }
+    if (alternate_desktop_shortcut && !alternate_shortcut_name.empty())
+      desktop_properties.set_shortcut_name(alternate_shortcut_name);
     ExecuteAndLogShortcutOperation(
         ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, desktop_properties,
         shortcut_operation);
 
     // On update there is no harm in always trying to update the alternate
-    // Desktop shortcut.
+    // Desktop shortcut (if it exists for this distribution).
     if (!alternate_desktop_shortcut &&
-        shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) {
+        shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING &&
+        !alternate_shortcut_name.empty()) {
       desktop_properties.set_shortcut_name(
           dist->GetShortcutName(
               BrowserDistribution::SHORTCUT_CHROME_ALTERNATE));
@@ -551,22 +551,6 @@
       RegisterChromeOnMachine(installer_state, *chrome_product,
           make_chrome_default || force_chrome_default_for_user);
 
-      // Configure auto-launch.
-      if (result == FIRST_INSTALL_SUCCESS) {
-        installer_state.UpdateStage(installer::CONFIGURE_AUTO_LAUNCH);
-
-        // Add auto-launch key if specified in master_preferences.
-        bool auto_launch_chrome = false;
-        prefs.GetBool(
-            installer::master_preferences::kAutoLaunchChrome,
-            &auto_launch_chrome);
-        if (auto_launch_chrome) {
-          auto_launch_util::EnableForegroundStartAtLogin(
-              base::ASCIIToUTF16(chrome::kInitialProfile),
-              installer_state.target_path());
-        }
-      }
-
       if (!installer_state.system_install()) {
         DCHECK_EQ(chrome_product->distribution(),
                   BrowserDistribution::GetDistribution());
diff --git a/chrome/installer/setup/install_unittest.cc b/chrome/installer/setup/install_unittest.cc
index da0e4cc..e6faeb4 100644
--- a/chrome/installer/setup/install_unittest.cc
+++ b/chrome/installer/setup/install_unittest.cc
@@ -233,7 +233,7 @@
       "      ShowNameOnSquare150x150Logo='on'\r\n"
       "      Square150x150Logo='0.0.0.0\\VisualElements\\Logo.png'\r\n"
       "      Square70x70Logo='0.0.0.0\\VisualElements\\SmallLogo.png'\r\n"
-      "      ForegroundText='light'>\r\n"
+      "      ForegroundText='light'\r\n"
       "      BackgroundColor='#323232'/>\r\n"
       "</Application>\r\n";
 
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index 63dc893e..e81dffd 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -1151,8 +1151,7 @@
                                      WorkItem::kWow64Default);
     }
 
-    auto_launch_util::DisableAllAutoStartFeatures(
-        base::ASCIIToUTF16(chrome::kInitialProfile));
+    auto_launch_util::DisableBackgroundStartAtLogin();
 
     // If user-level chrome is self-destructing as a result of encountering a
     // system-level chrome, retarget owned non-default shortcuts (app shortcuts,
diff --git a/chrome/installer/util/auto_launch_util.cc b/chrome/installer/util/auto_launch_util.cc
index 2c1081a..e61cf76 100644
--- a/chrome/installer/util/auto_launch_util.cc
+++ b/chrome/installer/util/auto_launch_util.cc
@@ -4,10 +4,16 @@
 
 #include "chrome/installer/util/auto_launch_util.h"
 
+#include <stdint.h>
+
+#include <string>
+
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/macros.h"
 #include "base/path_service.h"
+#include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/win_util.h"
@@ -17,234 +23,49 @@
 #include "chrome/installer/util/util_constants.h"
 #include "crypto/sha2.h"
 
-using base::ASCIIToUTF16;
-
-namespace auto_launch_util {
+namespace {
 
 // The prefix of the Chrome Auto-launch key under the Run key.
 const wchar_t kAutolaunchKeyValue[] = L"GoogleChromeAutoLaunch";
 
-// We use one Run key with flags specifying which feature we want to start up.
-// When we change our Run key we need to specify what we want to do with each
-// flag. This lists the possible actions we can take with the flags.
-enum FlagSetting {
-  FLAG_DISABLE,   // Disable the flag.
-  FLAG_ENABLE,    // Enable the flag.
-  FLAG_PRESERVE,  // Preserve the value that the flag has currently.
-};
-
-// A helper function that takes a |profile_directory| and builds a registry key
-// name to use when deciding where to read/write the auto-launch value
-// to/from. It takes into account the name of the profile (so that different
-// installations of Chrome don't conflict, and so the in the future different
-// profiles can be auto-launched (or not) separately).
-base::string16 ProfileToKeyName(const base::string16& profile_directory) {
+// Builds a registry key name to use when deciding where to read/write the auto-
+// launch value to/from. It takes into account the path of the profile so that
+// different installations of Chrome don't conflict.
+base::string16 GetAutoLaunchKeyName() {
   base::FilePath path;
-  const bool success = PathService::Get(chrome::DIR_USER_DATA, &path);
-  DCHECK(success);
-  path = path.Append(profile_directory);
+  if (!PathService::Get(chrome::DIR_USER_DATA, &path))
+    NOTREACHED();
+  // Background auto-launch is only supported for the Default profile at the
+  // moment, but keep the door opened to a multi-profile implementation by
+  // encoding the Default profile in the hash.
+  path = path.AppendASCII(chrome::kInitialProfile);
 
   std::string input(path.AsUTF8Unsafe());
-  uint8 hash[16];
-  crypto::SHA256HashString(input, hash, sizeof(hash));
-  std::string hash_string = base::HexEncode(hash, sizeof(hash));
-  return base::string16(kAutolaunchKeyValue) + ASCIIToUTF16("_") +
-         ASCIIToUTF16(hash_string);
+  uint8_t hash[16];
+  crypto::SHA256HashString(input, hash, arraysize(hash));
+  return base::string16(kAutolaunchKeyValue) + base::ASCIIToUTF16("_") +
+         base::ASCIIToUTF16(base::HexEncode(hash, arraysize(hash)));
 }
 
-// Returns whether the Chrome executable specified in |application_path| is set
-// to auto-launch at computer startup with a given |command_line_switch|.
-// NOTE: |application_path| is optional and should be blank in most cases (as
-// it will default to the application path of the current executable).
-// |profile_directory| is the name of the directory (leaf, not the full path)
-// that contains the profile that should be opened at computer startup.
-// |command_line_switch| is the switch we are optionally interested in and, if
-// not blank, must be present for the function to return true. If blank, it acts
-// like a wildcard.
-bool WillLaunchAtLoginWithSwitch(const base::FilePath& application_path,
-                                 const base::string16& profile_directory,
-                                 const std::string& command_line_switch) {
-  base::string16 key_name(ProfileToKeyName(profile_directory));
-  base::string16 autolaunch;
-  if (!base::win::ReadCommandFromAutoRun(
-      HKEY_CURRENT_USER, key_name, &autolaunch)) {
-    return false;
-  }
+}  // namespace
 
-  base::FilePath chrome_exe(application_path);
-  if (chrome_exe.empty()) {
-    if (!PathService::Get(base::DIR_EXE, &chrome_exe)) {
-      NOTREACHED();
-      return false;
-    }
-  }
-  chrome_exe = chrome_exe.Append(installer::kChromeExe);
-
-  if (autolaunch.find(chrome_exe.value()) == base::string16::npos)
-    return false;
-
-  return command_line_switch.empty() ||
-         autolaunch.find(ASCIIToUTF16(command_line_switch)) !=
-             base::string16::npos;
-}
-
-bool AutoStartRequested(const base::string16& profile_directory,
-                        bool window_requested,
-                        const base::FilePath& application_path) {
-  if (window_requested) {
-    return WillLaunchAtLoginWithSwitch(application_path,
-                                       profile_directory,
-                                       switches::kAutoLaunchAtStartup);
-  } else {
-    // Background mode isn't profile specific, but is attached to the Run key
-    // for the Default profile.
-    return WillLaunchAtLoginWithSwitch(application_path,
-                                       ASCIIToUTF16(chrome::kInitialProfile),
-                                       switches::kNoStartupWindow);
-  }
-}
-
-bool CheckAndRemoveDeprecatedBackgroundModeSwitch() {
-  // For backwards compatibility we need to provide a migration path from the
-  // previously used key "chromium" that the BackgroundMode used to set, as it
-  // is incompatible with the new key (can't have two Run keys with
-  // conflicting switches).
-  base::string16 chromium = ASCIIToUTF16("chromium");
-  base::string16 value;
-  if (base::win::ReadCommandFromAutoRun(HKEY_CURRENT_USER, chromium, &value)) {
-    if (value.find(ASCIIToUTF16(switches::kNoStartupWindow)) !=
-        base::string16::npos) {
-      base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, chromium);
-      return true;
-    }
-  }
-
-  return false;
-}
-
-void SetWillLaunchAtLogin(const base::FilePath& application_path,
-                          const base::string16& profile_directory,
-                          FlagSetting foreground_mode,
-                          FlagSetting background_mode) {
-  if (CheckAndRemoveDeprecatedBackgroundModeSwitch()) {
-    // We've found the deprecated switch, we must migrate it (unless background
-    // mode is being turned off).
-    if (profile_directory == ASCIIToUTF16(chrome::kInitialProfile) &&
-        background_mode == FLAG_PRESERVE) {
-      // Preserve in this case also covers the deprecated value, so we must
-      // explicitly turn the flag on and the rest will be taken care of below.
-      background_mode = FLAG_ENABLE;
-    } else {
-      // When we add support for multiple profiles for foreground mode we need
-      // to think about where to store the background mode switch. I think we
-      // need to store it with the Default profile (call SetWillLaunchAtLogin
-      // again specifying the Default profile), but concerns were raised in
-      // review.
-      NOTREACHED();
-    }
-  }
-  base::string16 key_name(ProfileToKeyName(profile_directory));
-
-  // Check which feature should be enabled.
-  bool in_foreground =
-      foreground_mode == FLAG_ENABLE ||
-      (foreground_mode == FLAG_PRESERVE &&
-          WillLaunchAtLoginWithSwitch(application_path,
-                                      profile_directory,
-                                      switches::kAutoLaunchAtStartup));
-  bool in_background =
-      background_mode == FLAG_ENABLE ||
-      (background_mode == FLAG_PRESERVE &&
-          WillLaunchAtLoginWithSwitch(application_path,
-                                      profile_directory,
-                                      switches::kNoStartupWindow));
-
-  // TODO(finnur): Convert this into a shortcut, instead of using the Run key.
-  if (in_foreground || in_background) {
-    base::FilePath path(application_path);
-    if (path.empty()) {
-      if (!PathService::Get(base::DIR_EXE, &path)) {
-        NOTREACHED();
-        return;
-      }
-    }
-    base::string16 cmd_line = ASCIIToUTF16("\"");
-    cmd_line += path.value();
-    cmd_line += ASCIIToUTF16("\\");
-    cmd_line += installer::kChromeExe;
-    cmd_line += ASCIIToUTF16("\"");
-
-    if (in_background) {
-      cmd_line += ASCIIToUTF16(" --");
-      cmd_line += ASCIIToUTF16(switches::kNoStartupWindow);
-    }
-    if (in_foreground) {
-      cmd_line += ASCIIToUTF16(" --");
-      cmd_line += ASCIIToUTF16(switches::kAutoLaunchAtStartup);
-
-      const base::CommandLine& command_line =
-          *base::CommandLine::ForCurrentProcess();
-
-      // Propagate --user-data-dir if it was specified on the command line.
-      // Retrieve the value from the PathService since some sanitation may have
-      // taken place. There is no need to add it to the command line in the
-      // event that the dir was overridden by Group Policy since the GP override
-      // will be in force when Chrome is launched.
-      if (command_line.HasSwitch(switches::kUserDataDir)) {
-        cmd_line += ASCIIToUTF16(" --");
-        cmd_line += ASCIIToUTF16(switches::kUserDataDir);
-        cmd_line += ASCIIToUTF16("=\"");
-        base::FilePath user_data_dir;
-        PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
-        cmd_line += user_data_dir.value();
-        cmd_line += ASCIIToUTF16("\"");
-      }
-
-      cmd_line += ASCIIToUTF16(" --");
-      cmd_line += ASCIIToUTF16(switches::kProfileDirectory);
-      cmd_line += ASCIIToUTF16("=\"");
-      cmd_line += profile_directory;
-      cmd_line += ASCIIToUTF16("\"");
-    }
-
-    base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, key_name, cmd_line);
-  } else {
-    base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER, key_name);
-  }
-}
-
-void DisableAllAutoStartFeatures(const base::string16& profile_directory) {
-  DisableForegroundStartAtLogin(profile_directory);
-  DisableBackgroundStartAtLogin();
-}
-
-void EnableForegroundStartAtLogin(const base::string16& profile_directory,
-                                  const base::FilePath& application_path) {
-  SetWillLaunchAtLogin(
-      application_path, profile_directory, FLAG_ENABLE, FLAG_PRESERVE);
-}
-
-void DisableForegroundStartAtLogin(const base::string16& profile_directory) {
-  SetWillLaunchAtLogin(
-      base::FilePath(), profile_directory, FLAG_DISABLE, FLAG_PRESERVE);
-}
+namespace auto_launch_util {
 
 void EnableBackgroundStartAtLogin() {
-  // Background mode isn't profile specific, but we specify the Default profile
-  // just to have a unique Run key to attach it to. FilePath is blank because
-  // this function is not called from the installer (see comments for
-  // EnableAutoStartAtLogin).
-  SetWillLaunchAtLogin(base::FilePath(),
-                       ASCIIToUTF16(chrome::kInitialProfile),
-                       FLAG_PRESERVE,
-                       FLAG_ENABLE);
+  base::FilePath application_dir;
+  if (!PathService::Get(base::DIR_EXE, &application_dir))
+    NOTREACHED();
+
+  base::CommandLine cmd_line(application_dir.Append(installer::kChromeExe));
+  cmd_line.AppendSwitch(switches::kNoStartupWindow);
+
+  base::win::AddCommandToAutoRun(HKEY_CURRENT_USER, GetAutoLaunchKeyName(),
+                                 cmd_line.GetCommandLineString());
 }
 
 void DisableBackgroundStartAtLogin() {
-  SetWillLaunchAtLogin(base::FilePath(),
-                       ASCIIToUTF16(chrome::kInitialProfile),
-                       FLAG_PRESERVE,
-                       FLAG_DISABLE);
+  base::win::RemoveCommandFromAutoRun(HKEY_CURRENT_USER,
+                                      GetAutoLaunchKeyName());
 }
 
 }  // namespace auto_launch_util
diff --git a/chrome/installer/util/auto_launch_util.h b/chrome/installer/util/auto_launch_util.h
index 65b3ba9..d635031 100644
--- a/chrome/installer/util/auto_launch_util.h
+++ b/chrome/installer/util/auto_launch_util.h
@@ -5,69 +5,14 @@
 #ifndef CHROME_INSTALLER_UTIL_AUTO_LAUNCH_UTIL_H_
 #define CHROME_INSTALLER_UTIL_AUTO_LAUNCH_UTIL_H_
 
-#include "base/strings/string16.h"
-
-namespace base {
-class FilePath;
-}
-
 // A namespace containing the platform specific implementation of setting Chrome
 // to launch at user login.
 namespace auto_launch_util {
 
-// Returns whether the Chrome executable in the directory |application_path| is
-// set to auto-start at user login.
-// |profile_directory| is the name of the directory (leaf, not the full path)
-// that contains the profile that should be opened at user login.
-// There are two flavors of auto-start, separated by whether a window is
-// requested at startup or not (called background mode). |window_requested|
-// specifies which flavor the caller is interested in.
-// NOTE: This function returns true only if the flavor the caller specifies has
-// been requested (or if both flavors have been requested). Therefore, it is
-// possible that Chrome auto-starts even if this function returns false (since
-// the other flavor might have been requested).
-// NOTE: Chrome being set to launch in the background (without a window)
-// does not necessarily mean that Chrome *will* launch without a window, since
-// when both flavors of the auto-start feature have been requested. In other
-// words, showing a window trumps not showing a window.
-// ALSO NOTE: |application_path| is optional and should be blank in most cases
-// (as it will default to the application path of the current executable).
-bool AutoStartRequested(const base::string16& profile_directory,
-                        bool window_requested,
-                        const base::FilePath& application_path);
-
-// Disables all auto-start features. |profile_directory| is the name of the
-// directory (leaf, not the full path) that contains the profile that was set
-// to be opened at user login.
-void DisableAllAutoStartFeatures(const base::string16& profile_directory);
-
-// Configures Chrome to auto-launch at user login and show a window. See also
-// EnableBackgroundStartAtLogin, which does the same, except without a window.
-// |profile_directory| is the name of the directory (leaf, not the full path)
-// that contains the profile that should be opened at user login.
-// |application_path| is needed when the caller is not the process being set to
-// auto-launch, ie. the installer. This is because |application_path|, if left
-// blank, defaults to the application path of the current executable.
-void EnableForegroundStartAtLogin(const base::string16& profile_directory,
-                                  const base::FilePath& application_path);
-
-// Disables auto-starting Chrome in foreground mode at user login.
-// |profile_directory| is the name of the directory (leaf, not the full path)
-// that contains the profile that was set to be opened at user login.
-// NOTE: Chrome may still launch if the other auto-start flavor is active
-// (background mode).
-void DisableForegroundStartAtLogin(const base::string16& profile_directory);
-
-// Requests that Chrome start in Background Mode at user login (without a
-// window being shown, except if EnableForegroundStartAtLogin has also been
-// called).
-// In short, EnableBackgroundStartAtLogin is the no-window version of calling
-// EnableForegroundStartAtLogin). If both are called, a window will be shown on
-// startup (foreground mode wins).
+// Requests that Chrome start in Background Mode at user login.
 void EnableBackgroundStartAtLogin();
 
-// Disables auto-starting Chrome in background mode at user login. Chrome may
-// still launch if the other auto-start flavor is active (foreground mode).
+// Disables auto-starting Chrome in background mode at user login.
 void DisableBackgroundStartAtLogin();
 
 }  // namespace auto_launch_util
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index f4b187c..4b4c294 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -82,7 +82,8 @@
   virtual base::string16 GetDisplayName();
 
   // Returns the localized name of the shortcut identified by |shortcut_type|
-  // for this distribution.
+  // for this distribution or empty string if |shortcut_type| is unsupported
+  // by this BrowserDistribution.
   virtual base::string16 GetShortcutName(ShortcutType shortcut_type);
 
   // Returns the index of the icon for the product identified by
diff --git a/chrome/installer/util/copy_tree_work_item.cc b/chrome/installer/util/copy_tree_work_item.cc
index 88bc244e..57ef3dc 100644
--- a/chrome/installer/util/copy_tree_work_item.cc
+++ b/chrome/installer/util/copy_tree_work_item.cc
@@ -83,8 +83,8 @@
       VLOG(1) << "Moved destination " << dest_path_.value() <<
                  " to backup path " << backup.value();
     } else {
-      LOG(ERROR) << "failed moving " << dest_path_.value()
-                 << " to " << backup.value();
+      PLOG(ERROR) << "failed moving " << dest_path_.value()
+                  << " to " << backup.value();
       return false;
     }
   }
@@ -115,8 +115,8 @@
   if (moved_to_backup_) {
     base::FilePath backup(backup_path_.path().Append(dest_path_.BaseName()));
     if (!base::Move(backup, dest_path_)) {
-      LOG(ERROR) << "failed move " << backup.value()
-                 << " to " << dest_path_.value();
+      PLOG(ERROR) << "failed move " << backup.value()
+                  << " to " << dest_path_.value();
     }
   }
   if (copied_to_alternate_path_ &&
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.cc b/chrome/installer/util/google_chrome_sxs_distribution.cc
index 57914f3..421d240 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.cc
+++ b/chrome/installer/util/google_chrome_sxs_distribution.cc
@@ -37,10 +37,8 @@
     ShortcutType shortcut_type) {
   switch (shortcut_type) {
     case SHORTCUT_CHROME_ALTERNATE:
-      // This should never be called. Returning the same string as Google Chrome
-      // preserves behavior, but it will result in a naming collision.
-      NOTREACHED();
-      return GoogleChromeDistribution::GetShortcutName(shortcut_type);
+      // There is no alternate shortcut name on SxS Chrome.
+      return base::string16();
     case SHORTCUT_APP_LAUNCHER:
       return installer::GetLocalizedString(
           IDS_APP_LIST_SHORTCUT_NAME_CANARY_BASE);
diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc
index 8754b701..cc5c1a56 100644
--- a/chrome/installer/util/master_preferences.cc
+++ b/chrome/installer/util/master_preferences.cc
@@ -125,8 +125,6 @@
     const char* cmd_line_switch;
     const char* distribution_switch;
   } translate_switches[] = {
-    { installer::switches::kAutoLaunchChrome,
-      installer::master_preferences::kAutoLaunchChrome },
     { installer::switches::kChrome,
       installer::master_preferences::kChrome },
     { installer::switches::kDisableLogging,
diff --git a/chrome/installer/util/master_preferences.h b/chrome/installer/util/master_preferences.h
index be0db3a..0c375c3 100644
--- a/chrome/installer/util/master_preferences.h
+++ b/chrome/installer/util/master_preferences.h
@@ -36,7 +36,6 @@
 // {
 //   "distribution": {
 //      "alternate_shortcut_text": false,
-//      "auto_launch_chrome": false,
 //      "chrome_shortcut_icon_index": 0,
 //      "create_all_shortcuts": true,
 //      "import_bookmarks": false,
diff --git a/chrome/installer/util/master_preferences_constants.cc b/chrome/installer/util/master_preferences_constants.cc
index 4bcfd36..0e7bcc8 100644
--- a/chrome/installer/util/master_preferences_constants.cc
+++ b/chrome/installer/util/master_preferences_constants.cc
@@ -7,7 +7,6 @@
 namespace installer {
 namespace master_preferences {
   const char kAltShortcutText[] = "alternate_shortcut_text";
-  const char kAutoLaunchChrome[] = "auto_launch_chrome";
   const char kChrome[] = "chrome";
   const char kChromeShortcutIconIndex[] = "chrome_shortcut_icon_index";
   const char kCreateAllShortcuts[] = "create_all_shortcuts";
diff --git a/chrome/installer/util/master_preferences_constants.h b/chrome/installer/util/master_preferences_constants.h
index bb53ae33..dbdd1dce 100644
--- a/chrome/installer/util/master_preferences_constants.h
+++ b/chrome/installer/util/master_preferences_constants.h
@@ -17,9 +17,6 @@
 
 // Boolean. Use alternate text for the shortcut. Cmd line override present.
 extern const char kAltShortcutText[];
-// Boolean. Whether to instruct the installer to auto-launch chrome on computer
-// startup. The default (if not provided) is |false|.
-extern const char kAutoLaunchChrome[];
 // Boolean. This is to be a Chrome install. (When using MultiInstall)
 extern const char kChrome[];
 // Integer. Icon index from chrome.exe to use for shortcuts.
diff --git a/chrome/installer/util/move_tree_work_item.cc b/chrome/installer/util/move_tree_work_item.cc
index 56671ba..a21db30 100644
--- a/chrome/installer/util/move_tree_work_item.cc
+++ b/chrome/installer/util/move_tree_work_item.cc
@@ -63,9 +63,9 @@
         } else {
           // We failed to move the source tree to the backup path. This is odd
           // but just fall through and attempt the regular behaviour as well.
-          LOG(ERROR) << "Failed to backup source " << source_path_.value()
-                     << " to backup path " << backup.value()
-                     << " for duplicate trees. Trying regular Move instead.";
+          PLOG(ERROR) << "Failed to backup source " << source_path_.value()
+                      << " to backup path " << backup.value()
+                      << " for duplicate trees. Trying regular Move instead.";
         }
       } else {
         VLOG(1) << "Source path " << source_path_.value()
@@ -100,18 +100,19 @@
 }
 
 void MoveTreeWorkItem::Rollback() {
-  if (moved_to_dest_path_ && !base::Move(dest_path_, source_path_))
-    LOG(ERROR) << "Can not move " << dest_path_.value()
-               << " to " << source_path_.value();
+  if (moved_to_dest_path_ && !base::Move(dest_path_, source_path_)) {
+    PLOG(ERROR) << "Can not move " << dest_path_.value()
+                << " to " << source_path_.value();
+  }
 
   base::FilePath backup = backup_path_.path().Append(dest_path_.BaseName());
   if (moved_to_backup_ && !base::Move(backup, dest_path_)) {
-    LOG(ERROR) << "failed move " << backup.value()
-               << " to " << dest_path_.value();
+    PLOG(ERROR) << "failed move " << backup.value()
+                << " to " << dest_path_.value();
   }
 
   if (source_moved_to_backup_ && !base::Move(backup, source_path_)) {
-    LOG(ERROR) << "Can not restore " << backup.value()
-               << " to " << source_path_.value();
+    PLOG(ERROR) << "Can not restore " << backup.value()
+                << " to " << source_path_.value();
   }
 }
diff --git a/chrome/installer/util/util_constants.cc b/chrome/installer/util/util_constants.cc
index a1afbcd..c15913c0 100644
--- a/chrome/installer/util/util_constants.cc
+++ b/chrome/installer/util/util_constants.cc
@@ -8,9 +8,6 @@
 
 namespace switches {
 
-// Whether to set Chrome to launch at computer startup.
-const char kAutoLaunchChrome[] = "auto-launch-chrome";
-
 // Install Chrome.
 // Currently this is only required when used in combination with kMultiInstall.
 const char kChrome[] = "chrome";
diff --git a/chrome/installer/util/util_constants.h b/chrome/installer/util/util_constants.h
index 20742f19..9d39ef7 100644
--- a/chrome/installer/util/util_constants.h
+++ b/chrome/installer/util/util_constants.h
@@ -118,7 +118,7 @@
   REGISTERING_CHROME = 13,         // Performing Chrome registration.
   REMOVING_OLD_VERSIONS = 14,      // Deleting old version directories.
   FINISHING = 15,                  // Finishing the install.
-  CONFIGURE_AUTO_LAUNCH = 16,      // Configuring Chrome to auto-launch.
+  // CONFIGURE_AUTO_LAUNCH = 16,
   CREATING_VISUAL_MANIFEST = 17,   // Creating VisualElementsManifest.xml
   // DEFERRING_TO_HIGHER_VERSION = 18,
   UNINSTALLING_BINARIES = 19,      // Uninstalling unused binaries.
@@ -133,7 +133,6 @@
 
 namespace switches {
 
-extern const char kAutoLaunchChrome[];
 extern const char kChrome[];
 extern const char kChromeFrame[];
 extern const char kChromeSxS[];
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index e5a0186..0db8e41 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -58,6 +58,7 @@
 #include "components/autofill/content/renderer/password_generation_agent.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
 #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h"
+#include "components/dom_distiller/content/renderer/distillability_agent.h"
 #include "components/dom_distiller/content/renderer/distiller_js_render_frame_observer.h"
 #include "components/dom_distiller/core/url_constants.h"
 #include "components/nacl/renderer/ppb_nacl_private.h"
@@ -530,6 +531,10 @@
   new dom_distiller::DistillerJsRenderFrameObserver(
       render_frame, chrome::ISOLATED_WORLD_ID_CHROME_INTERNAL);
 
+  // Create DistillabilityAgent to send distillability updates to
+  // DistillabilityDriver in the browser process.
+  new dom_distiller::DistillabilityAgent(render_frame);
+
   PasswordAutofillAgent* password_autofill_agent =
       new PasswordAutofillAgent(render_frame);
   PasswordGenerationAgent* password_generation_agent =
diff --git a/chrome/test/data/dom_distiller/non_og_article.html b/chrome/test/data/dom_distiller/non_og_article.html
new file mode 100644
index 0000000..928a566e
--- /dev/null
+++ b/chrome/test/data/dom_distiller/non_og_article.html
@@ -0,0 +1,8 @@
+<html>
+<head>
+  <title>Non-opengraph Article Title</title>
+</head>
+<body>
+Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque.
+</body>
+</html>
diff --git a/chrome/test/data/dom_distiller/og_article.html b/chrome/test/data/dom_distiller/og_article.html
new file mode 100644
index 0000000..9a6fbf7
--- /dev/null
+++ b/chrome/test/data/dom_distiller/og_article.html
@@ -0,0 +1,9 @@
+<html>
+<head prefix="og: http://ogp.me/ns#">
+  <title>Opengraph Article Title</title>
+  <meta property="og:type" content="article"/>
+</head>
+<body>
+Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque.
+</body>
+</html>
diff --git a/chrome/test/data/dom_distiller/simple_article.html b/chrome/test/data/dom_distiller/simple_article.html
index 4c0279f..ae8d3410 100644
--- a/chrome/test/data/dom_distiller/simple_article.html
+++ b/chrome/test/data/dom_distiller/simple_article.html
@@ -7,6 +7,12 @@
 <p>Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque.
 
 <p>Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque.
+
+<p>Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque.
+
+<p>Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque.
+
+<p>Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque.
 </div>
 </body>
 </html>
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/main.html b/chrome/test/data/extensions/platform_apps/extension_view/creation/main.html
similarity index 100%
rename from chrome/test/data/extensions/platform_apps/extension_view/main.html
rename to chrome/test/data/extensions/platform_apps/extension_view/creation/main.html
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/main.js b/chrome/test/data/extensions/platform_apps/extension_view/creation/main.js
similarity index 100%
rename from chrome/test/data/extensions/platform_apps/extension_view/main.js
rename to chrome/test/data/extensions/platform_apps/extension_view/creation/main.js
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/manifest.json b/chrome/test/data/extensions/platform_apps/extension_view/creation/manifest.json
similarity index 100%
rename from chrome/test/data/extensions/platform_apps/extension_view/manifest.json
rename to chrome/test/data/extensions/platform_apps/extension_view/creation/manifest.json
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/test.js b/chrome/test/data/extensions/platform_apps/extension_view/creation/test.js
similarity index 100%
rename from chrome/test/data/extensions/platform_apps/extension_view/test.js
rename to chrome/test/data/extensions/platform_apps/extension_view/creation/test.js
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton.crx b/chrome/test/data/extensions/platform_apps/extension_view/skeleton.crx
new file mode 100644
index 0000000..99912d1
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/extension_view/skeleton.crx
Binary files differ
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton.pem b/chrome/test/data/extensions/platform_apps/extension_view/skeleton.pem
new file mode 100644
index 0000000..9a3de96
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/extension_view/skeleton.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDvX1uz+m8tHS9w
+PtFscMv4zZqhYnKvvpSowAXCEs6v1fSDXPdGKzNnpoQ0iH3CndtA53izAIqWwPxm
+F5+hfxkRHJ+JrW8fP2cKGoua76lPbHoqJ8GRHfwmbNDwWHHlQfU4piTnX+VarKvE
+LQlADhifnzfWCqSdG4JOSO2cQjlC0b+4fZK1iT6ZZNwf7CIEwmnk1k73eHmtQQHh
+CRzUPZd1RSfDnVcnLl2L4Vg64TSd3BAARpZyVz2b9DnxXBWc01u9qnhB8XRSfahn
+wINnMoB/F0FD1Uvp1SZmytJ8GNR2IW+0uIvpTvPvh/jujU0dOykKOaPcCSim3PSu
+CuVBbIfvAgMBAAECggEBALjftTuz19nICLNwUN6n32ExqpOqLVl+n+IVLF1PmUJE
+xKwQSQpwoysSeFj6cea1dHkUTSwy5ta4BjfzVt6sAvgsWytCP+iqVzJ+fgQTxXgK
+F/Am9GDX/77NnDGEnbKq1nICH85zSfhWE/NXtSU7vdjKZ51wauLMND+yI5Hjs8Xe
+KwcQPv1KdBioUWjCp9V1m3fluzSReDDxGgLl7S9QzFSLkjdFIqTWYxiaRgYCFBUB
+LaPTKzk4PaQWGs1ALLwEl3cM865VX1Y/vn0k0/GLvz6nGHW5rhDIeKAEgPROD/r2
+Jwt1rNSUJgeUZf0+B1MO8cd7TndALb/cvxleOlrjLkECgYEA+eCqiGt0WryDpEsX
+Yv8/EWhzA7eFXUeIvhmfFUnH889g9v+XycRAaWiGH7oJtxqfETy8qWEtlLgHC47r
+oxApaUmdqz17GYKUt+27lPM4Fw2xVf8x70yLFAoS1GmMxaRgqKyyyXtttBg1p/g9
+ud18cfj4ORb4xsT7lMTkbjBtDysCgYEA9TzMvPB+FUAmZZZ/75MkLOvky6m7nTbw
+kn8w0QM/UksYood0PszaP85mhDSSQAQKhrrLhNtAHyMweWx1aggGOODef8KBNc/f
+xWafFZZpmJvkH3rDyvDE0yioxiaKQYMvrB3EVO3QcdUqMNPROzMCI9X+gQ0Xo9/3
+T18b7SCg6E0CgYAx+lGhf3yCOXpK/gnrbwn6PV3jvG0cPxaGjzFWXK91gGDwhiah
+4HLRompRJjCTQuvV0sQZTKqFOFmQYkGXF8Bwopy6h017yLZeI1qFbDAnzEFP5f7i
+0fhvRaSGf6X8UehTVFdeHSXQA5eXxPrzle0yDo33PTT87KE1HDxkHaNyiQKBgQCu
+zWm6e0nD5/f2jXIf2Kf+hR6OtSuQAms0YQjw0vm9tN2YbCjF4srmlD6qmbZtfvPp
+2RfcWVO5XiHdSxveOl4FCPRP6Nqk+sksMdvPTWlzaBsQ/Ta2XyxMvzyeETaXP+Up
+MAaT6vebTDBIoZMQOWmbFZvVbPmey7PCla6YNZu8OQKBgQDD+Y41atAIPpdSqN4W
+S9jKIw7HEPK59pjQNYB8MOSqXRyp83FudwGOrxl41iavqinsExB7buhnGsLVKfLi
+/zNqt3EBb2bSIM8IsiMOYUfATstt6MiVPzJyRVtITLbYNxYRGq9MX26tenAXV7qm
+2UvMG9E8r9lCSQEcqh7OzLo31Q==
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton/main.html b/chrome/test/data/extensions/platform_apps/extension_view/skeleton/main.html
deleted file mode 100644
index 4ecd1c5..0000000
--- a/chrome/test/data/extensions/platform_apps/extension_view/skeleton/main.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-  <body>
-    <div>Hello World!</div>
-  </body>
-</html>
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton/main.js b/chrome/test/data/extensions/platform_apps/extension_view/skeleton/main.js
deleted file mode 100644
index 49defed..0000000
--- a/chrome/test/data/extensions/platform_apps/extension_view/skeleton/main.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 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.
-
-chrome.app.runtime.onEmbedRequested.addListener(function(request) {
-  if (!request.embedderId)
-    request.deny();
-  if (!request.data.foo) {
-    request.allow('main.html');
-    return;
-  } else if (request.data.foo == 'bar') {
-    request.deny();
-  } else if (request.data.foo == 'bleep') {
-    request.allow('main.html');
-  }
-});
-
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton/manifest.json b/chrome/test/data/extensions/platform_apps/extension_view/skeleton/manifest.json
index 26c03d2..4d3e077d 100644
--- a/chrome/test/data/extensions/platform_apps/extension_view/skeleton/manifest.json
+++ b/chrome/test/data/extensions/platform_apps/extension_view/skeleton/manifest.json
@@ -1,11 +1,7 @@
 {
+  // pemeknaakobkocgmimdeamlcklioagkh
+  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA719bs/pvLR0vcD7RbHDL+M2aoWJyr76UqMAFwhLOr9X0g1z3RiszZ6aENIh9wp3bQOd4swCKlsD8ZhefoX8ZERyfia1vHz9nChqLmu+pT2x6KifBkR38JmzQ8Fhx5UH1OKYk51/lWqyrxC0JQA4Yn5831gqknRuCTkjtnEI5QtG/uH2StYk+mWTcH+wiBMJp5NZO93h5rUEB4Qkc1D2XdUUnw51XJy5di+FYOuE0ndwQAEaWclc9m/Q58VwVnNNbvap4QfF0Un2oZ8CDZzKAfxdBQ9VL6dUmZsrSfBjUdiFvtLiL6U7z74f47o1NHTspCjmj3Akoptz0rgrlQWyH7wIDAQAB",
   "manifest_version": 2,
   "name": "skeleton",
-  "minimum_chrome_version": "24.0.1307.0",
-  "version": "1.0",
-  "app": {
-    "background": {
-      "scripts": ["main.js"]
-    }
-  }
+  "version": "1.0"
 }
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two.crx b/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two.crx
new file mode 100644
index 0000000..507e9eb63e9
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two.crx
Binary files differ
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two.pem b/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two.pem
new file mode 100644
index 0000000..e1f7e6a
--- /dev/null
+++ b/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC2G1liqXzycv1y
+ERgLrvDIC3ItyDCw927oecGYo7Q0cKLNqDodk+dtO2N+W91bvYp2XwPAjMDg5Q3Z
+StxHswAgqeD2WI/zWO0No2dGR+RLGlvHzy1+h+ydl4utzGApBgN1NDB75hafp+9o
+lGiSSr9qliLHmLOW41V+Lb8XPoUZJSxYQB4g9IBWCWK4JkPPVIp8hkA8TAX+1oRV
++W7UTjxgWRAFVfDRA1BThQvlLj0d/tjadFm90UTNI4wVQbkAqu892nq8LBsm3eij
+Lo8kwP2QjPJ8WjWTDwmTxn4WkiOpNa2SBnBPkkcA6Diy9XMMRVIRr5jZOOBqHS1n
+1prD6uRPAgMBAAECggEAJdIaR1Zh/8yH/Ke2Mb78fN97sCxyiF5rJ1caMQRWyclW
+1pWItFniZ5o8+KJFn+cGmbzz/4p8CHkp3iYhB7cSYLZHZYJRKz4dxYZZTYxiyoJH
+64CIt02tg7FUrhzTH9IC59WV+DV6H2B2ZWblLPTfOljCEmgRbFX8jH8dv8sZQ3ZO
+P80ZFcWn6UzBGcI5kdD6CuGpf5hoV1b3iwUi38UQOk8eM6zAmE90ZYsZOE9A508Z
+1JyrPIo7KSFIDOaeUGPADKqwlO0r4TgOUR4J6xVssqBtNgtY17WaVaI8JhCXGLq0
+WXyu/2L59CsHe14M++V2a7xarcBSwPhRHYcrhWddcQKBgQDdV28+Xw3yEUxnaSfG
+P9GhFKMJQlvJM2J+ZstC0FXqfeDVp/3tlJlef9gDUqgdXdAheRsOugXlNSgrmURZ
+u9QA7I2C43hw1OhJJkk87jF1xJbCG/ZI7WCxfn94nrSK2Dd3DDLwgK4iby0xHqH1
+b3R2gdRREicEGuAI2i9/UVx1uQKBgQDSnyznwN77YFroVxNXvH2XdeyS+1T+rPWK
+Gb/mmITuTnESO0hli78Tm0xOiBhfnPklyl1z1//3k69xvzeF/r1hh4x6qmGu+i6o
+lny6OIdybfSTEt7qA1G7KS9KE0ic/F5lsL8CBE6qsEtfB9Y4fjTRYgZhmXWl5Dyr
+xOzPVpcuRwKBgDpR82nHufDyReNpfaVq411CBsNFzNFyzJzpkN0F791dVYR2Qx36
+bX7MyKn3eXxjX5eyRULYGP2PyAnU1IGgT/f+XDsEnJN+RcYgZGO9jyKsrdxvabFF
+epjJ7+RkTMXYuqSPfkyIW1mPWaT7oUj+GP2wr7S8x7L5MdajRqiRU39hAoGBAK7x
+PZhFsDB1qSyg3tUaH+tFLLos/j0HJm+N0cJUXt2d0/dDvG9z8sLzVB9KlYwdUyib
+fKHzAI4AYlKFdDXdECpJL1rX2IlBDq5DSNhYidB3GhVrMDKJjUJ7A+dwOvkB+dpX
+Q2AGedz2z7PgS4Pi+DYOSKSalYi0GdzGlbfmAW6TAoGBAJuu0aJ7V4vYaIdZRKXC
+Q6t+F6kly73pAVKaeO9bVOZeBROAIUzeoEhnDGQM6D7Ei+7bVr9710OvwexSWh6n
+GDqRsW3zxVCOEvWP6/wh9zqznxUJii1QD+fCMSgTMlCVuR89nuXdPANJDGslu3yU
+/ywhqyg12KiymsmxqVouzK7Y
+-----END PRIVATE KEY-----
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/main.html b/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/main.html
deleted file mode 100644
index 4ecd1c5..0000000
--- a/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/main.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-  <body>
-    <div>Hello World!</div>
-  </body>
-</html>
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/main.js b/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/main.js
deleted file mode 100644
index 49defed..0000000
--- a/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/main.js
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright 2015 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.
-
-chrome.app.runtime.onEmbedRequested.addListener(function(request) {
-  if (!request.embedderId)
-    request.deny();
-  if (!request.data.foo) {
-    request.allow('main.html');
-    return;
-  } else if (request.data.foo == 'bar') {
-    request.deny();
-  } else if (request.data.foo == 'bleep') {
-    request.allow('main.html');
-  }
-});
-
diff --git a/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/manifest.json b/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/manifest.json
index 668ad038..e0b5af53c 100644
--- a/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/manifest.json
+++ b/chrome/test/data/extensions/platform_apps/extension_view/skeleton_two/manifest.json
@@ -1,11 +1,7 @@
 {
+  // dppcjffonoklmpdmljnpdojmoaefcabf
+  "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAthtZYql88nL9chEYC67wyAtyLcgwsPdu6HnBmKO0NHCizag6HZPnbTtjflvdW72Kdl8DwIzA4OUN2UrcR7MAIKng9liP81jtDaNnRkfkSxpbx88tfofsnZeLrcxgKQYDdTQwe+YWn6fvaJRokkq/apYix5izluNVfi2/Fz6FGSUsWEAeIPSAVgliuCZDz1SKfIZAPEwF/taEVflu1E48YFkQBVXw0QNQU4UL5S49Hf7Y2nRZvdFEzSOMFUG5AKrvPdp6vCwbJt3ooy6PJMD9kIzyfFo1kw8Jk8Z+FpIjqTWtkgZwT5JHAOg4svVzDEVSEa+Y2Tjgah0tZ9aaw+rkTwIDAQAB",
   "manifest_version": 2,
   "name": "second skeleton",
-  "minimum_chrome_version": "24.0.1307.0",
-  "version": "1.0",
-  "app": {
-    "background": {
-      "scripts": ["main.js"]
-    }
-  }
+  "version": "1.0"
 }
diff --git a/chrome/test/data/extensions/platform_apps/window_api/test.js b/chrome/test/data/extensions/platform_apps/window_api/test.js
index 1092bbd..4b3a009c 100644
--- a/chrome/test/data/extensions/platform_apps/window_api/test.js
+++ b/chrome/test/data/extensions/platform_apps/window_api/test.js
@@ -274,7 +274,7 @@
 function testDeprecatedBounds() {
   chrome.test.runTests([
     function contentSize() {
-      var options = { bounds: { left: 0, top: 0, width: 250, height: 200 } };
+      var options = { bounds: { left: 0, top: 50, width: 250, height: 200 } };
       chrome.app.window.create('test.html', options, callbackPass(
       function(win) {
         var bounds = win.getBounds();
@@ -287,7 +287,7 @@
     },
 
     function windowPosition() {
-      var options = { bounds: { left: 0, top: 0, left: 250, top: 200 } };
+      var options = { bounds: { left: 0, top: 50, width: 250, height: 200 } };
       chrome.app.window.create('test.html', options, callbackPass(
       function(win) {
         var bounds = win.getBounds();
@@ -301,7 +301,7 @@
 
     function minSize() {
       var options = {
-        bounds: { left: 0, top: 0, width: 250, height: 250 },
+        bounds: { left: 0, top: 50, width: 250, height: 250 },
         minWidth: 400, minHeight: 450
       };
       chrome.app.window.create('test.html', options, callbackPass(
@@ -315,7 +315,7 @@
 
     function maxSize() {
       var options = {
-        bounds: { left: 0, top: 0, width: 250, height: 250 },
+        bounds: { left: 0, top: 50, width: 250, height: 250 },
         maxWidth: 200, maxHeight: 150
       };
       chrome.app.window.create('test.html', options, callbackPass(
@@ -329,7 +329,7 @@
 
     function minAndMaxSize() {
       var options = {
-        bounds: { left: 0, top: 0, width: 250, height: 250 },
+        bounds: { left: 0, top: 50, width: 250, height: 250 },
         minWidth: 400, minHeight: 450,
         maxWidth: 200, maxHeight: 150
       };
@@ -344,7 +344,7 @@
 
     function simpleSetBounds() {
       chrome.app.window.create('test.html', {
-        bounds: { left: 0, top: 0, width: 250, height: 200 }
+        bounds: { left: 0, top: 50, width: 250, height: 200 }
       }, callbackPass(function(win) {
         var newBounds = {width: 400, height: 450};
         win.setBounds(newBounds);
@@ -359,7 +359,7 @@
 
     function heightOnlySetBounds() {
       chrome.app.window.create('test.html', {
-        bounds: { left: 0, top: 0, width: 300, height: 256 }
+        bounds: { left: 0, top: 50, width: 300, height: 256 }
       }, callbackPass(function(win) {
         win.setBounds({ height: 300 });
         chrome.test.waitForRoundTrip('msg', callbackPass(function() {
diff --git a/chrome/test/data/save_page/frames-nested.htm b/chrome/test/data/save_page/frames-nested.htm
new file mode 100644
index 0000000..ad2f32f8
--- /dev/null
+++ b/chrome/test/data/save_page/frames-nested.htm
@@ -0,0 +1,23 @@
+<!doctype html>
+<html>
+<head></head>
+<body>
+  <h1>Test page features</h1>
+
+  When rewriting links for top-level frame, we need to use links of the
+  form: ./foo_files/some_file.png
+  When rewriting links for other frames (i.e. for frame getting saved
+  into ./foo_files/bar.htm), we need to use links of the form:
+  ./some_other_file.png (i.e. without "foo_files").
+
+  <h1>Test content</h1>
+
+  Content verification marker:
+  frames-nested.htm: 4388232f-8d45-4d2e-9807-721b381be153
+  <br>
+  <br>
+
+  <iframe src="frames-nested2.htm" width="400" height="400"></iframe>
+  <img src="1.png"/>
+</body>
+</html>
diff --git a/chrome/test/data/save_page/frames-nested2.htm b/chrome/test/data/save_page/frames-nested2.htm
new file mode 100644
index 0000000..dca2537
--- /dev/null
+++ b/chrome/test/data/save_page/frames-nested2.htm
@@ -0,0 +1,13 @@
+<!doctype html>
+<html>
+<head></head>
+<body>
+  <h1>Test content</h1>
+
+  Content verification marker:
+  frames-nested2.htm: 6d23dc47-f283-4977-96ec-66bcf72301a4
+
+  <iframe src="b.htm" width="300" height="300"></iframe>
+  <img src="1.png"/>
+</body>
+</html>
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index c59d30e..6bc775d 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -48,40 +48,40 @@
 
 TEST_F('CrExtensionsBrowserTest', 'ExtensionSidebarLayoutTest', function() {
   extension_sidebar_tests.registerTests();
-  mocha.grep(assert(extension_sidebar_tests.testNames.Layout)).run();
+  mocha.grep(assert(extension_sidebar_tests.TestNames.Layout)).run();
 });
 TEST_F('CrExtensionsBrowserTest', 'ExtensionSidebarClickHandlerTest',
        function() {
   extension_sidebar_tests.registerTests();
-  mocha.grep(assert(extension_sidebar_tests.testNames.ClickHandlers)).run();
+  mocha.grep(assert(extension_sidebar_tests.TestNames.ClickHandlers)).run();
 });
 
 function CrExtensionsBrowserTestWithInstalledExtension() {}
 
 TEST_F('CrExtensionsBrowserTest', 'ExtensionItemNormalStateTest', function() {
   extension_item_tests.registerTests();
-  var testNames = extension_item_tests.testNames;
-  mocha.grep(assert(testNames.ElementVisibilityNormalState)).run();
+  var TestNames = extension_item_tests.TestNames;
+  mocha.grep(assert(TestNames.ElementVisibilityNormalState)).run();
 });
 
 TEST_F('CrExtensionsBrowserTest', 'ExtensionItemDetailStateTest', function() {
   extension_item_tests.registerTests();
-  var testNames = extension_item_tests.testNames;
-  mocha.grep(assert(testNames.ElementVisibilityDetailState)).run();
+  var TestNames = extension_item_tests.TestNames;
+  mocha.grep(assert(TestNames.ElementVisibilityDetailState)).run();
 });
 
 TEST_F('CrExtensionsBrowserTest', 'ExtensionItemDeveloperStateTest',
        function() {
   extension_item_tests.registerTests();
-  var testNames = extension_item_tests.testNames;
-  mocha.grep(assert(testNames.ElementVisibilityDeveloperState)).run();
+  var TestNames = extension_item_tests.TestNames;
+  mocha.grep(assert(TestNames.ElementVisibilityDeveloperState)).run();
 });
 
 TEST_F('CrExtensionsBrowserTest', 'ExtensionItemClickableItemsTest',
        function() {
   extension_item_tests.registerTests();
-  var testNames = extension_item_tests.testNames;
-  mocha.grep(assert(testNames.ClickableItems)).run();
+  var TestNames = extension_item_tests.TestNames;
+  mocha.grep(assert(TestNames.ClickableItems)).run();
 });
 
 CrExtensionsBrowserTestWithInstalledExtension.prototype = {
@@ -97,21 +97,46 @@
 TEST_F('CrExtensionsBrowserTestWithInstalledExtension',
        'ExtensionServiceToggleEnableTest', function() {
   extension_service_tests.registerTests();
-  mocha.grep(assert(extension_service_tests.testNames.EnableAndDisable)).run();
+  mocha.grep(assert(extension_service_tests.TestNames.EnableAndDisable)).run();
 });
 TEST_F('CrExtensionsBrowserTestWithInstalledExtension',
        'ExtensionServiceToggleIncognitoTest', function() {
   extension_service_tests.registerTests();
   mocha.grep(
-      assert(extension_service_tests.testNames.ToggleIncognitoMode)).run();
+      assert(extension_service_tests.TestNames.ToggleIncognitoMode)).run();
 });
 TEST_F('CrExtensionsBrowserTestWithInstalledExtension',
        'ExtensionServiceUninstallTest', function() {
   extension_service_tests.registerTests();
-  mocha.grep(assert(extension_service_tests.testNames.Uninstall)).run();
+  mocha.grep(assert(extension_service_tests.TestNames.Uninstall)).run();
 });
 TEST_F('CrExtensionsBrowserTestWithInstalledExtension',
        'ExtensionServiceProfileSettingsTest', function() {
   extension_service_tests.registerTests();
-  mocha.grep(assert(extension_service_tests.testNames.ProfileSettings)).run();
+  mocha.grep(assert(extension_service_tests.TestNames.ProfileSettings)).run();
+});
+
+function CrExtensionsBrowserTestWithMultipleExtensionTypesInstalled() {}
+
+CrExtensionsBrowserTestWithMultipleExtensionTypesInstalled.prototype = {
+  __proto__: CrExtensionsBrowserTest.prototype,
+
+  /** @override */
+  testGenPreamble: function() {
+    GEN('  InstallGoodExtension();');
+    GEN('  InstallPackagedApp();');
+    GEN('  InstallHostedApp();');
+    GEN('  InstallPlatformApp();');
+  },
+
+  /** @override */
+  extraLibraries: CrExtensionsBrowserTest.prototype.extraLibraries.concat([
+    'extension_manager_test.js',
+  ]),
+};
+
+TEST_F('CrExtensionsBrowserTestWithMultipleExtensionTypesInstalled',
+       'ExtensionManagerSplitSectionsTest', function() {
+  extension_manager_tests.registerTests();
+  mocha.grep(assert(extension_manager_tests.TestNames.SplitSections)).run();
 });
diff --git a/chrome/test/data/webui/extensions/extension_item_test.js b/chrome/test/data/webui/extensions/extension_item_test.js
index f56b008..b837ad7 100644
--- a/chrome/test/data/webui/extensions/extension_item_test.js
+++ b/chrome/test/data/webui/extensions/extension_item_test.js
@@ -124,7 +124,8 @@
     testElementsVisibility(item, devElements, false);
   }
 
-  var testNames = {
+  /** @enum {string} */
+  var TestNames = {
     ElementVisibilityNormalState: 'element visibility: normal state',
     ElementVisibilityDetailState:
         'element visibility: after tapping show details',
@@ -156,7 +157,7 @@
         document.body.appendChild(item);
       });
 
-      test(assert(testNames.ElementVisibilityNormalState), function() {
+      test(assert(TestNames.ElementVisibilityNormalState), function() {
         testNormalElementsAreVisible(item);
         testDetailElementsAreHidden(item);
         testDeveloperElementsAreHidden(item);
@@ -168,14 +169,14 @@
         expectEquals('Disabled', item.$.enabled.textContent);
       });
 
-      test(assert(testNames.ElementVisibilityDetailState), function() {
+      test(assert(TestNames.ElementVisibilityDetailState), function() {
         MockInteractions.tap(item.$['show-details']);
         testNormalElementsAreVisible(item);
         testDetailElementsAreVisible(item);
         testDeveloperElementsAreHidden(item);
       });
 
-      test(assert(testNames.ElementVisibilityDeveloperState), function() {
+      test(assert(TestNames.ElementVisibilityDeveloperState), function() {
         MockInteractions.tap(item.$['show-details']);
         item.set('inDevMode', true);
 
@@ -191,7 +192,7 @@
       });
 
       /** Tests that the delegate methods are correctly called. */
-      test(assert(testNames.ClickableItems), function() {
+      test(assert(TestNames.ClickableItems), function() {
         MockInteractions.tap(item.$['show-details']);
         item.set('inDevMode', true);
 
@@ -216,6 +217,6 @@
 
   return {
     registerTests: registerTests,
-    testNames: testNames,
+    TestNames: TestNames,
   };
 });
diff --git a/chrome/test/data/webui/extensions/extension_manager_test.js b/chrome/test/data/webui/extensions/extension_manager_test.js
new file mode 100644
index 0000000..db452e3f
--- /dev/null
+++ b/chrome/test/data/webui/extensions/extension_manager_test.js
@@ -0,0 +1,74 @@
+// Copyright 2015 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.
+
+/** @fileoverview Suite of tests for extension-sidebar. */
+cr.define('extension_manager_tests', function() {
+  /** @enum {string} */
+  var TestNames = {
+    SplitSections: 'split sections',
+  };
+
+  function registerTests() {
+    suite('ExtensionManagerTest', function() {
+      /** @type {extensions.Manager} */
+      var manager;
+
+      setup(function() {
+        manager = document.querySelector('extensions-manager');
+      });
+
+      test(assert(TestNames.SplitSections), function() {
+        var testVisible = extension_test_util.testVisible.bind(null, manager);
+        // All sections and headers should be visible.
+        testVisible('#extensions-header', true);
+        testVisible('#extensions-list', true);
+        testVisible('#apps-header', true);
+        testVisible('#apps-list', true);
+        testVisible('#websites-header', true);
+        testVisible('#websites-list', true);
+
+        var findItemWithName = function(name) {
+          var result;
+          manager.forEachItem(function(item) {
+            if (item.data.name == name) {
+              expectFalse(!!result,
+                          'Found two items with the same name: ' + name);
+              result = item;
+            }
+          });
+          expectTrue(!!result);
+          return result;
+        };
+
+        // Find each type of extension. Each should be present, visible, and
+        // sorted in the correct section.
+        var extension = findItemWithName('My extension 1');
+        var selector = '#' + extension.data.id;
+        testVisible(selector, true)
+        expectTrue(!!manager.$$('#extensions-list').querySelector(selector));
+
+        var platform_app =
+            findItemWithName('Platform App Test: minimal platform app');
+        selector = '#' + platform_app.data.id
+        testVisible(selector, true)
+        expectTrue(!!manager.$$('#apps-list').querySelector(selector));
+
+        var hosted_app = findItemWithName('hosted_app');
+        selector = '#' + hosted_app.data.id;
+        testVisible(selector, true)
+        expectTrue(!!manager.$$('#websites-list').querySelector(selector));
+
+        var packaged_app = findItemWithName('Packaged App Test');
+        selector = '#' + packaged_app.data.id;
+        testVisible(selector, true)
+        expectTrue(!!manager.$$('#websites-list').querySelector(selector));
+      });
+    });
+  }
+
+  return {
+    registerTests: registerTests,
+    TestNames: TestNames,
+  };
+});
diff --git a/chrome/test/data/webui/extensions/extension_service_test.js b/chrome/test/data/webui/extensions/extension_service_test.js
index 24fb0fd..db2a867 100644
--- a/chrome/test/data/webui/extensions/extension_service_test.js
+++ b/chrome/test/data/webui/extensions/extension_service_test.js
@@ -58,7 +58,8 @@
                function() { return true; });
   }
 
-  var testNames = {
+  /** @enum {string} */
+  var TestNames = {
     EnableAndDisable: 'enable and disable',
     ToggleIncognitoMode: 'toggle incognito mode',
     Uninstall: 'uninstall',
@@ -92,7 +93,7 @@
         manager = document.getElementsByTagName('extensions-manager')[0];
       });
 
-      test(testNames.EnableAndDisable, function(done) {
+      test(assert(TestNames.EnableAndDisable), function(done) {
         var item = manager.getItem(kExtensionId);
         assertTrue(!!item);
         expectEquals(kExtensionId, item.id);
@@ -115,7 +116,7 @@
         });
       });
 
-      test(testNames.ToggleIncognitoMode, function(done) {
+      test(assert(TestNames.ToggleIncognitoMode), function(done) {
         var item = manager.getItem(kExtensionId);
         assertTrue(!!item);
         expectTrue(item.data.incognitoAccess.isEnabled);
@@ -141,7 +142,7 @@
         });
       });
 
-      test(testNames.Uninstall, function(done) {
+      test(assert(TestNames.Uninstall), function(done) {
         var item = manager.getItem(kExtensionId);
         assertTrue(!!item);
         var uninstallListener =
@@ -155,7 +156,7 @@
         });
       });
 
-      test(testNames.ProfileSettings, function(done) {
+      test(assert(TestNames.ProfileSettings), function(done) {
         var item = manager.getItem(kExtensionId);
         assertTrue(!!item);
         expectFalse(item.inDevMode);
@@ -180,6 +181,6 @@
   return {
     ChangeListener: ChangeListener,
     registerTests: registerTests,
-    testNames: testNames,
+    TestNames: TestNames,
   };
 });
diff --git a/chrome/test/data/webui/extensions/extension_sidebar_test.js b/chrome/test/data/webui/extensions/extension_sidebar_test.js
index 59cb165..71b6726e 100644
--- a/chrome/test/data/webui/extensions/extension_sidebar_test.js
+++ b/chrome/test/data/webui/extensions/extension_sidebar_test.js
@@ -8,6 +8,7 @@
    * A mock delegate for the sidebar.
    * @constructor
    * @implements {extensions.SidebarDelegate}
+   * @implements {extensions.SidebarScrollDelegate}
    * @extends {extension_test_util.ClickMock}
    */
   function MockDelegate() {}
@@ -26,9 +27,19 @@
 
     /** @override */
     updateAllExtensions: function() {},
+
+    /** @override */
+    scrollToExtensions: function() {},
+
+    /** @override */
+    scrollToApps: function() {},
+
+    /** @override */
+    scrollToWebsites: function() {},
   };
 
-  var testNames = {
+  /** @enum {string} */
+  var TestNames = {
     Layout: 'layout',
     ClickHandlers: 'click handlers',
   };
@@ -50,9 +61,10 @@
         sidebar = document.querySelector('extensions-manager').sidebar;
         mockDelegate = new MockDelegate();
         sidebar.setDelegate(mockDelegate);
+        sidebar.setScrollDelegate(mockDelegate);
       });
 
-      test(testNames.Layout, function() {
+      test(assert(TestNames.Layout), function() {
         var testVisible = extension_test_util.testVisible.bind(null, sidebar);
         testVisible('#load-unpacked', false);
         testVisible('#pack-extensions', false);
@@ -66,7 +78,7 @@
         testVisible('#update-now', true);
       });
 
-      test(testNames.ClickHandlers, function() {
+      test(assert(TestNames.ClickHandlers), function() {
         sidebar.set('inDevMode', true);
         Polymer.dom.flush();
 
@@ -82,12 +94,18 @@
             sidebar.$$('#pack-extensions'), 'packExtension', []);
         mockDelegate.testClickingCalls(
             sidebar.$$('#update-now'), 'updateAllExtensions', []);
+        mockDelegate.testClickingCalls(
+            sidebar.$$('#sections-extensions'), 'scrollToExtensions', []);
+        mockDelegate.testClickingCalls(
+            sidebar.$$('#sections-apps'), 'scrollToApps', []);
+        mockDelegate.testClickingCalls(
+            sidebar.$$('#sections-websites'), 'scrollToWebsites', []);
       });
     });
   }
 
   return {
     registerTests: registerTests,
-    testNames: testNames,
+    TestNames: TestNames,
   };
 });
diff --git a/chrome/test/data/webui/media_router/media_router_container_tests.js b/chrome/test/data/webui/media_router/media_router_container_tests.js
index e26af872..ccdb963 100644
--- a/chrome/test/data/webui/media_router/media_router_container_tests.js
+++ b/chrome/test/data/webui/media_router/media_router_container_tests.js
@@ -93,18 +93,11 @@
         assertEquals(hidden, element.hidden);
       };
 
-      // Checks whether |expected| and the text in the |elementId| element
-      // are equal.
+      // Checks whether |expected| and the text in the |element| are equal.
       var checkElementText = function(expected, element) {
         assertEquals(expected.trim(), element.textContent.trim());
       };
 
-      // Checks whether |expected| and the text in the |elementId| element
-      // are equal given an id.
-      var checkElementTextWithId = function(expected, elementId) {
-        checkElementText(expected, container.$[elementId]);
-      };
-
       // Checks whether |expected| and the |property| in |container| are equal.
       var checkPropertyValue = function(expected, property) {
         assertEquals(expected.trim(), container.property);
@@ -146,6 +139,8 @@
           new media_router.Route('id 2', 'sink id 2', 'Title 2', 1, true),
         ];
 
+        // Note: These need to be in-order by name to prevent shuffling.
+        // Sorting of sinks by name is tested separately.
         fakeSinkList = [
           new media_router.Sink('sink id 1', 'Sink 1',
               media_router.SinkIconType.CAST,
@@ -216,7 +211,7 @@
       // Tests that |container| returns to SINK_LIST view and arrow drop icon
       // toggles after a cast mode is selected.
       test('select cast mode', function(done) {
-        container.castModeList_ = fakeCastModeListWithNonDefaultModesOnly;
+        container.castModeList = fakeCastModeListWithNonDefaultModesOnly;
 
         MockInteractions.tap(container.$['container-header'].
             $['arrow-drop-icon']);
@@ -252,7 +247,7 @@
             container.selectCastModeHeaderText_);
         assertEquals(fakeCastModeList[1].description, container.headerText);
 
-        container.castModeList_ = fakeCastModeListWithNonDefaultModesOnly;
+        container.castModeList = fakeCastModeListWithNonDefaultModesOnly;
         setTimeout(function() {
           var castModeList =
               container.$['cast-mode-list'].querySelectorAll('paper-item');
@@ -275,7 +270,7 @@
       // Tests the header text when updated with a cast mode list with a mix of
       // default and non-default cast modes.
       test('cast modes with one default mode', function(done) {
-        container.castModeList_ = fakeCastModeList;
+        container.castModeList = fakeCastModeList;
 
         setTimeout(function() {
           var castModeList =
@@ -391,21 +386,18 @@
         container.showCastModeList_();
         checkElementsVisibleWithId(['cast-mode-list',
                                     'container-header',
-                                    'device-missing',
-                                    'sink-list']);
+                                    'device-missing']);
 
         // Set a non-blocking issue. The issue should stay hidden.
         container.issue = fakeNonBlockingIssue;
         checkElementsVisibleWithId(['cast-mode-list',
                                     'container-header',
-                                    'device-missing',
-                                    'sink-list']);
+                                    'device-missing']);
 
         // Set a blocking issue. The issue should stay hidden.
         container.issue = fakeBlockingIssue;
         checkElementsVisibleWithId(['container-header',
-                                    'device-missing',
-                                    'sink-list']);
+                                    'device-missing']);
       });
 
 
@@ -414,8 +406,7 @@
         container.showRouteDetails_();
         checkElementsVisibleWithId(['container-header',
                                     'device-missing',
-                                    'route-details',
-                                    'sink-list']);
+                                    'route-details']);
       });
 
       // Tests for expected visible UI when the view is ROUTE_DETAILS, and there
@@ -429,8 +420,7 @@
           checkElementsVisibleWithId(['container-header',
                                       'device-missing',
                                       'issue-banner',
-                                      'route-details',
-                                      'sink-list']);
+                                      'route-details']);
           done();
         });
       });
@@ -446,8 +436,7 @@
         setTimeout(function() {
           checkElementsVisibleWithId(['container-header',
                                       'device-missing',
-                                      'issue-banner',
-                                      'sink-list']);
+                                      'issue-banner']);
           done();
          });
       });
@@ -457,7 +446,6 @@
         container.showSinkList_();
         checkElementsVisibleWithId(['container-header',
                                     'device-missing',
-                                    'sink-list',
                                     'sink-list-view']);
 
         // Set an non-empty sink list.
@@ -575,6 +563,61 @@
           });
          });
       });
+
+      // Tests that sinks provided in some random order will be sorted by name
+      // when shown to the user.
+      test('sinks are shown sorted by name', function(done) {
+        var outOfOrderSinks = [
+          new media_router.Sink('6543', 'Sleepy',
+              media_router.SinkIconType.CAST,
+              media_router.SinkStatus.ACTIVE, [1]),
+          new media_router.Sink('543', 'Happy',
+              media_router.SinkIconType.CAST,
+              media_router.SinkStatus.ACTIVE, [1]),
+          new media_router.Sink('43', 'Bashful',
+              media_router.SinkIconType.CAST,
+              media_router.SinkStatus.ACTIVE, [1]),
+          new media_router.Sink('2', 'George',
+              media_router.SinkIconType.CAST_AUDIO,
+              media_router.SinkStatus.ACTIVE, [1]),
+          new media_router.Sink('1', 'George',
+              media_router.SinkIconType.CAST,
+              media_router.SinkStatus.ACTIVE, [1]),
+          new media_router.Sink('3', 'George',
+              media_router.SinkIconType.HANGOUT,
+              media_router.SinkStatus.ACTIVE, [1]),
+        ];
+
+        container.allSinks = outOfOrderSinks;
+
+        setTimeout(function() {
+          var sinkList =
+              container.$['sink-list'].querySelectorAll('paper-item');
+
+          assertEquals(6, sinkList.length);
+          checkElementText('Bashful', sinkList[0]);
+          checkElementText('George', sinkList[1]);
+          checkElementText('George', sinkList[2]);
+          checkElementText('George', sinkList[3]);
+          checkElementText('Happy', sinkList[4]);
+          checkElementText('Sleepy', sinkList[5]);
+
+          // There are three George's, so check that the first has id '1', the
+          // second has id '2', and the third has id '3'.  The icons are used to
+          // determine which is which.
+          assertEquals(
+              container.computeSinkIcon_(outOfOrderSinks[4]),
+              sinkList[1].querySelector('iron-icon').icon);
+          assertEquals(
+              container.computeSinkIcon_(outOfOrderSinks[3]),
+              sinkList[2].querySelector('iron-icon').icon);
+          assertEquals(
+              container.computeSinkIcon_(outOfOrderSinks[5]),
+              sinkList[3].querySelector('iron-icon').icon);
+
+          done();
+        });
+      });
     });
   }
 
diff --git a/chrome/test/media_router/media_router_e2e_browsertest.cc b/chrome/test/media_router/media_router_e2e_browsertest.cc
index 256f26d90..4b6ecd4 100644
--- a/chrome/test/media_router/media_router_e2e_browsertest.cc
+++ b/chrome/test/media_router/media_router_e2e_browsertest.cc
@@ -76,6 +76,7 @@
     content::WebContents* web_contents) {
   DCHECK(media_router_);
   observer_.reset(new TestMediaSinksObserver(media_router_, source));
+  observer_->Init();
 
   DVLOG(1) << "Receiver name: " << receiver_;
   // Wait for MediaSinks compatible with |source| to be discovered.
diff --git a/chrome/test/media_router/resources/common.js b/chrome/test/media_router/resources/common.js
index 8265f14..19baed4 100644
--- a/chrome/test/media_router/resources/common.js
+++ b/chrome/test/media_router/resources/common.js
@@ -30,7 +30,10 @@
     if (availability.value) {
       sendResult(true, '');
     } else {
-      sendResult(false, 'device unavailable');
+      availability.onchange = function(newAvailability) {
+        if (newAvailability)
+          sendResult(true, '');
+      }
     }
   }).catch(function(){
     sendResult(false, 'got error');
diff --git a/chrome_elf/BUILD.gn b/chrome_elf/BUILD.gn
index 50eca48..4f9c7474 100644
--- a/chrome_elf/BUILD.gn
+++ b/chrome_elf/BUILD.gn
@@ -58,7 +58,6 @@
     ":constants",
   ]
   sources = [
-    "chrome_elf_types.h",
     "chrome_elf_util.cc",
     "chrome_elf_util.h",
     "thunk_getter.cc",
diff --git a/chrome_elf/chrome_elf.gyp b/chrome_elf/chrome_elf.gyp
index 1532c17..26fc27ca 100644
--- a/chrome_elf/chrome_elf.gyp
+++ b/chrome_elf/chrome_elf.gyp
@@ -122,7 +122,6 @@
         '..',
       ],
       'sources': [
-        'chrome_elf_types.h',
         'chrome_elf_util.cc',
         'chrome_elf_util.h',
         'thunk_getter.cc',
diff --git a/chromecast/BUILD.gn b/chromecast/BUILD.gn
index 6ac19639..22b0a56 100644
--- a/chromecast/BUILD.gn
+++ b/chromecast/BUILD.gn
@@ -15,25 +15,12 @@
   use_chromecast_webui = true
 }
 
-# TODO(slan): This target is being used far too broadly. We should reduce the
-# uses of this config to targets that actually need it. (b/23814594)
-config("config") {
-  defines = []
-
-  if (use_playready) {
-    defines += [ "PLAYREADY_CDM_AVAILABLE" ]
+if (use_playready) {
+  config("playready_config") {
+    defines = [ "PLAYREADY_CDM_AVAILABLE" ]
   }
 }
 
-component("chromecast") {
-  deps = [
-    "//chromecast/base",
-    "//chromecast/base/metrics",
-    "//chromecast/crash",
-    "//chromecast/media",
-  ]
-}
-
 # A list of all public test() binaries. This is an organizational target that
 # cannot be depended upon or built directly. Build cast_group_test_list instead.
 cast_test_group("cast_tests") {
diff --git a/chromecast/app/BUILD.gn b/chromecast/app/BUILD.gn
index c3746d4..ba591b6 100644
--- a/chromecast/app/BUILD.gn
+++ b/chromecast/app/BUILD.gn
@@ -34,8 +34,6 @@
     "linux/cast_crash_reporter_client.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     "//base",
     "//chromecast/base",
diff --git a/chromecast/base/BUILD.gn b/chromecast/base/BUILD.gn
index 0cc4755..7ec6e603 100644
--- a/chromecast/base/BUILD.gn
+++ b/chromecast/base/BUILD.gn
@@ -37,8 +37,6 @@
     "task_runner_impl.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   public_deps = [
     "//chromecast/base/metrics",
     "//chromecast/public",
diff --git a/chromecast/base/metrics/BUILD.gn b/chromecast/base/metrics/BUILD.gn
index 191b304..a9556a5 100644
--- a/chromecast/base/metrics/BUILD.gn
+++ b/chromecast/base/metrics/BUILD.gn
@@ -11,8 +11,6 @@
     "grouped_histogram.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     "//base",
   ]
@@ -33,6 +31,4 @@
   deps = [
     "//base",
   ]
-
-  configs += [ "//chromecast:config" ]
 }
diff --git a/chromecast/browser/media/BUILD.gn b/chromecast/browser/media/BUILD.gn
index a562540..a643e3a2 100644
--- a/chromecast/browser/media/BUILD.gn
+++ b/chromecast/browser/media/BUILD.gn
@@ -18,6 +18,10 @@
     "media_pipeline_host.h",
   ]
 
+  if (use_playready) {
+    public_configs = [ "//chromecast:playready_config" ]
+  }
+
   deps = [
     "//base",
     "//chromecast/base",
diff --git a/chromecast/chromecast.gni b/chromecast/chromecast.gni
index 2edb0694..fa36ec98 100644
--- a/chromecast/chromecast.gni
+++ b/chromecast/chromecast.gni
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//build/config/chromecast_build.gni")
+
 # This args block should contain arguments used within the //chromecast
 # directory. Arguments which are used in other Chrome components should
 # be instead declared in //build/config/chromecast_build.gni.
@@ -15,7 +17,4 @@
 
   # Use Playready CDMs.
   use_playready = false
-
-  # Set this true to perform an audio-only build.
-  disable_display = false
 }
diff --git a/chromecast/crash/BUILD.gn b/chromecast/crash/BUILD.gn
index 28fb28b..ce4b31e5 100644
--- a/chromecast/crash/BUILD.gn
+++ b/chromecast/crash/BUILD.gn
@@ -27,8 +27,6 @@
     "linux/synchronized_minidump_manager.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     "//base",
     "//breakpad:client",
diff --git a/chromecast/crypto/BUILD.gn b/chromecast/crypto/BUILD.gn
index 8964b4d4..d7ff30df 100644
--- a/chromecast/crypto/BUILD.gn
+++ b/chromecast/crypto/BUILD.gn
@@ -11,8 +11,6 @@
     "signature_cache.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     "//base",
   ]
diff --git a/chromecast/media/BUILD.gn b/chromecast/media/BUILD.gn
index 5144799..b54ba7d1 100644
--- a/chromecast/media/BUILD.gn
+++ b/chromecast/media/BUILD.gn
@@ -36,8 +36,6 @@
     "cma/test/run_all_unittests.cc",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     ":media",
     "//chromecast/media/audio",
diff --git a/chromecast/media/audio/BUILD.gn b/chromecast/media/audio/BUILD.gn
index 3066fa4..4aeeb38 100644
--- a/chromecast/media/audio/BUILD.gn
+++ b/chromecast/media/audio/BUILD.gn
@@ -12,8 +12,6 @@
     "cast_audio_output_stream.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     "//base",
     "//chromecast/base",
diff --git a/chromecast/media/base/BUILD.gn b/chromecast/media/base/BUILD.gn
index b6d90b9..7d02a3a 100644
--- a/chromecast/media/base/BUILD.gn
+++ b/chromecast/media/base/BUILD.gn
@@ -16,8 +16,6 @@
     "//chromecast/public/media",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     "//base",
     "//chromecast/media/base:libcast_media_1.0",
@@ -31,7 +29,9 @@
     "key_systems_common.h",
   ]
 
-  configs += [ "//chromecast:config" ]
+  if (use_playready) {
+    public_configs = [ "//chromecast:playready_config" ]
+  }
 
   deps = [
     "//base",
@@ -62,8 +62,6 @@
     "//chromecast/public/media",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     ":libcast_media_1.0",
     "//base",
@@ -100,8 +98,6 @@
     "cast_media_default.cc",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   public_deps = [
     "//chromecast/public",
     "//chromecast/public/media",
@@ -123,8 +119,6 @@
     "cast_media_default.cc",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   public_deps = [
     "//chromecast/public",
     "//chromecast/public/media",
diff --git a/chromecast/media/cdm/BUILD.gn b/chromecast/media/cdm/BUILD.gn
index 1a929d0..cc9fa01 100644
--- a/chromecast/media/cdm/BUILD.gn
+++ b/chromecast/media/cdm/BUILD.gn
@@ -2,10 +2,15 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//chromecast/chromecast.gni")
+
+# GYP target: chromecast/media.gyp:media_cdm
 source_set("cdm") {
   sources = [
     "browser_cdm_cast.cc",
     "browser_cdm_cast.h",
+    "chromecast_init_data.cc",
+    "chromecast_init_data.h",
   ]
 
   deps = [
@@ -14,5 +19,12 @@
     "//media",
   ]
 
-  configs += [ "//chromecast:config" ]
+  if (is_android && use_playready) {
+    sources += [
+      "playready_drm_delegate_android.cc",
+      "playready_drm_delegate_android.h",
+    ]
+
+    deps += [ "//media/base/android" ]
+  }
 }
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn
index 4f30a05..fc72d02 100644
--- a/chromecast/media/cma/backend/BUILD.gn
+++ b/chromecast/media/cma/backend/BUILD.gn
@@ -20,6 +20,4 @@
   deps = [
     "//base",
   ]
-
-  configs += [ "//chromecast:config" ]
 }
diff --git a/chromecast/media/cma/base/BUILD.gn b/chromecast/media/cma/base/BUILD.gn
index b0ebefd..2e4059c 100644
--- a/chromecast/media/cma/base/BUILD.gn
+++ b/chromecast/media/cma/base/BUILD.gn
@@ -30,8 +30,6 @@
     "simple_media_task_runner.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   public_deps = [
     "//chromecast/public/media",
   ]
diff --git a/chromecast/media/cma/ipc/BUILD.gn b/chromecast/media/cma/ipc/BUILD.gn
index 85ed2ac03..e70b184 100644
--- a/chromecast/media/cma/ipc/BUILD.gn
+++ b/chromecast/media/cma/ipc/BUILD.gn
@@ -13,8 +13,6 @@
     "media_message_type.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   deps = [
     "//base",
     "//chromecast/media/cma/base",
diff --git a/chromecast/media/cma/ipc_streamer/BUILD.gn b/chromecast/media/cma/ipc_streamer/BUILD.gn
index 380a965..a3429d641 100644
--- a/chromecast/media/cma/ipc_streamer/BUILD.gn
+++ b/chromecast/media/cma/ipc_streamer/BUILD.gn
@@ -18,8 +18,6 @@
     "video_decoder_config_marshaller.h",
   ]
 
-  configs += [ "//chromecast:config" ]
-
   public_deps = [
     "//chromecast/public/media",
   ]
diff --git a/chromecast/media/cma/pipeline/BUILD.gn b/chromecast/media/cma/pipeline/BUILD.gn
index 1bfbd84..c8581e6 100644
--- a/chromecast/media/cma/pipeline/BUILD.gn
+++ b/chromecast/media/cma/pipeline/BUILD.gn
@@ -39,6 +39,4 @@
     "//media",
     "//third_party/boringssl",
   ]
-
-  configs += [ "//chromecast:config" ]
 }
diff --git a/chromecast/renderer/BUILD.gn b/chromecast/renderer/BUILD.gn
index cd7f240..940fc39 100644
--- a/chromecast/renderer/BUILD.gn
+++ b/chromecast/renderer/BUILD.gn
@@ -26,6 +26,10 @@
     ]
   }
 
+  if (use_playready) {
+    configs += [ "//chromecast:playready_config" ]
+  }
+
   deps = [
     "//base",
     "//chromecast/base",
diff --git a/chromecast/renderer/media/hole_frame_factory.cc b/chromecast/renderer/media/hole_frame_factory.cc
index 5d9adda..8c2cb0a 100644
--- a/chromecast/renderer/media/hole_frame_factory.cc
+++ b/chromecast/renderer/media/hole_frame_factory.cc
@@ -33,7 +33,9 @@
       gl->GenMailboxCHROMIUM(mailbox_.name);
       gl->ProduceTextureDirectCHROMIUM(texture_, GL_TEXTURE_2D, mailbox_.name);
 
-      sync_token_ = gpu::SyncToken(gl->InsertSyncPointCHROMIUM());
+      const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM();
+      gl->ShallowFlushCHROMIUM();
+      gl->GenSyncTokenCHROMIUM(fence_sync, sync_token_.GetData());
     }
   }
 }
diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp
index 2f93d9ed..4499f755 100644
--- a/chromeos/chromeos.gyp
+++ b/chromeos/chromeos.gyp
@@ -350,6 +350,8 @@
       'network/portal_detector/network_portal_detector_strategy.h',
       'network/portal_detector/network_portal_detector_stub.cc',
       'network/portal_detector/network_portal_detector_stub.h',
+      'network/prohibited_technologies_handler.cc',
+      'network/prohibited_technologies_handler.h',
       'network/shill_property_handler.cc',
       'network/shill_property_handler.h',
       'network/shill_property_util.cc',
@@ -446,6 +448,7 @@
       'network/onc/onc_translator_unittest.cc',
       'network/onc/onc_utils_unittest.cc',
       'network/onc/onc_validator_unittest.cc',
+      'network/prohibited_technologies_handler_unittest.cc',
       'network/shill_property_handler_unittest.cc',
       'process_proxy/process_output_watcher_unittest.cc',
       'process_proxy/process_proxy_unittest.cc',
diff --git a/chromeos/network/auto_connect_handler_unittest.cc b/chromeos/network/auto_connect_handler_unittest.cc
index 9749ee4..0181a74 100644
--- a/chromeos/network/auto_connect_handler_unittest.cc
+++ b/chromeos/network/auto_connect_handler_unittest.cc
@@ -121,7 +121,8 @@
     managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
     managed_config_handler_->Init(
         network_state_handler_.get(), network_profile_handler_.get(),
-        network_config_handler_.get(), nullptr /* network_device_handler */);
+        network_config_handler_.get(), nullptr /* network_device_handler */,
+        nullptr /* prohibited_technologies_handler */);
 
     client_cert_resolver_.reset(new ClientCertResolver());
     client_cert_resolver_->Init(network_state_handler_.get(),
diff --git a/chromeos/network/client_cert_resolver_unittest.cc b/chromeos/network/client_cert_resolver_unittest.cc
index 0109b8c..7f2035b 100644
--- a/chromeos/network/client_cert_resolver_unittest.cc
+++ b/chromeos/network/client_cert_resolver_unittest.cc
@@ -140,11 +140,11 @@
 
     network_profile_handler_->Init();
     network_config_handler_->Init(network_state_handler_.get(),
-                                  NULL /* network_device_handler */);
-    managed_config_handler_->Init(network_state_handler_.get(),
-                                  network_profile_handler_.get(),
-                                  network_config_handler_.get(),
-                                  NULL /* network_device_handler */);
+                                  nullptr /* network_device_handler */);
+    managed_config_handler_->Init(
+        network_state_handler_.get(), network_profile_handler_.get(),
+        network_config_handler_.get(), nullptr /* network_device_handler */,
+        nullptr /* prohibited_technologies_handler */);
     // Run all notifications before starting the cert loader to reduce run time.
     base::RunLoop().RunUntilIdle();
 
diff --git a/chromeos/network/managed_network_configuration_handler_impl.cc b/chromeos/network/managed_network_configuration_handler_impl.cc
index c040723..16648c3 100644
--- a/chromeos/network/managed_network_configuration_handler_impl.cc
+++ b/chromeos/network/managed_network_configuration_handler_impl.cc
@@ -34,6 +34,7 @@
 #include "chromeos/network/onc/onc_utils.h"
 #include "chromeos/network/onc/onc_validator.h"
 #include "chromeos/network/policy_util.h"
+#include "chromeos/network/prohibited_technologies_handler.h"
 #include "chromeos/network/shill_property_util.h"
 #include "components/onc/onc_constants.h"
 #include "third_party/cros_system_api/dbus/service_constants.h"
@@ -426,6 +427,19 @@
 
   policies->global_network_config.MergeDictionary(&global_network_config);
 
+  // Update prohibited technologies.
+  const base::ListValue* prohibited_list = nullptr;
+  if (policies->global_network_config.GetListWithoutPathExpansion(
+          ::onc::global_network_config::kDisableNetworkTypes,
+          &prohibited_list) &&
+      prohibited_technologies_handler_) {
+    // Prohobited technologies are only allowed in user policy.
+    DCHECK_EQ(::onc::ONC_SOURCE_DEVICE_POLICY, onc_source);
+
+    prohibited_technologies_handler_->SetProhibitedTechnologies(
+        prohibited_list);
+  }
+
   GuidToPolicyMap old_per_network_config;
   policies->per_network_config.swap(old_per_network_config);
 
@@ -709,12 +723,14 @@
     NetworkStateHandler* network_state_handler,
     NetworkProfileHandler* network_profile_handler,
     NetworkConfigurationHandler* network_configuration_handler,
-    NetworkDeviceHandler* network_device_handler) {
+    NetworkDeviceHandler* network_device_handler,
+    ProhibitedTechnologiesHandler* prohibited_technologies_handler) {
   network_state_handler_ = network_state_handler;
   network_profile_handler_ = network_profile_handler;
   network_configuration_handler_ = network_configuration_handler;
   network_device_handler_ = network_device_handler;
   network_profile_handler_->AddObserver(this);
+  prohibited_technologies_handler_ = prohibited_technologies_handler;
 }
 
 void ManagedNetworkConfigurationHandlerImpl::OnPolicyAppliedToNetwork(
diff --git a/chromeos/network/managed_network_configuration_handler_impl.h b/chromeos/network/managed_network_configuration_handler_impl.h
index a204b04..23a8f72 100644
--- a/chromeos/network/managed_network_configuration_handler_impl.h
+++ b/chromeos/network/managed_network_configuration_handler_impl.h
@@ -112,6 +112,7 @@
   friend class ManagedNetworkConfigurationHandlerTest;
   friend class NetworkConnectionHandlerTest;
   friend class NetworkHandler;
+  friend class ProhibitedTechnologiesHandlerTest;
 
   struct Policies;
   typedef base::Callback<void(const std::string& service_path,
@@ -130,7 +131,8 @@
   void Init(NetworkStateHandler* network_state_handler,
             NetworkProfileHandler* network_profile_handler,
             NetworkConfigurationHandler* network_configuration_handler,
-            NetworkDeviceHandler* network_device_handler);
+            NetworkDeviceHandler* network_device_handler,
+            ProhibitedTechnologiesHandler* prohibitied_technologies_handler);
 
   // Sends the response to the caller of GetManagedProperties.
   void SendManagedProperties(
@@ -201,6 +203,7 @@
   NetworkProfileHandler* network_profile_handler_;
   NetworkConfigurationHandler* network_configuration_handler_;
   NetworkDeviceHandler* network_device_handler_;
+  ProhibitedTechnologiesHandler* prohibited_technologies_handler_;
 
   // Owns the currently running PolicyApplicators.
   UserToPolicyApplicatorMap policy_applicators_;
diff --git a/chromeos/network/managed_network_configuration_handler_unittest.cc b/chromeos/network/managed_network_configuration_handler_unittest.cc
index c95d6b1..6580156 100644
--- a/chromeos/network/managed_network_configuration_handler_unittest.cc
+++ b/chromeos/network/managed_network_configuration_handler_unittest.cc
@@ -260,14 +260,13 @@
     network_configuration_handler_.reset(
         NetworkConfigurationHandler::InitializeForTest(
             network_state_handler_.get(),
-            NULL /* no NetworkDeviceHandler */));
+            nullptr /* no NetworkDeviceHandler */));
     managed_network_configuration_handler_.reset(
         new ManagedNetworkConfigurationHandlerImpl());
     managed_network_configuration_handler_->Init(
-        network_state_handler_.get(),
-        network_profile_handler_.get(),
-        network_configuration_handler_.get(),
-        NULL /* no DeviceHandler */);
+        network_state_handler_.get(), network_profile_handler_.get(),
+        network_configuration_handler_.get(), nullptr /* no DeviceHandler */,
+        nullptr /* no ProhibitedTechnologiesHandler */);
     managed_network_configuration_handler_->AddObserver(&policy_observer_);
 
     message_loop_.RunUntilIdle();
@@ -337,7 +336,10 @@
     // These calls occur in NetworkConfigurationHandler.
     EXPECT_CALL(*mock_manager_client_, GetProperties(_)).Times(AnyNumber());
     EXPECT_CALL(*mock_manager_client_,
-                AddPropertyChangedObserver(_)).Times(AnyNumber());
+                SetProperty("ProhibitedTechnologies", _, _, _))
+        .Times(AnyNumber());
+    EXPECT_CALL(*mock_manager_client_, AddPropertyChangedObserver(_))
+        .Times(AnyNumber());
     EXPECT_CALL(*mock_manager_client_,
                 RemovePropertyChangedObserver(_)).Times(AnyNumber());
   }
diff --git a/chromeos/network/network_connection_handler_unittest.cc b/chromeos/network/network_connection_handler_unittest.cc
index f4d2b1544..1ae00af 100644
--- a/chromeos/network/network_connection_handler_unittest.cc
+++ b/chromeos/network/network_connection_handler_unittest.cc
@@ -145,7 +145,8 @@
     managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
     managed_config_handler_->Init(
         network_state_handler_.get(), network_profile_handler_.get(),
-        network_config_handler_.get(), nullptr /* network_device_handler */);
+        network_config_handler_.get(), nullptr /* network_device_handler */,
+        nullptr /* prohibited_tecnologies_handler */);
 
     network_connection_handler_.reset(new NetworkConnectionHandler);
     network_connection_handler_->Init(network_state_handler_.get(),
diff --git a/chromeos/network/network_handler.cc b/chromeos/network/network_handler.cc
index 0ce9ff8c..b10bad7 100644
--- a/chromeos/network/network_handler.cc
+++ b/chromeos/network/network_handler.cc
@@ -21,6 +21,7 @@
 #include "chromeos/network/network_sms_handler.h"
 #include "chromeos/network/network_state_handler.h"
 #include "chromeos/network/network_state_handler_observer.h"
+#include "chromeos/network/prohibited_technologies_handler.h"
 
 namespace chromeos {
 
@@ -36,6 +37,7 @@
   network_configuration_handler_.reset(new NetworkConfigurationHandler());
   managed_network_configuration_handler_.reset(
       new ManagedNetworkConfigurationHandlerImpl());
+  prohibited_technologies_handler_.reset(new ProhibitedTechnologiesHandler());
   if (CertLoader::IsInitialized()) {
     auto_connect_handler_.reset(new AutoConnectHandler());
     network_cert_migrator_.reset(new NetworkCertMigrator());
@@ -57,10 +59,9 @@
   network_configuration_handler_->Init(network_state_handler_.get(),
                                        network_device_handler_.get());
   managed_network_configuration_handler_->Init(
-      network_state_handler_.get(),
-      network_profile_handler_.get(),
-      network_configuration_handler_.get(),
-      network_device_handler_.get());
+      network_state_handler_.get(), network_profile_handler_.get(),
+      network_configuration_handler_.get(), network_device_handler_.get(),
+      prohibited_technologies_handler_.get());
   network_connection_handler_->Init(
       network_state_handler_.get(),
       network_configuration_handler_.get(),
@@ -77,6 +78,9 @@
                                 network_state_handler_.get(),
                                 managed_network_configuration_handler_.get());
   }
+  prohibited_technologies_handler_->Init(
+      managed_network_configuration_handler_.get(),
+      network_state_handler_.get());
   network_sms_handler_->Init();
   geolocation_handler_->Init();
 }
@@ -144,4 +148,9 @@
   return geolocation_handler_.get();
 }
 
+ProhibitedTechnologiesHandler*
+NetworkHandler::prohibited_technologies_handler() {
+  return prohibited_technologies_handler_.get();
+}
+
 }  // namespace chromeos
diff --git a/chromeos/network/network_handler.h b/chromeos/network/network_handler.h
index 82d7441e..93658e0 100644
--- a/chromeos/network/network_handler.h
+++ b/chromeos/network/network_handler.h
@@ -27,6 +27,7 @@
 class NetworkProfileHandler;
 class NetworkStateHandler;
 class NetworkSmsHandler;
+class ProhibitedTechnologiesHandler;
 
 // Class for handling initialization and access to chromeos network handlers.
 // This class should NOT be used in unit tests. Instead, construct individual
@@ -61,6 +62,7 @@
   NetworkConnectionHandler* network_connection_handler();
   NetworkSmsHandler* network_sms_handler();
   GeolocationHandler* geolocation_handler();
+  ProhibitedTechnologiesHandler* prohibited_technologies_handler();
 
  private:
   NetworkHandler();
@@ -83,6 +85,7 @@
   scoped_ptr<AutoConnectHandler> auto_connect_handler_;
   scoped_ptr<NetworkSmsHandler> network_sms_handler_;
   scoped_ptr<GeolocationHandler> geolocation_handler_;
+  scoped_ptr<ProhibitedTechnologiesHandler> prohibited_technologies_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(NetworkHandler);
 };
diff --git a/chromeos/network/network_profile_handler.h b/chromeos/network/network_profile_handler.h
index 5b55ba6..af5045ad 100644
--- a/chromeos/network/network_profile_handler.h
+++ b/chromeos/network/network_profile_handler.h
@@ -65,6 +65,7 @@
   friend class ClientCertResolverTest;
   friend class NetworkConnectionHandlerTest;
   friend class NetworkHandler;
+  friend class ProhibitedTechnologiesHandlerTest;
   NetworkProfileHandler();
 
   // Add ShillManagerClient property observer and request initial list.
diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc
index e1f18902..5007837 100644
--- a/chromeos/network/network_state_handler.cc
+++ b/chromeos/network/network_state_handler.cc
@@ -144,6 +144,15 @@
   NotifyDeviceListChanged();
 }
 
+void NetworkStateHandler::SetProhibitedTechnologies(
+    const std::vector<std::string>& prohibited_technologies,
+    const network_handler::ErrorCallback& error_callback) {
+  shill_property_handler_->SetProhibitedTechnologies(prohibited_technologies,
+                                                     error_callback);
+  // Signal Device/Technology state changed.
+  NotifyDeviceListChanged();
+}
+
 const DeviceState* NetworkStateHandler::GetDeviceState(
     const std::string& device_path) const {
   const DeviceState* device = GetModifiableDeviceState(device_path);
diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h
index d7d1acd..a700f821 100644
--- a/chromeos/network/network_state_handler.h
+++ b/chromeos/network/network_state_handler.h
@@ -103,6 +103,13 @@
       bool enabled,
       const network_handler::ErrorCallback& error_callback);
 
+  // Asynchronously sets the list of prohibited technologies. The accepted
+  // values are the shill network technology identifiers. See also
+  // chromeos::onc::Validator::ValidateGlobalNetworkConfiguration().
+  void SetProhibitedTechnologies(
+      const std::vector<std::string>& prohibited_technologies,
+      const network_handler::ErrorCallback& error_callback);
+
   // Finds and returns a device state by |device_path| or NULL if not found.
   const DeviceState* GetDeviceState(const std::string& device_path) const;
 
diff --git a/chromeos/network/onc/onc_signature.cc b/chromeos/network/onc/onc_signature.cc
index 562730c..0587c11 100644
--- a/chromeos/network/onc/onc_signature.cc
+++ b/chromeos/network/onc/onc_signature.cc
@@ -341,6 +341,8 @@
 const OncFieldSignature global_network_configuration_fields[] = {
     {::onc::global_network_config::kAllowOnlyPolicyNetworksToAutoconnect,
      &kBoolSignature},
+    {::onc::global_network_config::kAllowOnlyPolicyNetworksToConnect,
+     &kBoolSignature},
     {::onc::global_network_config::kDisableNetworkTypes, &kStringListSignature},
     {NULL}};
 
diff --git a/chromeos/network/onc/onc_validator.cc b/chromeos/network/onc/onc_validator.cc
index 74512fa..ee681aac 100644
--- a/chromeos/network/onc/onc_validator.cc
+++ b/chromeos/network/onc/onc_validator.cc
@@ -887,11 +887,22 @@
   const base::ListValue* disabled_network_types = NULL;
   if (result->GetListWithoutPathExpansion(kDisableNetworkTypes,
                                           &disabled_network_types)) {
-    // The kDisableNetworkTypes field is only allowed in user policy.
+    // The kDisableNetworkTypes field is only allowed in device policy.
     if (!disabled_network_types->empty() &&
-        onc_source_ != ::onc::ONC_SOURCE_USER_POLICY) {
+        onc_source_ != ::onc::ONC_SOURCE_DEVICE_POLICY) {
       error_or_warning_found_ = true;
-      LOG(ERROR) << "Disabled network types only allowed in user policy.";
+      LOG(ERROR) << "Disabled network types only allowed in device policy.";
+      return false;
+    }
+  }
+
+  if (result->HasKey(kAllowOnlyPolicyNetworksToConnect)) {
+    // The kAllowOnlyPolicyNetworksToConnect field is only allowed in device
+    // policy.
+    if (onc_source_ != ::onc::ONC_SOURCE_DEVICE_POLICY) {
+      error_or_warning_found_ = true;
+      LOG(ERROR)
+          << "AllowOnlyPolicyNetworksToConnect only allowed in device policy.";
       return false;
     }
   }
diff --git a/chromeos/network/onc/onc_validator_unittest.cc b/chromeos/network/onc/onc_validator_unittest.cc
index 05c0df1..7fc6a26 100644
--- a/chromeos/network/onc/onc_validator_unittest.cc
+++ b/chromeos/network/onc/onc_validator_unittest.cc
@@ -149,11 +149,16 @@
                   &kToplevelConfigurationSignature,
                   true,
                   ::onc::ONC_SOURCE_DEVICE_POLICY),
-        // Disabled technologies are only allowed for user policies.
+        // Disabled technologies are only allowed for device policies.
         OncParams("managed_toplevel_with_disabled_technologies.onc",
                   &kToplevelConfigurationSignature,
                   true,
-                  ::onc::ONC_SOURCE_USER_POLICY),
+                  ::onc::ONC_SOURCE_DEVICE_POLICY),
+        // AllowOnlyPolicyNetworksToConnect is only allowed for device policies.
+        OncParams("managed_toplevel_with_only_managed.onc",
+                  &kToplevelConfigurationSignature,
+                  true,
+                  ::onc::ONC_SOURCE_DEVICE_POLICY),
         OncParams("managed_toplevel_l2tpipsec.onc",
                   &kToplevelConfigurationSignature,
                   true),
diff --git a/chromeos/network/prohibited_technologies_handler.cc b/chromeos/network/prohibited_technologies_handler.cc
new file mode 100644
index 0000000..5d41e31
--- /dev/null
+++ b/chromeos/network/prohibited_technologies_handler.cc
@@ -0,0 +1,112 @@
+// Copyright 2014 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 "chromeos/network/prohibited_technologies_handler.h"
+
+#include "chromeos/network/managed_network_configuration_handler.h"
+#include "chromeos/network/network_state_handler.h"
+#include "chromeos/network/network_util.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+ProhibitedTechnologiesHandler::ProhibitedTechnologiesHandler() {}
+
+ProhibitedTechnologiesHandler::~ProhibitedTechnologiesHandler() {
+  if (managed_network_configuration_handler_)
+    managed_network_configuration_handler_->RemoveObserver(this);
+  if (LoginState::IsInitialized())
+    LoginState::Get()->RemoveObserver(this);
+}
+
+void ProhibitedTechnologiesHandler::Init(
+    ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
+    NetworkStateHandler* network_state_handler) {
+  if (LoginState::IsInitialized())
+    LoginState::Get()->AddObserver(this);
+
+  managed_network_configuration_handler_ =
+      managed_network_configuration_handler;
+  if (managed_network_configuration_handler_)
+    managed_network_configuration_handler_->AddObserver(this);
+  network_state_handler_ = network_state_handler;
+
+  // Clear the list of prohibited network technologies. As a user logout always
+  // triggers a browser process restart, Init() is always invoked to reallow any
+  // network technology forbidden for the previous user.
+  network_state_handler_->SetProhibitedTechnologies(
+      std::vector<std::string>(), chromeos::network_handler::ErrorCallback());
+
+  if (LoginState::IsInitialized())
+    LoggedInStateChanged();
+}
+
+void ProhibitedTechnologiesHandler::LoggedInStateChanged() {
+  user_logged_in_ = LoginState::Get()->IsUserLoggedIn();
+  EnforceProhibitedTechnologies();
+}
+
+void ProhibitedTechnologiesHandler::PoliciesChanged(
+    const std::string& userhash) {}
+
+void ProhibitedTechnologiesHandler::PoliciesApplied(
+    const std::string& userhash) {
+  if (userhash.empty())
+    return;
+  user_policy_applied_ = true;
+  EnforceProhibitedTechnologies();
+}
+
+void ProhibitedTechnologiesHandler::SetProhibitedTechnologies(
+    const base::ListValue* prohibited_list) {
+  // Build up prohibited network type list and save it for furthur use when
+  // enforced
+  prohibited_technologies_.clear();
+  for (const base::Value* item : *prohibited_list) {
+    std::string prohibited_technology;
+    item->GetAsString(&prohibited_technology);
+    std::string translated_tech =
+        network_util::TranslateONCTypeToShill(prohibited_technology);
+    if (!translated_tech.empty())
+      prohibited_technologies_.push_back(translated_tech);
+  }
+  EnforceProhibitedTechnologies();
+}
+
+void ProhibitedTechnologiesHandler::EnforceProhibitedTechnologies() {
+  if (user_logged_in_ && user_policy_applied_) {
+    network_state_handler_->SetProhibitedTechnologies(
+        prohibited_technologies_, network_handler::ErrorCallback());
+    if (std::find(prohibited_technologies_.begin(),
+                  prohibited_technologies_.end(),
+                  shill::kTypeEthernet) != prohibited_technologies_.end())
+      return;
+  } else {
+    // This is done to make sure prohibited technologies are cleared
+    // before user policy is applied.
+    network_state_handler_->SetProhibitedTechnologies(
+        std::vector<std::string>(), network_handler::ErrorCallback());
+  }
+
+  // Enable ethernet back as user doesn't have a place to enable it back
+  // if user shuts down directly in a user session. As shill will persist
+  // ProhibitedTechnologies which may include ethernet, making users can
+  // not find Ethernet at next boot or logging out unless user log out first
+  // and then shutdown.
+  if (network_state_handler_->IsTechnologyAvailable(
+          NetworkTypePattern::Ethernet()) &&
+      !network_state_handler_->IsTechnologyEnabled(
+          NetworkTypePattern::Ethernet()))
+    network_state_handler_->SetTechnologyEnabled(
+        NetworkTypePattern::Ethernet(), true, network_handler::ErrorCallback());
+}
+
+std::vector<std::string>
+ProhibitedTechnologiesHandler::GetCurrentlyProhibitedTechnologies() {
+  if (user_logged_in_ && user_policy_applied_)
+    return prohibited_technologies_;
+  return std::vector<std::string>();
+}
+
+}  // namespace chromeos
diff --git a/chromeos/network/prohibited_technologies_handler.h b/chromeos/network/prohibited_technologies_handler.h
new file mode 100644
index 0000000..8f5136a
--- /dev/null
+++ b/chromeos/network/prohibited_technologies_handler.h
@@ -0,0 +1,59 @@
+// Copyright 2015 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.
+
+#ifndef CHROMEOS_NETWORK_PROHIBITED_TECHNOLOGIES_HANDLER_H_
+#define CHROMEOS_NETWORK_PROHIBITED_TECHNOLOGIES_HANDLER_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "chromeos/chromeos_export.h"
+#include "chromeos/login/login_state.h"
+#include "chromeos/network/network_handler.h"
+#include "chromeos/network/network_policy_observer.h"
+
+namespace chromeos {
+
+class CHROMEOS_EXPORT ProhibitedTechnologiesHandler
+    : public LoginState::Observer,
+      public NetworkPolicyObserver {
+ public:
+  ~ProhibitedTechnologiesHandler() override;
+
+  // LoginState::Observer
+  void LoggedInStateChanged() override;
+
+  // NetworkPolicyObserver
+  void PoliciesChanged(const std::string& userhash) override;
+  void PoliciesApplied(const std::string& userhash) override;
+
+  void SetProhibitedTechnologies(const base::ListValue* prohibited_list);
+  std::vector<std::string> GetCurrentlyProhibitedTechnologies();
+
+ private:
+  friend class NetworkHandler;
+  friend class ProhibitedTechnologiesHandlerTest;
+
+  ProhibitedTechnologiesHandler();
+
+  void Init(
+      ManagedNetworkConfigurationHandler* managed_network_configuration_handler,
+      NetworkStateHandler* network_state_handler);
+
+  void EnforceProhibitedTechnologies();
+
+  std::vector<std::string> prohibited_technologies_;
+  ManagedNetworkConfigurationHandler* managed_network_configuration_handler_ =
+      nullptr;
+  NetworkStateHandler* network_state_handler_ = nullptr;
+  bool user_logged_in_ = false;
+  bool user_policy_applied_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(ProhibitedTechnologiesHandler);
+};
+
+}  // namespace chromeos
+
+#endif  // CHROMEOS_NETWORK_PROHIBITED_TECHNOLOGIES_HANDLER_H_
diff --git a/chromeos/network/prohibited_technologies_handler_unittest.cc b/chromeos/network/prohibited_technologies_handler_unittest.cc
new file mode 100644
index 0000000..68e186f
--- /dev/null
+++ b/chromeos/network/prohibited_technologies_handler_unittest.cc
@@ -0,0 +1,190 @@
+// Copyright 2015 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 "chromeos/network/prohibited_technologies_handler.h"
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/json/json_reader.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/dbus/shill_manager_client.h"
+#include "chromeos/dbus/shill_profile_client.h"
+#include "chromeos/network/managed_network_configuration_handler_impl.h"
+#include "chromeos/network/network_configuration_handler.h"
+#include "chromeos/network/network_profile_handler.h"
+#include "chromeos/network/network_state_handler.h"
+#include "chromeos/network/onc/onc_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/cros_system_api/dbus/service_constants.h"
+
+namespace chromeos {
+
+namespace {
+const char* kUserHash = "user_hash";
+}
+
+class ProhibitedTechnologiesHandlerTest : public testing::Test {
+ public:
+  ProhibitedTechnologiesHandlerTest() {}
+
+  void SetUp() override {
+    DBusThreadManager::Initialize();
+    LoginState::Initialize();
+    DBusThreadManager* dbus_manager = DBusThreadManager::Get();
+    test_manager_client_ =
+        dbus_manager->GetShillManagerClient()->GetTestInterface();
+
+    test_manager_client_->AddTechnology(shill::kTypeWifi, true /* enabled */);
+    test_manager_client_->AddTechnology(shill::kTypeCellular,
+                                        true /* enabled */);
+    dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile(
+        "shared_profile_path", std::string() /* shared profile */);
+    dbus_manager->GetShillProfileClient()->GetTestInterface()->AddProfile(
+        "user_profile_path", kUserHash);
+
+    base::RunLoop().RunUntilIdle();
+    network_state_handler_.reset(NetworkStateHandler::InitializeForTest());
+    network_config_handler_.reset(
+        NetworkConfigurationHandler::InitializeForTest(
+            network_state_handler_.get(), NULL /* network_device_handler */));
+
+    network_profile_handler_.reset(new NetworkProfileHandler());
+    network_profile_handler_->Init();
+
+    managed_config_handler_.reset(new ManagedNetworkConfigurationHandlerImpl());
+    prohibited_technologies_handler_.reset(new ProhibitedTechnologiesHandler());
+
+    managed_config_handler_->Init(
+        network_state_handler_.get(), network_profile_handler_.get(),
+        network_config_handler_.get(), nullptr /* network_device_handler */,
+        prohibited_technologies_handler_.get());
+
+    prohibited_technologies_handler_->Init(managed_config_handler_.get(),
+                                           network_state_handler_.get());
+
+    base::RunLoop().RunUntilIdle();
+
+    PreparePolicies();
+  }
+
+  void PreparePolicies() {
+    scoped_ptr<base::ListValue> val(new base::ListValue());
+    val->AppendString("WiFi");
+    global_config_disable_wifi.Set("DisableNetworkTypes", val.Pass());
+    val.reset(new base::ListValue());
+    val->AppendString("WiFi");
+    val->AppendString("Cellular");
+    global_config_disable_wifi_and_cell.Set("DisableNetworkTypes", val.Pass());
+  }
+
+  void TearDown() override {
+    prohibited_technologies_handler_.reset();
+    managed_config_handler_.reset();
+    network_profile_handler_.reset();
+    network_config_handler_.reset();
+    network_state_handler_.reset();
+    LoginState::Shutdown();
+    DBusThreadManager::Shutdown();
+  }
+
+ protected:
+  void LoginToRegularUser() {
+    LoginState::Get()->SetLoggedInState(LoginState::LOGGED_IN_ACTIVE,
+                                        LoginState::LOGGED_IN_USER_REGULAR);
+    base::RunLoop().RunUntilIdle();
+  }
+
+  void SetupPolicy(const base::DictionaryValue& global_config,
+                   bool user_policy) {
+    if (user_policy) {
+      managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_USER_POLICY,
+                                         kUserHash, base::ListValue(),
+                                         global_config);
+    } else {
+      managed_config_handler_->SetPolicy(::onc::ONC_SOURCE_DEVICE_POLICY,
+                                         std::string(),  // no username hash
+                                         base::ListValue(), global_config);
+    }
+    base::RunLoop().RunUntilIdle();
+  }
+
+  scoped_ptr<ProhibitedTechnologiesHandler> prohibited_technologies_handler_;
+  scoped_ptr<NetworkStateHandler> network_state_handler_;
+  scoped_ptr<NetworkConfigurationHandler> network_config_handler_;
+  scoped_ptr<ManagedNetworkConfigurationHandlerImpl> managed_config_handler_;
+  scoped_ptr<NetworkProfileHandler> network_profile_handler_;
+  ShillManagerClient::TestInterface* test_manager_client_;
+  base::MessageLoopForUI message_loop_;
+  base::DictionaryValue global_config_disable_wifi;
+  base::DictionaryValue global_config_disable_wifi_and_cell;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ProhibitedTechnologiesHandlerTest);
+};
+
+TEST_F(ProhibitedTechnologiesHandlerTest,
+       ProhibitedTechnologiesAllowedLoginScreen) {
+  EXPECT_TRUE(
+      network_state_handler_->IsTechnologyEnabled(NetworkTypePattern::WiFi()));
+  EXPECT_TRUE(network_state_handler_->IsTechnologyEnabled(
+      NetworkTypePattern::Cellular()));
+  SetupPolicy(global_config_disable_wifi_and_cell, false);
+  EXPECT_TRUE(
+      network_state_handler_->IsTechnologyEnabled(NetworkTypePattern::WiFi()));
+  EXPECT_TRUE(network_state_handler_->IsTechnologyEnabled(
+      NetworkTypePattern::Cellular()));
+};
+
+TEST_F(ProhibitedTechnologiesHandlerTest,
+       ProhibitedTechnologiesNotAllowedUserSession) {
+  EXPECT_TRUE(
+      network_state_handler_->IsTechnologyEnabled(NetworkTypePattern::WiFi()));
+  EXPECT_TRUE(network_state_handler_->IsTechnologyEnabled(
+      NetworkTypePattern::Cellular()));
+  SetupPolicy(global_config_disable_wifi_and_cell, false);
+
+  LoginToRegularUser();
+  EXPECT_TRUE(
+      network_state_handler_->IsTechnologyEnabled(NetworkTypePattern::WiFi()));
+  EXPECT_TRUE(network_state_handler_->IsTechnologyEnabled(
+      NetworkTypePattern::Cellular()));
+
+  SetupPolicy(base::DictionaryValue(), true);  // wait for user policy
+
+  // Should be disabled after logged in
+  EXPECT_FALSE(
+      network_state_handler_->IsTechnologyEnabled(NetworkTypePattern::WiFi()));
+  EXPECT_FALSE(network_state_handler_->IsTechnologyEnabled(
+      NetworkTypePattern::Cellular()));
+
+  // Can not enable it back
+  network_state_handler_->SetTechnologyEnabled(
+      NetworkTypePattern::WiFi(), true, network_handler::ErrorCallback());
+  network_state_handler_->SetTechnologyEnabled(
+      NetworkTypePattern::Cellular(), true, network_handler::ErrorCallback());
+  message_loop_.RunUntilIdle();
+  EXPECT_FALSE(
+      network_state_handler_->IsTechnologyEnabled(NetworkTypePattern::WiFi()));
+  EXPECT_FALSE(network_state_handler_->IsTechnologyEnabled(
+      NetworkTypePattern::Cellular()));
+
+  // Can enable Cellular back after modifying policy
+  SetupPolicy(global_config_disable_wifi, false);
+  network_state_handler_->SetTechnologyEnabled(
+      NetworkTypePattern::WiFi(), true, network_handler::ErrorCallback());
+  network_state_handler_->SetTechnologyEnabled(
+      NetworkTypePattern::Cellular(), true, network_handler::ErrorCallback());
+  message_loop_.RunUntilIdle();
+  EXPECT_FALSE(
+      network_state_handler_->IsTechnologyEnabled(NetworkTypePattern::WiFi()));
+  EXPECT_TRUE(network_state_handler_->IsTechnologyEnabled(
+      NetworkTypePattern::Cellular()));
+};
+
+}  // namespace chromeos
diff --git a/chromeos/network/shill_property_handler.cc b/chromeos/network/shill_property_handler.cc
index 02b620d..eb73b832 100644
--- a/chromeos/network/shill_property_handler.cc
+++ b/chromeos/network/shill_property_handler.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/format_macros.h"
 #include "base/stl_util.h"
+#include "base/strings/string_util.h"
 #include "base/values.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "chromeos/dbus/shill_device_client.h"
@@ -104,8 +105,7 @@
 
 ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
     : listener_(listener),
-      shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()) {
-}
+      shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()) {}
 
 ShillPropertyHandler::~ShillPropertyHandler() {
   // Delete network service observers.
@@ -153,6 +153,14 @@
     bool enabled,
     const network_handler::ErrorCallback& error_callback) {
   if (enabled) {
+    if (prohibited_technologies_.find(technology) !=
+        prohibited_technologies_.end()) {
+      chromeos::network_handler::RunErrorCallback(
+          error_callback, "", "prohibited_technologies",
+          "Ignored: Attempt to enable prohibited network technology " +
+              technology);
+      return;
+    }
     enabling_technologies_.insert(technology);
     shill_manager_->EnableTechnology(
         technology, base::Bind(&base::DoNothing),
@@ -169,6 +177,35 @@
   }
 }
 
+void ShillPropertyHandler::SetProhibitedTechnologies(
+    const std::vector<std::string>& prohibited_technologies,
+    const network_handler::ErrorCallback& error_callback) {
+  prohibited_technologies_.clear();
+  prohibited_technologies_.insert(prohibited_technologies.begin(),
+                                  prohibited_technologies.end());
+
+  // Remove technologies from the other lists.
+  // And manually disable them.
+  for (const auto& technology : prohibited_technologies) {
+    enabling_technologies_.erase(technology);
+    enabled_technologies_.erase(technology);
+    shill_manager_->DisableTechnology(
+        technology, base::Bind(&base::DoNothing),
+        base::Bind(&network_handler::ShillErrorCallbackFunction,
+                   "DisableTechnology Failed", technology, error_callback));
+  }
+
+  // Send updated prohibited technology list to shill.
+  const std::string prohibited_list =
+      base::JoinString(prohibited_technologies, ",");
+  base::StringValue value(prohibited_list);
+  shill_manager_->SetProperty(
+      "ProhibitedTechnologies", value, base::Bind(&base::DoNothing),
+      base::Bind(&network_handler::ShillErrorCallbackFunction,
+                 "SetTechnologiesProhibited Failed", prohibited_list,
+                 error_callback));
+}
+
 void ShillPropertyHandler::SetCheckPortalList(
     const std::string& check_portal_list) {
   base::StringValue value(check_portal_list);
diff --git a/chromeos/network/shill_property_handler.h b/chromeos/network/shill_property_handler.h
index 8b2cd427..d88ac28 100644
--- a/chromeos/network/shill_property_handler.h
+++ b/chromeos/network/shill_property_handler.h
@@ -9,6 +9,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <vector>
 
 #include "base/memory/weak_ptr.h"
 #include "chromeos/dbus/dbus_method_call_status.h"
@@ -122,6 +123,13 @@
       bool enabled,
       const network_handler::ErrorCallback& error_callback);
 
+  // Asynchronously sets the prohibited state for every network technology
+  // listed in |technologies|. Note: Modifies Manager state. Calls
+  // |error_callback| on failure.
+  void SetProhibitedTechnologies(
+      const std::vector<std::string>& technologies,
+      const network_handler::ErrorCallback& error_callback);
+
   // Sets the list of devices on which portal check is enabled.
   void SetCheckPortalList(const std::string& check_portal_list);
 
@@ -214,6 +222,8 @@
                            DBusMethodCallStatus call_status,
                            const base::DictionaryValue& properties);
 
+  void SetProhibitedTechnologiesEnforced(bool enforced);
+
   // Pointer to containing class (owns this)
   Listener* listener_;
 
@@ -237,6 +247,7 @@
   std::set<std::string> available_technologies_;
   std::set<std::string> enabled_technologies_;
   std::set<std::string> enabling_technologies_;
+  std::set<std::string> prohibited_technologies_;
   std::set<std::string> uninitialized_technologies_;
 
   DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandler);
diff --git a/chromeos/network/shill_property_handler_unittest.cc b/chromeos/network/shill_property_handler_unittest.cc
index 3f705ab7..7593194 100644
--- a/chromeos/network/shill_property_handler_unittest.cc
+++ b/chromeos/network/shill_property_handler_unittest.cc
@@ -501,4 +501,34 @@
       shill::kServiceCompleteListProperty)[kTestServicePath2]);
 }
 
+TEST_F(ShillPropertyHandlerTest, ProhibitedTechnologies) {
+  std::vector<std::string> prohibited_technologies;
+  prohibited_technologies.push_back(shill::kTypeEthernet);
+  EXPECT_TRUE(
+      shill_property_handler_->IsTechnologyEnabled(shill::kTypeEthernet));
+  shill_property_handler_->SetProhibitedTechnologies(
+      prohibited_technologies, network_handler::ErrorCallback());
+  message_loop_.RunUntilIdle();
+  // Disabled
+  EXPECT_FALSE(
+      shill_property_handler_->IsTechnologyEnabled(shill::kTypeEthernet));
+
+  // Can not enable it back
+  shill_property_handler_->SetTechnologyEnabled(
+      shill::kTypeEthernet, true, network_handler::ErrorCallback());
+  message_loop_.RunUntilIdle();
+  EXPECT_FALSE(
+      shill_property_handler_->IsTechnologyEnabled(shill::kTypeEthernet));
+
+  // Can enable it back after policy changes
+  prohibited_technologies.clear();
+  shill_property_handler_->SetProhibitedTechnologies(
+      prohibited_technologies, network_handler::ErrorCallback());
+  shill_property_handler_->SetTechnologyEnabled(
+      shill::kTypeEthernet, true, network_handler::ErrorCallback());
+  message_loop_.RunUntilIdle();
+  EXPECT_TRUE(
+      shill_property_handler_->IsTechnologyEnabled(shill::kTypeEthernet));
+}
+
 }  // namespace chromeos
diff --git a/chromeos/test/data/network/managed_toplevel_with_only_managed.onc b/chromeos/test/data/network/managed_toplevel_with_only_managed.onc
new file mode 100644
index 0000000..e83e1a0e
--- /dev/null
+++ b/chromeos/test/data/network/managed_toplevel_with_only_managed.onc
@@ -0,0 +1,16 @@
+{
+  "GlobalNetworkConfiguration":{
+    "AllowOnlyPolicyNetworksToAutoconnect": true,
+    "AllowOnlyPolicyNetworksToConnect": true,
+  },
+  "NetworkConfigurations":[
+    {
+      "Ethernet":{
+        "Authentication":"None"
+      },
+      "GUID":"guid",
+      "Name":"name",
+      "Type":"Ethernet"
+    }
+  ]
+}
diff --git a/cloud_print/service/win/chrome_launcher.cc b/cloud_print/service/win/chrome_launcher.cc
index f959411..c6acb22 100644
--- a/cloud_print/service/win/chrome_launcher.cc
+++ b/cloud_print/service/win/chrome_launcher.cc
@@ -214,7 +214,6 @@
       cmd.AppendSwitch(switches::kNoServiceAutorun);
 
       // Optional.
-      cmd.AppendSwitch(switches::kAutoLaunchAtStartup);
       cmd.AppendSwitch(switches::kDisableDefaultApps);
       cmd.AppendSwitch(switches::kDisableExtensions);
       cmd.AppendSwitch(switches::kDisableGpu);
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 5f68cdd..85ea0356 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -18,7 +18,6 @@
   visibility = [ "//:*" ]  # Only for the root targets to bring in.
 
   deps = [
-    "//components/bitmap_uploader",
     "//components/bookmarks/browser",
     "//components/bookmarks/common",
     "//components/bookmarks/managed",
@@ -45,10 +44,12 @@
     "//components/omnibox/browser",
     "//components/infobars/core",
     "//components/version_ui",
+    "//components/os_crypt",
   ]
 
   if (!is_ios) {
     deps += [
+      "//components/bitmap_uploader",
       "//components/dom_distiller/core",
       "//components/enhanced_bookmarks",
       "//components/certificate_reporting",
@@ -107,7 +108,6 @@
       "//components/offline_pages",
       "//components/onc",
       "//components/open_from_clipboard",
-      "//components/os_crypt",
       "//components/packed_ct_ev_whitelist",
       "//components/pairing",
       "//components/password_manager/content/browser",
@@ -331,6 +331,7 @@
     "//components/leveldb_proto:unit_tests",
     "//components/suggestions:unit_tests",
     "//components/omnibox/browser:unit_tests",
+    "//components/os_crypt:unit_tests",
   ]
 
   if (!is_ios) {
@@ -393,7 +394,6 @@
       "//components/network_time:unit_tests",
       "//components/offline_pages:unit_tests",
       "//components/open_from_clipboard:unit_tests",
-      "//components/os_crypt:unit_tests",
       "//components/packed_ct_ev_whitelist:unit_tests",
       "//components/password_manager/content/browser:unit_tests",
       "//components/password_manager/core/browser:unit_tests",
diff --git a/components/OWNERS b/components/OWNERS
index 71e8f1ce..6b85029 100644
--- a/components/OWNERS
+++ b/components/OWNERS
@@ -272,6 +272,11 @@
 per-file search_provider_logos*=newt@chromium.org
 per-file search_provider_logos*=justincohen@chromium.org
 
+per-file security_interstitials*=estark@chromium.org
+per-file security_interstitials*=felt@chromium.org
+per-file security_interstitials*=meacer@chromium.org
+per-file security_interstitials*=palmer@chromium.org
+
 per-file session_manager.gypi=antrim@chromium.org
 per-file session_manager.gypi=dzhioev@chromium.org
 per-file session_manager.gypi=nkostylev@chromium.org
@@ -282,6 +287,9 @@
 per-file signin*=atwilson@chromium.org
 per-file signin*=rogerta@chromium.org
 
+per-file ssl_errors*=estark@chromium.org
+per-file ssl_errors*=felt@chromium.org
+
 per-file storage_monitor.gypi=gbillock@chromium.org
 per-file storage_monitor.gypi=thestig@chromium.org
 per-file storage_monitor.gypi=vandebo@chromium.org
diff --git a/components/autofill/content/browser/content_autofill_driver_factory.cc b/components/autofill/content/browser/content_autofill_driver_factory.cc
index 3d78a89..d19bd574 100644
--- a/components/autofill/content/browser/content_autofill_driver_factory.cc
+++ b/components/autofill/content/browser/content_autofill_driver_factory.cc
@@ -92,9 +92,6 @@
     content::RenderFrameHost* rfh,
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
-  // TODO(vabr): Remove those as soon as http://crbug.com/554479 is clarified.
-  CHECK(rfh->IsRenderFrameLive());
-  CHECK(ContainsKey(frame_driver_map_, rfh));
   frame_driver_map_[rfh]->DidNavigateFrame(details, params);
 }
 
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index a468fa00..f21a52d 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -926,23 +926,29 @@
         return;
     }
 
-    // Check for a CVC in order to determine whether we can prompt the user to
-    // upload their card.
-    for (const auto& field : submitted_form) {
-      if (field->Type().GetStorableType() == CREDIT_CARD_VERIFICATION_CODE) {
-        upload_request_.cvc = field->value;
-        break;
+    upload_request_ = payments::PaymentsClient::UploadRequestDetails();
+    if (IsCreditCardUploadEnabled()) {
+      // Check for a CVC in order to determine whether we can prompt the user to
+      // upload their card.
+      for (const auto& field : submitted_form) {
+        if (field->Type().GetStorableType() == CREDIT_CARD_VERIFICATION_CODE) {
+          upload_request_.cvc = field->value;
+          break;
+        }
       }
+
+      // Upload also requires recently used or modified profiles with matching
+      // names.
+      upload_request_.profiles =
+          GetProfilesForCreditCardUpload(*imported_credit_card);
     }
 
-    if (!upload_request_.cvc.empty() && IsCreditCardUploadEnabled()) {
-      // Initiate the upload flow if a CVC was entered into the form and the
-      // feature is enabled.
-      upload_request_ = payments::PaymentsClient::UploadRequestDetails();
+    if (!upload_request_.cvc.empty() && !upload_request_.profiles.empty()) {
       upload_request_.card = *imported_credit_card;
       payments_client_->GetUploadDetails(app_locale_);
     } else {
-      // Otherwise, prompt the user for local save.
+      // If upload isn't enabled or not possible, prompt the user for local
+      // save.
       client_->ConfirmSaveCreditCardLocally(base::Bind(
           base::IgnoreResult(&PersonalDataManager::SaveImportedCreditCard),
           base::Unretained(personal_data_), *imported_credit_card));
@@ -950,6 +956,32 @@
   }
 }
 
+std::vector<AutofillProfile> AutofillManager::GetProfilesForCreditCardUpload(
+    const CreditCard& card) {
+  std::vector<AutofillProfile> profiles;
+  const base::Time now = base::Time::Now();
+  const base::TimeDelta fifteen_minutes = base::TimeDelta::FromMinutes(15);
+
+  for (AutofillProfile* profile : personal_data_->GetProfiles()) {
+    if ((now - profile->use_date()) > fifteen_minutes &&
+        (now - profile->modification_date()) > fifteen_minutes) {
+      continue;
+    }
+
+    if (profile->GetInfo(AutofillType(NAME_FULL), app_locale_) !=
+        card.GetInfo(AutofillType(CREDIT_CARD_NAME), app_locale_)) {
+      continue;
+    }
+
+    if (profile->GetRawInfo(ADDRESS_HOME_ZIP).empty())
+      continue;
+
+    profiles.push_back(*profile);
+  }
+
+  return profiles;
+}
+
 // Note that |submitted_form| is passed as a pointer rather than as a reference
 // so that we can get memory management right across threads.  Note also that we
 // explicitly pass in all the time stamps of interest, as the cached ones might
diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h
index 90c30e4..56dfad4 100644
--- a/components/autofill/core/browser/autofill_manager.h
+++ b/components/autofill/core/browser/autofill_manager.h
@@ -373,6 +373,12 @@
   // Imports the form data, submitted by the user, into |personal_data_|.
   void ImportFormData(const FormStructure& submitted_form);
 
+  // Returns all web profiles known to the personal data manager whose names
+  // match the name on |card| and that have been created or used within the last
+  // 15 minutes.
+  std::vector<AutofillProfile> GetProfilesForCreditCardUpload(
+      const CreditCard& card);
+
   // If |initial_interaction_timestamp_| is unset or is set to a later time than
   // |interaction_timestamp|, updates the cached timestamp.  The latter check is
   // needed because IPC messages can arrive out of order.
diff --git a/components/autofill/core/browser/autofill_manager_unittest.cc b/components/autofill/core/browser/autofill_manager_unittest.cc
index 7383a8e..e2c0346 100644
--- a/components/autofill/core/browser/autofill_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_manager_unittest.cc
@@ -137,10 +137,12 @@
   }
 
   void AddProfile(AutofillProfile* profile) {
+    profile->set_modification_date(base::Time::Now());
     web_profiles_.push_back(profile);
   }
 
   void AddCreditCard(CreditCard* credit_card) {
+    credit_card->set_modification_date(base::Time::Now());
     local_credit_cards_.push_back(credit_card);
   }
 
@@ -826,6 +828,26 @@
     form->fields.push_back(field);
   }
 
+  // Fills the fields in |form| with test data.
+  void ManuallyFillAddressForm(FormData* form) {
+    for (FormFieldData& field : form->fields) {
+      if (base::EqualsASCII(field.name, "firstname"))
+        field.value = ASCIIToUTF16("Flo");
+      else if (base::EqualsASCII(field.name, "lastname"))
+        field.value = ASCIIToUTF16("Master");
+      else if (base::EqualsASCII(field.name, "addr1"))
+        field.value = ASCIIToUTF16("123 Maple");
+      else if (base::EqualsASCII(field.name, "city"))
+        field.value = ASCIIToUTF16("Dallas");
+      else if (base::EqualsASCII(field.name, "state"))
+        field.value = ASCIIToUTF16("Texas");
+      else if (base::EqualsASCII(field.name, "zipcode"))
+        field.value = ASCIIToUTF16("77401");
+      else if (base::EqualsASCII(field.name, "country"))
+        field.value = ASCIIToUTF16("US");
+    }
+  }
+
   // Tests if credit card data gets saved
   void TestSaveCreditCards(bool is_https) {
     // Set up our form data.
@@ -3268,22 +3290,7 @@
   form = FormData();
   test::CreateTestAddressFormData(&form);
   FormsSeen(std::vector<FormData>(1, form));
-  for (size_t i = 0; i < form.fields.size(); ++i) {
-    if (form.fields[i].name == ASCIIToUTF16("firstname"))
-      form.fields[i].value = ASCIIToUTF16("Flo");
-    else if (form.fields[i].name == ASCIIToUTF16("lastname"))
-      form.fields[i].value = ASCIIToUTF16("Master");
-    else if (form.fields[i].name == ASCIIToUTF16("addr1"))
-      form.fields[i].value = ASCIIToUTF16("123 Maple");
-    else if (form.fields[i].name == ASCIIToUTF16("city"))
-      form.fields[i].value = ASCIIToUTF16("Dallas");
-    else if (form.fields[i].name == ASCIIToUTF16("state"))
-      form.fields[i].value = ASCIIToUTF16("Texas");
-    else if (form.fields[i].name == ASCIIToUTF16("zipcode"))
-      form.fields[i].value = ASCIIToUTF16("77401");
-    else if (form.fields[i].name == ASCIIToUTF16("country"))
-      form.fields[i].value = ASCIIToUTF16("US");
-  }
+  ManuallyFillAddressForm(&form);
   autofill_manager_->OnFormSubmitted(form);
 }
 
@@ -3310,59 +3317,111 @@
 }
 
 TEST_F(AutofillManagerTest, UploadCreditCard) {
-  // Set up our form data.
-  FormData form;
-  CreateTestCreditCardFormData(&form, true, false);
-  std::vector<FormData> forms(1, form);
-  FormsSeen(forms);
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm(&address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
 
   // Edit the data, and submit
-  form.fields[1].value = ASCIIToUTF16("4111111111111111");
-  form.fields[2].value = ASCIIToUTF16("11");
-  form.fields[3].value = ASCIIToUTF16("2017");
-  form.fields[4].value = ASCIIToUTF16("123");
+  credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("11");
+  credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
 
-  FormSubmitted(form);
+  FormSubmitted(credit_card_form);
   EXPECT_TRUE(autofill_manager_->credit_card_was_uploaded());
 }
 
 TEST_F(AutofillManagerTest, DontUploadCreditCardIfFeatureNotEnabled) {
   autofill_manager_->set_credit_card_upload_enabled(false);
 
-  // Set up our form data.
-  FormData form;
-  CreateTestCreditCardFormData(&form, true, false);
-  std::vector<FormData> forms(1, form);
-  FormsSeen(forms);
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm(&address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
 
   // Edit the data, and submit
-  form.fields[1].value = ASCIIToUTF16("4111111111111111");
-  form.fields[2].value = ASCIIToUTF16("11");
-  form.fields[3].value = ASCIIToUTF16("2017");
-  form.fields[4].value = ASCIIToUTF16("123");
+  credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("11");
+  credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
 
   // The save prompt should be shown instead of doing an upload.
   EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
-  FormSubmitted(form);
+  FormSubmitted(credit_card_form);
   EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
 }
 
 TEST_F(AutofillManagerTest, DontUploadCreditCardIfCvcUnavailable) {
-  // Set up our form data.
-  FormData form;
-  CreateTestCreditCardFormData(&form, true, false);
-  std::vector<FormData> forms(1, form);
-  FormsSeen(forms);
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm(&address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
 
   // Edit the data, and submit
-  form.fields[1].value = ASCIIToUTF16("4111111111111111");
-  form.fields[2].value = ASCIIToUTF16("11");
-  form.fields[3].value = ASCIIToUTF16("2017");
-  form.fields[4].value = ASCIIToUTF16("");  // CVC
+  credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("11");
+  credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+  credit_card_form.fields[4].value = ASCIIToUTF16("");  // CVC MISSING
 
   // The save prompt should be shown instead of doing an upload.
   EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
-  FormSubmitted(form);
+  FormSubmitted(credit_card_form);
+  EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
+}
+
+TEST_F(AutofillManagerTest, DontUploadCreditCardIfNoMatchingProfileAvailable) {
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm(&address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
+
+  // Edit the data, and submit
+  // The address form has "Flo Master" but the credit card has "Bob Master".
+  credit_card_form.fields[0].value = ASCIIToUTF16("Bob Master");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("11");
+  credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
+
+  // The save prompt should be shown instead of doing an upload.
+  EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
+  FormSubmitted(credit_card_form);
   EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
 }
 
@@ -3371,21 +3430,29 @@
   // response.
   autofill_manager_->set_app_locale("pt-BR");
 
-  // Set up our form data.
-  FormData form;
-  CreateTestCreditCardFormData(&form, true, false);
-  std::vector<FormData> forms(1, form);
-  FormsSeen(forms);
+  // Create, fill and submit an address form in order to establish a recent
+  // profile which can be selected for the upload request.
+  FormData address_form;
+  test::CreateTestAddressFormData(&address_form);
+  FormsSeen(std::vector<FormData>(1, address_form));
+  ManuallyFillAddressForm(&address_form);
+  FormSubmitted(address_form);
+
+  // Set up our credit card form data.
+  FormData credit_card_form;
+  CreateTestCreditCardFormData(&credit_card_form, true, false);
+  FormsSeen(std::vector<FormData>(1, credit_card_form));
 
   // Edit the data, and submit
-  form.fields[1].value = ASCIIToUTF16("4111111111111111");
-  form.fields[2].value = ASCIIToUTF16("11");
-  form.fields[3].value = ASCIIToUTF16("2017");
-  form.fields[4].value = ASCIIToUTF16("123");
+  credit_card_form.fields[0].value = ASCIIToUTF16("Flo Master");
+  credit_card_form.fields[1].value = ASCIIToUTF16("4111111111111111");
+  credit_card_form.fields[2].value = ASCIIToUTF16("11");
+  credit_card_form.fields[3].value = ASCIIToUTF16("2017");
+  credit_card_form.fields[4].value = ASCIIToUTF16("123");
 
   // The save prompt should be shown instead of doing an upload.
   EXPECT_CALL(autofill_client_, ConfirmSaveCreditCardLocally(_)).Times(1);
-  FormSubmitted(form);
+  FormSubmitted(credit_card_form);
   EXPECT_FALSE(autofill_manager_->credit_card_was_uploaded());
 }
 
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index aacd534..4452e2f 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -106,7 +106,61 @@
 
   risk_data->SetString("value", encoded_risk_data);
 
-  return risk_data.Pass();
+  return risk_data;
+}
+
+scoped_ptr<base::DictionaryValue> BuildAddressDictionary(
+    const AutofillProfile& profile,
+    const std::string& app_locale) {
+  scoped_ptr<base::DictionaryValue> address(new base::DictionaryValue());
+
+  scoped_ptr<base::DictionaryValue> postal_address(new base::DictionaryValue());
+  postal_address->SetString(
+      "recipient_name", profile.GetInfo(AutofillType(NAME_FULL), app_locale));
+
+  scoped_ptr<base::ListValue> address_lines(new base::ListValue());
+  const base::string16 address_line1 =
+      profile.GetInfo(AutofillType(ADDRESS_HOME_LINE1), app_locale);
+  if (!address_line1.empty())
+    address_lines->AppendString(address_line1);
+  const base::string16 address_line2 =
+      profile.GetInfo(AutofillType(ADDRESS_HOME_LINE2), app_locale);
+  if (!address_line2.empty())
+    address_lines->AppendString(address_line2);
+  const base::string16 address_line3 =
+      profile.GetInfo(AutofillType(ADDRESS_HOME_LINE3), app_locale);
+  if (!address_line3.empty())
+    address_lines->AppendString(address_line3);
+  if (!address_lines->empty())
+    postal_address->Set("address_line", address_lines.Pass());
+
+  const base::string16 city =
+      profile.GetInfo(AutofillType(ADDRESS_HOME_CITY), app_locale);
+  if (!city.empty())
+    postal_address->SetString("locality_name", city);
+
+  const base::string16 state =
+      profile.GetInfo(AutofillType(ADDRESS_HOME_STATE), app_locale);
+  if (!state.empty())
+    postal_address->SetString("administrative_area_name", state);
+
+  postal_address->SetString(
+      "postal_code_number",
+      profile.GetInfo(AutofillType(ADDRESS_HOME_ZIP), app_locale));
+
+  // Use GetRawInfo to get a country code instead of the country name:
+  const base::string16 country_code = profile.GetRawInfo(ADDRESS_HOME_COUNTRY);
+  if (!country_code.empty())
+    postal_address->SetString("country_name_code", country_code);
+
+  address->Set("postal_address", postal_address.Pass());
+
+  const base::string16 phone_number =
+      profile.GetInfo(AutofillType(PHONE_HOME_WHOLE_NUMBER), app_locale);
+  if (!phone_number.empty())
+    address->SetString("phone_number", phone_number);
+
+  return address;
 }
 
 class UnmaskCardRequest : public PaymentsRequest {
@@ -232,33 +286,35 @@
     request_dict.Set("risk_data_encoded",
                      BuildRiskDictionary(request_details_.risk_data));
 
+    const std::string& app_locale = request_details_.app_locale;
     scoped_ptr<base::DictionaryValue> context(new base::DictionaryValue());
-    context->SetString("language_code", request_details_.app_locale);
+    context->SetString("language_code", app_locale);
     request_dict.Set("context", context.Pass());
 
-    request_dict.SetString(
-        "cardholder_name",
-        request_details_.card.GetInfo(AutofillType(CREDIT_CARD_NAME),
-                                      request_details_.app_locale));
+    request_dict.SetString("cardholder_name",
+                           request_details_.card.GetInfo(
+                               AutofillType(CREDIT_CARD_NAME), app_locale));
 
-    // TODO(jdonnelly): Get address(es) from the current session or available
-    // profiles and add to the request.
+    scoped_ptr<base::ListValue> addresses(new base::ListValue());
+    for (const AutofillProfile& profile : request_details_.profiles) {
+      addresses->Append(BuildAddressDictionary(profile, app_locale));
+    }
+    request_dict.Set("address", addresses.Pass());
 
     request_dict.SetString("context_token", request_details_.context_token);
 
     int value = 0;
     base::string16 exp_month = request_details_.card.GetInfo(
-        AutofillType(CREDIT_CARD_EXP_MONTH), request_details_.app_locale);
+        AutofillType(CREDIT_CARD_EXP_MONTH), app_locale);
     base::string16 exp_year = request_details_.card.GetInfo(
-        AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR),
-        request_details_.app_locale);
+        AutofillType(CREDIT_CARD_EXP_4_DIGIT_YEAR), app_locale);
     if (base::StringToInt(exp_month, &value))
       request_dict.SetInteger("expiration_month", value);
     if (base::StringToInt(exp_year, &value))
       request_dict.SetInteger("expiration_year", value);
 
     base::string16 pan = request_details_.card.GetInfo(
-        AutofillType(CREDIT_CARD_NUMBER), request_details_.app_locale);
+        AutofillType(CREDIT_CARD_NUMBER), app_locale);
     std::string json_request;
     base::JSONWriter::Write(request_dict, &json_request);
     std::string request_content = base::StringPrintf(
diff --git a/components/autofill/core/browser/payments/payments_client.h b/components/autofill/core/browser/payments/payments_client.h
index a6a23af..b83c8af 100644
--- a/components/autofill/core/browser/payments/payments_client.h
+++ b/components/autofill/core/browser/payments/payments_client.h
@@ -9,6 +9,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/core/browser/autofill_profile.h"
 #include "components/autofill/core/browser/card_unmask_delegate.h"
 #include "components/autofill/core/browser/credit_card.h"
 #include "google_apis/gaia/oauth2_token_service.h"
@@ -76,6 +77,7 @@
 
     CreditCard card;
     base::string16 cvc;
+    std::vector<AutofillProfile> profiles;
     base::string16 context_token;
     std::string risk_data;
     std::string app_locale;
diff --git a/components/autofill/core/common/autofill_switches.cc b/components/autofill/core/common/autofill_switches.cc
index 63edd24..cefd0ecb 100644
--- a/components/autofill/core/common/autofill_switches.cc
+++ b/components/autofill/core/common/autofill_switches.cc
@@ -71,6 +71,10 @@
 const char kEnableSuggestionsWithSubstringMatch[] =
     "enable-suggestions-with-substring-match";
 
+// Enables syncing usage counts and last use dates of Wallet addresses and
+// cards.
+const char kEnableWalletMetadataSync[]      = "enable-wallet-metadata-sync";
+
 // Ignores autocomplete="off" for Autofill data (profiles + credit cards).
 const char kIgnoreAutocompleteOffForAutofill[] =
     "ignore-autocomplete-off-autofill";
diff --git a/components/autofill/core/common/autofill_switches.h b/components/autofill/core/common/autofill_switches.h
index 1c34827..8be409a 100644
--- a/components/autofill/core/common/autofill_switches.h
+++ b/components/autofill/core/common/autofill_switches.h
@@ -28,6 +28,7 @@
 extern const char kEnablePasswordGeneration[];
 extern const char kEnableSingleClickAutofill[];
 extern const char kEnableSuggestionsWithSubstringMatch[];
+extern const char kEnableWalletMetadataSync[];
 extern const char kIgnoreAutocompleteOffForAutofill[];
 extern const char kLocalHeuristicsOnlyForPasswordGeneration[];
 extern const char kShowAutofillTypePredictions[];
diff --git a/components/component_updater/component_updater_service.cc b/components/component_updater/component_updater_service.cc
index 29b120ea..1c49d26 100644
--- a/components/component_updater/component_updater_service.cc
+++ b/components/component_updater/component_updater_service.cc
@@ -89,6 +89,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   VLOG(1) << "CrxUpdateService stopping";
   timer_.Stop();
+  update_client_->Stop();
 }
 
 // Adds a component to be checked for upgrades. If the component exists it
diff --git a/components/component_updater/component_updater_service_unittest.cc b/components/component_updater/component_updater_service_unittest.cc
index c44c63b..9d78eb8 100644
--- a/components/component_updater/component_updater_service_unittest.cc
+++ b/components/component_updater/component_updater_service_unittest.cc
@@ -71,6 +71,7 @@
   MOCK_CONST_METHOD2(GetCrxUpdateState,
                      bool(const std::string& id, CrxUpdateItem* update_item));
   MOCK_CONST_METHOD1(IsUpdating, bool(const std::string& id));
+  MOCK_METHOD0(Stop, void());
 
  private:
   ~MockUpdateClient() override;
@@ -190,12 +191,14 @@
 TEST_F(ComponentUpdaterTest, AddObserver) {
   MockServiceObserver observer;
   EXPECT_CALL(update_client(), AddObserver(&observer)).Times(1);
+  EXPECT_CALL(update_client(), Stop()).Times(1);
   component_updater().AddObserver(&observer);
 }
 
 TEST_F(ComponentUpdaterTest, RemoveObserver) {
   MockServiceObserver observer;
   EXPECT_CALL(update_client(), RemoveObserver(&observer)).Times(1);
+  EXPECT_CALL(update_client(), Stop()).Times(1);
   component_updater().RemoveObserver(&observer);
 }
 
@@ -250,6 +253,7 @@
       .WillRepeatedly(Invoke(&loop_handler, &LoopHandler::OnUpdate));
 
   EXPECT_CALL(update_client(), IsUpdating(id1)).Times(1);
+  EXPECT_CALL(update_client(), Stop()).Times(1);
 
   EXPECT_TRUE(component_updater().RegisterComponent(crx_component1));
   EXPECT_TRUE(component_updater().RegisterComponent(crx_component2));
@@ -301,6 +305,7 @@
   EXPECT_CALL(update_client(),
               Install("jebgalgnebhfojomionfpkfelancnnkf", _, _))
       .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
+  EXPECT_CALL(update_client(), Stop()).Times(1);
 
   EXPECT_TRUE(cus.RegisterComponent(crx_component));
   EXPECT_TRUE(OnDemandTester::OnDemand(&cus, id));
@@ -345,6 +350,7 @@
   EXPECT_CALL(update_client(),
               Install("jebgalgnebhfojomionfpkfelancnnkf", _, _))
       .WillOnce(Invoke(&loop_handler, &LoopHandler::OnInstall));
+  EXPECT_CALL(update_client(), Stop()).Times(1);
 
   EXPECT_TRUE(component_updater().RegisterComponent(crx_component));
   component_updater().MaybeThrottle(
diff --git a/components/component_updater/configurator_impl.cc b/components/component_updater/configurator_impl.cc
index ed7daf4..fb8f1db 100644
--- a/components/component_updater/configurator_impl.cc
+++ b/components/component_updater/configurator_impl.cc
@@ -109,9 +109,12 @@
   pings_enabled_ = !HasSwitchValue(switch_values, kSwitchDisablePings);
   deltas_enabled_ = !HasSwitchValue(switch_values, kSwitchDisableDeltaUpdates);
 
-  // Disable BITS on all platforms in all cases until crbug.com/475872 is
-  // resolved.
+#if defined(OS_WIN)
+  background_downloads_enabled_ =
+      !HasSwitchValue(switch_values, kSwitchDisableBackgroundDownloads);
+#else
   background_downloads_enabled_ = false;
+#endif
 
   const std::string switch_url_source =
       GetSwitchArgument(switch_values, kSwitchUrlSource);
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index 98a13805..7866e3d0 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -97,6 +97,9 @@
     'certificate_transparency_unittest_sources': [
       'certificate_transparency/log_proof_fetcher_unittest.cc',
     ],
+    'child_trace_message_filter_unittest_sources': [
+      'tracing/child_trace_message_filter_unittest.cc',
+    ],
     'cloud_devices_unittest_sources': [
       'cloud_devices/common/cloud_devices_urls_unittest.cc',
       'cloud_devices/common/printer_description_unittest.cc',
@@ -256,6 +259,7 @@
       'gcm_driver/crypto/gcm_encryption_provider_unittest.cc',
       'gcm_driver/crypto/gcm_key_store_unittest.cc',
       'gcm_driver/crypto/gcm_message_cryptographer_unittest.cc',
+      'gcm_driver/crypto/p256_key_util_unittest.cc',
     ],
     'google_unittest_sources': [
       'google/core/browser/google_url_tracker_unittest.cc',
@@ -618,6 +622,7 @@
     'search_engines_unittest_sources': [
       'search_engines/default_search_manager_unittest.cc',
       'search_engines/default_search_pref_migration_unittest.cc',
+      'search_engines/detect_desktop_search_win_unittest.cc',
       'search_engines/keyword_table_unittest.cc',
       'search_engines/search_host_to_urls_map_unittest.cc',
       'search_engines/template_url_prepopulate_data_unittest.cc',
@@ -859,6 +864,7 @@
         '<@(bubble_unittest_sources)',
         '<@(captive_portal_unittest_sources)',
         '<@(certificate_reporting_unittest_sources)',
+        '<@(child_trace_message_filter_unittest_sources)',
         '<@(cloud_devices_unittest_sources)',
         '<@(component_updater_unittest_sources)',
         '<@(compression_unittest_sources)',
@@ -1416,7 +1422,6 @@
           ],
           'sources': [
             '<@(policy_unittest_sources)',
-            'search_engines/default_search_policy_handler_unittest.cc',
             'sync_driver/sync_policy_handler_unittest.cc',
           ],
           'conditions': [
@@ -1456,6 +1461,11 @@
               ],
             }],
           ],
+        }, {  # configuration_policy!=1
+          'sources!': [
+            'search_engines/default_search_policy_handler_unittest.cc',
+            'sync_driver/sync_policy_handler_unittest.cc',
+          ],
         }],
         ['enable_plugins == 1', {
           'sources': [
diff --git a/components/devtools_http_handler/devtools_http_handler.cc b/components/devtools_http_handler/devtools_http_handler.cc
index 63727fd..0bdfd9f6 100644
--- a/components/devtools_http_handler/devtools_http_handler.cc
+++ b/components/devtools_http_handler/devtools_http_handler.cc
@@ -492,7 +492,7 @@
 }
 
 std::string DevToolsHttpHandler::GetFrontendURLInternal(
-    const std::string id,
+    const std::string& id,
     const std::string& host) {
   return base::StringPrintf(
       "%s%sws=%s%s%s",
diff --git a/components/devtools_http_handler/devtools_http_handler.h b/components/devtools_http_handler/devtools_http_handler.h
index 89b7ddc..7db42920 100644
--- a/components/devtools_http_handler/devtools_http_handler.h
+++ b/components/devtools_http_handler/devtools_http_handler.h
@@ -119,7 +119,7 @@
                        const net::HttpServerRequestInfo& request);
 
   // Returns the front end url without the host at the beginning.
-  std::string GetFrontendURLInternal(const std::string target_id,
+  std::string GetFrontendURLInternal(const std::string& target_id,
                                      const std::string& host);
 
   base::DictionaryValue* SerializeDescriptor(
diff --git a/components/dom_distiller.gypi b/components/dom_distiller.gypi
index a4f94e1..1fd4196 100644
--- a/components/dom_distiller.gypi
+++ b/components/dom_distiller.gypi
@@ -5,6 +5,24 @@
 {
   'targets': [
     {
+      # GN version: //components/dom_distiller/content:content_common
+      'target_name': 'dom_distiller_content_common',
+      'type': 'static_library',
+      'include_dirs': [
+        '..',
+      ],
+      'dependencies': [
+        '../base/base.gyp:base',
+        '../content/content.gyp:content_common',
+        '../ipc/ipc.gyp:ipc',
+        '../url/url.gyp:url_lib',
+      ],
+      'sources': [
+        'dom_distiller/content/common/distiller_messages.cc',
+        'dom_distiller/content/common/distiller_messages.h',
+      ],
+    },
+    {
       # GN version: //components/dom_distiller/webui
       'target_name': 'dom_distiller_webui',
       'type': 'static_library',
@@ -182,6 +200,7 @@
           'target_name': 'dom_distiller_content_browser',
           'type': 'static_library',
           'dependencies': [
+            'dom_distiller_content_common',
             'dom_distiller_core',
             'dom_distiller_mojo_bindings',
             'dom_distiller_protos',
@@ -201,6 +220,8 @@
             '..',
           ],
           'sources': [
+            'dom_distiller/content/browser/distillability_driver.cc',
+            'dom_distiller/content/browser/distillability_driver.h',
             'dom_distiller/content/browser/distillable_page_utils.cc',
             'dom_distiller/content/browser/distillable_page_utils.h',
             'dom_distiller/content/browser/distillable_page_utils_android.cc',
@@ -231,7 +252,9 @@
           'target_name': 'dom_distiller_content_renderer',
           'type': 'static_library',
           'dependencies': [
+            'dom_distiller_content_common',
             'dom_distiller_mojo_bindings',
+            'dom_distiller_protos',
             '../base/base.gyp:base',
             '../content/content.gyp:content_browser',
             '../gin/gin.gyp:gin',
@@ -241,7 +264,12 @@
           'include_dirs': [
             '..',
           ],
+          'export_dependent_settings': [
+            'dom_distiller_protos',
+          ],
           'sources': [
+            'dom_distiller/content/renderer/distillability_agent.cc',
+            'dom_distiller/content/renderer/distillability_agent.h',
             'dom_distiller/content/renderer/distiller_js_render_frame_observer.cc',
             'dom_distiller/content/renderer/distiller_js_render_frame_observer.h',
             'dom_distiller/content/renderer/distiller_native_javascript.cc',
diff --git a/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java b/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java
index 0f7c794..959a71be 100644
--- a/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java
+++ b/components/dom_distiller/android/java/src/org/chromium/components/dom_distiller/content/DistillablePageUtils.java
@@ -33,5 +33,30 @@
 
     private static native void nativeIsPageDistillable(
             WebContents webContents, boolean isMobileOptimized, PageDistillableCallback callback);
-}
 
+    /**
+     * Delegate to receive distillability updates.
+     */
+    public static interface PageDistillableDelegate {
+        /**
+         * Called when the distillability status changes.
+         * @param isDistillable Whether the page is distillable.
+         * @param isLast Whether the update is the last one for this page.
+         */
+        public void onIsPageDistillableResult(boolean isDistillable, boolean isLast);
+    }
+
+    public static void setDelegate(WebContents webContents,
+            PageDistillableDelegate delegate) {
+        nativeSetDelegate(webContents, delegate);
+    }
+
+    @CalledByNative
+    private static void callOnIsPageDistillableUpdate(
+            PageDistillableDelegate delegate, boolean isDistillable, boolean isLast) {
+        delegate.onIsPageDistillableResult(isDistillable, isLast);
+    }
+
+    private static native void nativeSetDelegate(
+            WebContents webContents, PageDistillableDelegate delegate);
+}
diff --git a/components/dom_distiller/content/BUILD.gn b/components/dom_distiller/content/BUILD.gn
index f9cce20..806df19 100644
--- a/components/dom_distiller/content/BUILD.gn
+++ b/components/dom_distiller/content/BUILD.gn
@@ -14,9 +14,26 @@
   ]
 }
 
+# GYP version: components/dom_distiller.gypi:dom_distiller_content_common
+static_library("content_common") {
+  sources = [
+    "common/distiller_messages.cc",
+    "common/distiller_messages.h",
+  ]
+
+  deps = [
+    "//base",
+    "//content/public/common",
+    "//ipc",
+    "//url",
+  ]
+}
+
 # GYP version: components/dom_distiller.gypi:dom_distiller_content_browser
 static_library("content_browser") {
   sources = [
+    "browser/distillability_driver.cc",
+    "browser/distillability_driver.h",
     "browser/distillable_page_utils.cc",
     "browser/distillable_page_utils.h",
     "browser/distiller_javascript_service_impl.cc",
@@ -37,6 +54,7 @@
     "//content/public/browser",
   ]
   deps = [
+    ":content_common",
     ":mojo_bindings",
     "//base",
     "//components/resources",
@@ -66,6 +84,8 @@
 # GYP version: components/dom_distiller.gypi:dom_distiller_content_renderer
 static_library("content_renderer") {
   sources = [
+    "renderer/distillability_agent.cc",
+    "renderer/distillability_agent.h",
     "renderer/distiller_js_render_frame_observer.cc",
     "renderer/distiller_js_render_frame_observer.h",
     "renderer/distiller_native_javascript.cc",
@@ -74,7 +94,11 @@
     "renderer/distiller_page_notifier_service_impl.h",
   ]
 
+  public_deps = [
+    "//components/dom_distiller/core/proto",
+  ]
   deps = [
+    ":content_common",
     ":mojo_bindings",
     "//base",
     "//content/public/common",
@@ -82,6 +106,7 @@
     "//gin",
     "//mojo/environment:chromium",
     "//mojo/public/cpp/bindings",
+    "//skia",
     "//third_party/WebKit/public:blink_headers",
     "//v8",
   ]
diff --git a/components/dom_distiller/content/DEPS b/components/dom_distiller/content/DEPS
index 50f350df..4688a57 100644
--- a/components/dom_distiller/content/DEPS
+++ b/components/dom_distiller/content/DEPS
@@ -2,6 +2,7 @@
   "+components/keyed_service",
   "+content/public",
   "+content/shell",
+  "+ipc",
   "+net/base",
   "+net/test",
 ]
diff --git a/components/dom_distiller/content/browser/distillability_driver.cc b/components/dom_distiller/content/browser/distillability_driver.cc
new file mode 100644
index 0000000..8af458f
--- /dev/null
+++ b/components/dom_distiller/content/browser/distillability_driver.cc
@@ -0,0 +1,58 @@
+// Copyright 2015 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 "components/dom_distiller/content/browser/distillability_driver.h"
+#include "components/dom_distiller/content/common/distiller_messages.h"
+
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(
+    dom_distiller::DistillabilityDriver);
+
+namespace dom_distiller {
+
+DistillabilityDriver::DistillabilityDriver(
+    content::WebContents* web_contents)
+    : content::WebContentsObserver(web_contents) {
+}
+
+DistillabilityDriver::~DistillabilityDriver() {
+  CleanUp();
+}
+
+void DistillabilityDriver::SetDelegate(
+    const base::Callback<void(bool, bool)>& delegate) {
+  m_delegate_ = delegate;
+}
+
+bool DistillabilityDriver::OnMessageReceived(const IPC::Message &msg,
+    content::RenderFrameHost* render_frame_host) {
+  bool handled = true;
+  IPC_BEGIN_MESSAGE_MAP(DistillabilityDriver, msg)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_Distillability,
+                        OnDistillability)
+  IPC_MESSAGE_UNHANDLED(handled = false)
+  IPC_END_MESSAGE_MAP()
+  return handled;
+}
+
+void DistillabilityDriver::OnDistillability(
+    bool distillable, bool is_last) {
+  if (m_delegate_.is_null()) return;
+
+  m_delegate_.Run(distillable, is_last);
+}
+
+void DistillabilityDriver::RenderProcessGone(
+    base::TerminationStatus status) {
+  CleanUp();
+}
+
+void DistillabilityDriver::CleanUp() {
+  content::WebContentsObserver::Observe(NULL);
+}
+
+}  // namespace dom_distiller
diff --git a/components/dom_distiller/content/browser/distillability_driver.h b/components/dom_distiller/content/browser/distillability_driver.h
new file mode 100644
index 0000000..795b9bf
--- /dev/null
+++ b/components/dom_distiller/content/browser/distillability_driver.h
@@ -0,0 +1,44 @@
+// Copyright 2015 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.
+
+#ifndef COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLIBILITY_DRIVER_H_
+#define COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLIBILITY_DRIVER_H_
+
+#include "base/macros.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace dom_distiller {
+
+// This is an IPC helper for determining whether a page should be distilled.
+class DistillabilityDriver
+    : public content::WebContentsObserver,
+      public content::WebContentsUserData<DistillabilityDriver> {
+ public:
+  ~DistillabilityDriver() override;
+
+  void SetDelegate(const base::Callback<void(bool, bool)>& delegate);
+
+  // content::WebContentsObserver implementation.
+  bool OnMessageReceived(const IPC::Message& message,
+                         content::RenderFrameHost* rfh) override;
+  void RenderProcessGone(base::TerminationStatus status) override;
+
+ private:
+  explicit DistillabilityDriver(content::WebContents* web_contents);
+  friend class content::WebContentsUserData<DistillabilityDriver>;
+
+  void OnDistillability(bool distillable, bool is_last);
+
+  // Removes the observer and clears the WebContents member.
+  void CleanUp();
+
+  base::Callback<void(bool, bool)> m_delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(DistillabilityDriver);
+};
+
+}  // namespace dom_distiller
+
+#endif  // COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLIBILITY_DRIVER_H_
diff --git a/components/dom_distiller/content/browser/distillable_page_utils.cc b/components/dom_distiller/content/browser/distillable_page_utils.cc
index 5487c62..56d606b 100644
--- a/components/dom_distiller/content/browser/distillable_page_utils.cc
+++ b/components/dom_distiller/content/browser/distillable_page_utils.cc
@@ -10,6 +10,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/values.h"
+#include "components/dom_distiller/content/browser/distillability_driver.h"
 #include "components/dom_distiller/content/browser/distiller_javascript_utils.h"
 #include "components/dom_distiller/core/distillable_page_detector.h"
 #include "components/dom_distiller/core/experiments.h"
@@ -98,4 +99,15 @@
       base::Bind(OnExtractFeaturesJsResult, detector, callback));
 }
 
+void setDelegate(content::WebContents* web_contents,
+                 DistillabilityDelegate delegate) {
+  CHECK(web_contents);
+  DistillabilityDriver::CreateForWebContents(web_contents);
+
+  DistillabilityDriver *driver =
+      DistillabilityDriver::FromWebContents(web_contents);
+  CHECK(driver);
+  driver->SetDelegate(delegate);
+}
+
 }  // namespace dom_distiller
diff --git a/components/dom_distiller/content/browser/distillable_page_utils.h b/components/dom_distiller/content/browser/distillable_page_utils.h
index bcc6d40..dd3e00a 100644
--- a/components/dom_distiller/content/browser/distillable_page_utils.h
+++ b/components/dom_distiller/content/browser/distillable_page_utils.h
@@ -28,6 +28,12 @@
 void IsDistillablePageForDetector(content::WebContents* web_contents,
                                   const DistillablePageDetector* detector,
                                   base::Callback<void(bool)> callback);
+
+typedef base::Callback<void(bool, bool)> DistillabilityDelegate;
+
+// Set the delegate to receive the result of whether the page is distillable.
+void setDelegate(content::WebContents* web_contents,
+                 DistillabilityDelegate delegate);
 }
 
 #endif  // COMPONENTS_DOM_DISTILLER_CONTENT_BROWSER_DISTILLABLE_PAGE_UTILS_H_
diff --git a/components/dom_distiller/content/browser/distillable_page_utils_android.cc b/components/dom_distiller/content/browser/distillable_page_utils_android.cc
index 56dfffaf..0b48f85 100644
--- a/components/dom_distiller/content/browser/distillable_page_utils_android.cc
+++ b/components/dom_distiller/content/browser/distillable_page_utils_android.cc
@@ -22,6 +22,14 @@
       base::android::AttachCurrentThread(), callback_holder->obj(),
       isDistillable);
 }
+
+void OnIsPageDistillableUpdate(
+    ScopedJavaGlobalRef<jobject>* callback_holder,
+    bool isDistillable, bool isLast) {
+  Java_DistillablePageUtils_callOnIsPageDistillableUpdate(
+      base::android::AttachCurrentThread(), callback_holder->obj(),
+      isDistillable, isLast);
+}
 }  // namespace
 
 static void IsPageDistillable(JNIEnv* env,
@@ -46,6 +54,26 @@
       base::Bind(OnIsPageDistillableResult, base::Passed(&callback_holder)));
 }
 
+static void SetDelegate(JNIEnv* env,
+                        const JavaParamRef<jclass>& jcaller,
+                        const JavaParamRef<jobject>& webContents,
+                        const JavaParamRef<jobject>& callback) {
+  content::WebContents* web_contents(
+      content::WebContents::FromJavaWebContents(webContents));
+  if (!web_contents) {
+    return;
+  }
+
+  // TODO(wychen): check memory management
+  ScopedJavaGlobalRef<jobject>* callback_holder(
+      new ScopedJavaGlobalRef<jobject>());
+  callback_holder->Reset(env, callback);
+
+  DistillabilityDelegate delegate =
+      base::Bind(OnIsPageDistillableUpdate, base::Owned(callback_holder));
+  setDelegate(web_contents, delegate);
+}
+
 bool RegisterDistillablePageUtils(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
index cc315e9b..252f9b00 100644
--- a/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
+++ b/components/dom_distiller/content/browser/dom_distiller_viewer_source.cc
@@ -199,6 +199,10 @@
     std::string css = viewer::GetCss();
     callback.Run(base::RefCountedString::TakeString(&css));
     return;
+  } else if (kViewerLoadingImagePath == path) {
+    std::string image = viewer::GetLoadingImage();
+    callback.Run(base::RefCountedString::TakeString(&image));
+    return;
   } else if (base::StartsWith(path, kViewerSaveFontScalingPath,
                               base::CompareCase::SENSITIVE)) {
     double scale = 1.0;
@@ -259,6 +263,8 @@
     const std::string& path) const {
   if (kViewerCssPath == path) {
     return "text/css";
+  } else if (kViewerLoadingImagePath == path) {
+    return "image/svg+xml";
   }
   return "text/html";
 }
diff --git a/components/dom_distiller/content/common/distiller_messages.cc b/components/dom_distiller/content/common/distiller_messages.cc
new file mode 100644
index 0000000..e336f9e
--- /dev/null
+++ b/components/dom_distiller/content/common/distiller_messages.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2015 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.
+
+// Get basic type definitions.
+#define IPC_MESSAGE_IMPL
+#include "components/dom_distiller/content/common/distiller_messages.h"
+
+// Generate constructors.
+#include "ipc/struct_constructor_macros.h"
+#include "components/dom_distiller/content/common/distiller_messages.h"
+
+// Generate destructors.
+#include "ipc/struct_destructor_macros.h"
+#include "components/dom_distiller/content/common/distiller_messages.h"
+
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "components/dom_distiller/content/common/distiller_messages.h"
+}  // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "components/dom_distiller/content/common/distiller_messages.h"
+}  // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "components/dom_distiller/content/common/distiller_messages.h"
+}  // namespace IPC
diff --git a/components/dom_distiller/content/common/distiller_messages.h b/components/dom_distiller/content/common/distiller_messages.h
new file mode 100644
index 0000000..84c4081
--- /dev/null
+++ b/components/dom_distiller/content/common/distiller_messages.h
@@ -0,0 +1,21 @@
+// Copyright 2015 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.
+
+// Multiply-included message file, hence no include guard.
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string16.h"
+#include "content/public/common/common_param_traits.h"
+#include "content/public/common/common_param_traits_macros.h"
+#include "ipc/ipc_message_macros.h"
+#include "ipc/ipc_message_utils.h"
+
+#define IPC_MESSAGE_START DistillerMsgStart
+
+// Whether a page is suitable for DOM distiller to process.
+IPC_MESSAGE_ROUTED2(FrameHostMsg_Distillability,
+                    bool /* is_distillable */,
+                    bool /* is_last_update */)
diff --git a/components/dom_distiller/content/renderer/distillability_agent.cc b/components/dom_distiller/content/renderer/distillability_agent.cc
new file mode 100644
index 0000000..eab0e0a6
--- /dev/null
+++ b/components/dom_distiller/content/renderer/distillability_agent.cc
@@ -0,0 +1,120 @@
+// Copyright 2015 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 "components/dom_distiller/content/common/distiller_messages.h"
+#include "components/dom_distiller/content/renderer/distillability_agent.h"
+#include "components/dom_distiller/core/distillable_page_detector.h"
+#include "components/dom_distiller/core/experiments.h"
+#include "components/dom_distiller/core/page_features.h"
+#include "components/dom_distiller/core/url_utils.h"
+#include "content/public/renderer/render_frame.h"
+
+#include "third_party/WebKit/public/platform/WebDistillability.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebElement.h"
+#include "third_party/WebKit/public/web/WebLocalFrame.h"
+
+namespace dom_distiller {
+
+using namespace blink;
+
+namespace {
+
+// Returns whether it is necessary to send updates back to the browser.
+// The number of updates can be from 0 to 2. See the tests in
+// "distillable_page_utils_browsertest.cc".
+// Most heuristics types only require one update after parsing.
+// Adaboost is the only one doing the second update, which is after loading.
+bool NeedToUpdate(bool is_loaded) {
+  switch (GetDistillerHeuristicsType()) {
+    case DistillerHeuristicsType::ALWAYS_TRUE:
+      return !is_loaded;
+    case DistillerHeuristicsType::OG_ARTICLE:
+      return !is_loaded;
+    case DistillerHeuristicsType::ADABOOST_MODEL:
+      return true;
+    case DistillerHeuristicsType::NONE:
+    default:
+      return false;
+  }
+}
+
+// Returns whether this update is the last one for the page.
+bool IsLast(bool is_loaded) {
+  if (GetDistillerHeuristicsType() == DistillerHeuristicsType::ADABOOST_MODEL)
+    return is_loaded;
+
+  return true;
+}
+
+bool IsDistillablePageAdaboost(WebDocument& doc,
+                               const DistillablePageDetector* detector) {
+  WebDistillabilityFeatures features = doc.distillabilityFeatures();
+  GURL parsed_url(doc.url());
+  if (!parsed_url.is_valid()) {
+    return false;
+  }
+  // The adaboost model is only applied to non-mobile pages.
+  if (features.isMobileFriendly) {
+    return false;
+  }
+  return detector->Classify(CalculateDerivedFeatures(
+    features.openGraph,
+    parsed_url,
+    features.elementCount,
+    features.anchorCount,
+    features.formCount,
+    features.mozScore,
+    features.mozScoreAllSqrt,
+    features.mozScoreAllLinear
+  ));
+}
+
+bool IsDistillablePage(WebDocument& doc) {
+  switch (GetDistillerHeuristicsType()) {
+    case DistillerHeuristicsType::ALWAYS_TRUE:
+      return true;
+    case DistillerHeuristicsType::OG_ARTICLE:
+      return doc.distillabilityFeatures().openGraph;
+    case DistillerHeuristicsType::ADABOOST_MODEL:
+      return IsDistillablePageAdaboost(
+          doc, DistillablePageDetector::GetNewModel());
+    case DistillerHeuristicsType::NONE:
+    default:
+      return false;
+  }
+}
+
+}  // namespace
+
+DistillabilityAgent::DistillabilityAgent(
+    content::RenderFrame* render_frame)
+    : RenderFrameObserver(render_frame) {
+}
+
+void DistillabilityAgent::DidMeaningfulLayout(
+    WebMeaningfulLayout layout_type) {
+  if (layout_type != WebMeaningfulLayout::FinishedParsing &&
+      layout_type != WebMeaningfulLayout::FinishedLoading) {
+    return;
+  }
+
+  DCHECK(render_frame());
+  if (!render_frame()->IsMainFrame()) return;
+  DCHECK(render_frame()->GetWebFrame());
+  WebDocument doc = render_frame()->GetWebFrame()->document();
+  if (doc.isNull() || doc.body().isNull()) return;
+  if (!url_utils::IsUrlDistillable(doc.url())) return;
+
+  bool is_loaded = layout_type == WebMeaningfulLayout::FinishedLoading;
+  if (!NeedToUpdate(is_loaded)) return;
+
+  Send(new FrameHostMsg_Distillability(routing_id(),
+      IsDistillablePage(doc), IsLast(is_loaded)));
+}
+
+
+DistillabilityAgent::~DistillabilityAgent() {}
+
+}  // namespace dom_distiller
diff --git a/components/dom_distiller/content/renderer/distillability_agent.h b/components/dom_distiller/content/renderer/distillability_agent.h
new file mode 100644
index 0000000..940f7c1
--- /dev/null
+++ b/components/dom_distiller/content/renderer/distillability_agent.h
@@ -0,0 +1,24 @@
+// Copyright 2015 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.
+
+#ifndef COMPONENTS_DOM_DISTILLER_CONTENT_RENDERER_DISTILLABILITY_AGENT_H_
+#define COMPONENTS_DOM_DISTILLER_CONTENT_RENDERER_DISTILLABILITY_AGENT_H_
+
+#include "content/public/renderer/render_frame_observer.h"
+
+namespace dom_distiller {
+
+// DistillabilityAgent returns distillability result to DistillabilityDriver.
+class DistillabilityAgent : public content::RenderFrameObserver {
+ public:
+  DistillabilityAgent(content::RenderFrame* render_frame);
+  ~DistillabilityAgent() override;
+
+  // content::RenderFrameObserver:
+  void DidMeaningfulLayout(blink::WebMeaningfulLayout layout_type) override;
+};
+
+}  // namespace dom_distiller
+
+#endif  // COMPONENTS_DOM_DISTILLER_CONTENT_RENDERER_DISTILLABILITY_AGENT_H_
diff --git a/components/dom_distiller/core/css/distilledpage.css b/components/dom_distiller/core/css/distilledpage.css
index 3f0a67b3..80dc711 100644
--- a/components/dom_distiller/core/css/distilledpage.css
+++ b/components/dom_distiller/core/css/distilledpage.css
@@ -226,6 +226,18 @@
 
 /* Content. */
 
+#loadingIndicator {
+  width: 100%;
+  padding-bottom: 2em;
+}
+
+#loadingIndicator > img, #loadingIndicator > svg {
+  display: block;
+  height: 2.5em;
+  margin: auto;
+  width: 2.5em;
+}
+
 /* Margins for Show Original link. */
 
 .light #closeReaderView {
@@ -478,408 +490,3 @@
   width: 100%;
 }
 
-/* Loading Indicator. */
-#loader {
-  height: 22px;
-  margin-left: auto;
-  margin-right: auto;
-  position: relative;
-  width: 22px;
-}
-
-#loader * {
-  display: block;
-  position: absolute;
-}
-
-#loader .circle {
-  border-radius: 50%;
-  height: 100%;
-  opacity: 0;
-  overflow: hidden;
-  width: 100%;
-}
-
-#loader .mask {
-  height: 100%;
-  opacity: 0;
-  overflow: hidden;
-  width: 100%;
-}
-
-#loader .mask.first {
-  transition-delay: 0.22s;
-  transition-duration: 0s;
-  transition-property: border-color;
-}
-
-#loader .circle.initial .mask {
-  height: 50%;
-  top: 0;
-}
-
-#loader .circle.red .mask.first {
-  border-bottom: 1px solid #555;
-  height: 50%;
-  top: 0;
-}
-
-#loader .circle.red .mask.second {
-  bottom: 0;
-  height: 50%;
-}
-
-#loader .circle.yellow .mask.first {
-  border-left: 1px solid #888;
-  right: 0;
-  width: 50%;
-}
-
-#loader .circle.yellow .mask.second {
-  left: 0;
-  width: 50%;
-}
-
-#loader .circle.green .mask.first {
-  border-top: 1px solid #555;
-  bottom: 0;
-  height: 50%;
-}
-
-#loader .circle.green .mask.second {
-  height: 50%;
-  top: 0;
-}
-
-#loader .circle.blue .mask.first {
-  border-right: 1px solid #888;
-  left: 0;
-  width: 50%;
-}
-
-#loader .circle.blue .mask.second {
-  right: 0;
-  width: 50%;
-}
-
-#loader .circle .mask .base {
-  border-radius: 50%;
-  height: 100%;
-  opacity: 0;
-  transition-property: opacity;
-  transition-timing-function: linear;
-  transition-duration: 0s;
-  transition-delay: 0s;
-  width: 100%;
-}
-
-#loader .circle .mask .mover {
-  border-radius: 50%;
-  height: 100%;
-  transition-delay: 0s;
-  transition-duration: 0.22s;
-  transition-property: background-color, left, top, right, bottom, width,
-      height;
-  transition-timing-function: ease-in;
-  width: 100%;
-}
-
-#loader .circle .mask.second .mover,
-#loader .circle.initial .mask .mover {
-  transition-delay: 0.22s;
-  transition-timing-function: ease-out;
-}
-
-#loader .circle.red .mask.first .base {
-  height: 200%;
-  top: 0;
-}
-#loader .circle.red .mask.second .base {
-  bottom: 0;
-  height: 200%;
-}
-
-#loader .circle.yellow .mask.first .base {
-  right: 0;
-  width: 200%;
-}
-
-#loader .circle.yellow .mask.second .base {
-  left: 0;
-  width: 200%;
-}
-
-#loader .circle.green .mask.first .base {
-  bottom: 0;
-  height: 200%;
-}
-
-#loader .circle.green .mask.second .base {
-  height: 200%;
-  top: 0;
-}
-
-#loader .circle.blue .mask.first .base {
-  left: 0;
-  width: 200%;
-}
-
-#loader .circle.blue .mask.second .base {
-  right: 0;
-  width: 200%;
-}
-
-#loader .circle.initial .mask .mover {
-  height: 0;
-  top: 100%;
-}
-
-#loader .circle.red .mask.first .mover {
-  height: 200%;
-  top: 0;
-}
-
-#loader .circle.red .mask.second .mover {
-  bottom: 100%;
-  height: 0;
-}
-
-#loader .circle.yellow .mask.first .mover {
-  right: 0;
-  width: 200%;
-}
-
-#loader .circle.yellow .mask.second .mover {
-  left: 100%;
-  width: 0;
-}
-
-#loader .circle.green .mask.first .mover {
-  bottom: 0;
-  height: 200%;
-}
-
-#loader .circle.green .mask.second .mover {
- height: 0;
- top: 100%;
-}
-
-#loader .circle.blue .mask.first .mover {
-  left: 0;
-  width: 200%;
-}
-
-#loader .circle.blue .mask.second .mover {
-  right: 100%;
-  width: 0;
-}
-
-/* Initial State. */
-#loader.initial .circle.initial,
-#loader.initial .circle.initial .mask {
-  opacity: 1;
-}
-#loader.initial .circle.initial .mask .mover {
-  height: 200%;
-  top: 0;
-}
-
-/* Moving from Red to Yellow. */
-#loader.yellow .circle.yellow,
-#loader.yellow .circle.yellow .mask,
-#loader.yellow .circle.yellow .mask .base {
-  opacity: 1;
-}
-#loader.yellow .circle.yellow .mask.first .mover {
-  right: 100%;
-  width: 0;
-}
-#loader.yellow .circle.yellow .mask.second .mover {
-  left: 0;
-  width: 200%;
-}
-
-/* Moving from Yellow to Green. */
-#loader.green .circle.green,
-#loader.green .circle.green .mask,
-#loader.green .circle.green .mask .base {
-  opacity: 1;
-}
-#loader.green .circle.green .mask.first .mover {
-  bottom: 100%;
-  height: 0;
-}
-#loader.green .circle.green .mask.second .mover {
-  height: 200%;
-  top: 0;
-}
-
-
-/* Moving from Green to Blue. */
-#loader.blue .circle.blue,
-#loader.blue .circle.blue .mask,
-#loader.blue .circle.blue .mask .base {
-  opacity: 1;
-}
-#loader.blue .circle.blue .mask.first .mover {
-  left: 100%;
-  width: 0;
-}
-#loader.blue .circle.blue .mask.second .mover {
-  right: 0;
-  width: 200%;
-}
-
-/* Moving from Blue to Red. */
-#loader.red .circle.red,
-#loader.red .circle.red .mask,
-#loader.red .circle.red .mask .base {
-  opacity: 1;
-}
-#loader.red.firstTime .circle.red .mask.second .base {
-  opacity: 0;
-}
-#loader.red .circle.red .mask.first .mover {
-  height: 0;
-  top: 100%;
-}
-#loader.red .circle.red .mask.second .mover {
-  bottom: 0;
-  height: 200%;
-}
-
-#loader .circle.red .mask.first {
-  border-bottom-color: rgb(60,120,248);
-}
-
-#loader .circle.yellow .mask.first {
-  border-left-color: rgb(250,36,36);
-}
-
-#loader .circle.green .mask.first {
-  border-top-color: rgb(255,211,75);
-}
-
-#loader .circle.blue .mask.first {
-  border-right-color: rgb(0,177,95);
-}
-
-#loader .circle.red .mask.first .base {
-  background-color: rgb(250,36,36);
-}
-
-#loader .circle.red .mask.second .base {
-  background-color: rgb(60,120,248);
-}
-
-#loader .circle.yellow .mask.first .base {
-  background-color: rgb(255,211,75);
-}
-
-#loader .circle.yellow .mask.second .base {
-  background-color: rgb(250,36,36);
-}
-
-#loader .circle.green .mask.first .base {
-  background-color: rgb(0,177,95);
-}
-
-#loader .circle.green .mask.second .base {
-  background-color: rgb(255,211,75);
-}
-
-#loader .circle.blue .mask.first .base {
-  background-color: rgb(60,120,248);
-}
-
-#loader .circle.blue .mask.second .base {
-  background-color: rgb(0,177,95);
-}
-
-#loader .circle.initial .mask .mover {
-  background-color: rgb(33,89,189);
-}
-
-#loader .circle.red .mask.first .mover {
-  background-color: rgb(60,120,248);
-}
-
-#loader .circle.red .mask.second .mover {
-  background-color: rgb(158,18,18);
-}
-
-#loader .circle.yellow .mask.first .mover {
-  background-color: rgb(250,36,36);
-}
-
-#loader .circle.yellow .mask.second .mover {
-  background-color: rgb(222,161,26);
-}
-
-#loader .circle.green .mask.first .mover {
-  background-color: rgb(255,211,75);
-}
-
-#loader .circle.green .mask.second .mover {
-  background-color: rgb(0,137,72);
-}
-
-#loader .circle.blue .mask.first .mover {
-  background-color: rgb(0,177,95);
-}
-
-#loader .circle.blue .mask.second .mover {
-  background-color: rgb(33,89,189);
-}
-
-#loader.initial .circle.initial .mask .mover {
-  background-color: rgb(60,120,248);
-}
-
-#loader.yellow .circle.yellow .mask.first {
-  border-color: rgb(255,211,75);
-}
-
-#loader.yellow .circle.yellow .mask.first .mover {
-  background-color: rgb(158,18,18);
-}
-
-#loader.yellow .circle.yellow .mask.second .mover {
-  background-color: rgb(255,211,75);
-}
-
-#loader.green .circle.green .mask.first {
- border-color: rgb(0,177,95);
-}
-
-#loader.green .circle.green .mask.first .mover {
- background-color: rgb(222,161,26);
-}
-
-#loader.green .circle.green .mask.second .mover {
- background-color: rgb(0,177,95);
-}
-
-#loader.blue .circle.blue .mask.first {
-  border-color: rgb(60,120,248);
-}
-
-#loader.blue .circle.blue .mask.first .mover {
-  background-color: rgb(0,137,72);
-}
-
-#loader.blue .circle.blue .mask.second .mover {
-  background-color: rgb(60,120,248);
-}
-
-#loader.red .circle.red .mask.first {
-  border-color: rgb(250,36,36);
-}
-
-#loader.red .circle.red .mask.first .mover {
-  background-color: rgb(33,89,189);
-}
-
-#loader.red .circle.red .mask.second .mover {
-  background-color: rgb(250,36,36);
-}
diff --git a/components/dom_distiller/core/data/distillable_page_model_new.bin b/components/dom_distiller/core/data/distillable_page_model_new.bin
new file mode 100644
index 0000000..5930236
--- /dev/null
+++ b/components/dom_distiller/core/data/distillable_page_model_new.bin
Binary files differ
diff --git a/components/dom_distiller/core/distillable_page_detector.cc b/components/dom_distiller/core/distillable_page_detector.cc
index aa7ddcf30..43499a7 100644
--- a/components/dom_distiller/core/distillable_page_detector.cc
+++ b/components/dom_distiller/core/distillable_page_detector.cc
@@ -24,6 +24,20 @@
   return detector;
 }
 
+const DistillablePageDetector* DistillablePageDetector::GetNewModel() {
+  static DistillablePageDetector* detector = nullptr;
+  if (!detector) {
+    std::string serialized_proto =
+        ResourceBundle::GetSharedInstance()
+            .GetRawDataResource(IDR_DISTILLABLE_PAGE_SERIALIZED_MODEL_NEW)
+            .as_string();
+    scoped_ptr<AdaBoostProto> proto(new AdaBoostProto);
+    CHECK(proto->ParseFromString(serialized_proto));
+    detector = new DistillablePageDetector(proto.Pass());
+  }
+  return detector;
+}
+
 DistillablePageDetector::DistillablePageDetector(
     scoped_ptr<AdaBoostProto> proto)
     : proto_(proto.Pass()), threshold_(0.0) {
diff --git a/components/dom_distiller/core/distillable_page_detector.h b/components/dom_distiller/core/distillable_page_detector.h
index fbe36bf8..819e5ff 100644
--- a/components/dom_distiller/core/distillable_page_detector.h
+++ b/components/dom_distiller/core/distillable_page_detector.h
@@ -19,6 +19,7 @@
 class DistillablePageDetector {
  public:
   static const DistillablePageDetector* GetDefault();
+  static const DistillablePageDetector* GetNewModel();
   explicit DistillablePageDetector(scoped_ptr<AdaBoostProto> proto);
   ~DistillablePageDetector();
 
diff --git a/components/dom_distiller/core/dom_distiller_request_view_base.cc b/components/dom_distiller/core/dom_distiller_request_view_base.cc
index 7dbc67d..ceb2868 100644
--- a/components/dom_distiller/core/dom_distiller_request_view_base.cc
+++ b/components/dom_distiller/core/dom_distiller_request_view_base.cc
@@ -118,7 +118,6 @@
   // Getting the viewer handle means this is not an error page, send
   // the viewer JavaScript and show the loading indicator.
   SendCommonJavaScript();
-  SendJavaScript(viewer::GetToggleLoadingIndicatorJs(false));
 }
 
 void DomDistillerRequestViewBase::SendCommonJavaScript() {
diff --git a/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc b/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc
index e372af0d..a13e4d1 100644
--- a/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc
+++ b/components/dom_distiller/core/dom_distiller_request_view_base_unittest.cc
@@ -211,10 +211,6 @@
   TestRequestViewHandle handle(distilled_page_prefs_.get());
   handle.TakeViewerHandle(NULL);
 
-  // The loading indicator should show before any content is displayed.
-  EXPECT_THAT(handle.GetJavaScriptBuffer(), HasSubstr(show_loader));
-  handle.ClearJavaScriptBuffer();
-
   std::vector<scoped_refptr<ArticleDistillationUpdate::RefCountedPageProto>>
       pages;
   scoped_refptr<base::RefCountedData<DistilledPageProto>> page_proto =
diff --git a/components/dom_distiller/core/html/dom_distiller_viewer.html b/components/dom_distiller/core/html/dom_distiller_viewer.html
index d3071a1..2a4a97c5 100644
--- a/components/dom_distiller/core/html/dom_distiller_viewer.html
+++ b/components/dom_distiller/core/html/dom_distiller_viewer.html
@@ -30,60 +30,11 @@
         <div id="content"><noscript>$5</noscript></div>
       </article>
       <div id="loadingIndicator" class="visible">
-        <div id="loader">
-          <div class="circle initial">
-            <span class="mask">
-              <span class="mover"></span>
-            </span>
-          </div>
-
-          <div class="circle red">
-            <span class="mask first">
-              <span class="base"></span>
-              <span class="mover"></span>
-            </span>
-            <span class="mask second">
-              <span class="base"></span>
-              <span class="mover"></span>
-            </span>
-          </div>
-
-          <div class="circle yellow">
-            <span class="mask first">
-              <span class="base"></span>
-              <span class="mover"></span>
-            </span>
-            <span class="mask second">
-              <span class="base"></span>
-              <span class="mover"></span>
-            </span>
-          </div>
-
-          <div class="circle green">
-            <span class="mask first">
-              <span class="base"></span>
-              <span class="mover"></span>
-            </span>
-            <span class="mask second">
-              <span class="base"></span>
-              <span class="mover"></span>
-            </span>
-          </div>
-
-          <div class="circle blue">
-            <span class="mask first">
-              <span class="base"></span>
-              <span class="mover"></span>
-            </span>
-            <span class="mask second">
-              <span class="base"></span>
-              <span class="mover"></span>
-            </span>
-          </div>
-        </div>
+        <!-- SVG material loading spinner. -->
+        $6
       </div>
     </div>
-    <a href="$6" id="closeReaderView">$7</a>
+    <a href="$7" id="closeReaderView">$8</a>
   </div>
   <div id="feedbackContainer" class="footerFeedback hidden">
     <div class="feedbackContent">
diff --git a/components/dom_distiller/core/images/dom_distiller_material_spinner.svg b/components/dom_distiller/core/images/dom_distiller_material_spinner.svg
new file mode 100644
index 0000000..538e71a
--- /dev/null
+++ b/components/dom_distiller/core/images/dom_distiller_material_spinner.svg
@@ -0,0 +1,107 @@
+<svg version="1" xmlns="http://www.w3.org/2000/svg"
+                 xmlns:xlink="http://www.w3.org/1999/xlink"
+     width="16px" height="16px" viewBox="0 0 28 28">
+  <!-- 28= RADIUS*2 + STROKEWIDTH -->
+
+  <title>Material design circular activity spinner with CSS3 animation</title>
+  <style type="text/css">
+      /**************************/
+      /* STYLES FOR THE SPINNER */
+      /**************************/
+
+      /*
+       * Constants:
+       *      RADIUS      = 12.5
+       *      STROKEWIDTH = 3
+       *      ARCSIZE     = 270 degrees (amount of circle the arc takes up)
+       *      ARCTIME     = 1333ms (time it takes to expand and contract arc)
+       *      ARCSTARTROT = 216 degrees (how much the start location of the arc
+       *                                should rotate each time, 216 gives us a
+       *                                5 pointed star shape (it's 360/5 * 2).
+       *                                For a 7 pointed star, we might do
+       *                                360/7 * 3 = 154.286)
+       *
+       *      SHRINK_TIME = 400ms
+       */
+
+      .qp-circular-loader {
+        width:28px;  /* 2*RADIUS + STROKEWIDTH */
+        height:28px; /* 2*RADIUS + STROKEWIDTH */
+      }
+      .qp-circular-loader-path {
+        stroke-dasharray: 58.9;  /* 2*RADIUS*PI * ARCSIZE/360 */
+        stroke-dashoffset: 58.9; /* 2*RADIUS*PI * ARCSIZE/360 */
+                                 /* hides things initially */
+      }
+
+      /* SVG elements seem to have a different default origin */
+      .qp-circular-loader, .qp-circular-loader * {
+        -webkit-transform-origin: 50% 50%;
+      }
+
+      /* Rotating the whole thing */
+      @-webkit-keyframes rotate {
+        from {-webkit-transform: rotate(0deg);}
+        to {-webkit-transform: rotate(360deg);}
+      }
+      .qp-circular-loader {
+        -webkit-animation-name: rotate;
+        -webkit-animation-duration: 1568.63ms; /* 360 * ARCTIME / (ARCSTARTROT + (360-ARCSIZE)) */
+        -webkit-animation-iteration-count: infinite;
+        -webkit-animation-timing-function: linear;
+      }
+
+      /* Filling and unfilling the arc */
+      @-webkit-keyframes fillunfill {
+        from {
+          stroke-dashoffset: 58.8 /* 2*RADIUS*PI * ARCSIZE/360 - 0.1 */
+                                  /* 0.1 a bit of a magic constant here */
+        }
+        50% {
+          stroke-dashoffset: 0;
+        }
+        to {
+          stroke-dashoffset: -58.4 /* -(2*RADIUS*PI * ARCSIZE/360 - 0.5) */
+                                   /* 0.5 a bit of a magic constant here */
+        }
+      }
+      @-webkit-keyframes rot {
+        from {
+          -webkit-transform: rotate(0deg);
+        }
+        to {
+          -webkit-transform: rotate(-360deg);
+        }
+      }
+      @-webkit-keyframes colors {
+        from {
+          stroke: #4285f4;
+        }
+        to {
+          stroke: #4285f4;
+        }
+      }
+      .qp-circular-loader-path {
+        -webkit-animation-name: fillunfill, rot, colors;
+        -webkit-animation-duration: 1333ms, 5332ms, 5332ms; /* ARCTIME, 4*ARCTIME, 4*ARCTIME */
+        -webkit-animation-iteration-count: infinite, infinite, infinite;
+        -webkit-animation-timing-function: cubic-bezier(0.4, 0.0, 0.2, 1), steps(4), linear;
+        -webkit-animation-play-state: running, running, running;
+        -webkit-animation-fill-mode: forwards;
+      }
+
+  </style>
+
+  <!-- 3= STROKEWIDTH -->
+  <!-- 14= RADIUS + STROKEWIDTH/2 -->
+  <!-- 12.5= RADIUS -->
+  <!-- 1.5=  STROKEWIDTH/2 -->
+  <!-- ARCSIZE would affect the 1.5,14 part of this... 1.5,14 is specific to
+       270 degress -->
+  <g class="qp-circular-loader">
+    <path class="qp-circular-loader-path" fill="none" 
+          d="M 14,1.5 A 12.5,12.5 0 1 1 1.5,14" stroke-width="3"
+          stroke-linecap="round"></path>
+  </g>
+</svg>
+
diff --git a/components/dom_distiller/core/javascript/dom_distiller_viewer.js b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
index 69a08b0..c875d43f 100644
--- a/components/dom_distiller/core/javascript/dom_distiller_viewer.js
+++ b/components/dom_distiller/core/javascript/dom_distiller_viewer.js
@@ -48,7 +48,6 @@
 function showLoadingIndicator(isLastPage) {
   document.getElementById('loadingIndicator').className =
       isLastPage ? 'hidden' : 'visible';
-  updateLoadingIndicator(isLastPage);
 }
 
 // Sets the title.
@@ -120,24 +119,6 @@
   pincher.useFontScaling(scaling);
 }
 
-var updateLoadingIndicator = function() {
-  var colors = ["red", "yellow", "green", "blue"];
-  return function(isLastPage) {
-    if (!isLastPage && typeof this.colorShuffle == "undefined") {
-      var loader = document.getElementById("loader");
-      if (loader) {
-        var colorIndex = -1;
-        this.colorShuffle = setInterval(function() {
-          colorIndex = (colorIndex + 1) % colors.length;
-          loader.className = colors[colorIndex];
-        }, 600);
-      }
-    } else if (isLastPage && typeof this.colorShuffle != "undefined") {
-      clearInterval(this.colorShuffle);
-    }
-  };
-}();
-
 /**
  * Show the distiller feedback form.
  * @param questionText The i18n text for the feedback question.
diff --git a/components/dom_distiller/core/url_constants.cc b/components/dom_distiller/core/url_constants.cc
index cfe28b8..cc54b28 100644
--- a/components/dom_distiller/core/url_constants.cc
+++ b/components/dom_distiller/core/url_constants.cc
@@ -10,6 +10,7 @@
 const char kEntryIdKey[] = "entry_id";
 const char kUrlKey[] = "url";
 const char kViewerCssPath[] = "dom_distiller_viewer.css";
+const char kViewerLoadingImagePath[] = "dom_distiller_material_spinner.svg";
 const char kViewerSaveFontScalingPath[] = "savefontscaling/";
 
 }  // namespace dom_distiller
diff --git a/components/dom_distiller/core/url_constants.h b/components/dom_distiller/core/url_constants.h
index 3b10e67..867141e8 100644
--- a/components/dom_distiller/core/url_constants.h
+++ b/components/dom_distiller/core/url_constants.h
@@ -11,6 +11,7 @@
 extern const char kEntryIdKey[];
 extern const char kUrlKey[];
 extern const char kViewerCssPath[];
+extern const char kViewerLoadingImagePath[];
 extern const char kViewerSaveFontScalingPath[];
 
 }  // namespace dom_distiller
diff --git a/components/dom_distiller/core/viewer.cc b/components/dom_distiller/core/viewer.cc
index a6a36c18..0ea152d 100644
--- a/components/dom_distiller/core/viewer.cc
+++ b/components/dom_distiller/core/viewer.cc
@@ -110,12 +110,15 @@
   std::vector<std::string> substitutions;
 
   std::ostringstream css;
+  std::ostringstream svg;
 #if defined(OS_IOS)
   // On iOS the content is inlined as there is no API to detect those requests
   // and return the local data once a page is loaded.
   css << "<style>" << viewer::GetCss() << viewer::GetIOSCss() << "</style>";
+  svg << viewer::GetLoadingImage();
 #else
   css << "<link rel=\"stylesheet\" href=\"/" << kViewerCssPath << "\">";
+  svg << "<img src=\"/" << kViewerLoadingImagePath << "\">";
 #endif  // defined(OS_IOS)
 
   substitutions.push_back(
@@ -131,10 +134,12 @@
       l10n_util::GetStringUTF8(
           IDS_DOM_DISTILLER_JAVASCRIPT_DISABLED_CONTENT));                // $5
 
-  substitutions.push_back(original_url);                                  // $6
+  substitutions.push_back(svg.str());                                     // $6
+
+  substitutions.push_back(original_url);                                  // $7
   substitutions.push_back(
       l10n_util::GetStringUTF8(
-          IDS_DOM_DISTILLER_VIEWER_CLOSE_READER_VIEW));                   // $7
+          IDS_DOM_DISTILLER_VIEWER_CLOSE_READER_VIEW));                   // $8
 
   return base::ReplaceStringPlaceholders(html_template, substitutions, NULL);
 }
@@ -187,6 +192,7 @@
   base::JSONWriter::Write(value, &output);
   page_update += "addToPage(" + output + ");";
   page_update += GetSetTextDirectionJs(std::string("auto"));
+  page_update += GetToggleLoadingIndicatorJs(true);
   if (ShouldShowFeedbackForm()) {
     page_update += GetShowFeedbackFormJs();
   }
@@ -244,6 +250,11 @@
           IDR_DISTILLER_CSS).as_string();
 }
 
+const std::string GetLoadingImage() {
+  return ResourceBundle::GetSharedInstance().GetRawDataResource(
+          IDR_DISTILLER_LOADING_IMAGE).as_string();
+}
+
 const std::string GetIOSCss() {
   return ResourceBundle::GetSharedInstance().GetRawDataResource(
           IDR_DISTILLER_IOS_CSS).as_string();
diff --git a/components/dom_distiller/core/viewer.h b/components/dom_distiller/core/viewer.h
index 277a7a10..9c36f42 100644
--- a/components/dom_distiller/core/viewer.h
+++ b/components/dom_distiller/core/viewer.h
@@ -69,6 +69,9 @@
 // Returns the default CSS to be used for a viewer.
 const std::string GetCss();
 
+// Returns the animated SVG loading image for a viewer.
+const std::string GetLoadingImage();
+
 // Returns the iOS specific CSS to be used for the distiller viewer.
 const std::string GetIOSCss();
 
diff --git a/components/enhanced_bookmarks/BUILD.gn b/components/enhanced_bookmarks/BUILD.gn
index 76fd35af..966622f 100644
--- a/components/enhanced_bookmarks/BUILD.gn
+++ b/components/enhanced_bookmarks/BUILD.gn
@@ -45,7 +45,6 @@
     "//base:prefs",
     "//components/bookmarks/browser",
     "//components/enhanced_bookmarks/proto",
-    "//components/keyed_service/content",
     "//components/keyed_service/core",
     "//components/offline_pages",
     "//components/pref_registry",
diff --git a/components/enhanced_bookmarks/bookmark_server_cluster_service.h b/components/enhanced_bookmarks/bookmark_server_cluster_service.h
index 8bbf5ed..65b9b1c 100644
--- a/components/enhanced_bookmarks/bookmark_server_cluster_service.h
+++ b/components/enhanced_bookmarks/bookmark_server_cluster_service.h
@@ -10,7 +10,6 @@
 
 #include "base/compiler_specific.h"
 #include "components/enhanced_bookmarks/bookmark_server_service.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/signin/core/browser/signin_manager_base.h"
 #include "components/sync_driver/sync_service_observer.h"
 #include "net/url_request/url_fetcher.h"
diff --git a/components/gcm_driver.gypi b/components/gcm_driver.gypi
index fbf61c4..7ac49c9 100644
--- a/components/gcm_driver.gypi
+++ b/components/gcm_driver.gypi
@@ -233,11 +233,16 @@
         'gcm_driver/crypto/gcm_message_cryptographer.h',
         'gcm_driver/crypto/gcm_message_cryptographer_nss.cc',
         'gcm_driver/crypto/gcm_message_cryptographer_openssl.cc',
+        'gcm_driver/crypto/p256_key_util.cc',
+        'gcm_driver/crypto/p256_key_util.h',
+        'gcm_driver/crypto/p256_key_util_nss.cc',
+        'gcm_driver/crypto/p256_key_util_openssl.cc',
       ],
       'conditions': [
         ['use_openssl==1', {
           'sources!': [
             'gcm_driver/crypto/gcm_message_cryptographer_nss.cc',
+            'gcm_driver/crypto/p256_key_util_nss.cc',
           ],
           'dependencies': [
             '../third_party/boringssl/boringssl.gyp:boringssl',
@@ -245,6 +250,7 @@
         }, {
           'sources!': [
             'gcm_driver/crypto/gcm_message_cryptographer_openssl.cc',
+            'gcm_driver/crypto/p256_key_util_openssl.cc',
           ],
         }],
       ],
diff --git a/components/gcm_driver/crypto/BUILD.gn b/components/gcm_driver/crypto/BUILD.gn
index 26fe643..95dc4125 100644
--- a/components/gcm_driver/crypto/BUILD.gn
+++ b/components/gcm_driver/crypto/BUILD.gn
@@ -17,6 +17,10 @@
     "gcm_message_cryptographer.h",
     "gcm_message_cryptographer_nss.cc",
     "gcm_message_cryptographer_openssl.cc",
+    "p256_key_util.cc",
+    "p256_key_util.h",
+    "p256_key_util_nss.cc",
+    "p256_key_util_openssl.cc",
   ]
 
   deps = [
@@ -29,9 +33,15 @@
   ]
 
   if (use_openssl) {
-    sources -= [ "gcm_message_cryptographer_nss.cc" ]
+    sources -= [
+      "gcm_message_cryptographer_nss.cc",
+      "p256_key_util_nss.cc",
+    ]
   } else {
-    sources -= [ "gcm_message_cryptographer_openssl.cc" ]
+    sources -= [
+      "gcm_message_cryptographer_openssl.cc",
+      "p256_key_util_openssl.cc",
+    ]
   }
 }
 
@@ -42,6 +52,7 @@
     "gcm_encryption_provider_unittest.cc",
     "gcm_key_store_unittest.cc",
     "gcm_message_cryptographer_unittest.cc",
+    "p256_key_util_unittest.cc",
   ]
 
   deps = [
diff --git a/components/gcm_driver/crypto/gcm_encryption_provider.cc b/components/gcm_driver/crypto/gcm_encryption_provider.cc
index f4b5c71..486ba16 100644
--- a/components/gcm_driver/crypto/gcm_encryption_provider.cc
+++ b/components/gcm_driver/crypto/gcm_encryption_provider.cc
@@ -13,8 +13,8 @@
 #include "components/gcm_driver/crypto/encryption_header_parsers.h"
 #include "components/gcm_driver/crypto/gcm_key_store.h"
 #include "components/gcm_driver/crypto/gcm_message_cryptographer.h"
+#include "components/gcm_driver/crypto/p256_key_util.h"
 #include "components/gcm_driver/crypto/proto/gcm_encryption_data.pb.h"
-#include "crypto/curve25519.h"
 
 namespace gcm {
 
@@ -113,7 +113,7 @@
   }
 
   if (encryption_key_header_values.size() != 1u ||
-      encryption_key_header_values[0].dh.size() != crypto::curve25519::kBytes) {
+      !encryption_key_header_values[0].dh.size()) {
     DLOG(ERROR) << "Invalid values supplied in the Encryption-Key header";
     failure_callback.Run(DECRYPTION_FAILURE_INVALID_ENCRYPTION_KEY_HEADER);
     return;
@@ -138,7 +138,7 @@
     return;
   }
 
-  DCHECK_EQ(KeyPair::ECDH_CURVE_25519, pair.type());
+  DCHECK_EQ(KeyPair::ECDH_P256, pair.type());
   callback.Run(pair.public_key());
 }
 
@@ -150,7 +150,7 @@
     return;
   }
 
-  DCHECK_EQ(KeyPair::ECDH_CURVE_25519, pair.type());
+  DCHECK_EQ(KeyPair::ECDH_P256, pair.type());
   callback.Run(pair.public_key());
 }
 
@@ -168,24 +168,21 @@
     return;
   }
 
-  DCHECK_EQ(KeyPair::ECDH_CURVE_25519, pair.type());
+  DCHECK_EQ(KeyPair::ECDH_P256, pair.type());
 
-  uint8_t shared_key[crypto::curve25519::kBytes];
-
-  // Calculate the shared secret for the message.
-  crypto::curve25519::ScalarMult(
-      reinterpret_cast<const unsigned char*>(pair.private_key().data()),
-      reinterpret_cast<const unsigned char*>(dh.data()),
-      shared_key);
-
-  base::StringPiece shared_key_string_piece(
-      reinterpret_cast<char*>(shared_key), crypto::curve25519::kBytes);
+  std::string shared_secret;
+  if (!ComputeSharedP256Secret(pair.private_key(), pair.public_key_x509(), dh,
+                               &shared_secret)) {
+    DLOG(ERROR) << "Unable to calculate the shared secret.";
+    failure_callback.Run(DECRYPTION_FAILURE_INVALID_PUBLIC_KEY);
+    return;
+  }
 
   std::string plaintext;
 
   GCMMessageCryptographer cryptographer;
-  if (!cryptographer.Decrypt(message.raw_data, shared_key_string_piece, salt,
-                             rs, &plaintext)) {
+  if (!cryptographer.Decrypt(message.raw_data, shared_secret, salt, rs,
+                             &plaintext)) {
     DLOG(ERROR) << "Unable to decrypt the incoming data.";
     failure_callback.Run(DECRYPTION_FAILURE_INVALID_PAYLOAD);
     return;
diff --git a/components/gcm_driver/crypto/gcm_encryption_provider.h b/components/gcm_driver/crypto/gcm_encryption_provider.h
index c4ff271..50772802 100644
--- a/components/gcm_driver/crypto/gcm_encryption_provider.h
+++ b/components/gcm_driver/crypto/gcm_encryption_provider.h
@@ -47,6 +47,9 @@
     // No public/private key-pair was associated with the app_id.
     DECRYPTION_FAILURE_NO_KEYS,
 
+    // The public key provided in the Encryption-Key header is invalid.
+    DECRYPTION_FAILURE_INVALID_PUBLIC_KEY,
+
     // The payload could not be decrypted as AES-128-GCM.
     DECRYPTION_FAILURE_INVALID_PAYLOAD
   };
diff --git a/components/gcm_driver/crypto/gcm_encryption_provider_unittest.cc b/components/gcm_driver/crypto/gcm_encryption_provider_unittest.cc
index 14a6f71..ba3ca605 100644
--- a/components/gcm_driver/crypto/gcm_encryption_provider_unittest.cc
+++ b/components/gcm_driver/crypto/gcm_encryption_provider_unittest.cc
@@ -18,7 +18,7 @@
 #include "components/gcm_driver/common/gcm_messages.h"
 #include "components/gcm_driver/crypto/gcm_key_store.h"
 #include "components/gcm_driver/crypto/gcm_message_cryptographer.h"
-#include "crypto/curve25519.h"
+#include "components/gcm_driver/crypto/p256_key_util.h"
 #include "crypto/random.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -33,7 +33,8 @@
 const char kInvalidEncryptionHeader[] = "keyid";
 
 const char kValidEncryptionKeyHeader[] =
-    "keyid=foo;dh=NjU0MzIxMDk4NzY1NDMyMTEyMzQ1Njc4OTAxMjM0NTY";
+    "keyid=foo;dh=BL_UGhfudEkXMUd4U4-D4nP5KHxKjQHsW6j88ybbehXM7fqi1OMFefDUEi0eJ"
+    "vsKfyVBWYkQjH-lSPJKxjAyslg";
 const char kInvalidEncryptionKeyHeader[] = "keyid";
 
 // TODO(peter): Unify the Base64Url implementations. https://crbug.com/536745.
@@ -231,7 +232,7 @@
   // Getting (or creating) the public key will be done asynchronously.
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_EQ(crypto::curve25519::kBytes, public_key.size());
+  ASSERT_GT(public_key.size(), 0u);
 
   ASSERT_NO_FATAL_FAILURE(Decrypt(message));
   ASSERT_EQ(DECRYPTION_FAILED, decryption_result());
@@ -263,11 +264,11 @@
   // Creating the public keys will be done asynchronously.
   base::RunLoop().RunUntilIdle();
 
-  ASSERT_EQ(crypto::curve25519::kScalarBytes, pair.private_key().size());
-  ASSERT_EQ(crypto::curve25519::kBytes, pair.public_key().size());
+  ASSERT_GT(pair.public_key().size(), 0u);
+  ASSERT_GT(server_pair.public_key().size(), 0u);
 
-  ASSERT_EQ(crypto::curve25519::kScalarBytes, server_pair.private_key().size());
-  ASSERT_EQ(crypto::curve25519::kBytes, server_pair.public_key().size());
+  ASSERT_GT(pair.private_key().size(), 0u);
+  ASSERT_GT(server_pair.private_key().size(), 0u);
 
   std::string salt;
 
@@ -275,14 +276,10 @@
   // calculate the shared secret for the message.
   crypto::RandBytes(base::WriteInto(&salt, 16 + 1), 16);
 
-  uint8_t shared_key[crypto::curve25519::kBytes];
-  crypto::curve25519::ScalarMult(
-      reinterpret_cast<const unsigned char*>(server_pair.private_key().data()),
-      reinterpret_cast<const unsigned char*>(pair.public_key().data()),
-      shared_key);
-
-  base::StringPiece shared_key_string_piece(
-      reinterpret_cast<char*>(shared_key), crypto::curve25519::kBytes);
+  std::string shared_secret;
+  ASSERT_TRUE(ComputeSharedP256Secret(
+      pair.private_key(), pair.public_key_x509(), server_pair.public_key(),
+      &shared_secret));
 
   IncomingMessage message;
   size_t record_size;
@@ -290,8 +287,8 @@
   // Encrypts the |kExampleMessage| using the generated shared key and the
   // random |salt|, storing the result in |record_size| and the message.
   GCMMessageCryptographer cryptographer;
-  ASSERT_TRUE(cryptographer.Encrypt(kExampleMessage, shared_key_string_piece,
-                                    salt, &record_size, &message.raw_data));
+  ASSERT_TRUE(cryptographer.Encrypt(kExampleMessage, shared_secret, salt,
+                                    &record_size, &message.raw_data));
 
   std::string encoded_salt, encoded_key;
 
diff --git a/components/gcm_driver/crypto/gcm_key_store.cc b/components/gcm_driver/crypto/gcm_key_store.cc
index d853b781..10976e7 100644
--- a/components/gcm_driver/crypto/gcm_key_store.cc
+++ b/components/gcm_driver/crypto/gcm_key_store.cc
@@ -7,8 +7,8 @@
 #include <utility>
 
 #include "base/logging.h"
+#include "components/gcm_driver/crypto/p256_key_util.h"
 #include "components/leveldb_proto/proto_database_impl.h"
-#include "crypto/curve25519.h"
 #include "crypto/random.h"
 
 namespace gcm {
@@ -73,23 +73,23 @@
   // Only allow creating new keys if no keys currently exist.
   DCHECK_EQ(0u, key_pairs_.count(app_id));
 
-  // Create a Curve25519 private/public key-pair.
-  uint8_t private_key[crypto::curve25519::kScalarBytes];
-  uint8_t public_key[crypto::curve25519::kBytes];
+  std::string private_key, public_key_x509, public_key;
+  if (!CreateP256KeyPair(&private_key, &public_key_x509, &public_key)) {
+    NOTREACHED() << "Unable to initialize a P-256 key pair.";
 
-  crypto::RandBytes(private_key, sizeof(private_key));
-
-  // Compute the |public_key| based on the |private_key|.
-  crypto::curve25519::ScalarBaseMult(private_key, public_key);
+    callback.Run(KeyPair());
+    return;
+  }
 
   // Store the keys in a new EncryptionData object.
   EncryptionData encryption_data;
   encryption_data.set_app_id(app_id);
 
   KeyPair* pair = encryption_data.add_keys();
-  pair->set_type(KeyPair::ECDH_CURVE_25519);
-  pair->set_private_key(private_key, sizeof(private_key));
-  pair->set_public_key(public_key, sizeof(public_key));
+  pair->set_type(KeyPair::ECDH_P256);
+  pair->set_private_key(private_key);
+  pair->set_public_key_x509(public_key_x509);
+  pair->set_public_key(public_key);
 
   using EntryVectorType =
       leveldb_proto::ProtoDatabase<EncryptionData>::KeyEntryVector;
diff --git a/components/gcm_driver/crypto/gcm_key_store_unittest.cc b/components/gcm_driver/crypto/gcm_key_store_unittest.cc
index 56aae87..27f659d 100644
--- a/components/gcm_driver/crypto/gcm_key_store_unittest.cc
+++ b/components/gcm_driver/crypto/gcm_key_store_unittest.cc
@@ -9,7 +9,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/thread_task_runner_handle.h"
-#include "crypto/curve25519.h"
+#include "components/gcm_driver/crypto/p256_key_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace gcm {
@@ -89,12 +89,11 @@
   base::RunLoop().RunUntilIdle();
 
   ASSERT_TRUE(pair.IsInitialized());
-
   ASSERT_TRUE(pair.has_private_key());
-  EXPECT_EQ(crypto::curve25519::kScalarBytes, pair.private_key().size());
-
   ASSERT_TRUE(pair.has_public_key());
-  EXPECT_EQ(crypto::curve25519::kBytes, pair.public_key().size());
+
+  EXPECT_GT(pair.public_key().size(), 0u);
+  EXPECT_GT(pair.private_key().size(), 0u);
 
   KeyPair read_pair;
   gcm_key_store()->GetKeys(kFakeAppId,
diff --git a/components/gcm_driver/crypto/p256_key_util.cc b/components/gcm_driver/crypto/p256_key_util.cc
new file mode 100644
index 0000000..7fd38b561
--- /dev/null
+++ b/components/gcm_driver/crypto/p256_key_util.cc
@@ -0,0 +1,90 @@
+// Copyright 2015 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 "components/gcm_driver/crypto/p256_key_util.h"
+
+#include <stdint.h>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/stl_util.h"
+#include "crypto/ec_private_key.h"
+
+namespace gcm {
+
+namespace {
+
+// The first byte in an uncompressed P-256 point per SEC1 2.3.3.
+const char kUncompressedPointForm = 0x04;
+
+// A P-256 field element consists of 32 bytes.
+const size_t kFieldBytes = 32;
+
+// A P-256 point in uncompressed form consists of 0x04 (to denote that the point
+// is uncompressed per SEC1 2.3.3) followed by two, 32-byte field elements.
+const size_t kUncompressedPointBytes = 1 + 2 * kFieldBytes;
+
+}  // namespace
+
+bool CreateP256KeyPair(std::string* out_private_key,
+                       std::string* out_public_key_x509,
+                       std::string* out_public_key) {
+  DCHECK(out_private_key);
+  DCHECK(out_public_key);
+
+  scoped_ptr<crypto::ECPrivateKey> key_pair(crypto::ECPrivateKey::Create());
+  if (!key_pair.get()) {
+    DLOG(ERROR) << "Unable to generate a new P-256 key pair.";
+    return false;
+  }
+
+  std::vector<uint8_t> private_key;
+
+  // Export the encrypted private key with an empty password. This is not done
+  // to provide any security, but rather to achieve a consistent private key
+  // storage between the BoringSSL and NSS implementations.
+  if (!key_pair->ExportEncryptedPrivateKey(
+          "" /* password */, 1 /* iteration */, &private_key)) {
+    DLOG(ERROR) << "Unable to export the private key.";
+    return false;
+  }
+
+  std::string candidate_public_key;
+
+  // ECPrivateKey::ExportRawPublicKey() returns the EC point in the uncompressed
+  // point format, but does not include the leading byte of value 0x04 that
+  // indicates usage of uncompressed points, per SEC1 2.3.3.
+  if (!key_pair->ExportRawPublicKey(&candidate_public_key) ||
+      candidate_public_key.size() != 2 * kFieldBytes) {
+    DLOG(ERROR) << "Unable to export the public key.";
+    return false;
+  }
+
+  std::vector<uint8_t> public_key_x509;
+
+  // Export the public key to an X.509 SubjectPublicKeyInfo for enabling NSS to
+  // import the key material when computing a shared secret.
+  if (!key_pair->ExportPublicKey(&public_key_x509)) {
+    DLOG(ERROR) << "Unable to export the public key as an X.509 "
+                << "SubjectPublicKeyInfo block.";
+    return false;
+  }
+
+  out_private_key->assign(
+      reinterpret_cast<const char*>(vector_as_array(&private_key)),
+      private_key.size());
+  out_public_key_x509->assign(
+      reinterpret_cast<const char*>(vector_as_array(&public_key_x509)),
+      public_key_x509.size());
+
+  // Concatenate the leading 0x04 byte and the two uncompressed points.
+  out_public_key->reserve(kUncompressedPointBytes);
+  out_public_key->push_back(kUncompressedPointForm);
+  out_public_key->append(candidate_public_key);
+
+  return true;
+}
+
+}  // namespace gcm
diff --git a/components/gcm_driver/crypto/p256_key_util.h b/components/gcm_driver/crypto/p256_key_util.h
new file mode 100644
index 0000000..bf24adc
--- /dev/null
+++ b/components/gcm_driver/crypto/p256_key_util.h
@@ -0,0 +1,43 @@
+// Copyright 2015 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.
+
+#ifndef COMPONENTS_GCM_DRIVER_CRYPTO_P256_KEY_UTIL_H_
+#define COMPONENTS_GCM_DRIVER_CRYPTO_P256_KEY_UTIL_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/strings/string_piece.h"
+
+namespace gcm {
+
+// Creates a new key pair for key exchanges using elliptic-curve Diffie-
+// Hellman using the NIST P-256 curve. Returns whether the key pair could be
+// created successfully, and was written to the out arguments.
+//
+// The |out_private_key| will be an ASN.1-encoded PKCS#8 EncryptedPrivateKeyInfo
+// block, |out_public_key_x509| an X.509 SubjectPublicKeyInfo block and
+// |out_public_key| an octet string in uncompressed form per SEC1 2.3.3.
+bool CreateP256KeyPair(std::string* out_private_key,
+                       std::string* out_public_key_x509,
+                       std::string* out_public_key) WARN_UNUSED_RESULT;
+
+// Computes the shared secret between |private_key| and |peer_public_key|. The
+// |public_key| associated with the |private_key| is necessary for NSS. Returns
+// whether the secret could be computed, and was written to the out argument.
+//
+// The |private_key| must be an ASN.1-encoded PKCS#8 EncryptedPrivateKeyInfo
+// block together, where |public_key_x509| must be an X.509 SubjectPublicKeyInfo
+// block. This is necessary for NSS to be able to import the |private_key|.
+//
+// The |peer_public_key| must be an octet string in uncompressed form per
+// SEC1 2.3.3.
+bool ComputeSharedP256Secret(const base::StringPiece& private_key,
+                             const base::StringPiece& public_key_x509,
+                             const base::StringPiece& peer_public_key,
+                             std::string* out_shared_secret) WARN_UNUSED_RESULT;
+
+}  // namespace gcm
+
+#endif  // COMPONENTS_GCM_DRIVER_CRYPTO_P256_KEY_UTIL_H_
diff --git a/components/gcm_driver/crypto/p256_key_util_nss.cc b/components/gcm_driver/crypto/p256_key_util_nss.cc
new file mode 100644
index 0000000..22ed2a2
--- /dev/null
+++ b/components/gcm_driver/crypto/p256_key_util_nss.cc
@@ -0,0 +1,100 @@
+// Copyright 2015 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 "components/gcm_driver/crypto/p256_key_util.h"
+
+#include <stdint.h>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "crypto/ec_private_key.h"
+#include "crypto/scoped_nss_types.h"
+
+namespace gcm {
+
+namespace {
+
+// A P-256 field element consists of 32 bytes.
+const size_t kFieldBytes = 32;
+
+}  // namespace
+
+bool ComputeSharedP256Secret(const base::StringPiece& private_key,
+                             const base::StringPiece& public_key_x509,
+                             const base::StringPiece& peer_public_key,
+                             std::string* out_shared_secret) {
+  DCHECK(out_shared_secret);
+
+  scoped_ptr<crypto::ECPrivateKey> local_key_pair(
+      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
+          "" /* no password */,
+          std::vector<uint8_t>(
+              private_key.data(), private_key.data() + private_key.size()),
+          std::vector<uint8_t>(
+              public_key_x509.data(),
+              public_key_x509.data() + public_key_x509.size())));
+
+  if (!local_key_pair) {
+    DLOG(ERROR) << "Unable to create the local key pair.";
+    return false;
+  }
+
+  SECKEYPublicKey public_key_peer;
+  memset(&public_key_peer, 0, sizeof(public_key_peer));
+
+  public_key_peer.keyType = ecKey;
+  // Both sides of a ECDH key exchange need to use the same EC params.
+  public_key_peer.u.ec.DEREncodedParams.len =
+      local_key_pair->public_key()->u.ec.DEREncodedParams.len;
+  public_key_peer.u.ec.DEREncodedParams.data =
+      local_key_pair->public_key()->u.ec.DEREncodedParams.data;
+
+  public_key_peer.u.ec.publicValue.type = siBuffer;
+  public_key_peer.u.ec.publicValue.data =
+      reinterpret_cast<uint8_t*>(const_cast<char*>(peer_public_key.data()));
+  public_key_peer.u.ec.publicValue.len = peer_public_key.size();
+
+  // The NSS function performing ECDH key exchange is PK11_PubDeriveWithKDF.
+  // As this function is used for SSL/TLS's ECDH key exchanges it has many
+  // arguments, most of which are not required. Key derivation function CKD_NULL
+  // is used because the return value of |CalculateSharedKey| is the actual ECDH
+  // shared key, not any derived keys from it.
+  crypto::ScopedPK11SymKey premaster_secret(
+      PK11_PubDeriveWithKDF(
+          local_key_pair->key(),
+          &public_key_peer,
+          PR_FALSE /* isSender */,
+          nullptr /* randomA */,
+          nullptr /* randomB */,
+          CKM_ECDH1_DERIVE,
+          CKM_GENERIC_SECRET_KEY_GEN,
+          CKA_DERIVE,
+          0 /* keySize */,
+          CKD_NULL /* kdf */,
+          nullptr /* sharedData */,
+          nullptr /* wincx */));
+
+  if (!premaster_secret) {
+    DLOG(ERROR) << "Unable to derive the ECDH shared key.";
+    return false;
+  }
+
+  if (PK11_ExtractKeyValue(premaster_secret.get()) != SECSuccess) {
+    DLOG(ERROR) << "Unable to extract the raw ECDH shared secret.";
+    return false;
+  }
+
+  SECItem* key_data = PK11_GetKeyData(premaster_secret.get());
+  if (!key_data || !key_data->data || key_data->len != kFieldBytes) {
+    DLOG(ERROR) << "The raw ECDH shared secret is invalid.";
+    return false;
+  }
+
+  out_shared_secret->assign(
+      reinterpret_cast<char*>(key_data->data), key_data->len);
+  return true;
+}
+
+}  // namespace gcm
diff --git a/components/gcm_driver/crypto/p256_key_util_openssl.cc b/components/gcm_driver/crypto/p256_key_util_openssl.cc
new file mode 100644
index 0000000..e550b15f
--- /dev/null
+++ b/components/gcm_driver/crypto/p256_key_util_openssl.cc
@@ -0,0 +1,79 @@
+// Copyright 2015 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 "components/gcm_driver/crypto/p256_key_util.h"
+
+#include <stdint.h>
+
+#include <openssl/ec.h>
+#include <openssl/ecdh.h>
+#include <openssl/evp.h>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "crypto/ec_private_key.h"
+#include "crypto/scoped_openssl_types.h"
+
+namespace gcm {
+
+namespace {
+
+// A P-256 field element consists of 32 bytes.
+const size_t kFieldBytes = 32;
+
+}  // namespace
+
+bool ComputeSharedP256Secret(const base::StringPiece& private_key,
+                             const base::StringPiece& public_key_x509,
+                             const base::StringPiece& peer_public_key,
+                             std::string* out_shared_secret) {
+  DCHECK(out_shared_secret);
+
+  scoped_ptr<crypto::ECPrivateKey> local_key_pair(
+      crypto::ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
+          "" /* no password */,
+          std::vector<uint8_t>(
+              private_key.data(), private_key.data() + private_key.size()),
+          std::vector<uint8_t>(
+              public_key_x509.data(),
+              public_key_x509.data() + public_key_x509.size())));
+
+  if (!local_key_pair) {
+    DLOG(ERROR) << "Unable to create the local key pair.";
+    return false;
+  }
+
+  crypto::ScopedEC_KEY ec_private_key(
+      EVP_PKEY_get1_EC_KEY(local_key_pair->key()));
+
+  if (!ec_private_key || !EC_KEY_check_key(ec_private_key.get())) {
+    DLOG(ERROR) << "The private key is invalid.";
+    return false;
+  }
+
+  crypto::ScopedEC_POINT point(
+      EC_POINT_new(EC_KEY_get0_group(ec_private_key.get())));
+
+  if (!point ||
+      !EC_POINT_oct2point(EC_KEY_get0_group(ec_private_key.get()), point.get(),
+                                            reinterpret_cast<const uint8_t*>(
+                                                peer_public_key.data()),
+                                            peer_public_key.size(), nullptr)) {
+    DLOG(ERROR) << "Can't convert peer public value to curve point.";
+    return false;
+  }
+
+  uint8_t result[kFieldBytes];
+  if (ECDH_compute_key(result, sizeof(result), point.get(),
+                       ec_private_key.get(), nullptr) != sizeof(result)) {
+    DLOG(ERROR) << "Unable to compute the ECDH shared secret.";
+    return false;
+  }
+
+  out_shared_secret->assign(reinterpret_cast<char*>(result), sizeof(result));
+  return true;
+}
+
+}  // namespace gcm
diff --git a/components/gcm_driver/crypto/p256_key_util_unittest.cc b/components/gcm_driver/crypto/p256_key_util_unittest.cc
new file mode 100644
index 0000000..aedfe15
--- /dev/null
+++ b/components/gcm_driver/crypto/p256_key_util_unittest.cc
@@ -0,0 +1,155 @@
+// Copyright 2015 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 "components/gcm_driver/crypto/p256_key_util.h"
+
+#include <set>
+
+#include "base/base64.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gcm {
+
+namespace {
+
+// A P-256 point in uncompressed form consists of 0x04 (to denote that the point
+// is uncompressed per SEC1 2.3.3) followed by two, 32-byte field elements.
+const size_t kUncompressedPointBytes = 1 + 2 * 32;
+
+// Precomputed private/public key-pair. Keys are stored on disk, so previously
+// created values must continue to be usable for computing shared secrets.
+const char kBobPrivateKey[] =
+    "MIGwMBsGCiqGSIb3DQEMAQMwDQQIyCB6/yia3wACAQEEgZCp4yoEpn9ZITGy7mt2+zqI1IFgHy"
+    "1RglXKiPdy+Ue5eubZ3Xe/pz/5yQWvysXLaTT+/LeuAoq2gwKK2AINTWglIEMCmcveERa0gZDW"
+    "avhYEYtEynNLVop4bHlii5DcUY1/e9DY5Dxh7b2dYdWI2Ev+529KughVKK8qFu12wn3cSSlfXh"
+    "9Hb8Nh/4yP0jg6k5k=";
+const char kBobPublicKeyX509[] =
+    "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVVJqpW6OqkeXNhDBZjweZb+he+5Iyca7vwIYU3"
+    "IdDHup4xG3A1Ih03GQE6jBz+0g9x/Rf/J2tgEg2DWl2TxD/Q==";
+const char kBobPublicKey[] =
+    "BFVSaqVujqpHlzYQwWY8HmW/oXvuSMnGu78CGFNyHQx7qeMRtwNSIdNxkBOowc/tIPcf0X/ydr"
+    "YBINg1pdk8Q/0=";
+
+const char kCarolPrivateKey[] =
+    "MIGwMBsGCiqGSIb3DQEMAQMwDQQIOyIGhczk5TECAQEEgZCQO0tXSd0dCxuKCcmU462i+VNwJz"
+    "J4KT/C32F6K3edQnZ2J750g6nMVtkoK9TF23UcEIVB0Lo7FG4T5WF03wjC4A+5FC/1mYzsWFHO"
+    "6AugLhum5psqX3fq6UmgYoir9dJsI7Rmmn1JH8Gtw6KJHMncPi1lGriLZqzcrw+oULVf6dcnH1"
+    "z9F39GuYob5+sY7ak=";
+const char kCarolPublicKeyX509[] =
+    "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETqNDkapziFRUvEXfP9zEpwJi+kYh/+JbV5BZDD"
+    "QKS9kmXvKz+ahuKVmpYNkDI0ZdYM1KkNMUxd4/hprQ1L9sEA==";
+const char kCarolPublicKey[] =
+    "BE6jQ5Gqc4hUVLxF3z/cxKcCYvpGIf/iW1eQWQw0CkvZJl7ys/mobilZqWDZAyNGXWDNSpDTFM"
+    "XeP4aa0NS/bBA=";
+
+// The shared secret between Bob and Carol.
+const char kBobCarolSharedSecret[] =
+    "epd8m4CulXi284tsHYbGIZJg73xnxoNvlP/qLyqkA30=";
+
+TEST(P256KeyUtilTest, UniqueKeyPairGeneration) {
+  // Canary for determining that no key repetitions are found in few iterations.
+  std::set<std::string> seen_private_keys;
+  std::set<std::string> seen_public_keys_x509;
+  std::set<std::string> seen_public_keys;
+
+  for (int iteration = 0; iteration < 10; ++iteration) {
+    SCOPED_TRACE(iteration);
+
+    std::string private_key, public_key_x509, public_key;
+    ASSERT_TRUE(CreateP256KeyPair(&private_key, &public_key_x509, &public_key));
+
+    EXPECT_NE(private_key, public_key);
+    EXPECT_GT(private_key.size(), 0u);
+    EXPECT_GT(public_key_x509.size(), 0u);
+    EXPECT_EQ(public_key.size(), kUncompressedPointBytes);
+
+    EXPECT_EQ(0u, seen_private_keys.count(private_key));
+    EXPECT_EQ(0u, seen_public_keys_x509.count(public_key_x509));
+    EXPECT_EQ(0u, seen_public_keys.count(public_key));
+
+    seen_private_keys.insert(private_key);
+    seen_public_keys_x509.insert(public_key_x509);
+    seen_public_keys.insert(public_key);
+  }
+}
+
+TEST(P256KeyUtilTest, SharedSecretCalculation) {
+  std::string bob_private_key, bob_public_key_x509, bob_public_key;
+  std::string alice_private_key, alice_public_key_x509, alice_public_key;
+
+  ASSERT_TRUE(CreateP256KeyPair(
+      &bob_private_key, &bob_public_key_x509, &bob_public_key));
+  ASSERT_TRUE(CreateP256KeyPair(
+      &alice_private_key, &alice_public_key_x509, &alice_public_key));
+  ASSERT_NE(bob_private_key, alice_private_key);
+
+  std::string bob_shared_secret, alice_shared_secret;
+  ASSERT_TRUE(ComputeSharedP256Secret(bob_private_key, bob_public_key_x509,
+                                      alice_public_key, &bob_shared_secret));
+  ASSERT_TRUE(ComputeSharedP256Secret(alice_private_key, alice_public_key_x509,
+                                      bob_public_key, &alice_shared_secret));
+
+  EXPECT_GT(bob_shared_secret.size(), 0u);
+  EXPECT_EQ(bob_shared_secret, alice_shared_secret);
+
+  std::string unused_shared_secret;
+
+  // Empty and too short peer public values should be considered invalid.
+  ASSERT_FALSE(ComputeSharedP256Secret(bob_private_key, bob_public_key_x509,
+                                       "", &unused_shared_secret));
+  ASSERT_FALSE(ComputeSharedP256Secret(bob_private_key, bob_public_key_x509,
+                                       bob_public_key.substr(1),
+                                       &unused_shared_secret));
+
+}
+
+TEST(P256KeyUtilTest, SharedSecretWithPreExistingKey) {
+  std::string bob_private_key, bob_public_key_x509, bob_public_key;
+  std::string alice_private_key, alice_public_key_x509, alice_public_key;
+
+  ASSERT_TRUE(base::Base64Decode(kBobPrivateKey, &bob_private_key));
+  ASSERT_TRUE(base::Base64Decode(kBobPublicKeyX509, &bob_public_key_x509));
+  ASSERT_TRUE(base::Base64Decode(kBobPublicKey, &bob_public_key));
+
+  // First verify against a newly created, ephemeral key-pair.
+  ASSERT_TRUE(CreateP256KeyPair(
+      &alice_private_key, &alice_public_key_x509, &alice_public_key));
+
+  std::string bob_shared_secret, alice_shared_secret;
+  ASSERT_TRUE(ComputeSharedP256Secret(bob_private_key, bob_public_key_x509,
+                                      alice_public_key, &bob_shared_secret));
+  ASSERT_TRUE(ComputeSharedP256Secret(alice_private_key, alice_public_key_x509,
+                                      bob_public_key, &alice_shared_secret));
+
+  EXPECT_GT(bob_shared_secret.size(), 0u);
+  EXPECT_EQ(bob_shared_secret, alice_shared_secret);
+
+  std::string carol_private_key, carol_public_key_x509, carol_public_key;
+
+  ASSERT_TRUE(base::Base64Decode(kCarolPrivateKey, &carol_private_key));
+  ASSERT_TRUE(base::Base64Decode(kCarolPublicKeyX509, &carol_public_key_x509));
+  ASSERT_TRUE(base::Base64Decode(kCarolPublicKey, &carol_public_key));
+
+  bob_shared_secret.clear();
+  std::string carol_shared_secret;
+
+  // Then verify against another stored key-pair and shared secret.
+  ASSERT_TRUE(ComputeSharedP256Secret(bob_private_key, bob_public_key_x509,
+                                      carol_public_key, &bob_shared_secret));
+  ASSERT_TRUE(ComputeSharedP256Secret(carol_private_key, carol_public_key_x509,
+                                      bob_public_key, &carol_shared_secret));
+
+  EXPECT_GT(carol_shared_secret.size(), 0u);
+  EXPECT_EQ(carol_shared_secret, bob_shared_secret);
+
+  std::string bob_carol_shared_secret;
+  ASSERT_TRUE(base::Base64Decode(
+      kBobCarolSharedSecret, &bob_carol_shared_secret));
+
+  EXPECT_EQ(carol_shared_secret, bob_carol_shared_secret);
+}
+
+}  // namespace
+
+}  // namespace gcm
diff --git a/components/gcm_driver/crypto/proto/gcm_encryption_data.proto b/components/gcm_driver/crypto/proto/gcm_encryption_data.proto
index 4c6ad49..16cf212 100644
--- a/components/gcm_driver/crypto/proto/gcm_encryption_data.proto
+++ b/components/gcm_driver/crypto/proto/gcm_encryption_data.proto
@@ -9,21 +9,24 @@
 package gcm;
 
 // Stores a public/private key-pair.
-// Next tag: 3
+// Next tag: 5
 message KeyPair {
   // The type of key used for key agreement. Currently only the ECDH key
-  // agreement scheme is supported, using Curve 25519.
+  // agreement scheme is supported, using NIST P-256.
   enum KeyType {
-    ECDH_CURVE_25519 = 0;
+    ECDH_P256 = 0;
   }
 
   required KeyType type = 1;
 
   // The private key matching the size requirements of |type|.
-  required bytes private_key = 2;
+  optional bytes private_key = 2;
 
-  // The public key matching the size requirements of |type|.
-  required bytes public_key = 3;
+  // The public key as an X.509 SubjectPublicKeyInfo block.
+  optional bytes public_key_x509 = 3;
+
+  // The public key as an uncompressed EC point according to SEC 2.3.3.
+  optional bytes public_key = 4;
 }
 
 // Stores a vector of public/private key-pairs associated with an app id.
@@ -33,7 +36,7 @@
 // in case we need to force-cycle all keys, allowing the old keys to remain
 // valid for a period of time enabling the web app to update.
 //
-// Next tag: 2 
+// Next tag: 3
 message EncryptionData {
   // The app id to whom this encryption data belongs.
   required string app_id = 1;
diff --git a/components/gpu/OWNERS b/components/gpu/OWNERS
deleted file mode 100644
index 14172cf3..0000000
--- a/components/gpu/OWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-ben@chromium.org
-erg@chromium.org
-fsamuel@chromium.org
-msw@chromium.org
-sky@chromium.org
diff --git a/components/gpu/public/interfaces/BUILD.gn b/components/gpu/public/interfaces/BUILD.gn
deleted file mode 100644
index 7fb2254..0000000
--- a/components/gpu/public/interfaces/BUILD.gn
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2014 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.
-
-import("//mojo/public/tools/bindings/mojom.gni")
-
-mojom("interfaces") {
-  sources = [
-    "command_buffer.mojom",
-    "gpu.mojom",
-    "gpu_capabilities.mojom",
-  ]
-
-  deps = [
-    "//ui/mojo/geometry:interfaces",
-  ]
-}
diff --git a/components/mus/BUILD.gn b/components/mus/BUILD.gn
index cc353333..e89df7e 100644
--- a/components/mus/BUILD.gn
+++ b/components/mus/BUILD.gn
@@ -70,8 +70,8 @@
     "//base",
     "//cc",
     "//cc/surfaces",
+    "//components/mus/common",
     "//components/mus/gles2",
-    "//components/mus/public/cpp:common",
     "//components/mus/public/interfaces",
     "//components/mus/surfaces",
     "//components/mus/ws:lib",
diff --git a/components/mus/common/BUILD.gn b/components/mus/common/BUILD.gn
index f9c375e..45e56ed 100644
--- a/components/mus/common/BUILD.gn
+++ b/components/mus/common/BUILD.gn
@@ -4,7 +4,11 @@
 
 source_set("common") {
   sources = [
+    "args.cc",
+    "args.h",
     "transient_window_utils.h",
+    "types.h",
+    "util.h",
   ]
   deps = [
     "//components/mus/public/interfaces",
diff --git a/components/mus/public/cpp/lib/args.cc b/components/mus/common/args.cc
similarity index 88%
rename from components/mus/public/cpp/lib/args.cc
rename to components/mus/common/args.cc
index e45a9f0b..c60d591 100644
--- a/components/mus/public/cpp/lib/args.cc
+++ b/components/mus/common/args.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/mus/public/cpp/args.h"
+#include "components/mus/common/args.h"
 
 namespace mus {
 
diff --git a/components/mus/public/cpp/args.h b/components/mus/common/args.h
similarity index 74%
rename from components/mus/public/cpp/args.h
rename to components/mus/common/args.h
index 6fc6f26..29c3de8 100644
--- a/components/mus/public/cpp/args.h
+++ b/components/mus/common/args.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_MUS_PUBLIC_CPP_ARGS_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_ARGS_H_
+#ifndef COMPONENTS_MUS_COMMON_ARGS_H_
+#define COMPONENTS_MUS_COMMON_ARGS_H_
 
 namespace mus {
 
@@ -13,4 +13,4 @@
 
 }  // namespace mus
 
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_ARGS_H_
+#endif  // COMPONENTS_MUS_COMMON_ARGS_H_
diff --git a/components/mus/public/cpp/types.h b/components/mus/common/types.h
similarity index 83%
rename from components/mus/public/cpp/types.h
rename to components/mus/common/types.h
index 4e93ff4f..dca7884 100644
--- a/components/mus/public/cpp/types.h
+++ b/components/mus/common/types.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_MUS_PUBLIC_CPP_TYPES_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_TYPES_H_
+#ifndef COMPONENTS_MUS_COMMON_TYPES_H_
+#define COMPONENTS_MUS_COMMON_TYPES_H_
 
 #include <stdint.h>
 
@@ -22,4 +22,4 @@
 
 }  // namespace mus
 
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_TYPES_H_
+#endif  // COMPONENTS_MUS_COMMON_TYPES_H_
diff --git a/components/mus/public/cpp/util.h b/components/mus/common/util.h
similarity index 74%
rename from components/mus/public/cpp/util.h
rename to components/mus/common/util.h
index c9cd91f..435baf58 100644
--- a/components/mus/public/cpp/util.h
+++ b/components/mus/common/util.h
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_MUS_PUBLIC_CPP_UTIL_H_
-#define COMPONENTS_MUS_PUBLIC_CPP_UTIL_H_
+#ifndef COMPONENTS_MUS_COMMON_UTIL_H_
+#define COMPONENTS_MUS_COMMON_UTIL_H_
 
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 
 // TODO(beng): #$*&@#(@ MacOSX SDK!
 #if defined(HiWord)
@@ -27,4 +27,4 @@
 
 }  // namespace mus
 
-#endif  // COMPONENTS_MUS_PUBLIC_CPP_UTIL_H_
+#endif  // COMPONENTS_MUS_COMMON_UTIL_H_
diff --git a/components/mus/example/views_examples/BUILD.gn b/components/mus/example/views_examples/BUILD.gn
index 0f8a3f78..ecc10f1 100644
--- a/components/mus/example/views_examples/BUILD.gn
+++ b/components/mus/example/views_examples/BUILD.gn
@@ -18,6 +18,7 @@
 
   deps = [
     "//base",
+    "//components/mus/public/interfaces",
     "//mojo/application/public/cpp",
     "//mojo/application/public/cpp:sources",
     "//mojo/converters/geometry",
diff --git a/components/mus/example/window_type_launcher/BUILD.gn b/components/mus/example/window_type_launcher/BUILD.gn
index 7c345b48..95a6b0c0 100644
--- a/components/mus/example/window_type_launcher/BUILD.gn
+++ b/components/mus/example/window_type_launcher/BUILD.gn
@@ -21,6 +21,7 @@
     ":window_type_launcher_resources",
     "//base",
     "//base:base_static",
+    "//components/mus/public/interfaces",
     "//mojo/application/public/cpp",
     "//mojo/application/public/interfaces",
     "//mojo/common:common_base",
diff --git a/components/mus/example/wm/BUILD.gn b/components/mus/example/wm/BUILD.gn
index af1dcd40..ec214f1 100644
--- a/components/mus/example/wm/BUILD.gn
+++ b/components/mus/example/wm/BUILD.gn
@@ -41,6 +41,7 @@
   deps = [
     "//base",
     "//components/mus/example/wm/public/interfaces",
+    "//components/mus/common",
     "//components/mus/public/cpp",
     "//components/mus/public/interfaces",
     "//mojo/application/public/cpp",
diff --git a/components/mus/example/wm/window_manager_application.cc b/components/mus/example/wm/window_manager_application.cc
index 83a5b609..2dc4d91 100644
--- a/components/mus/example/wm/window_manager_application.cc
+++ b/components/mus/example/wm/window_manager_application.cc
@@ -4,11 +4,11 @@
 
 #include "components/mus/example/wm/window_manager_application.h"
 
+#include "components/mus/common/util.h"
 #include "components/mus/example/wm/background_layout.h"
 #include "components/mus/example/wm/shelf_layout.h"
 #include "components/mus/example/wm/window_layout.h"
 #include "components/mus/example/wm/window_manager_impl.h"
-#include "components/mus/public/cpp/util.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/public/cpp/window_tree_host_factory.h"
diff --git a/components/mus/example/wm/window_manager_application.h b/components/mus/example/wm/window_manager_application.h
index 1ddb8895..fdcec92 100644
--- a/components/mus/example/wm/window_manager_application.h
+++ b/components/mus/example/wm/window_manager_application.h
@@ -8,8 +8,8 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
+#include "components/mus/common/types.h"
 #include "components/mus/example/wm/public/interfaces/container.mojom.h"
-#include "components/mus/public/cpp/types.h"
 #include "components/mus/public/cpp/window_manager_delegate.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/cpp/window_tree_delegate.h"
diff --git a/components/mus/example/wm/window_manager_impl.cc b/components/mus/example/wm/window_manager_impl.cc
index 6dc2c0bf..ae7fca9 100644
--- a/components/mus/example/wm/window_manager_impl.cc
+++ b/components/mus/example/wm/window_manager_impl.cc
@@ -4,13 +4,13 @@
 
 #include "components/mus/example/wm/window_manager_impl.h"
 
+#include "components/mus/common/types.h"
 #include "components/mus/example/wm/move_loop.h"
 #include "components/mus/example/wm/non_client_frame_controller.h"
 #include "components/mus/example/wm/property_util.h"
 #include "components/mus/example/wm/public/interfaces/container.mojom.h"
 #include "components/mus/example/wm/window_manager_application.h"
 #include "components/mus/public/cpp/property_type_converters.h"
-#include "components/mus/public/cpp/types.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_property.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
diff --git a/components/mus/example/wm/window_manager_impl.h b/components/mus/example/wm/window_manager_impl.h
index 934f751..ea13dd1 100644
--- a/components/mus/example/wm/window_manager_impl.h
+++ b/components/mus/example/wm/window_manager_impl.h
@@ -8,7 +8,7 @@
 #include <set>
 
 #include "base/macros.h"
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/interfaces/window_manager.mojom.h"
 
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc
index de7815bd..421ebff 100644
--- a/components/mus/mus_app.cc
+++ b/components/mus/mus_app.cc
@@ -5,8 +5,8 @@
 #include "components/mus/mus_app.h"
 
 #include "base/stl_util.h"
+#include "components/mus/common/args.h"
 #include "components/mus/gles2/gpu_impl.h"
-#include "components/mus/public/cpp/args.h"
 #include "components/mus/surfaces/surfaces_scheduler.h"
 #include "components/mus/ws/client_connection.h"
 #include "components/mus/ws/connection_manager.h"
diff --git a/components/mus/public/cpp/BUILD.gn b/components/mus/public/cpp/BUILD.gn
index 50266af2..dc8114a 100644
--- a/components/mus/public/cpp/BUILD.gn
+++ b/components/mus/public/cpp/BUILD.gn
@@ -39,7 +39,6 @@
   ]
 
   public_deps = [
-    ":common",
     "../interfaces",
     "//mojo/services/network/public/interfaces",
   ]
@@ -67,12 +66,3 @@
     "//components/mus",
   ]
 }
-
-source_set("common") {
-  sources = [
-    "args.h",
-    "lib/args.cc",
-    "types.h",
-    "util.h",
-  ]
-}
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.cc b/components/mus/public/cpp/lib/window_tree_client_impl.cc
index d4554c2..9c6b625 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.cc
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.cc
@@ -5,9 +5,9 @@
 #include "components/mus/public/cpp/lib/window_tree_client_impl.h"
 
 #include "base/bind.h"
+#include "components/mus/common/util.h"
 #include "components/mus/public/cpp/lib/in_flight_change.h"
 #include "components/mus/public/cpp/lib/window_private.h"
-#include "components/mus/public/cpp/util.h"
 #include "components/mus/public/cpp/window_manager_delegate.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
diff --git a/components/mus/public/cpp/lib/window_tree_client_impl.h b/components/mus/public/cpp/lib/window_tree_client_impl.h
index 34760dc..78e37f1 100644
--- a/components/mus/public/cpp/lib/window_tree_client_impl.h
+++ b/components/mus/public/cpp/lib/window_tree_client_impl.h
@@ -6,7 +6,7 @@
 #define COMPONENTS_MUS_PUBLIC_CPP_LIB_WINDOW_TREE_CLIENT_IMPL_H_
 
 #include "base/containers/scoped_ptr_map.h"
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
diff --git a/components/mus/public/cpp/tests/BUILD.gn b/components/mus/public/cpp/tests/BUILD.gn
index 6e69f13..b9cf72b9 100644
--- a/components/mus/public/cpp/tests/BUILD.gn
+++ b/components/mus/public/cpp/tests/BUILD.gn
@@ -49,6 +49,7 @@
     ":unittest_support",
     "//base",
     "//base/test:test_support",
+    "//components/mus/common",
     "//components/mus/public/cpp",
     "//mojo/application/public/cpp",
     "//mojo/converters/geometry",
diff --git a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
index 769edc7..2b92cbb4 100644
--- a/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
+++ b/components/mus/public/cpp/tests/window_tree_client_impl_unittest.cc
@@ -5,11 +5,11 @@
 #include "components/mus/public/cpp/lib/window_tree_client_impl.h"
 
 #include "base/logging.h"
+#include "components/mus/common/util.h"
 #include "components/mus/public/cpp/lib/window_private.h"
 #include "components/mus/public/cpp/property_type_converters.h"
 #include "components/mus/public/cpp/tests/test_window.h"
 #include "components/mus/public/cpp/tests/test_window_tree.h"
-#include "components/mus/public/cpp/util.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/cpp/window_property.h"
diff --git a/components/mus/public/cpp/tests/window_unittest.cc b/components/mus/public/cpp/tests/window_unittest.cc
index f0386c9..da7bf3b 100644
--- a/components/mus/public/cpp/tests/window_unittest.cc
+++ b/components/mus/public/cpp/tests/window_unittest.cc
@@ -7,10 +7,10 @@
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/stringprintf.h"
+#include "components/mus/common/util.h"
 #include "components/mus/public/cpp/lib/window_private.h"
 #include "components/mus/public/cpp/property_type_converters.h"
 #include "components/mus/public/cpp/tests/test_window.h"
-#include "components/mus/public/cpp/util.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/cpp/window_property.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/components/mus/public/cpp/window.h b/components/mus/public/cpp/window.h
index ded4fd36..f25664e 100644
--- a/components/mus/public/cpp/window.h
+++ b/components/mus/public/cpp/window.h
@@ -10,7 +10,7 @@
 
 #include "base/callback.h"
 #include "base/observer_list.h"
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/interfaces/mus_constants.mojom.h"
 #include "components/mus/public/interfaces/surface_id.mojom.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
diff --git a/components/mus/public/cpp/window_tree_connection.h b/components/mus/public/cpp/window_tree_connection.h
index 1f26737..659dc62c 100644
--- a/components/mus/public/cpp/window_tree_connection.h
+++ b/components/mus/public/cpp/window_tree_connection.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 
diff --git a/components/mus/ws/BUILD.gn b/components/mus/ws/BUILD.gn
index b830ff89..663d03a2 100644
--- a/components/mus/ws/BUILD.gn
+++ b/components/mus/ws/BUILD.gn
@@ -62,7 +62,6 @@
     "//cc/surfaces:surface_id",
     "//components/mus/common",
     "//components/mus/gles2:gles2",
-    "//components/mus/public/cpp:common",
     "//components/mus/public/interfaces",
     "//components/mus/surfaces",
     "//mojo/application/public/cpp",
@@ -94,8 +93,8 @@
 
   deps = [
     "//base",
+    "//components/mus/common",
     "//components/mus/public/cpp",
-    "//components/mus/public/cpp:common",
     "//components/mus/public/interfaces",
     "//mojo/common",
     "//mojo/public/cpp/bindings:bindings",
@@ -129,9 +128,9 @@
     ":lib",
     "//base",
     "//base/test:test_config",
+    "//components/mus/common",
     "//components/mus/surfaces",
     "//components/mus/public/cpp",
-    "//components/mus/public/cpp:common",
     "//components/mus/public/interfaces",
     "//mojo/application/public/interfaces",
     "//mojo/converters/geometry",
@@ -168,6 +167,7 @@
     ":test_support",
     "//base",
     "//base/test:test_config",
+    "//components/mus/common",
     "//components/mus/public/cpp",
     "//components/mus/public/cpp/tests:test_support",
     "//components/mus/public/interfaces",
diff --git a/components/mus/ws/connection_manager_delegate.h b/components/mus/ws/connection_manager_delegate.h
index e160944..5fbef7b 100644
--- a/components/mus/ws/connection_manager_delegate.h
+++ b/components/mus/ws/connection_manager_delegate.h
@@ -7,7 +7,7 @@
 
 #include <string>
 
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 
diff --git a/components/mus/ws/ids.h b/components/mus/ws/ids.h
index 684366a..3c814d0 100644
--- a/components/mus/ws/ids.h
+++ b/components/mus/ws/ids.h
@@ -5,8 +5,8 @@
 #ifndef COMPONENTS_MUS_WS_IDS_H_
 #define COMPONENTS_MUS_WS_IDS_H_
 
-#include "components/mus/public/cpp/types.h"
-#include "components/mus/public/cpp/util.h"
+#include "components/mus/common/types.h"
+#include "components/mus/common/util.h"
 
 namespace mus {
 
diff --git a/components/mus/ws/operation.h b/components/mus/ws/operation.h
index b1dcc53a..27441a6 100644
--- a/components/mus/ws/operation.h
+++ b/components/mus/ws/operation.h
@@ -8,7 +8,7 @@
 #include <set>
 
 #include "base/macros.h"
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 
 namespace mus {
 namespace ws {
diff --git a/components/mus/ws/test_change_tracker.cc b/components/mus/ws/test_change_tracker.cc
index 5f1e686..a128c017 100644
--- a/components/mus/ws/test_change_tracker.cc
+++ b/components/mus/ws/test_change_tracker.cc
@@ -6,7 +6,7 @@
 
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
-#include "components/mus/public/cpp/util.h"
+#include "components/mus/common/util.h"
 #include "mojo/common/common_type_converters.h"
 
 using mojo::Array;
diff --git a/components/mus/ws/test_change_tracker.h b/components/mus/ws/test_change_tracker.h
index faa5fe7..aa7a5a6 100644
--- a/components/mus/ws/test_change_tracker.h
+++ b/components/mus/ws/test_change_tracker.h
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/basictypes.h"
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "mojo/public/cpp/bindings/array.h"
 #include "ui/mojo/geometry/geometry.mojom.h"
diff --git a/components/mus/ws/window_manager_client_apptest.cc b/components/mus/ws/window_manager_client_apptest.cc
index 67ade08..e38b7634 100644
--- a/components/mus/ws/window_manager_client_apptest.cc
+++ b/components/mus/ws/window_manager_client_apptest.cc
@@ -5,8 +5,8 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/run_loop.h"
+#include "components/mus/common/util.h"
 #include "components/mus/public/cpp/tests/window_server_test_base.h"
-#include "components/mus/public/cpp/util.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
 #include "components/mus/public/cpp/window_tree_delegate.h"
diff --git a/components/mus/ws/window_tree_host_impl.cc b/components/mus/ws/window_tree_host_impl.cc
index c6e8a173..6f84e0e7c 100644
--- a/components/mus/ws/window_tree_host_impl.cc
+++ b/components/mus/ws/window_tree_host_impl.cc
@@ -5,7 +5,7 @@
 #include "components/mus/ws/window_tree_host_impl.h"
 
 #include "base/strings/utf_string_conversions.h"
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/ws/connection_manager.h"
 #include "components/mus/ws/display_manager.h"
 #include "components/mus/ws/focus_controller.h"
diff --git a/components/mus/ws/window_tree_host_impl.h b/components/mus/ws/window_tree_host_impl.h
index c3c5f1d2..dd7f0032 100644
--- a/components/mus/ws/window_tree_host_impl.h
+++ b/components/mus/ws/window_tree_host_impl.h
@@ -7,7 +7,7 @@
 
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/interfaces/window_tree_host.mojom.h"
 #include "components/mus/ws/display_manager.h"
 #include "components/mus/ws/event_dispatcher.h"
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc
index bef682c..3c13428 100644
--- a/components/mus/ws/window_tree_unittest.cc
+++ b/components/mus/ws/window_tree_unittest.cc
@@ -6,8 +6,8 @@
 #include <vector>
 
 #include "base/message_loop/message_loop.h"
-#include "components/mus/public/cpp/types.h"
-#include "components/mus/public/cpp/util.h"
+#include "components/mus/common/types.h"
+#include "components/mus/common/util.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "components/mus/surfaces/surfaces_state.h"
 #include "components/mus/ws/client_connection.h"
diff --git a/components/offline_pages/offline_page_model.cc b/components/offline_pages/offline_page_model.cc
index 1453004..7b0922e 100644
--- a/components/offline_pages/offline_page_model.cc
+++ b/components/offline_pages/offline_page_model.cc
@@ -540,17 +540,43 @@
   // Delete the offline page from the in memory cache regardless of success in
   // store.
   base::Time now = base::Time::Now();
+  int64 total_size = 0;
   for (int64 bookmark_id : bookmark_ids) {
     auto iter = offline_pages_.find(bookmark_id);
     if (iter == offline_pages_.end())
       continue;
-    UMA_HISTOGRAM_CUSTOM_COUNTS("OfflinePages.PageLifetime",
-                                (now - iter->second.creation_time).InMinutes(),
-                                1,
-                                base::TimeDelta::FromDays(365).InMinutes(),
-                                100);
+    total_size += iter->second.file_size;
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "OfflinePages.PageLifetime",
+        (now - iter->second.creation_time).InMinutes(),
+        1,
+        base::TimeDelta::FromDays(365).InMinutes(),
+        100);
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "OfflinePages.DeletePage.TimeSinceLastOpen",
+        (now - iter->second.last_access_time).InMinutes(),
+        1,
+        base::TimeDelta::FromDays(365).InMinutes(),
+        100);
+    UMA_HISTOGRAM_CUSTOM_COUNTS(
+        "OfflinePages.DeletePage.LastOpenToCreated",
+        (iter->second.last_access_time - iter->second.creation_time).
+            InMinutes(),
+        1,
+        base::TimeDelta::FromDays(365).InMinutes(),
+        100);
+    UMA_HISTOGRAM_MEMORY_KB(
+        "OfflinePages.DeletePage.PageSize", iter->second.file_size / 1024);
+    UMA_HISTOGRAM_COUNTS(
+        "OfflinePages.DeletePage.AccessCount", iter->second.access_count);
     offline_pages_.erase(iter);
   }
+  if (bookmark_ids.size() > 1) {
+    UMA_HISTOGRAM_COUNTS(
+        "OfflinePages.BatchDelete.Count", bookmark_ids.size());
+    UMA_HISTOGRAM_MEMORY_KB(
+        "OfflinePages.BatchDelete.TotalPageSize", total_size / 1024);
+  }
   // Deleting multiple pages always succeeds when it gets to this point.
   InformDeletePageDone(
       callback,
diff --git a/components/omnibox/browser/keyword_provider.cc b/components/omnibox/browser/keyword_provider.cc
index 8992f02..360d94b 100644
--- a/components/omnibox/browser/keyword_provider.cc
+++ b/components/omnibox/browser/keyword_provider.cc
@@ -15,6 +15,8 @@
 #include "components/omnibox/browser/autocomplete_provider_client.h"
 #include "components/omnibox/browser/autocomplete_provider_listener.h"
 #include "components/omnibox/browser/keyword_extensions_delegate.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
+#include "components/omnibox/browser/search_provider.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
 #include "grit/components_strings.h"
@@ -27,15 +29,18 @@
 // Helper functor for Start(), for sorting keyword matches by quality.
 class CompareQuality {
  public:
-  // A keyword is of higher quality when a greater fraction of it has been
-  // typed, that is, when it is shorter.
+  // A keyword is of higher quality when a greater fraction of the important
+  // part of it has been typed, that is, when the meaningful keyword length is
+  // shorter.
   //
   // TODO(pkasting): Most recent and most frequent keywords are probably
   // better rankings than the fraction of the keyword typed.  We should
   // always put any exact matches first no matter what, since the code in
   // Start() assumes this (and it makes sense).
-  bool operator()(const TemplateURL* t_url1, const TemplateURL* t_url2) const {
-    return t_url1->keyword().length() < t_url2->keyword().length();
+  bool operator()(
+      const TemplateURLService::TURLAndMeaningfulLength t_url_match1,
+      const TemplateURLService::TURLAndMeaningfulLength t_url_match2) const {
+    return t_url_match1.second < t_url_match2.second;
   }
 };
 
@@ -196,8 +201,9 @@
     const AutocompleteInput& input) {
   // A verbatim match is allowed to be the default match.
   return CreateAutocompleteMatch(
-      GetTemplateURLService()->GetTemplateURLForKeyword(keyword), input,
-      keyword.length(), SplitReplacementStringFromInput(text, true), true, 0);
+      GetTemplateURLService()->GetTemplateURLForKeyword(keyword),
+      keyword.length(), input, keyword.length(),
+      SplitReplacementStringFromInput(text, true), true, 0);
 }
 
 void KeywordProvider::Start(const AutocompleteInput& input,
@@ -243,13 +249,17 @@
   // |minimal_changes| case, but since we'd still have to recalculate their
   // relevances and we can just recreate the results synchronously anyway, we
   // don't bother.
-  TemplateURLService::TemplateURLVector matches;
-  GetTemplateURLService()->FindMatchingKeywords(
+  TemplateURLService::TURLsAndMeaningfulLengths matches;
+  GetTemplateURLService()->AddMatchingKeywords(
       keyword, !remaining_input.empty(), &matches);
+  if (!OmniboxFieldTrial::KeywordRequiresPrefixMatch()) {
+    GetTemplateURLService()->AddMatchingDomainKeywords(
+        keyword, !remaining_input.empty(), &matches);
+  }
 
-  for (TemplateURLService::TemplateURLVector::iterator i(matches.begin());
-       i != matches.end(); ) {
-    const TemplateURL* template_url = *i;
+  for (TemplateURLService::TURLsAndMeaningfulLengths::iterator
+           i(matches.begin()); i != matches.end(); ) {
+    const TemplateURL* template_url = i->first;
 
     // Prune any extension keywords that are disallowed in incognito mode (if
     // we're incognito), or disabled.
@@ -280,8 +290,9 @@
   // in the autocomplete popup.
   // Any exact match is going to be the highest quality match, and thus at the
   // front of our vector.
-  if (matches.front()->keyword() == keyword) {
-    const TemplateURL* template_url = matches.front();
+  if (matches.front().first->keyword() == keyword) {
+    const TemplateURL* template_url = matches.front().first;
+    const size_t meaningful_keyword_length = matches.front().second;
     const bool is_extension_keyword =
         template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
 
@@ -300,7 +311,8 @@
     // remaining query or an extension keyword, possibly with remaining
     // input), allow the match to be the default match.
     matches_.push_back(CreateAutocompleteMatch(
-        template_url, input, keyword.length(), remaining_input, true, -1));
+        template_url, meaningful_keyword_length, input, keyword.length(),
+        remaining_input, true, -1));
 
     if (is_extension_keyword && extensions_delegate_) {
       if (extensions_delegate_->Start(input, minimal_changes, template_url,
@@ -308,12 +320,23 @@
         keyword_mode_toggle.StayInKeywordMode();
     }
   } else {
-    if (matches.size() > kMaxMatches)
-      matches.erase(matches.begin() + kMaxMatches, matches.end());
-    for (TemplateURLService::TemplateURLVector::const_iterator i(
-         matches.begin()); i != matches.end(); ++i) {
-      matches_.push_back(CreateAutocompleteMatch(
-          *i, input, keyword.length(), remaining_input, false, -1));
+    for (TemplateURLService::TURLsAndMeaningfulLengths::const_iterator i(
+             matches.begin());
+         (i != matches.end()) && (matches_.size() < kMaxMatches); ++i) {
+      // Skip keywords that we've already added.  It's possible we may have
+      // retrieved the same keyword twice.  For example, the keyword
+      // "abc.abc.com" may be retrieved for the input "abc" from the full
+      // keyword matching and the domain matching passes.
+      ACMatches::const_iterator duplicate = std::find_if(
+          matches_.begin(), matches_.end(),
+          [&i] (const AutocompleteMatch& m) {
+            return m.keyword == i->first->keyword();
+          });
+      if (duplicate == matches_.end()) {
+        matches_.push_back(CreateAutocompleteMatch(
+            i->first, i->second, input, keyword.length(), remaining_input,
+            false, -1));
+      }
     }
   }
 }
@@ -346,29 +369,28 @@
 // static
 int KeywordProvider::CalculateRelevance(metrics::OmniboxInputType::Type type,
                                         bool complete,
+                                        bool sufficiently_complete,
                                         bool supports_replacement,
                                         bool prefer_keyword,
                                         bool allow_exact_keyword_match) {
-  // This function is responsible for scoring suggestions of keywords
-  // themselves and the suggestion of the verbatim query on an
-  // extension keyword.  SearchProvider::CalculateRelevanceForKeywordVerbatim()
-  // scores verbatim query suggestions for non-extension keywords.
-  // These two functions are currently in sync, but there's no reason
-  // we couldn't decide in the future to score verbatim matches
-  // differently for extension and non-extension keywords.  If you
-  // make such a change, however, you should update this comment to
-  // describe it, so it's clear why the functions diverge.
-  if (!complete)
+  if (!complete) {
+    const int sufficiently_complete_score =
+        OmniboxFieldTrial::KeywordScoreForSufficientlyCompleteMatch();
+    // If we have a special score to apply for sufficiently-complete matches,
+    // do so.
+    if (sufficiently_complete && (sufficiently_complete_score > -1))
+      return sufficiently_complete_score;
     return (type == metrics::OmniboxInputType::URL) ? 700 : 450;
-  if (!supports_replacement || (allow_exact_keyword_match && prefer_keyword))
+  }
+  if (!supports_replacement)
     return 1500;
-  return (allow_exact_keyword_match &&
-          (type == metrics::OmniboxInputType::QUERY)) ?
-      1450 : 1100;
+  return SearchProvider::CalculateRelevanceForKeywordVerbatim(
+      type, allow_exact_keyword_match, prefer_keyword);
 }
 
 AutocompleteMatch KeywordProvider::CreateAutocompleteMatch(
     const TemplateURL* template_url,
+    const size_t meaningful_keyword_length,
     const AutocompleteInput& input,
     size_t prefix_length,
     const base::string16& remaining_input,
@@ -384,9 +406,12 @@
   // choice and immediately begin typing in query input.
   const base::string16& keyword = template_url->keyword();
   const bool keyword_complete = (prefix_length == keyword.length());
+  const bool sufficiently_complete =
+      (prefix_length >= meaningful_keyword_length);
   if (relevance < 0) {
     relevance =
         CalculateRelevance(input.type(), keyword_complete,
+                           sufficiently_complete,
                            // When the user wants keyword matches to take
                            // preference, score them highly regardless of
                            // whether the input provides query text.
diff --git a/components/omnibox/browser/keyword_provider.h b/components/omnibox/browser/keyword_provider.h
index 3be6313b..e82e6cdd 100644
--- a/components/omnibox/browser/keyword_provider.h
+++ b/components/omnibox/browser/keyword_provider.h
@@ -111,12 +111,13 @@
                                       base::string16* remaining_input);
 
   // Determines the relevance for some input, given its type, whether the user
-  // typed the complete keyword, and whether the user is in "prefer keyword
-  // matches" mode, and whether the keyword supports replacement.
-  // If |allow_exact_keyword_match| is false, the relevance for complete
-  // keywords that support replacements is degraded.
+  // typed the complete keyword (or close to it), and whether the user is in
+  // "prefer keyword matches" mode, and whether the keyword supports
+  // replacement. If |allow_exact_keyword_match| is false, the relevance for
+  // complete keywords that support replacements is degraded.
   static int CalculateRelevance(metrics::OmniboxInputType::Type type,
                                 bool complete,
+                                bool sufficiently_complete,
                                 bool support_replacement,
                                 bool prefer_keyword,
                                 bool allow_exact_keyword_match);
@@ -125,6 +126,7 @@
   // If |relevance| is negative, calculate a relevance based on heuristics.
   AutocompleteMatch CreateAutocompleteMatch(
       const TemplateURL* template_url,
+      const size_t meaningful_keyword_length,
       const AutocompleteInput& input,
       size_t prefix_length,
       const base::string16& remaining_input,
diff --git a/components/omnibox/browser/keyword_provider_unittest.cc b/components/omnibox/browser/keyword_provider_unittest.cc
index 15be17c..ff66f15 100644
--- a/components/omnibox/browser/keyword_provider_unittest.cc
+++ b/components/omnibox/browser/keyword_provider_unittest.cc
@@ -4,15 +4,19 @@
 
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
 #include "base/strings/utf_string_conversions.h"
 #include "components/metrics/proto/omnibox_event.pb.h"
 #include "components/omnibox/browser/autocomplete_match.h"
 #include "components/omnibox/browser/autocomplete_scheme_classifier.h"
 #include "components/omnibox/browser/keyword_provider.h"
 #include "components/omnibox/browser/mock_autocomplete_provider_client.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/search_engines/search_engines_switches.h"
 #include "components/search_engines/template_url.h"
 #include "components/search_engines/template_url_service.h"
+#include "components/variations/entropy_provider.h"
+#include "components/variations/variations_associated_data.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -48,10 +52,22 @@
     const MatchType<ResultType> output[3];
   };
 
-  KeywordProviderTest() : kw_provider_(NULL) { }
+  KeywordProviderTest() : kw_provider_(NULL) {
+    // Destroy the existing FieldTrialList before creating a new one to avoid
+    // a DCHECK.
+    field_trial_list_.reset();
+    field_trial_list_.reset(new base::FieldTrialList(
+        new metrics::SHA1EntropyProvider("foo")));
+    variations::testing::ClearAllVariationParams();
+  }
   ~KeywordProviderTest() override {}
 
-  void SetUp() override;
+  // Should be called at least once during a test case.  This is a separate
+  // function from SetUp() because the client may want to set parameters
+  // (e.g., field trials) before initializing TemplateURLService and the
+  // related internal variables here.
+  void SetUpClientAndKeywordProvider();
+
   void TearDown() override;
 
   template<class ResultType>
@@ -62,6 +78,7 @@
  protected:
   static const TemplateURLService::Initializer kTestData[];
 
+  scoped_ptr<base::FieldTrialList> field_trial_list_;
   scoped_refptr<KeywordProvider> kw_provider_;
   scoped_ptr<MockAutocompleteProviderClient> client_;
 };
@@ -76,9 +93,18 @@
   { "www", " +%2B?={searchTerms}foo ", "www" },
   { "nonsub", "http://nonsubstituting-keyword.com/", "nonsub" },
   { "z", "{searchTerms}=z", "z" },
+  { "host.site.com", "http://host.site.com/?q={searchTerms}", "host.site.com" },
+  { "ignoremelong.domain.com",
+    "http://ignoremelong.domain.com/?q={searchTerms}",
+    "ignoremelong.domain.com" },
+  { "ignoreme.domain2.com",
+    "http://ignoreme.domain2.com/?q={searchTerms}",
+    "ignoreme.domain2.com" },
+  { "fooshort.com", "http://fooshort.com/?q={searchTerms}", "fooshort.com" },
+  { "foolong.co.uk", "http://foolong.co.uk/?q={searchTerms}", "foolong.co.uk" },
 };
 
-void KeywordProviderTest::SetUp() {
+void KeywordProviderTest::SetUpClientAndKeywordProvider() {
   scoped_ptr<TemplateURLService> template_url_service(
       new TemplateURLService(kTestData, arraysize(kTestData)));
   client_.reset(new MockAutocompleteProviderClient());
@@ -151,6 +177,10 @@
       { { ASCIIToUTF16("aa "), false },
         { ASCIIToUTF16("ab "), false },
         { ASCIIToUTF16("aaaa "), false } } },
+    { ASCIIToUTF16("foo hello"), 2,
+      { { ASCIIToUTF16("fooshort.com hello"), false },
+        { ASCIIToUTF16("foolong.co.uk hello"), false },
+        kEmptyMatch } },
     // Exact matches should prevent returning inexact matches.  Also, the
     // verbatim query for this keyword match should not be returned.  (It's
     // returned by SearchProvider.)
@@ -159,6 +189,17 @@
     { ASCIIToUTF16("www.aaaa foo"), 0,
       { kEmptyMatch, kEmptyMatch, kEmptyMatch } },
 
+    // Matches should be retrieved by typing the prefix of the keyword, not the
+    // domain name.
+    { ASCIIToUTF16("host foo"), 1,
+      { { ASCIIToUTF16("host.site.com foo"), false },
+        kEmptyMatch, kEmptyMatch } },
+    { ASCIIToUTF16("host.site foo"), 1,
+      { { ASCIIToUTF16("host.site.com foo"), false },
+        kEmptyMatch, kEmptyMatch } },
+    { ASCIIToUTF16("site foo"), 0,
+      { kEmptyMatch, kEmptyMatch, kEmptyMatch } },
+
     // Clean up keyword input properly.  "http" and "https" are the only
     // allowed schemes.
     { ASCIIToUTF16("www"), 1,
@@ -190,8 +231,105 @@
       { { ASCIIToUTF16("nonsub"), true }, kEmptyMatch, kEmptyMatch } },
   };
 
+  SetUpClientAndKeywordProvider();
   RunTest<base::string16>(edit_cases, arraysize(edit_cases),
-                    &AutocompleteMatch::fill_into_edit);
+                          &AutocompleteMatch::fill_into_edit);
+}
+
+TEST_F(KeywordProviderTest, DomainMatches) {
+  const MatchType<base::string16> kEmptyMatch = { base::string16(), false };
+  TestData<base::string16> edit_cases[] = {
+    // Searching for a nonexistent prefix should give nothing.
+    { ASCIIToUTF16("Not Found"), 0,
+      { kEmptyMatch, kEmptyMatch, kEmptyMatch } },
+    { ASCIIToUTF16("aaaaaNot Found"), 0,
+      { kEmptyMatch, kEmptyMatch, kEmptyMatch } },
+
+    // Matches should be limited to three and sorted in quality order.
+    // This order depends on whether we're using the pre-domain-name text
+    // for matching--when matching the domain, we sort by the length of the
+    // domain, not the length of the whole keyword.
+    { ASCIIToUTF16("ignore foo"), 2,
+      { { ASCIIToUTF16("ignoreme.domain2.com foo"), false },
+        { ASCIIToUTF16("ignoremelong.domain.com foo"), false },
+        kEmptyMatch } },
+    { ASCIIToUTF16("dom foo"), 2,
+      { { ASCIIToUTF16("ignoremelong.domain.com foo"), false },
+        { ASCIIToUTF16("ignoreme.domain2.com foo"), false },
+        kEmptyMatch } },
+
+    // Matches should be retrieved by typing the domain name, not only
+    // a prefix to the keyword.
+    { ASCIIToUTF16("host foo"), 1,
+      { { ASCIIToUTF16("host.site.com foo"), false },
+        kEmptyMatch, kEmptyMatch } },
+    { ASCIIToUTF16("host.site foo"), 1,
+      { { ASCIIToUTF16("host.site.com foo"), false },
+        kEmptyMatch, kEmptyMatch } },
+    { ASCIIToUTF16("site foo"), 1,
+      { { ASCIIToUTF16("host.site.com foo"), false },
+        kEmptyMatch, kEmptyMatch } },
+  };
+
+  // Add a rule enabling matching in the domain name of keywords (i.e.,
+  // non-prefix matching).
+  {
+    std::map<std::string, std::string> params;
+    params[OmniboxFieldTrial::kKeywordRequiresPrefixMatchRule] = "false";
+    ASSERT_TRUE(variations::AssociateVariationParams(
+        OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
+  }
+  base::FieldTrialList::CreateFieldTrial(
+      OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
+
+  SetUpClientAndKeywordProvider();
+  RunTest<base::string16>(edit_cases, arraysize(edit_cases),
+                          &AutocompleteMatch::fill_into_edit);
+}
+
+TEST_F(KeywordProviderTest, IgnoreRegistryForScoring) {
+  const MatchType<base::string16> kEmptyMatch = { base::string16(), false };
+  TestData<base::string16> edit_cases[] = {
+    // Matches should be limited to three and sorted in quality order.
+    // When ignoring the registry length, this order of suggestions should
+    // result (sorted by keyword length sans registry).  The "Edit" test case
+    // has this exact test for when not ignoring the registry to check that
+    // the other order (shorter full keyword) results there.
+    { ASCIIToUTF16("foo hello"), 2,
+      { { ASCIIToUTF16("foolong.co.uk hello"), false },
+        { ASCIIToUTF16("fooshort.com hello"), false },
+        kEmptyMatch } },
+
+    // Keywords that don't have full hostnames should keep the same order
+    // as normal.
+    { ASCIIToUTF16("aaa"), 2,
+      { { ASCIIToUTF16("aaaa "), false },
+        { ASCIIToUTF16("aaaaa "), false },
+        kEmptyMatch } },
+    { ASCIIToUTF16("a 1 2 3"), 3,
+     { { ASCIIToUTF16("aa 1 2 3"), false },
+       { ASCIIToUTF16("ab 1 2 3"), false },
+       { ASCIIToUTF16("aaaa 1 2 3"), false } } },
+    { ASCIIToUTF16("www.a"), 3,
+      { { ASCIIToUTF16("aa "), false },
+        { ASCIIToUTF16("ab "), false },
+        { ASCIIToUTF16("aaaa "), false } } },
+  };
+
+  // Add a rule to make matching in the registry portion of a keyword
+  // unimportant.
+  {
+    std::map<std::string, std::string> params;
+    params[OmniboxFieldTrial::kKeywordRequiresRegistryRule] = "false";
+    ASSERT_TRUE(variations::AssociateVariationParams(
+        OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A", params));
+  }
+  base::FieldTrialList::CreateFieldTrial(
+      OmniboxFieldTrial::kBundledExperimentFieldTrialName, "A");
+
+  SetUpClientAndKeywordProvider();
+  RunTest<base::string16>(edit_cases, arraysize(edit_cases),
+                          &AutocompleteMatch::fill_into_edit);
 }
 
 TEST_F(KeywordProviderTest, URL) {
@@ -225,6 +363,7 @@
         kEmptyMatch } },
   };
 
+  SetUpClientAndKeywordProvider();
   RunTest<GURL>(url_cases, arraysize(url_cases),
                 &AutocompleteMatch::destination_url);
 }
@@ -268,11 +407,13 @@
         { ASCIIToUTF16("Search aaaa for 1 2+ 3"), false } } },
   };
 
+  SetUpClientAndKeywordProvider();
   RunTest<base::string16>(contents_cases, arraysize(contents_cases),
-                    &AutocompleteMatch::contents);
+                          &AutocompleteMatch::contents);
 }
 
 TEST_F(KeywordProviderTest, AddKeyword) {
+  SetUpClientAndKeywordProvider();
   TemplateURLData data;
   data.SetShortName(ASCIIToUTF16("Test"));
   base::string16 keyword(ASCIIToUTF16("foo"));
@@ -286,6 +427,7 @@
 }
 
 TEST_F(KeywordProviderTest, RemoveKeyword) {
+  SetUpClientAndKeywordProvider();
   TemplateURLService* template_url_service = client_->GetTemplateURLService();
   base::string16 url(ASCIIToUTF16("http://aaaa/?aaaa=1&b={searchTerms}&c"));
   template_url_service->Remove(
@@ -295,6 +437,7 @@
 }
 
 TEST_F(KeywordProviderTest, GetKeywordForInput) {
+  SetUpClientAndKeywordProvider();
   EXPECT_EQ(ASCIIToUTF16("aa"),
       kw_provider_->GetKeywordForText(ASCIIToUTF16("aa")));
   EXPECT_EQ(base::string16(),
@@ -344,6 +487,7 @@
     { "aa foo", base::string16::npos, false, "", "aa foo",
       base::string16::npos },
   };
+  SetUpClientAndKeywordProvider();
   for (size_t i = 0; i < arraysize(cases); i++) {
     AutocompleteInput input(ASCIIToUTF16(cases[i].text),
                             cases[i].cursor_position, std::string(), GURL(),
@@ -375,11 +519,13 @@
         { GURL("http://aaaa/?aaaa=1&b=1+2+3&c"), false } } },
   };
 
+  SetUpClientAndKeywordProvider();
   RunTest<GURL>(url_cases, arraysize(url_cases),
                 &AutocompleteMatch::destination_url);
 }
 
 TEST_F(KeywordProviderTest, DoesNotProvideMatchesOnFocus) {
+  SetUpClientAndKeywordProvider();
   AutocompleteInput input(ASCIIToUTF16("aaa"), base::string16::npos,
                           std::string(), GURL(),
                           metrics::OmniboxEventProto::INVALID_SPEC, true, false,
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index b45f0b2..b07ce446 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -440,6 +440,35 @@
       kPreventUWYTDefaultForNonURLInputsRule) == "true";
 }
 
+bool OmniboxFieldTrial::KeywordRequiresRegistry() {
+  const std::string& value = variations::GetVariationParamValue(
+      kBundledExperimentFieldTrialName,
+      kKeywordRequiresRegistryRule);
+  return value.empty() || (value == "true");
+}
+
+bool OmniboxFieldTrial::KeywordRequiresPrefixMatch() {
+  const std::string& value = variations::GetVariationParamValue(
+      kBundledExperimentFieldTrialName,
+      kKeywordRequiresPrefixMatchRule);
+  return value.empty() || (value == "true");
+}
+
+int OmniboxFieldTrial::KeywordScoreForSufficientlyCompleteMatch() {
+  std::string value_str = variations::GetVariationParamValue(
+      kBundledExperimentFieldTrialName,
+      kKeywordScoreForSufficientlyCompleteMatchRule);
+  if (value_str.empty())
+    return -1;
+  // This is a best-effort conversion; we trust the hand-crafted parameters
+  // downloaded from the server to be perfect.  There's no need for handle
+  // errors smartly.
+  int value;
+  base::StringToInt(value_str, &value);
+  return value;
+}
+
+
 const char OmniboxFieldTrial::kBundledExperimentFieldTrialName[] =
     "OmniboxBundledExperimentV1";
 const char OmniboxFieldTrial::kDisableProvidersRule[] = "DisableProviders";
@@ -469,6 +498,12 @@
     "HQPAlsoDoHUPLikeScoring";
 const char OmniboxFieldTrial::kPreventUWYTDefaultForNonURLInputsRule[] =
     "PreventUWYTDefaultForNonURLInputs";
+const char OmniboxFieldTrial::kKeywordRequiresRegistryRule[] =
+    "KeywordRequiresRegistry";
+const char OmniboxFieldTrial::kKeywordRequiresPrefixMatchRule[] =
+    "KeywordRequiresPrefixMatch";
+const char OmniboxFieldTrial::kKeywordScoreForSufficientlyCompleteMatchRule[] =
+    "KeywordScoreForSufficientlyCompleteMatch";
 
 const char OmniboxFieldTrial::kHUPNewScoringEnabledParam[] =
     "HUPExperimentalScoringEnabled";
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index b6e3549..674170f 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -320,6 +320,28 @@
   static bool PreventUWYTDefaultForNonURLInputs();
 
   // ---------------------------------------------------------
+  // For the aggressive keyword matching experiment that's part of the bundled
+  // omnibox field trial.
+
+  // Returns whether KeywordProvider should consider the registry portion
+  // (e.g., co.uk) of keywords that look like hostnames as an important part of
+  // the keyword name for matching purposes.  Returns true if the experiment
+  // isn't active.
+  static bool KeywordRequiresRegistry();
+
+  // For keywords that look like hostnames, returns whether KeywordProvider
+  // should require users to type a prefix of the hostname to match against
+  // them, rather than just the domain name portion.  In other words, returns
+  // whether the prefix before the domain name should be considered important
+  // for matching purposes.  Returns true if the experiment isn't active.
+  static bool KeywordRequiresPrefixMatch();
+
+  // Returns the relevance score that KeywordProvider should assign to keywords
+  // with sufficiently-complete matches, i.e., the user has typed all of the
+  // important part of the keyword.  Returns -1 if the experiment isn't active.
+  static int KeywordScoreForSufficientlyCompleteMatch();
+
+  // ---------------------------------------------------------
   // Exposed publicly for the sake of unittests.
   static const char kBundledExperimentFieldTrialName[];
   // Rule names used by the bundled experiment.
@@ -341,6 +363,9 @@
   static const char kHQPNumTitleWordsRule[];
   static const char kHQPAlsoDoHUPLikeScoringRule[];
   static const char kPreventUWYTDefaultForNonURLInputsRule[];
+  static const char kKeywordRequiresRegistryRule[];
+  static const char kKeywordRequiresPrefixMatchRule[];
+  static const char kKeywordScoreForSufficientlyCompleteMatchRule[];
 
   // Parameter names used by the HUP new scoring experiments.
   static const char kHUPNewScoringEnabledParam[];
diff --git a/components/omnibox/browser/search_provider.cc b/components/omnibox/browser/search_provider.cc
index 914aeb5..c3c9a25 100644
--- a/components/omnibox/browser/search_provider.cc
+++ b/components/omnibox/browser/search_provider.cc
@@ -137,48 +137,43 @@
   return match.GetAdditionalInfo(kSuggestMetadataKey);
 }
 
-void SearchProvider::ResetSession() {
-  set_field_trial_triggered_in_session(false);
-}
-
-void SearchProvider::OnTemplateURLServiceChanged() {
-  // Only update matches at this time if we haven't already claimed we're done
-  // processing the query.
-  if (done_)
+void SearchProvider::RegisterDisplayedAnswers(
+    const AutocompleteResult& result) {
+  if (result.empty())
     return;
 
-  // Check that the engines we're using weren't renamed or deleted.  (In short,
-  // require that an engine still exists with the keywords in use.)  For each
-  // deleted engine, cancel the in-flight request if any, drop its suggestions,
-  // and, in the case when the default provider was affected, point the cached
-  // default provider keyword name at the new name for the default provider.
+  // The answer must be in the first or second slot to be considered. It should
+  // only be in the second slot if AutocompleteController ranked a local search
+  // history or a verbatim item higher than the answer.
+  AutocompleteResult::const_iterator match = result.begin();
+  if (match->answer_contents.empty() && result.size() > 1)
+    ++match;
+  if (match->answer_contents.empty() || match->answer_type.empty() ||
+      match->fill_into_edit.empty())
+    return;
 
-  // Get...ProviderURL() looks up the provider using the cached keyword name
-  // stored in |providers_|.
-  const TemplateURL* template_url = providers_.GetDefaultProviderURL();
-  if (!template_url) {
-    CancelFetcher(&default_fetcher_);
-    default_results_.Clear();
-    providers_.set(client()
-                       ->GetTemplateURLService()
-                       ->GetDefaultSearchProvider()
-                       ->keyword(),
-                   providers_.keyword_provider());
-  }
-  template_url = providers_.GetKeywordProviderURL();
-  if (!providers_.keyword_provider().empty() && !template_url) {
-    CancelFetcher(&keyword_fetcher_);
-    keyword_results_.Clear();
-    providers_.set(providers_.default_provider(), base::string16());
-  }
-  // It's possible the template URL changed without changing associated keyword.
-  // Hence, it's always necessary to update matches to use the new template
-  // URL.  (One could cache the template URL and only call UpdateMatches() and
-  // OnProviderUpdate() if a keyword was deleted/renamed or the template URL
-  // was changed.  That would save extra calls to these functions.  However,
-  // this is uncommon and not likely to be worth the extra work.)
-  UpdateMatches();
-  listener_->OnProviderUpdate(true);  // always pretend something changed
+  // Valid answer encountered, cache it for further queries.
+  answers_cache_.UpdateRecentAnswers(match->fill_into_edit, match->answer_type);
+}
+
+// static
+int SearchProvider::CalculateRelevanceForKeywordVerbatim(
+    metrics::OmniboxInputType::Type type,
+    bool allow_exact_keyword_match,
+    bool prefer_keyword) {
+  // This function is responsible for scoring verbatim query matches
+  // for non-extension substituting keywords.
+  // KeywordProvider::CalculateRelevance() scores all other types of
+  // keyword verbatim matches.
+  if (allow_exact_keyword_match && prefer_keyword)
+    return 1500;
+  return (allow_exact_keyword_match &&
+          (type == metrics::OmniboxInputType::QUERY)) ?
+      1450 : 1100;
+}
+
+void SearchProvider::ResetSession() {
+  set_field_trial_triggered_in_session(false);
 }
 
 SearchProvider::~SearchProvider() {
@@ -188,25 +183,6 @@
 }
 
 // static
-int SearchProvider::CalculateRelevanceForKeywordVerbatim(
-    metrics::OmniboxInputType::Type type,
-    bool prefer_keyword) {
-  // This function is responsible for scoring verbatim query matches
-  // for non-extension keywords.  KeywordProvider::CalculateRelevance()
-  // scores verbatim query matches for extension keywords, as well as
-  // for keyword matches (i.e., suggestions of a keyword itself, not a
-  // suggestion of a query on a keyword search engine).  These two
-  // functions are currently in sync, but there's no reason we
-  // couldn't decide in the future to score verbatim matches
-  // differently for extension and non-extension keywords.  If you
-  // make such a change, however, you should update this comment to
-  // describe it, so it's clear why the functions diverge.
-  if (prefer_keyword)
-    return 1500;
-  return (type == metrics::OmniboxInputType::QUERY) ? 1450 : 1100;
-}
-
-// static
 void SearchProvider::UpdateOldResults(
     bool minimal_changes,
     SearchSuggestionParser::Results* results) {
@@ -368,6 +344,46 @@
   }
 }
 
+void SearchProvider::OnTemplateURLServiceChanged() {
+  // Only update matches at this time if we haven't already claimed we're done
+  // processing the query.
+  if (done_)
+    return;
+
+  // Check that the engines we're using weren't renamed or deleted.  (In short,
+  // require that an engine still exists with the keywords in use.)  For each
+  // deleted engine, cancel the in-flight request if any, drop its suggestions,
+  // and, in the case when the default provider was affected, point the cached
+  // default provider keyword name at the new name for the default provider.
+
+  // Get...ProviderURL() looks up the provider using the cached keyword name
+  // stored in |providers_|.
+  const TemplateURL* template_url = providers_.GetDefaultProviderURL();
+  if (!template_url) {
+    CancelFetcher(&default_fetcher_);
+    default_results_.Clear();
+    providers_.set(client()
+                       ->GetTemplateURLService()
+                       ->GetDefaultSearchProvider()
+                       ->keyword(),
+                   providers_.keyword_provider());
+  }
+  template_url = providers_.GetKeywordProviderURL();
+  if (!providers_.keyword_provider().empty() && !template_url) {
+    CancelFetcher(&keyword_fetcher_);
+    keyword_results_.Clear();
+    providers_.set(providers_.default_provider(), base::string16());
+  }
+  // It's possible the template URL changed without changing associated keyword.
+  // Hence, it's always necessary to update matches to use the new template
+  // URL.  (One could cache the template URL and only call UpdateMatches() and
+  // OnProviderUpdate() if a keyword was deleted/renamed or the template URL
+  // was changed.  That would save extra calls to these functions.  However,
+  // this is uncommon and not likely to be worth the extra work.)
+  UpdateMatches();
+  listener_->OnProviderUpdate(true);  // always pretend something changed
+}
+
 void SearchProvider::OnURLFetchComplete(const net::URLFetcher* source) {
   DCHECK(!done_);
   const bool is_keyword = source == keyword_fetcher_.get();
@@ -1324,6 +1340,7 @@
   return use_server_relevance ?
       keyword_results_.verbatim_relevance :
       CalculateRelevanceForKeywordVerbatim(keyword_input_.type(),
+                                           true,
                                            keyword_input_.prefer_keyword());
 }
 
@@ -1472,25 +1489,6 @@
   return current_token_;
 }
 
-void SearchProvider::RegisterDisplayedAnswers(
-    const AutocompleteResult& result) {
-  if (result.empty())
-    return;
-
-  // The answer must be in the first or second slot to be considered. It should
-  // only be in the second slot if AutocompleteController ranked a local search
-  // history or a verbatim item higher than the answer.
-  AutocompleteResult::const_iterator match = result.begin();
-  if (match->answer_contents.empty() && result.size() > 1)
-    ++match;
-  if (match->answer_contents.empty() || match->answer_type.empty() ||
-      match->fill_into_edit.empty())
-    return;
-
-  // Valid answer encountered, cache it for further queries.
-  answers_cache_.UpdateRecentAnswers(match->fill_into_edit, match->answer_type);
-}
-
 AnswersQueryData SearchProvider::FindAnswersPrefetchData() {
   // Retrieve the top entry from scored history results.
   MatchMap map;
diff --git a/components/omnibox/browser/search_provider.h b/components/omnibox/browser/search_provider.h
index 2680630..259e7c6 100644
--- a/components/omnibox/browser/search_provider.h
+++ b/components/omnibox/browser/search_provider.h
@@ -66,6 +66,15 @@
   // match for Autocomplete and registers the contained answer data, if any.
   void RegisterDisplayedAnswers(const AutocompleteResult& result);
 
+  // Calculates the relevance score for the keyword verbatim result (if the
+  // input matches one of the profile's keywords).  If
+  // |allow_exact_keyword_match| is false, the relevance for complete
+  // keywords that support replacements is degraded.
+  static int CalculateRelevanceForKeywordVerbatim(
+      metrics::OmniboxInputType::Type type,
+      bool allow_exact_keyword_match,
+      bool prefer_keyword);
+
   // AutocompleteProvider:
   void ResetSession() override;
 
@@ -142,12 +151,6 @@
 
   typedef std::vector<history::KeywordSearchTermVisit> HistoryResults;
 
-  // Calculates the relevance score for the keyword verbatim result (if the
-  // input matches one of the profile's keyword).
-  static int CalculateRelevanceForKeywordVerbatim(
-      metrics::OmniboxInputType::Type type,
-      bool prefer_keyword);
-
   // A helper function for UpdateAllOldResults().
   static void UpdateOldResults(bool minimal_changes,
                                SearchSuggestionParser::Results* results);
diff --git a/components/onc/onc_constants.cc b/components/onc/onc_constants.cc
index 268122a1..7b3c014 100644
--- a/components/onc/onc_constants.cc
+++ b/components/onc/onc_constants.cc
@@ -416,6 +416,8 @@
 namespace global_network_config {
 const char kAllowOnlyPolicyNetworksToAutoconnect[] =
     "AllowOnlyPolicyNetworksToAutoconnect";
+const char kAllowOnlyPolicyNetworksToConnect[] =
+    "AllowOnlyPolicyNetworksToConnect";
 const char kDisableNetworkTypes[] = "DisableNetworkTypes";
 }  // global_network_config
 
diff --git a/components/onc/onc_constants.h b/components/onc/onc_constants.h
index d773933..f0fb7ec 100644
--- a/components/onc/onc_constants.h
+++ b/components/onc/onc_constants.h
@@ -429,6 +429,7 @@
 
 namespace global_network_config {
 ONC_EXPORT extern const char kAllowOnlyPolicyNetworksToAutoconnect[];
+ONC_EXPORT extern const char kAllowOnlyPolicyNetworksToConnect[];
 ONC_EXPORT extern const char kDisableNetworkTypes[];
 }  // global_network_config
 
diff --git a/components/os_crypt/BUILD.gn b/components/os_crypt/BUILD.gn
index da4e59e..457b3cd2 100644
--- a/components/os_crypt/BUILD.gn
+++ b/components/os_crypt/BUILD.gn
@@ -24,15 +24,17 @@
     "//crypto:platform",
   ]
 
-  if (is_mac) {
+  if (is_mac || is_ios) {
     sources -= [ "os_crypt_posix.cc" ]
   }
 
   if (is_ios) {
+    set_sources_assignment_filter([])
     sources += [
       "keychain_password_mac.mm",
       "os_crypt_mac.mm",
     ]
+    set_sources_assignment_filter(sources_assignment_filter)
   }
 }
 
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index c8bd56a..7e753bca 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -121,11 +121,11 @@
 
 PageLoadTracker::PageLoadTracker(
     bool in_foreground,
-    rappor::RapporService* const rappor_service,
+    PageLoadMetricsEmbedderInterface* embedder_interface,
     base::ObserverList<PageLoadMetricsObserver, true>* observers)
     : has_commit_(false),
       started_in_foreground_(in_foreground),
-      rappor_service_(rappor_service),
+      embedder_interface_(embedder_interface),
       observers_(observers) {}
 
 PageLoadTracker::~PageLoadTracker() {
@@ -347,14 +347,16 @@
 
 void PageLoadTracker::RecordRappor() {
   DCHECK(!GetCommittedURL().is_empty());
-  if (!rappor_service_)
+  rappor::RapporService* rappor_service =
+      embedder_interface_->GetRapporService();
+  if (!rappor_service)
     return;
   base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_);
   // Log the eTLD+1 of sites that show poor loading performance.
   if (!first_contentful_paint.is_zero() &&
       first_contentful_paint < GetBackgroundDelta()) {
     scoped_ptr<rappor::Sample> sample =
-        rappor_service_->CreateSample(rappor::UMA_RAPPOR_TYPE);
+        rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE);
     sample->SetStringField("Domain", rappor::GetDomainAndRegistrySampleFromGURL(
                                          GetCommittedURL()));
     uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint);
@@ -363,7 +365,7 @@
     // The IsSlow flag is just a one bit boolean if the first layout was > 10s.
     sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10,
                           1);
-    rappor_service_->RecordSampleObj(
+    rappor_service->RecordSampleObj(
         "PageLoad.CoarseTiming.NavigationToFirstContentfulPaint",
         sample.Pass());
   }
@@ -372,19 +374,20 @@
 // static
 MetricsWebContentsObserver::MetricsWebContentsObserver(
     content::WebContents* web_contents,
-    rappor::RapporService* rappor_service)
+    scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface)
     : content::WebContentsObserver(web_contents),
       in_foreground_(false),
-      rappor_service_(rappor_service) {}
+      embedder_interface_(embedder_interface.Pass()) {}
 
 MetricsWebContentsObserver* MetricsWebContentsObserver::CreateForWebContents(
     content::WebContents* web_contents,
-    rappor::RapporService* rappor_service) {
+    scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) {
   DCHECK(web_contents);
 
   MetricsWebContentsObserver* metrics = FromWebContents(web_contents);
   if (!metrics) {
-    metrics = new MetricsWebContentsObserver(web_contents, rappor_service);
+    metrics =
+        new MetricsWebContentsObserver(web_contents, embedder_interface.Pass());
     web_contents->SetUserData(UserDataKey(), metrics);
   }
   return metrics;
@@ -425,16 +428,19 @@
     content::NavigationHandle* navigation_handle) {
   if (!navigation_handle->IsInMainFrame())
     return;
+  if (embedder_interface_->IsPrerendering(web_contents()))
+    return;
   // We can have two provisional loads in some cases. E.g. a same-site
   // navigation can have a concurrent cross-process navigation started
   // from the omnibox.
   DCHECK_GT(2ul, provisional_loads_.size());
-  // Passing a raw pointer to observers_ is safe because the
-  // MetricsWebContentsObserver owns the PageLoadMetricsObserver list and is
-  // torn down after the PageLoadTracker.
-  provisional_loads_.insert(navigation_handle,
-                            make_scoped_ptr(new PageLoadTracker(
-                                in_foreground_, rappor_service_, &observers_)));
+  // Passing raw pointers to observers_ and embedder_interface_ is safe because
+  // the MetricsWebContentsObserver owns them both list and they are torn down
+  // after the PageLoadTracker.
+  provisional_loads_.insert(
+      navigation_handle,
+      make_scoped_ptr(new PageLoadTracker(
+          in_foreground_, embedder_interface_.get(), &observers_)));
 }
 
 void MetricsWebContentsObserver::DidFinishNavigation(
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h
index 4a9e061a..e6fd36e 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.h
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -158,6 +158,15 @@
   ERR_LAST_ENTRY
 };
 
+// This class serves as a functional interface to various chrome// features.
+// Impl version is defined in chrome/browser/page_load_metrics.
+class PageLoadMetricsEmbedderInterface {
+ public:
+  virtual ~PageLoadMetricsEmbedderInterface() {}
+  virtual rappor::RapporService* GetRapporService() = 0;
+  virtual bool IsPrerendering(content::WebContents* web_contents) = 0;
+};
+
 // This class tracks a given page load, starting from navigation start /
 // provisional load, until a new navigation commits or the navigation fails. It
 // also records RAPPOR/UMA about the page load.
@@ -165,9 +174,10 @@
 // well as a committed PageLoadTracker.
 class PageLoadTracker {
  public:
-  // Caller must guarantee that the observers pointer outlives this class.
+  // Caller must guarantee that the observers and embedder_interface pointers
+  // outlives this class.
   PageLoadTracker(bool in_foreground,
-                  rappor::RapporService* const rappor_service,
+                  PageLoadMetricsEmbedderInterface* embedder_interface,
                   base::ObserverList<PageLoadMetricsObserver, true>* observers);
   ~PageLoadTracker();
   void Commit(content::NavigationHandle* navigation_handle);
@@ -201,10 +211,8 @@
   PageLoadTiming timing_;
   GURL url_;
 
-  // This RapporService is owned by and shares a lifetime with
-  // g_browser_process's MetricsServicesManager. It can be NULL. The underlying
-  // RapporService will be freed when the when the browser process is killed.
-  rappor::RapporService* const rappor_service_;
+  // Interface to chrome features. Must outlive the class.
+  PageLoadMetricsEmbedderInterface* const embedder_interface_;
 
   // List of observers. This must outlive the class.
   base::ObserverList<PageLoadMetricsObserver, true>* observers_;
@@ -224,9 +232,10 @@
   // outlive the WebContents.
   static MetricsWebContentsObserver* CreateForWebContents(
       content::WebContents* web_contents,
-      rappor::RapporService* rappor_service);
-  MetricsWebContentsObserver(content::WebContents* web_contents,
-                             rappor::RapporService* rappor_service);
+      scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface);
+  MetricsWebContentsObserver(
+      content::WebContents* web_contents,
+      scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface);
   ~MetricsWebContentsObserver() override;
 
   void AddObserver(PageLoadMetricsObserver* observer) override;
@@ -261,7 +270,7 @@
       provisional_loads_;
   scoped_ptr<PageLoadTracker> committed_load_;
 
-  rappor::RapporService* const rappor_service_;
+  scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface_;
   base::ObserverList<PageLoadMetricsObserver, true> observers_;
 
   DISALLOW_COPY_AND_ASSIGN(MetricsWebContentsObserver);
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index de5431f..b3bad62 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -27,6 +27,25 @@
 
 }  //  namespace
 
+class TestPageLoadMetricsEmbedderInterface
+    : public PageLoadMetricsEmbedderInterface {
+ public:
+  TestPageLoadMetricsEmbedderInterface() : is_prerendering_(false) {}
+  rappor::TestRapporService* GetRapporService() override {
+    return &rappor_tester_;
+  }
+  bool IsPrerendering(content::WebContents* web_contents) override {
+    return is_prerendering_;
+  }
+  void set_is_prerendering(bool is_prerendering) {
+    is_prerendering_ = is_prerendering;
+  }
+
+ private:
+  bool is_prerendering_;
+  rappor::TestRapporService rappor_tester_;
+};
+
 class MetricsWebContentsObserverTest
     : public content::RenderViewHostTestHarness {
  public:
@@ -43,8 +62,9 @@
   }
 
   void AttachObserver() {
-    observer_.reset(
-        new MetricsWebContentsObserver(web_contents(), &rappor_tester_));
+    embedder_interface_ = new TestPageLoadMetricsEmbedderInterface();
+    observer_.reset(new MetricsWebContentsObserver(
+        web_contents(), make_scoped_ptr(embedder_interface_)));
     observer_->WasShown();
   }
 
@@ -97,7 +117,7 @@
 
  protected:
   base::HistogramTester histogram_tester_;
-  rappor::TestRapporService rappor_tester_;
+  TestPageLoadMetricsEmbedderInterface* embedder_interface_;
   scoped_ptr<MetricsWebContentsObserver> observer_;
 
  private:
@@ -316,6 +336,23 @@
   histogram_tester_.ExpectTotalCount(kHistogramNameFirstTextPaint, 0);
 }
 
+TEST_F(MetricsWebContentsObserverTest, DontLogPrerender) {
+  PageLoadTiming timing;
+  timing.navigation_start = base::Time::FromDoubleT(1);
+  timing.first_layout = base::TimeDelta::FromMilliseconds(10);
+  content::WebContentsTester* web_contents_tester =
+      content::WebContentsTester::For(web_contents());
+  embedder_interface_->set_is_prerendering(true);
+
+  web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
+  observer_->OnMessageReceived(
+      PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
+      web_contents()->GetMainFrame());
+
+  web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
+  AssertNoHistogramsLogged();
+}
+
 TEST_F(MetricsWebContentsObserverTest, OnlyBackgroundLaterEvents) {
   PageLoadTiming timing;
   timing.navigation_start = base::Time::FromDoubleT(
@@ -618,7 +655,8 @@
 
 TEST_F(MetricsWebContentsObserverTest, NoRappor) {
   rappor::TestSample::Shadow* sample_obj =
-      rappor_tester_.GetRecordedSampleForMetric(kRapporMetricsNameCoarseTiming);
+      embedder_interface_->GetRapporService()->GetRecordedSampleForMetric(
+          kRapporMetricsNameCoarseTiming);
   EXPECT_EQ(sample_obj, nullptr);
 }
 
@@ -638,7 +676,8 @@
   // Navigate again to force logging RAPPOR.
   web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
   rappor::TestSample::Shadow* sample_obj =
-      rappor_tester_.GetRecordedSampleForMetric(kRapporMetricsNameCoarseTiming);
+      embedder_interface_->GetRapporService()->GetRecordedSampleForMetric(
+          kRapporMetricsNameCoarseTiming);
   const auto& string_it = sample_obj->string_fields.find("Domain");
   EXPECT_NE(string_it, sample_obj->string_fields.end());
   EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)),
@@ -665,7 +704,8 @@
   // Navigate again to force logging RAPPOR.
   web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
   rappor::TestSample::Shadow* sample_obj =
-      rappor_tester_.GetRecordedSampleForMetric(kRapporMetricsNameCoarseTiming);
+      embedder_interface_->GetRapporService()->GetRecordedSampleForMetric(
+          kRapporMetricsNameCoarseTiming);
   const auto& string_it = sample_obj->string_fields.find("Domain");
   EXPECT_NE(string_it, sample_obj->string_fields.end());
   EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)),
diff --git a/components/password_manager/content/browser/content_password_manager_driver_factory.cc b/components/password_manager/content/browser/content_password_manager_driver_factory.cc
index 8a07ab9..222c743 100644
--- a/components/password_manager/content/browser/content_password_manager_driver_factory.cc
+++ b/components/password_manager/content/browser/content_password_manager_driver_factory.cc
@@ -89,8 +89,6 @@
 bool ContentPasswordManagerDriverFactory::OnMessageReceived(
     const IPC::Message& message,
     content::RenderFrameHost* render_frame_host) {
-  if (!render_frame_host->IsRenderFrameLive())
-    return false;
   return frame_driver_map_.find(render_frame_host)
       ->second->HandleMessage(message);
 }
@@ -99,11 +97,6 @@
     content::RenderFrameHost* render_frame_host,
     const content::LoadCommittedDetails& details,
     const content::FrameNavigateParams& params) {
-  // TODO(vabr): Remove those as soon as http://crbug.com/554479 is clarified.
-  CHECK(render_frame_host->IsRenderFrameLive());
-  CHECK(ContainsKey(frame_driver_map_, render_frame_host));
-  if (!render_frame_host->IsRenderFrameLive())
-    return;
   frame_driver_map_.find(render_frame_host)
       ->second->DidNavigateFrame(details, params);
 }
diff --git a/components/password_manager/core/browser/affiliation_utils.cc b/components/password_manager/core/browser/affiliation_utils.cc
index 8018ec4e..20f3be3 100644
--- a/components/password_manager/core/browser/affiliation_utils.cc
+++ b/components/password_manager/core/browser/affiliation_utils.cc
@@ -338,13 +338,18 @@
 
 std::string GetHumanReadableOrigin(const autofill::PasswordForm& password_form,
                                    const std::string& languages) {
-  password_manager::FacetURI facet_uri =
-      password_manager::FacetURI::FromPotentiallyInvalidSpec(
-          password_form.signon_realm);
+  FacetURI facet_uri =
+      FacetURI::FromPotentiallyInvalidSpec(password_form.signon_realm);
   if (facet_uri.IsValidAndroidFacetURI())
-    return facet_uri.scheme() + "://" + facet_uri.android_package_name();
+    return GetHumanReadableOriginForAndroidUri(facet_uri);
+
   return base::UTF16ToUTF8(url_formatter::FormatUrlForSecurityDisplay(
       password_form.origin, languages));
 }
 
+std::string GetHumanReadableOriginForAndroidUri(const FacetURI facet_uri) {
+  DCHECK(facet_uri.IsValidAndroidFacetURI());
+  return facet_uri.scheme() + "://" + facet_uri.android_package_name();
+}
+
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/affiliation_utils.h b/components/password_manager/core/browser/affiliation_utils.h
index 75821562..92a30cb 100644
--- a/components/password_manager/core/browser/affiliation_utils.h
+++ b/components/password_manager/core/browser/affiliation_utils.h
@@ -205,6 +205,9 @@
 std::string GetHumanReadableOrigin(const autofill::PasswordForm& password_form,
                                    const std::string& languages);
 
+// Returns the Android origin URI for presenting to a user.
+std::string GetHumanReadableOriginForAndroidUri(const FacetURI facet_uri);
+
 // For logging use only.
 std::ostream& operator<<(std::ostream& os, const FacetURI& facet_uri);
 
diff --git a/components/password_manager/core/browser/password_ui_utils.cc b/components/password_manager/core/browser/password_ui_utils.cc
index 2b9d99d..11d12df 100644
--- a/components/password_manager/core/browser/password_ui_utils.cc
+++ b/components/password_manager/core/browser/password_ui_utils.cc
@@ -8,6 +8,8 @@
 
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/core/browser/affiliation_utils.h"
 #include "components/url_formatter/elide_url.h"
 
 namespace password_manager {
@@ -19,9 +21,17 @@
 
 }  // namespace
 
-std::string GetShownOrigin(const GURL& url, const std::string& languages) {
-  std::string original = base::UTF16ToUTF8(
-      url_formatter::FormatUrlForSecurityDisplayOmitScheme(url, languages));
+std::string GetShownOrigin(const autofill::PasswordForm& password_form,
+                           const std::string& languages) {
+  password_manager::FacetURI facet_uri =
+      password_manager::FacetURI::FromPotentiallyInvalidSpec(
+          password_form.signon_realm);
+  if (facet_uri.IsValidAndroidFacetURI())
+    return GetHumanReadableOriginForAndroidUri(facet_uri);
+
+  std::string original =
+      base::UTF16ToUTF8(url_formatter::FormatUrlForSecurityDisplayOmitScheme(
+          password_form.origin, languages));
   base::StringPiece result = original;
   for (base::StringPiece prefix : kRemovedPrefixes) {
     if (base::StartsWith(result, prefix,
diff --git a/components/password_manager/core/browser/password_ui_utils.h b/components/password_manager/core/browser/password_ui_utils.h
index 48eb33f..b0cb41e7 100644
--- a/components/password_manager/core/browser/password_ui_utils.h
+++ b/components/password_manager/core/browser/password_ui_utils.h
@@ -11,12 +11,18 @@
 
 #include "url/gurl.h"
 
+namespace autofill {
+struct PasswordForm;
+}
+
 namespace password_manager {
 
 // Returns a string suitable for security display to the user (just like
-// |FormatUrlForSecurityDisplayOmitScheme| based on |url| and |languages|) and
-// without prefixes "m.", "mobile." or "www.".
-std::string GetShownOrigin(const GURL& url, const std::string& languages);
+// |FormatUrlForSecurityDisplayOmitScheme| based on origin of |password_form|
+// and |languages|) and without prefixes "m.", "mobile." or "www.". For Android
+// URIs, returns the result of GetHumanReadableOriginForAndroidUri.
+std::string GetShownOrigin(const autofill::PasswordForm& password_form,
+                           const std::string& languages);
 
 }  // namespace password_manager
 
diff --git a/components/password_manager/core/browser/password_ui_utils_unittest.cc b/components/password_manager/core/browser/password_ui_utils_unittest.cc
index 4af70178..25e4b59 100644
--- a/components/password_manager/core/browser/password_ui_utils_unittest.cc
+++ b/components/password_manager/core/browser/password_ui_utils_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "components/autofill/core/common/password_form.h"
 #include "components/password_manager/core/browser/password_ui_utils.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
@@ -29,9 +30,22 @@
       {"https://WWW.Example.DE", "example.de"}};
 
   for (const auto& test_case : kTestCases) {
-    EXPECT_EQ(test_case.output, GetShownOrigin(GURL(test_case.input), ""))
+    autofill::PasswordForm password_form;
+    password_form.signon_realm = "https://non.android.signon.com";
+    password_form.origin = GURL(test_case.input);
+    EXPECT_EQ(test_case.output, GetShownOrigin(password_form, ""))
         << "for input " << test_case.input;
   }
 }
 
+TEST(GetShownOriginTest, OriginFromAndroidForm) {
+  autofill::PasswordForm android_form;
+  android_form.signon_realm =
+      "android://"
+      "m3HSJL1i83hdltRq0-o9czGb-8KJDKra4t_"
+      "3JRlnPKcjI8PZm6XBHXx6zG4UuMXaDEZjR1wuXDre9G9zvN7AQw=="
+      "@com.example.android";
+  EXPECT_EQ(GetShownOrigin(android_form, ""), "android://com.example.android");
+}
+
 }  // namespace password_manager
diff --git a/components/pdf_viewer/DEPS b/components/pdf_viewer/DEPS
index d6857afc..b625831 100644
--- a/components/pdf_viewer/DEPS
+++ b/components/pdf_viewer/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+components/bitmap_uploader",
+  "+components/mus/common",
   "+components/mus/public",
   "+components/web_view/public",
   "+gpu/GLES2",
diff --git a/components/pdf_viewer/pdf_viewer.cc b/components/pdf_viewer/pdf_viewer.cc
index dcc5f93..5dc90974 100644
--- a/components/pdf_viewer/pdf_viewer.cc
+++ b/components/pdf_viewer/pdf_viewer.cc
@@ -7,8 +7,8 @@
 #include "base/containers/hash_tables.h"
 #include "base/memory/scoped_ptr.h"
 #include "components/bitmap_uploader/bitmap_uploader.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/cpp/scoped_window_ptr.h"
-#include "components/mus/public/cpp/types.h"
 #include "components/mus/public/cpp/window.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/mus/public/cpp/window_tree_connection.h"
diff --git a/components/policy/core/browser/BUILD.gn b/components/policy/core/browser/BUILD.gn
index 9352898..d528db6b 100644
--- a/components/policy/core/browser/BUILD.gn
+++ b/components/policy/core/browser/BUILD.gn
@@ -78,25 +78,25 @@
   }
 }
 
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "android/android_combined_policy_provider_unittest.cc",
-    "android/policy_converter_unittest.cc",
-    "autofill_policy_handler_unittest.cc",
-    "browser_policy_connector_unittest.cc",
-    "configuration_policy_handler_unittest.cc",
-    "configuration_policy_pref_store_unittest.cc",
-    "proxy_policy_handler_unittest.cc",
-    "url_blacklist_manager_unittest.cc",
-    "url_blacklist_policy_handler_unittest.cc",
-  ]
-  deps = [
-    "//components/url_formatter",
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-  if (enable_configuration_policy) {
-    deps += [ "//components/policy:policy_component_test_support" ]
+if (enable_configuration_policy) {
+  source_set("unit_tests") {
+    testonly = true
+    sources = [
+      "android/android_combined_policy_provider_unittest.cc",
+      "android/policy_converter_unittest.cc",
+      "autofill_policy_handler_unittest.cc",
+      "browser_policy_connector_unittest.cc",
+      "configuration_policy_handler_unittest.cc",
+      "configuration_policy_pref_store_unittest.cc",
+      "proxy_policy_handler_unittest.cc",
+      "url_blacklist_manager_unittest.cc",
+      "url_blacklist_policy_handler_unittest.cc",
+    ]
+    deps = [
+      "//components/policy:policy_component_test_support",
+      "//components/url_formatter",
+      "//testing/gmock",
+      "//testing/gtest",
+    ]
   }
 }
diff --git a/components/policy/core/common/BUILD.gn b/components/policy/core/common/BUILD.gn
index 2da67c2..744954a 100644
--- a/components/policy/core/common/BUILD.gn
+++ b/components/policy/core/common/BUILD.gn
@@ -211,76 +211,76 @@
   }
 }
 
-source_set("unit_tests") {
-  testonly = true
-  sources = [
-    "async_policy_provider_unittest.cc",
-    "cloud/cloud_policy_client_unittest.cc",
-    "cloud/cloud_policy_constants_unittest.cc",
-    "cloud/cloud_policy_core_unittest.cc",
-    "cloud/cloud_policy_manager_unittest.cc",
-    "cloud/cloud_policy_refresh_scheduler_unittest.cc",
-    "cloud/cloud_policy_service_unittest.cc",
-    "cloud/cloud_policy_validator_unittest.cc",
-    "cloud/component_cloud_policy_service_unittest.cc",
-    "cloud/component_cloud_policy_store_unittest.cc",
-    "cloud/component_cloud_policy_updater_unittest.cc",
-    "cloud/device_management_service_unittest.cc",
-    "cloud/external_policy_data_fetcher_unittest.cc",
-    "cloud/external_policy_data_updater_unittest.cc",
-    "cloud/policy_header_io_helper_unittest.cc",
-    "cloud/policy_header_service_unittest.cc",
-    "cloud/resource_cache_unittest.cc",
-    "cloud/user_cloud_policy_manager_unittest.cc",
-    "cloud/user_cloud_policy_store_unittest.cc",
-    "cloud/user_info_fetcher_unittest.cc",
-    "config_dir_policy_loader_unittest.cc",
-    "generate_policy_source_unittest.cc",
-    "policy_bundle_unittest.cc",
-    "policy_loader_ios_unittest.mm",
-    "policy_loader_mac_unittest.cc",
-    "policy_loader_win_unittest.cc",
-    "policy_map_unittest.cc",
-    "policy_service_impl_unittest.cc",
-    "policy_statistics_collector_unittest.cc",
-    "preg_parser_win_unittest.cc",
-    "registry_dict_win_unittest.cc",
-    "remote_commands/remote_commands_queue_unittest.cc",
-    "remote_commands/remote_commands_service_unittest.cc",
-    "schema_map_unittest.cc",
-    "schema_registry_tracking_policy_provider_unittest.cc",
-    "schema_registry_unittest.cc",
-    "schema_unittest.cc",
-  ]
-
-  if (is_chromeos) {
-    sources -= [
-      "cloud/user_cloud_policy_manager_unittest.cc",
-      "cloud/user_cloud_policy_store_unittest.cc",
-    ]
-  }
-
-  if (is_android) {
-    sources -= [ "async_policy_provider_unittest.cc" ]
-  }
-
-  if (is_android || is_ios) {
-    sources -= [
+if (enable_configuration_policy) {
+  source_set("unit_tests") {
+    testonly = true
+    sources = [
+      "async_policy_provider_unittest.cc",
+      "cloud/cloud_policy_client_unittest.cc",
+      "cloud/cloud_policy_constants_unittest.cc",
+      "cloud/cloud_policy_core_unittest.cc",
+      "cloud/cloud_policy_manager_unittest.cc",
+      "cloud/cloud_policy_refresh_scheduler_unittest.cc",
+      "cloud/cloud_policy_service_unittest.cc",
+      "cloud/cloud_policy_validator_unittest.cc",
       "cloud/component_cloud_policy_service_unittest.cc",
       "cloud/component_cloud_policy_store_unittest.cc",
       "cloud/component_cloud_policy_updater_unittest.cc",
+      "cloud/device_management_service_unittest.cc",
       "cloud/external_policy_data_fetcher_unittest.cc",
       "cloud/external_policy_data_updater_unittest.cc",
+      "cloud/policy_header_io_helper_unittest.cc",
+      "cloud/policy_header_service_unittest.cc",
       "cloud/resource_cache_unittest.cc",
+      "cloud/user_cloud_policy_manager_unittest.cc",
+      "cloud/user_cloud_policy_store_unittest.cc",
+      "cloud/user_info_fetcher_unittest.cc",
       "config_dir_policy_loader_unittest.cc",
+      "generate_policy_source_unittest.cc",
+      "policy_bundle_unittest.cc",
+      "policy_loader_ios_unittest.mm",
+      "policy_loader_mac_unittest.cc",
+      "policy_loader_win_unittest.cc",
+      "policy_map_unittest.cc",
+      "policy_service_impl_unittest.cc",
+      "policy_statistics_collector_unittest.cc",
+      "preg_parser_win_unittest.cc",
+      "registry_dict_win_unittest.cc",
+      "remote_commands/remote_commands_queue_unittest.cc",
+      "remote_commands/remote_commands_service_unittest.cc",
+      "schema_map_unittest.cc",
+      "schema_registry_tracking_policy_provider_unittest.cc",
+      "schema_registry_unittest.cc",
+      "schema_unittest.cc",
     ]
-  }
 
-  deps = [
-    "//testing/gmock",
-    "//testing/gtest",
-  ]
-  if (enable_configuration_policy) {
-    deps += [ "//components/policy:policy_component_test_support" ]
+    if (is_chromeos) {
+      sources -= [
+        "cloud/user_cloud_policy_manager_unittest.cc",
+        "cloud/user_cloud_policy_store_unittest.cc",
+      ]
+    }
+
+    if (is_android) {
+      sources -= [ "async_policy_provider_unittest.cc" ]
+    }
+
+    if (is_android || is_ios) {
+      sources -= [
+        "cloud/component_cloud_policy_service_unittest.cc",
+        "cloud/component_cloud_policy_store_unittest.cc",
+        "cloud/component_cloud_policy_updater_unittest.cc",
+        "cloud/external_policy_data_fetcher_unittest.cc",
+        "cloud/external_policy_data_updater_unittest.cc",
+        "cloud/resource_cache_unittest.cc",
+        "config_dir_policy_loader_unittest.cc",
+      ]
+    }
+
+    deps = [
+      "//components/policy:policy_component_test_support",
+      "//testing/gmock",
+      "//testing/gtest",
+    ]
   }
 }
diff --git a/components/policy/policy_common.gypi b/components/policy/policy_common.gypi
index 5e876ac..55573e6 100644
--- a/components/policy/policy_common.gypi
+++ b/components/policy/policy_common.gypi
@@ -141,7 +141,6 @@
         'core/common/schema_registry_tracking_policy_provider.cc',
         'core/common/schema_registry_tracking_policy_provider.h',
         'policy_export.h',
-        'policy/policy_risk_tag.h'
       ],
       'conditions': [
         ['OS=="android"', {
diff --git a/components/resources/dom_distiller_resources.grdp b/components/resources/dom_distiller_resources.grdp
index ef5b6093..cc1e30e 100644
--- a/components/resources/dom_distiller_resources.grdp
+++ b/components/resources/dom_distiller_resources.grdp
@@ -8,7 +8,9 @@
   <include name="IDR_DISTILLER_JS" file="../dom_distiller/core/javascript/domdistiller.js" flattenhtml="true" type="BINDATA" />
   <include name="IDR_DISTILLER_CSS" file="../dom_distiller/core/css/distilledpage.css" type="BINDATA" />
   <include name="IDR_DISTILLER_IOS_CSS" file="../dom_distiller/core/css/distilledpage_ios.css" type="BINDATA" />
+  <include name="IDR_DISTILLER_LOADING_IMAGE" file="../dom_distiller/core/images/dom_distiller_material_spinner.svg" type="BINDATA" />
   <include name="IDR_IS_DISTILLABLE_JS" file="../dom_distiller/core/javascript/is_distillable_trigger.js" type="BINDATA" />
   <include name="IDR_EXTRACT_PAGE_FEATURES_JS" file="../dom_distiller/core/javascript/extract_features.js" type="BINDATA" />
   <include name="IDR_DISTILLABLE_PAGE_SERIALIZED_MODEL" file="../dom_distiller/core/data/distillable_page_model.bin" type="BINDATA" />
+  <include name="IDR_DISTILLABLE_PAGE_SERIALIZED_MODEL_NEW" file="../dom_distiller/core/data/distillable_page_model_new.bin" type="BINDATA" />
 </grit-part>
diff --git a/components/search_engines.gypi b/components/search_engines.gypi
index d1a34df..64ddbe9 100644
--- a/components/search_engines.gypi
+++ b/components/search_engines.gypi
@@ -44,6 +44,8 @@
         'search_engines/default_search_policy_handler.h',
         'search_engines/default_search_pref_migration.cc',
         'search_engines/default_search_pref_migration.h',
+        'search_engines/detect_desktop_search_win.cc',
+        'search_engines/detect_desktop_search_win.h',
         'search_engines/keyword_table.cc',
         'search_engines/keyword_table.h',
         'search_engines/keyword_web_data_service.cc',
diff --git a/components/search_engines/BUILD.gn b/components/search_engines/BUILD.gn
index 478b1e71..3176fc6 100644
--- a/components/search_engines/BUILD.gn
+++ b/components/search_engines/BUILD.gn
@@ -11,6 +11,8 @@
     "default_search_manager.h",
     "default_search_pref_migration.cc",
     "default_search_pref_migration.h",
+    "detect_desktop_search_win.cc",
+    "detect_desktop_search_win.h",
     "keyword_table.cc",
     "keyword_table.h",
     "keyword_web_data_service.cc",
@@ -100,6 +102,7 @@
   sources = [
     "default_search_manager_unittest.cc",
     "default_search_pref_migration_unittest.cc",
+    "detect_desktop_search_win_unittest.cc",
     "keyword_table_unittest.cc",
     "search_host_to_urls_map_unittest.cc",
     "template_url_prepopulate_data_unittest.cc",
diff --git a/components/search_engines/DEPS b/components/search_engines/DEPS
index 91a1059c..aef4d1b 100644
--- a/components/search_engines/DEPS
+++ b/components/search_engines/DEPS
@@ -3,6 +3,8 @@
   "+components/history/core",
   "+components/keyed_service/core",
   "+components/metrics/proto",
+  # TODO(mpearson): for experiment; remove after crbug.com/488901 is launched.
+  "+components/omnibox/browser/omnibox_field_trial.h",
   "+components/policy/core",
   "+components/pref_registry",
   "+components/rappor",
diff --git a/components/search_engines/detect_desktop_search_win.cc b/components/search_engines/detect_desktop_search_win.cc
new file mode 100644
index 0000000..563e80d
--- /dev/null
+++ b/components/search_engines/detect_desktop_search_win.cc
@@ -0,0 +1,48 @@
+// Copyright 2015 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 "components/search_engines/detect_desktop_search_win.h"
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_util.h"
+#include "components/search_engines/prepopulated_engines.h"
+#include "components/search_engines/template_url.h"
+#include "components/search_engines/template_url_prepopulate_data.h"
+#include "net/base/url_util.h"
+
+bool DetectWindowsDesktopSearch(const GURL& url,
+                                const SearchTermsData& search_terms_data,
+                                base::string16* search_terms) {
+  DCHECK(search_terms);
+
+  scoped_ptr<TemplateURLData> template_url_data =
+      TemplateURLPrepopulateData::MakeTemplateURLDataFromPrepopulatedEngine(
+          TemplateURLPrepopulateData::bing);
+  TemplateURL template_url(*template_url_data);
+
+  if (!template_url.ExtractSearchTermsFromURL(url, search_terms_data,
+                                              search_terms))
+    return false;
+
+  // Query parameter that tells the source of a Bing search URL, and values
+  // associated with Windows desktop search.
+  const char kBingSourceQueryKey[] = "form";
+  const char kBingSourceDesktopText[] = "WNSGPH";
+  const char kBingSourceDesktopVoice[] = "WNSBOX";
+
+  for (net::QueryIterator it(url); !it.IsAtEnd(); it.Advance()) {
+    // Use a case-insensitive comparison because the key is sometimes in capital
+    // letters.
+    if (base::EqualsCaseInsensitiveASCII(it.GetKey(), kBingSourceQueryKey)) {
+      std::string source = it.GetValue();
+      if (source == kBingSourceDesktopText || source == kBingSourceDesktopVoice)
+        return true;
+    }
+  }
+
+  search_terms->clear();
+  return false;
+}
diff --git a/components/search_engines/detect_desktop_search_win.h b/components/search_engines/detect_desktop_search_win.h
new file mode 100644
index 0000000..3d648a62
--- /dev/null
+++ b/components/search_engines/detect_desktop_search_win.h
@@ -0,0 +1,19 @@
+// Copyright 2015 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.
+
+#ifndef COMPONENTS_SEARCH_ENGINES_DETECT_DESKTOP_SEARCH_WIN_H_
+#define COMPONENTS_SEARCH_ENGINES_DETECT_DESKTOP_SEARCH_WIN_H_
+
+#include "base/strings/string16.h"
+
+class GURL;
+class SearchTermsData;
+
+// Detects whether a URL comes from a Windows Desktop search. If so, puts the
+// search terms in |search_terms| and returns true.
+bool DetectWindowsDesktopSearch(const GURL& url,
+                                const SearchTermsData& search_terms_data,
+                                base::string16* search_terms);
+
+#endif  // COMPONENTS_SEARCH_ENGINES_DETECT_DESKTOP_SEARCH_WIN_H_
diff --git a/components/search_engines/detect_desktop_search_win_unittest.cc b/components/search_engines/detect_desktop_search_win_unittest.cc
new file mode 100644
index 0000000..e3477a6
--- /dev/null
+++ b/components/search_engines/detect_desktop_search_win_unittest.cc
@@ -0,0 +1,45 @@
+// Copyright 2015 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 "components/search_engines/detect_desktop_search_win.h"
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/search_engines/testing_search_terms_data.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace {
+struct DetectWindowsDesktopSearchTestData {
+  const char* url;
+  const wchar_t* expected_search_terms;
+};
+}  // namespace
+
+TEST(DetectWindowsDesktopSearch, DetectWindowsDesktopSearch) {
+  const DetectWindowsDesktopSearchTestData test_data[] = {
+      {"https://www.google.com", L""},
+      {"https://www.bing.com/search", L""},
+      {"https://www.bing.com/search?q=keyword&form=QBLH", L""},
+      {"https://www.bing.com/search?q=keyword&form=WNSGPH", L"keyword"},
+      {"https://www.bing.com/search?q=keyword&form=WNSBOX", L"keyword"},
+      {"https://www.bing.com/search?q=keyword&FORM=WNSGPH", L"keyword"},
+      {"https://www.bing.com/search?q=keyword&FORM=WNSBOX", L"keyword"},
+      {"https://www.bing.com/search?form=WNSGPH&q=keyword", L"keyword"},
+      {"https://www.bing.com/search?q=keyword&form=WNSGPH&other=stuff",
+       L"keyword"},
+      {"https://www.bing.com/search?q=%C3%A8+%C3%A9&form=WNSGPH", L"\xE8 \xE9"},
+  };
+
+  for (size_t i = 0; i < arraysize(test_data); ++i) {
+    TestingSearchTermsData search_terms_data("https://www.google.com");
+    base::string16 search_terms;
+    bool is_desktop_search = DetectWindowsDesktopSearch(
+        GURL(test_data[i].url), search_terms_data, &search_terms);
+    const base::string16 expected_search_terms(
+        test_data[i].expected_search_terms);
+    EXPECT_EQ(!expected_search_terms.empty(), is_desktop_search);
+    EXPECT_EQ(expected_search_terms, search_terms);
+  }
+}
diff --git a/components/search_engines/search_engines_switches.cc b/components/search_engines/search_engines_switches.cc
index 190662c..f15afa7a 100644
--- a/components/search_engines/search_engines_switches.cc
+++ b/components/search_engines/search_engines_switches.cc
@@ -10,4 +10,10 @@
 // testing.
 const char kExtraSearchQueryParams[] = "extra-search-query-params";
 
+#if defined(OS_WIN)
+// Use the default search provider for desktop search.
+const char kUseDefaultSearchProviderForDesktopSearch[] =
+    "use-default-search-provider-for-desktop-search";
+#endif  // defined(OS_WIN)
+
 }  // namespace switches
diff --git a/components/search_engines/search_engines_switches.h b/components/search_engines/search_engines_switches.h
index 42b9253e..fc3ab109 100644
--- a/components/search_engines/search_engines_switches.h
+++ b/components/search_engines/search_engines_switches.h
@@ -5,10 +5,16 @@
 #ifndef COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINES_SWITCHES_H_
 #define COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINES_SWITCHES_H_
 
+#include "build/build_config.h"
+
 namespace switches {
 
 extern const char kExtraSearchQueryParams[];
 
+#if defined(OS_WIN)
+extern const char kUseDefaultSearchProviderForDesktopSearch[];
+#endif  // defined(OS_WIN)
+
 }  // namespace switches
 
 #endif  // COMPONENTS_SEARCH_ENGINES_SEARCH_ENGINES_SWITCHES_H_
diff --git a/components/search_engines/template_url_prepopulate_data.cc b/components/search_engines/template_url_prepopulate_data.cc
index eed0465..3edbcd4 100644
--- a/components/search_engines/template_url_prepopulate_data.cc
+++ b/components/search_engines/template_url_prepopulate_data.cc
@@ -1079,34 +1079,6 @@
   return t_urls.Pass();
 }
 
-scoped_ptr<TemplateURLData>
-    MakePrepopulatedTemplateURLDataFromPrepopulateEngine(
-        const PrepopulatedEngine& engine) {
-  base::ListValue alternate_urls;
-  if (engine.alternate_urls) {
-    for (size_t i = 0; i < engine.alternate_urls_size; ++i)
-      alternate_urls.AppendString(std::string(engine.alternate_urls[i]));
-  }
-
-  return MakePrepopulatedTemplateURLData(base::WideToUTF16(engine.name),
-                                         base::WideToUTF16(engine.keyword),
-                                         engine.search_url,
-                                         engine.suggest_url,
-                                         engine.instant_url,
-                                         engine.image_url,
-                                         engine.new_tab_url,
-                                         engine.contextual_search_url,
-                                         engine.search_url_post_params,
-                                         engine.suggest_url_post_params,
-                                         engine.instant_url_post_params,
-                                         engine.image_url_post_params,
-                                         engine.favicon_url,
-                                         engine.encoding,
-                                         alternate_urls,
-                                         engine.search_terms_replacement_key,
-                                         engine.id);
-}
-
 bool SameDomain(const GURL& given_url, const GURL& prepopulated_url) {
   return prepopulated_url.is_valid() &&
       net::registry_controlled_domains::SameDomainOrHost(
@@ -1145,12 +1117,30 @@
   size_t num_engines;
   GetPrepopulationSetFromCountryID(prefs, &engines, &num_engines);
   for (size_t i = 0; i != num_engines; ++i) {
-    t_urls.push_back(MakePrepopulatedTemplateURLDataFromPrepopulateEngine(
-                         *engines[i]).release());
+    t_urls.push_back(
+        MakeTemplateURLDataFromPrepopulatedEngine(*engines[i]).release());
   }
   return t_urls.Pass();
 }
 
+scoped_ptr<TemplateURLData> MakeTemplateURLDataFromPrepopulatedEngine(
+    const PrepopulatedEngine& engine) {
+  base::ListValue alternate_urls;
+  if (engine.alternate_urls) {
+    for (size_t i = 0; i < engine.alternate_urls_size; ++i)
+      alternate_urls.AppendString(std::string(engine.alternate_urls[i]));
+  }
+
+  return MakePrepopulatedTemplateURLData(
+      base::WideToUTF16(engine.name), base::WideToUTF16(engine.keyword),
+      engine.search_url, engine.suggest_url, engine.instant_url,
+      engine.image_url, engine.new_tab_url, engine.contextual_search_url,
+      engine.search_url_post_params, engine.suggest_url_post_params,
+      engine.instant_url_post_params, engine.image_url_post_params,
+      engine.favicon_url, engine.encoding, alternate_urls,
+      engine.search_terms_replacement_key, engine.id);
+}
+
 void ClearPrepopulatedEnginesInPrefs(PrefService* prefs) {
   if (!prefs)
     return;
diff --git a/components/search_engines/template_url_prepopulate_data.h b/components/search_engines/template_url_prepopulate_data.h
index 65230f56..0b22aad8 100644
--- a/components/search_engines/template_url_prepopulate_data.h
+++ b/components/search_engines/template_url_prepopulate_data.h
@@ -26,6 +26,8 @@
 
 namespace TemplateURLPrepopulateData {
 
+struct PrepopulatedEngine;
+
 extern const int kMaxPrepopulatedEngineID;
 
 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
@@ -42,6 +44,10 @@
     PrefService* prefs,
     size_t* default_search_provider_index);
 
+// Returns a TemplateURLData for the specified prepopulated engine.
+scoped_ptr<TemplateURLData> MakeTemplateURLDataFromPrepopulatedEngine(
+    const PrepopulatedEngine& engine);
+
 // Removes prepopulated engines and their version stored in user prefs.
 void ClearPrepopulatedEnginesInPrefs(PrefService* prefs);
 
diff --git a/components/search_engines/template_url_service.cc b/components/search_engines/template_url_service.cc
index 3402ce3..908f7d9 100644
--- a/components/search_engines/template_url_service.cc
+++ b/components/search_engines/template_url_service.cc
@@ -22,6 +22,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/default_clock.h"
 #include "base/time/time.h"
+#include "components/omnibox/browser/omnibox_field_trial.h"
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "components/rappor/rappor_service.h"
 #include "components/search_engines/search_engines_pref_names.h"
@@ -149,8 +150,42 @@
   UMA_HISTOGRAM_COUNTS_100("Search.SearchEngineDuplicateCounts", num_dupes);
 }
 
-}  // namespace
+// Returns the length of the registry portion of a hostname.  For example,
+// www.google.co.uk will return 5 (the length of co.uk).
+size_t GetRegistryLength(const base::string16& host) {
+  return net::registry_controlled_domains::GetRegistryLength(
+      base::UTF16ToUTF8(host),
+      net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
+      net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
+}
 
+// Returns the domain name (including registry) of a hostname.  For example,
+// www.google.co.uk will return google.co.uk.
+base::string16 GetDomainAndRegistry(const base::string16& host) {
+  return base::UTF8ToUTF16(
+      net::registry_controlled_domains::GetDomainAndRegistry(
+          base::UTF16ToUTF8(host),
+          net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES));
+}
+
+// Returns the length of the important part of the |keyword|, assumed to be
+// associated with the TemplateURL.  For instance, for the keyword
+// google.co.uk, this can return 6 (the length of "google").
+size_t GetMeaningfulKeywordLength(const base::string16& keyword,
+                                  const TemplateURL* turl) {
+  if (OmniboxFieldTrial::KeywordRequiresRegistry())
+    return keyword.length();
+  const size_t registry_length = GetRegistryLength(keyword);
+  if (registry_length == std::string::npos)
+    return keyword.length();
+  DCHECK_LT(registry_length, keyword.length());
+  // The meaningful keyword length is the length of any portion before the
+  // registry ("co.uk") and its preceding dot.
+  return keyword.length() - (registry_length ? (registry_length + 1) : 0);
+
+}
+
+}  // namespace
 
 // TemplateURLService::LessWithPrefix -----------------------------------------
 
@@ -168,9 +203,10 @@
   // Unfortunately the calling convention is not "prefix and element" but
   // rather "two elements", so we pass the prefix as a fake "element" which has
   // a NULL KeywordDataElement pointer.
-  bool operator()(const KeywordToTemplateMap::value_type& elem1,
-                  const KeywordToTemplateMap::value_type& elem2) const {
-    return (elem1.second == NULL) ?
+  bool operator()(
+      const KeywordToTURLAndMeaningfulLength::value_type& elem1,
+      const KeywordToTURLAndMeaningfulLength::value_type& elem2) const {
+    return (elem1.second.first == NULL) ?
         (elem2.first.compare(0, elem1.first.length(), elem1.first) > 0) :
         (elem1.first < elem2.first);
   }
@@ -344,44 +380,29 @@
       CanAddAutogeneratedKeywordForHost(url.host());
 }
 
-void TemplateURLService::FindMatchingKeywords(
+void TemplateURLService::AddMatchingKeywords(
     const base::string16& prefix,
-    bool support_replacement_only,
-    TemplateURLVector* matches) {
-  // Sanity check args.
-  if (prefix.empty())
-    return;
-  DCHECK(matches != NULL);
-  DCHECK(matches->empty());  // The code for exact matches assumes this.
+    bool supports_replacement_only,
+    TURLsAndMeaningfulLengths* matches) {
+  AddMatchingKeywordsHelper(
+      keyword_to_turl_and_length_, prefix, supports_replacement_only, matches);
+}
 
-  // Required for VS2010: http://connect.microsoft.com/VisualStudio/feedback/details/520043/error-converting-from-null-to-a-pointer-type-in-std-pair
-  TemplateURL* const kNullTemplateURL = NULL;
-
-  // Find matching keyword range.  Searches the element map for keywords
-  // beginning with |prefix| and stores the endpoints of the resulting set in
-  // |match_range|.
-  const std::pair<KeywordToTemplateMap::const_iterator,
-                  KeywordToTemplateMap::const_iterator> match_range(
-      std::equal_range(
-          keyword_to_template_map_.begin(), keyword_to_template_map_.end(),
-          KeywordToTemplateMap::value_type(prefix, kNullTemplateURL),
-          LessWithPrefix()));
-
-  // Return vector of matching keywords.
-  for (KeywordToTemplateMap::const_iterator i(match_range.first);
-       i != match_range.second; ++i) {
-    if (!support_replacement_only ||
-        i->second->url_ref().SupportsReplacement(search_terms_data()))
-      matches->push_back(i->second);
-  }
+void TemplateURLService::AddMatchingDomainKeywords(
+    const base::string16& prefix,
+    bool supports_replacement_only,
+    TURLsAndMeaningfulLengths* matches) {
+  AddMatchingKeywordsHelper(
+      keyword_domain_to_turl_and_length_, prefix, supports_replacement_only,
+      matches);
 }
 
 TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
     const base::string16& keyword) {
-  KeywordToTemplateMap::const_iterator elem(
-      keyword_to_template_map_.find(keyword));
-  if (elem != keyword_to_template_map_.end())
-    return elem->second;
+  KeywordToTURLAndMeaningfulLength::const_iterator elem(
+      keyword_to_turl_and_length_.find(keyword));
+  if (elem != keyword_to_turl_and_length_.end())
+    return elem->second.first;
   return (!loaded_ &&
       initial_default_search_provider_.get() &&
       (initial_default_search_provider_->keyword() == keyword)) ?
@@ -390,8 +411,8 @@
 
 TemplateURL* TemplateURLService::GetTemplateURLForGUID(
     const std::string& sync_guid) {
-  GUIDToTemplateMap::const_iterator elem(guid_to_template_map_.find(sync_guid));
-  if (elem != guid_to_template_map_.end())
+  GUIDToTURL::const_iterator elem(guid_to_turl_.find(sync_guid));
+  if (elem != guid_to_turl_.end())
     return elem->second;
   return (!loaded_ &&
       initial_default_search_provider_.get() &&
@@ -1413,8 +1434,8 @@
 
 void TemplateURLService::RemoveFromMaps(TemplateURL* template_url) {
   const base::string16& keyword = template_url->keyword();
-  DCHECK_NE(0U, keyword_to_template_map_.count(keyword));
-  if (keyword_to_template_map_[keyword] == template_url) {
+  DCHECK_NE(0U, keyword_to_turl_and_length_.count(keyword));
+  if (keyword_to_turl_and_length_[keyword].first == template_url) {
     // We need to check whether the keyword can now be provided by another
     // TemplateURL.  See the comments in AddToMaps() for more information on
     // extension keywords and how they can coexist with non-extension keywords.
@@ -1434,17 +1455,20 @@
             (turl->id() > best_fallback->id()))))
         best_fallback = turl;
     }
-    if (best_fallback)
-      keyword_to_template_map_[keyword] = best_fallback;
-    else
-      keyword_to_template_map_.erase(keyword);
+    RemoveFromDomainMap(template_url);
+    if (best_fallback) {
+      AddToMap(best_fallback);
+      AddToDomainMap(best_fallback);
+    } else {
+      keyword_to_turl_and_length_.erase(keyword);
+    }
   }
 
   if (template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION)
     return;
 
   if (!template_url->sync_guid().empty())
-    guid_to_template_map_.erase(template_url->sync_guid());
+    guid_to_turl_.erase(template_url->sync_guid());
   // |provider_map_| is only initialized after loading has completed.
   if (loaded_) {
     provider_map_->Remove(template_url);
@@ -1455,12 +1479,13 @@
   bool template_url_is_omnibox_api =
       template_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
   const base::string16& keyword = template_url->keyword();
-  KeywordToTemplateMap::const_iterator i =
-      keyword_to_template_map_.find(keyword);
-  if (i == keyword_to_template_map_.end()) {
-    keyword_to_template_map_[keyword] = template_url;
+  KeywordToTURLAndMeaningfulLength::const_iterator i =
+      keyword_to_turl_and_length_.find(keyword);
+  if (i == keyword_to_turl_and_length_.end()) {
+    AddToMap(template_url);
+    AddToDomainMap(template_url);
   } else {
-    const TemplateURL* existing_url = i->second;
+    const TemplateURL* existing_url = i->second.first;
     // We should only have overlapping keywords when at least one comes from
     // an extension.  In that case, the ranking order is:
     //   Manually-modified keywords > extension keywords > replaceable keywords
@@ -1469,20 +1494,57 @@
         existing_url->GetType() == TemplateURL::OMNIBOX_API_EXTENSION;
     DCHECK(existing_url_is_omnibox_api || template_url_is_omnibox_api);
     if (existing_url_is_omnibox_api ?
-        !CanReplace(template_url) : CanReplace(existing_url))
-      keyword_to_template_map_[keyword] = template_url;
+        !CanReplace(template_url) : CanReplace(existing_url)) {
+      RemoveFromDomainMap(existing_url);
+      AddToMap(template_url);
+      AddToDomainMap(template_url);
+    }
   }
 
   if (template_url_is_omnibox_api)
     return;
 
   if (!template_url->sync_guid().empty())
-    guid_to_template_map_[template_url->sync_guid()] = template_url;
+    guid_to_turl_[template_url->sync_guid()] = template_url;
   // |provider_map_| is only initialized after loading has completed.
   if (loaded_)
     provider_map_->Add(template_url, search_terms_data());
 }
 
+void TemplateURLService::RemoveFromDomainMap(const TemplateURL* template_url) {
+  const base::string16 domain = GetDomainAndRegistry(template_url->keyword());
+  if (domain.empty())
+    return;
+
+  const auto match_range(
+      keyword_domain_to_turl_and_length_.equal_range(domain));
+  for (auto it(match_range.first); it != match_range.second; ) {
+    if (it->second.first == template_url)
+      it = keyword_domain_to_turl_and_length_.erase(it);
+    else
+      ++it;
+  }
+}
+
+void TemplateURLService::AddToDomainMap(TemplateURL* template_url) {
+  const base::string16 domain = GetDomainAndRegistry(template_url->keyword());
+  // Only bother adding an entry to the domain map if its key in the domain
+  // map would be different from the key in the regular map.
+  if (domain != template_url->keyword()) {
+    keyword_domain_to_turl_and_length_.insert(std::make_pair(
+        domain,
+        TURLAndMeaningfulLength(
+            template_url, GetMeaningfulKeywordLength(domain, template_url))));
+  }
+}
+
+void TemplateURLService::AddToMap(TemplateURL* template_url) {
+  const base::string16& keyword = template_url->keyword();
+  keyword_to_turl_and_length_[keyword] =
+      TURLAndMeaningfulLength(
+          template_url, GetMeaningfulKeywordLength(keyword, template_url));
+}
+
 // Helper for partition() call in next function.
 bool HasValidID(TemplateURL* t_url) {
   return t_url->id() != kInvalidTemplateURLID;
@@ -1593,9 +1655,10 @@
   DCHECK_NE(TemplateURL::OMNIBOX_API_EXTENSION, existing_turl->GetType());
 
   base::string16 old_keyword(existing_turl->keyword());
-  keyword_to_template_map_.erase(old_keyword);
+  keyword_to_turl_and_length_.erase(old_keyword);
+  RemoveFromDomainMap(existing_turl);
   if (!existing_turl->sync_guid().empty())
-    guid_to_template_map_.erase(existing_turl->sync_guid());
+    guid_to_turl_.erase(existing_turl->sync_guid());
 
   // |provider_map_| is only initialized after loading has completed.
   if (loaded_)
@@ -1610,10 +1673,11 @@
   }
 
   const base::string16& keyword = existing_turl->keyword();
-  KeywordToTemplateMap::const_iterator i =
-      keyword_to_template_map_.find(keyword);
-  if (i == keyword_to_template_map_.end()) {
-    keyword_to_template_map_[keyword] = existing_turl;
+  KeywordToTURLAndMeaningfulLength::const_iterator i =
+      keyword_to_turl_and_length_.find(keyword);
+  if (i == keyword_to_turl_and_length_.end()) {
+    AddToMap(existing_turl);
+    AddToDomainMap(existing_turl);
   } else {
     // We can theoretically reach here in two cases:
     //   * There is an existing extension keyword and sync brings in a rename of
@@ -1623,21 +1687,24 @@
     //     at load time causes it to conflict with an existing keyword.  In this
     //     case we delete the existing keyword if it's replaceable, or else undo
     //     the change in keyword for |existing_turl|.
-    TemplateURL* existing_keyword_turl = i->second;
+    TemplateURL* existing_keyword_turl = i->second.first;
     if (existing_keyword_turl->GetType() != TemplateURL::NORMAL) {
-      if (!CanReplace(existing_turl))
-        keyword_to_template_map_[keyword] = existing_turl;
+      if (!CanReplace(existing_turl)) {
+        AddToMap(existing_turl);
+        AddToDomainMap(existing_turl);
+      }
     } else {
       if (CanReplace(existing_keyword_turl)) {
         RemoveNoNotify(existing_keyword_turl);
       } else {
         existing_turl->data_.SetKeyword(old_keyword);
-        keyword_to_template_map_[old_keyword] = existing_turl;
+        AddToMap(existing_turl);
+        AddToDomainMap(existing_turl);
       }
     }
   }
   if (!existing_turl->sync_guid().empty())
-    guid_to_template_map_[existing_turl->sync_guid()] = existing_turl;
+    guid_to_turl_[existing_turl->sync_guid()] = existing_turl;
 
   if (web_data_service_.get())
     web_data_service_->UpdateKeyword(existing_turl->data());
@@ -1754,18 +1821,18 @@
     if (t_url->HasGoogleBaseURLs(search_terms_data())) {
       TemplateURL updated_turl(t_url->data());
       updated_turl.ResetKeywordIfNecessary(search_terms_data(), false);
-      KeywordToTemplateMap::const_iterator existing_entry =
-          keyword_to_template_map_.find(updated_turl.keyword());
-      if ((existing_entry != keyword_to_template_map_.end()) &&
-          (existing_entry->second != t_url)) {
+      KeywordToTURLAndMeaningfulLength::const_iterator existing_entry =
+          keyword_to_turl_and_length_.find(updated_turl.keyword());
+      if ((existing_entry != keyword_to_turl_and_length_.end()) &&
+          (existing_entry->second.first != t_url)) {
         // The new autogenerated keyword conflicts with another TemplateURL.
         // Overwrite it if it's replaceable; otherwise, leave |t_url| using its
         // current keyword.  (This will not prevent |t_url| from auto-updating
         // the keyword in the future if the conflicting TemplateURL disappears.)
         // Note that we must still update |t_url| in this case, or the
         // |provider_map_| will not be updated correctly.
-        if (CanReplace(existing_entry->second))
-          RemoveNoNotify(existing_entry->second);
+        if (CanReplace(existing_entry->second.first))
+          RemoveNoNotify(existing_entry->second.first);
         else
           updated_turl.data_.SetKeyword(t_url->keyword());
       }
@@ -1964,7 +2031,7 @@
       web_data_service_->AddKeyword(template_url->data());
 
     // Inform sync of the addition. Note that this will assign a GUID to
-    // template_url and add it to the guid_to_template_map_.
+    // template_url and add it to the guid_to_turl_.
     ProcessTemplateURLChange(FROM_HERE,
                              template_url,
                              syncer::SyncChange::ACTION_ADD);
@@ -2280,6 +2347,35 @@
     default_search_manager_.SetUserSelectedDefaultSearchEngine(turl->data());
 }
 
+template <typename Container>
+void TemplateURLService::AddMatchingKeywordsHelper(
+    const Container& keyword_to_turl_and_length,
+    const base::string16& prefix,
+    bool supports_replacement_only,
+    TURLsAndMeaningfulLengths* matches) {
+  // Sanity check args.
+  if (prefix.empty())
+    return;
+  DCHECK(matches);
+
+  // Find matching keyword range.  Searches the element map for keywords
+  // beginning with |prefix| and stores the endpoints of the resulting set in
+  // |match_range|.
+  const auto match_range(std::equal_range(
+      keyword_to_turl_and_length.begin(), keyword_to_turl_and_length.end(),
+      typename Container::value_type(prefix,
+                                     TURLAndMeaningfulLength(nullptr, 0)),
+      LessWithPrefix()));
+
+  // Add to vector of matching keywords.
+  for (typename Container::const_iterator i(match_range.first);
+    i != match_range.second; ++i) {
+    if (!supports_replacement_only ||
+        i->second.first->url_ref().SupportsReplacement(search_terms_data()))
+      matches->push_back(i->second);
+  }
+}
+
 TemplateURL* TemplateURLService::FindPrepopulatedTemplateURL(
     int prepopulated_id) {
   for (TemplateURLVector::const_iterator i = template_urls_.begin();
diff --git a/components/search_engines/template_url_service.h b/components/search_engines/template_url_service.h
index f77879c..2bac422 100644
--- a/components/search_engines/template_url_service.h
+++ b/components/search_engines/template_url_service.h
@@ -72,10 +72,18 @@
                            public KeyedService,
                            public syncer::SyncableService {
  public:
-  typedef std::map<std::string, std::string> QueryTerms;
-  typedef std::vector<TemplateURL*> TemplateURLVector;
-  typedef std::map<std::string, syncer::SyncData> SyncDataMap;
-  typedef base::CallbackList<void(void)>::Subscription Subscription;
+  using QueryTerms = std::map<std::string, std::string>;
+  using TemplateURLVector = std::vector<TemplateURL*>;
+  using SyncDataMap = std::map<std::string, syncer::SyncData>;
+  using Subscription = base::CallbackList<void(void)>::Subscription;
+
+  // We may want to treat the keyword in a TemplateURL as being a different
+  // length than it actually is.  For example, for keywords that end in a
+  // registry, e.g., '.com', we want to consider the registry characters as not
+  // a meaningful part of the keyword and not penalize for the user not typing
+  // those.)
+  using TURLAndMeaningfulLength = std::pair<TemplateURL*, size_t>;
+  using TURLsAndMeaningfulLengths = std::vector<TURLAndMeaningfulLength>;
 
   // Struct used for initializing the data store with fake data.
   // Each initializer is mapped to a TemplateURL.
@@ -120,12 +128,23 @@
                                   const GURL& url,
                                   TemplateURL** template_url_to_replace);
 
-  // Returns (in |matches|) all TemplateURLs whose keywords begin with |prefix|,
-  // sorted shortest keyword-first. If |support_replacement_only| is true, only
+  // Adds to |matches| all TemplateURLs whose keywords begin with |prefix|,
+  // sorted shortest-keyword-first. If |supports_replacement_only| is true, only
   // TemplateURLs that support replacement are returned.
-  void FindMatchingKeywords(const base::string16& prefix,
-                            bool support_replacement_only,
-                            TemplateURLVector* matches);
+  void AddMatchingKeywords(const base::string16& prefix,
+                           bool supports_replacement_only,
+                           TURLsAndMeaningfulLengths* matches);
+
+  // Adds to |matches| all TemplateURLs for search engines with the domain
+  // name part of the keyword starts with |prefix|, sorted
+  // shortest-domain-name-first. If |supports_replacement_only| is true, only
+  // TemplateURLs that support replacement are returned.  Does not bother
+  // searching/returning keywords that would've been found with an identical
+  // call to FindMatchingKeywords(); i.e., doesn't search keywords for which
+  // the domain name is the keyword.
+  void AddMatchingDomainKeywords(const base::string16& prefix,
+                                 bool supports_replacement_only,
+                                 TURLsAndMeaningfulLengths* matches);
 
   // Looks up |keyword| and returns the element it maps to.  Returns NULL if
   // the keyword was not found.
@@ -382,8 +401,22 @@
   friend class InstantUnitTestBase;
   friend class TemplateURLServiceTestUtil;
 
-  typedef std::map<base::string16, TemplateURL*> KeywordToTemplateMap;
-  typedef std::map<std::string, TemplateURL*> GUIDToTemplateMap;
+  using GUIDToTURL = std::map<std::string, TemplateURL*>;
+
+  // A mapping from keywords to the corresponding TemplateURLs and their
+  // meaningful keyword lengths.  A keyword can appear only once here because
+  // there can be only one active TemplateURL associated with a given keyword.
+  using KeywordToTURLAndMeaningfulLength =
+      std::map<base::string16, TURLAndMeaningfulLength>;
+
+  // A mapping from domain names to corresponding TemplateURLs and their
+  // meaningful keyword lengths.  Specifically, for a keyword that is a
+  // hostname containing more than just a domain name, e.g., 'abc.def.com',
+  // the keyword is added to this map under the domain key 'def.com'.  This
+  // means multiple keywords from the same domain share the same key, so this
+  // must be a multimap.
+  using KeywordDomainToTURLAndMeaningfulLength =
+      std::multimap<base::string16, TURLAndMeaningfulLength>;
 
   // Declaration of values to be used in an enumerated histogram to tally
   // changes to the default search provider from various entry points. In
@@ -420,10 +453,30 @@
 
   void Init(const Initializer* initializers, int num_initializers);
 
+  // Removes |template_url| from various internal maps
+  // (|keyword_to_turl_and_length_|, |keyword_domain_to_turl_and_length_|,
+  // |guid_to_turl_|, |provider_map_|).
   void RemoveFromMaps(TemplateURL* template_url);
 
+  // Adds |template_url| to various internal maps
+  // (|keyword_to_turl_and_length_|, |keyword_domain_to_turl_and_length_|,
+  // |guid_to_turl_|, |provider_map_|) if appropriate.  (It might not be
+  // appropriate if, for instance, |template_url|'s keyword conflicts with
+  // the keyword of a custom search engine already existing in the maps that
+  // is not allowed to be replaced.)
   void AddToMaps(TemplateURL* template_url);
 
+  // Helper function for removing an element from
+  // |keyword_domain_to_turl_and_length_|.
+  void RemoveFromDomainMap(const TemplateURL* template_url);
+
+  // Helper fuction for adding an element to
+  // |keyword_domain_to_turl_and_length_| if appropriate.
+  void AddToDomainMap(TemplateURL* template_url);
+
+  // Helper function for adding an element to |keyword_to_turl_and_length_|.
+  void AddToMap(TemplateURL* template_url);
+
   // Sets the keywords. This is used once the keywords have been loaded.
   // This does NOT notify the delegate or the database.
   //
@@ -608,6 +661,17 @@
   // |template_urls| on exit.
   void AddTemplateURLs(TemplateURLVector* template_urls);
 
+  // Adds to |matches| all TemplateURLs stored in |keyword_to_turl_and_length|
+  // whose keywords begin with |prefix|, sorted shortest-keyword-first.  If
+  // |supports_replacement_only| is true, only TemplateURLs that support
+  // replacement are returned.
+  template <typename Container>
+  void AddMatchingKeywordsHelper(
+      const Container& keyword_to_turl_and_length,
+      const base::string16& prefix,
+      bool supports_replacement_only,
+      TURLsAndMeaningfulLengths* matches);
+
   // Returns the TemplateURL corresponding to |prepopulated_id|, if any.
   TemplateURL* FindPrepopulatedTemplateURL(int prepopulated_id);
 
@@ -649,10 +713,21 @@
   PrefChangeRegistrar pref_change_registrar_;
 
   // Mapping from keyword to the TemplateURL.
-  KeywordToTemplateMap keyword_to_template_map_;
+  KeywordToTURLAndMeaningfulLength keyword_to_turl_and_length_;
+
+  // Mapping from keyword domain to the TemplateURL.
+  // Entries are only allowed here if there is a corresponding entry in
+  // |keyword_to_turl_and_length_|, i.e., if a template URL doesn't have an
+  // entry in |keyword_to_turl_and_length_| because it's subsumed by another
+  // template URL with an identical keyword, the template URL will not have an
+  // entry in this map either.  This map will also not bother including entries
+  // for keywords in which the keyword is the domain name, with no subdomain
+  // before the domain name.  (The ordinary |keyword_to_turl_and_length|
+  // suffices for that.)
+  KeywordDomainToTURLAndMeaningfulLength keyword_domain_to_turl_and_length_;
 
   // Mapping from Sync GUIDs to the TemplateURL.
-  GUIDToTemplateMap guid_to_template_map_;
+  GUIDToTURL guid_to_turl_;
 
   TemplateURLVector template_urls_;
 
diff --git a/components/sessions/content/content_serialized_navigation_builder.cc b/components/sessions/content/content_serialized_navigation_builder.cc
index d371994..47eb7c0 100644
--- a/components/sessions/content/content_serialized_navigation_builder.cc
+++ b/components/sessions/content/content_serialized_navigation_builder.cc
@@ -85,19 +85,18 @@
 }
 
 // static
-ScopedVector<content::NavigationEntry>
+std::vector<scoped_ptr<content::NavigationEntry>>
 ContentSerializedNavigationBuilder::ToNavigationEntries(
     const std::vector<SerializedNavigationEntry>& navigations,
     content::BrowserContext* browser_context) {
   int page_id = 0;
-  ScopedVector<content::NavigationEntry> entries;
-  for (std::vector<SerializedNavigationEntry>::const_iterator
-       it = navigations.begin(); it != navigations.end(); ++it) {
-    entries.push_back(
-        ToNavigationEntry(&(*it), page_id, browser_context).release());
+  std::vector<scoped_ptr<content::NavigationEntry>> entries;
+  entries.reserve(navigations.size());
+  for (const auto& navigation : navigations) {
+    entries.push_back(ToNavigationEntry(&navigation, page_id, browser_context));
     ++page_id;
   }
-  return entries.Pass();
+  return entries;
 }
 
 }  // namespace sessions
diff --git a/components/sessions/content/content_serialized_navigation_builder.h b/components/sessions/content/content_serialized_navigation_builder.h
index bde17af..34c8483 100644
--- a/components/sessions/content/content_serialized_navigation_builder.h
+++ b/components/sessions/content/content_serialized_navigation_builder.h
@@ -8,7 +8,6 @@
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "components/sessions/core/sessions_export.h"
 
 namespace content {
@@ -39,7 +38,7 @@
 
   // Converts a set of SerializedNavigationEntrys into a list of
   // NavigationEntrys with sequential page IDs and the given context.
-  static ScopedVector<content::NavigationEntry> ToNavigationEntries(
+  static std::vector<scoped_ptr<content::NavigationEntry>> ToNavigationEntries(
       const std::vector<SerializedNavigationEntry>& navigations,
       content::BrowserContext* browser_context);
 };
diff --git a/components/tracing/OWNERS b/components/tracing/OWNERS
index 1a389403..683996a 100644
--- a/components/tracing/OWNERS
+++ b/components/tracing/OWNERS
@@ -1,6 +1,7 @@
+dsinclair@chromium.org
 jbauman@chromium.org
 nduca@chromium.org
-dsinclair@chromium.org
+oysteine@chromium.org
 simonhatch@chromium.org
 
 # Changes to IPC messages require a security review to avoid introducing
diff --git a/components/tracing/child_trace_message_filter.cc b/components/tracing/child_trace_message_filter.cc
index 5d08734..0694a174 100644
--- a/components/tracing/child_trace_message_filter.cc
+++ b/components/tracing/child_trace_message_filter.cc
@@ -34,6 +34,10 @@
       this);
 }
 
+void ChildTraceMessageFilter::SetSenderForTesting(IPC::Sender* sender) {
+  sender_ = sender;
+}
+
 void ChildTraceMessageFilter::OnFilterRemoved() {
   ChildMemoryDumpManagerDelegateImpl::GetInstance()->SetChildTraceMessageFilter(
       nullptr);
@@ -306,10 +310,6 @@
     base::HistogramBase::Sample max;
     base::HistogramBase::Count count;
     sample_iterator->Get(&min, &max, &count);
-    if (count == 0) {
-      sample_iterator->Next();
-      continue;
-    }
 
     if (min >= histogram_lower_value && max <= histogram_upper_value) {
       ipc_task_runner_->PostTask(
@@ -322,7 +322,10 @@
           base::Bind(
               &ChildTraceMessageFilter::SendAbortBackgroundTracingMessage,
               this));
+      break;
     }
+
+    sample_iterator->Next();
   }
 }
 
diff --git a/components/tracing/child_trace_message_filter.h b/components/tracing/child_trace_message_filter.h
index 9f7755c..47999762 100644
--- a/components/tracing/child_trace_message_filter.h
+++ b/components/tracing/child_trace_message_filter.h
@@ -42,6 +42,8 @@
   ~ChildTraceMessageFilter() override;
 
  private:
+  friend class ChildTraceMessageFilterTest;
+
   // Message handlers.
   void OnBeginTracing(const std::string& trace_config_str,
                       base::TimeTicks browser_time,
@@ -84,6 +86,8 @@
 
   void OnProcessMemoryDumpDone(uint64 dump_guid, bool success);
 
+  void SetSenderForTesting(IPC::Sender* sender);
+
   IPC::Sender* sender_;
   base::SingleThreadTaskRunner* ipc_task_runner_;
 
diff --git a/components/tracing/child_trace_message_filter_unittest.cc b/components/tracing/child_trace_message_filter_unittest.cc
new file mode 100644
index 0000000..75d1ad8
--- /dev/null
+++ b/components/tracing/child_trace_message_filter_unittest.cc
@@ -0,0 +1,87 @@
+// Copyright 2015 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 "components/tracing/child_trace_message_filter.h"
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "components/tracing/tracing_messages.h"
+#include "ipc/ipc_message.h"
+#include "ipc/ipc_sender.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracing {
+
+class FakeSender : public IPC::Sender {
+ public:
+  FakeSender() {}
+
+  ~FakeSender() override {}
+
+  bool Send(IPC::Message* msg) override {
+    last_message_.reset(msg);
+    return true;
+  }
+
+  scoped_ptr<IPC::Message> last_message_;
+};
+
+class ChildTraceMessageFilterTest : public testing::Test {
+ public:
+  ChildTraceMessageFilterTest() {
+    message_filter_ =
+        new tracing::ChildTraceMessageFilter(message_loop_.task_runner().get());
+    message_filter_->SetSenderForTesting(&fake_sender_);
+  }
+
+  void OnSetUMACallback(const std::string& histogram,
+                        int low,
+                        int high,
+                        bool repeat) {
+    fake_sender_.last_message_.reset();
+    message_filter_->OnSetUMACallback(histogram, low, high, repeat);
+  }
+
+  base::MessageLoop message_loop_;
+  FakeSender fake_sender_;
+  scoped_refptr<tracing::ChildTraceMessageFilter> message_filter_;
+};
+
+TEST_F(ChildTraceMessageFilterTest, TestHistogramDoesNotTrigger) {
+  LOCAL_HISTOGRAM_COUNTS("foo1", 10);
+
+  OnSetUMACallback("foo1", 20000, 25000, true);
+
+  message_loop_.RunUntilIdle();
+
+  EXPECT_FALSE(fake_sender_.last_message_);
+}
+
+TEST_F(ChildTraceMessageFilterTest, TestHistogramTriggers) {
+  LOCAL_HISTOGRAM_COUNTS("foo2", 2);
+
+  OnSetUMACallback("foo2", 1, 3, true);
+
+  message_loop_.RunUntilIdle();
+
+  EXPECT_TRUE(fake_sender_.last_message_);
+  EXPECT_EQ(fake_sender_.last_message_->type(),
+            TracingHostMsg_TriggerBackgroundTrace::ID);
+}
+
+TEST_F(ChildTraceMessageFilterTest, TestHistogramAborts) {
+  LOCAL_HISTOGRAM_COUNTS("foo3", 10);
+
+  OnSetUMACallback("foo3", 1, 3, false);
+
+  message_loop_.RunUntilIdle();
+
+  EXPECT_TRUE(fake_sender_.last_message_);
+  EXPECT_EQ(fake_sender_.last_message_->type(),
+            TracingHostMsg_AbortBackgroundTrace::ID);
+}
+
+}  // namespace tracing
diff --git a/components/translate/core/browser/translate_client.h b/components/translate/core/browser/translate_client.h
index e5c9e35..b6272bf7 100644
--- a/components/translate/core/browser/translate_client.h
+++ b/components/translate/core/browser/translate_client.h
@@ -57,8 +57,8 @@
   // Called when the embedder should present UI to the user corresponding to the
   // user's current |step|.
   virtual void ShowTranslateUI(translate::TranslateStep step,
-                               const std::string source_language,
-                               const std::string target_language,
+                               const std::string& source_language,
+                               const std::string& target_language,
                                TranslateErrors::Type error_type,
                                bool triggered_from_menu) = 0;
 
diff --git a/components/update_client/task.h b/components/update_client/task.h
index a6d1f6c..0a5b7f3 100644
--- a/components/update_client/task.h
+++ b/components/update_client/task.h
@@ -26,6 +26,11 @@
 
   virtual void Run() = 0;
 
+  // Does a best effort attempt to make a task release its resources and stop
+  // soon. It is possible that a running task may complete even if this
+  // method is called.
+  virtual void Cancel() = 0;
+
   // Returns the ids corresponding to the CRXs associated with this update task.
   virtual std::vector<std::string> GetIds() const = 0;
 };
diff --git a/components/update_client/task_update.cc b/components/update_client/task_update.cc
index d253466..c6a72e6 100644
--- a/components/update_client/task_update.cc
+++ b/components/update_client/task_update.cc
@@ -8,6 +8,7 @@
 #include "base/location.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
+#include "components/update_client/update_client.h"
 #include "components/update_client/update_engine.h"
 
 namespace update_client {
@@ -32,23 +33,30 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   if (ids_.empty()) {
-    RunComplete(-1);
+    TaskComplete(Error::ERROR_UPDATE_INVALID_ARGUMENT);
     return;
   }
 
   update_engine_->Update(
       is_foreground_, ids_, crx_data_callback_,
-      base::Bind(&TaskUpdate::RunComplete, base::Unretained(this)));
+      base::Bind(&TaskUpdate::TaskComplete, base::Unretained(this)));
+}
+
+void TaskUpdate::Cancel() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  TaskComplete(Error::ERROR_UPDATE_CANCELED);
 }
 
 std::vector<std::string> TaskUpdate::GetIds() const {
   return ids_;
 }
 
-void TaskUpdate::RunComplete(int error) {
+void TaskUpdate::TaskComplete(int error) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  callback_.Run(this, error);
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::Bind(callback_, this, error));
 }
 
 }  // namespace update_client
diff --git a/components/update_client/task_update.h b/components/update_client/task_update.h
index 3d0963f..aa3ce9d 100644
--- a/components/update_client/task_update.h
+++ b/components/update_client/task_update.h
@@ -40,11 +40,14 @@
 
   void Run() override;
 
+  void Cancel() override;
+
   std::vector<std::string> GetIds() const override;
 
  private:
-  // Called when the Run function associated with this task has completed.
-  void RunComplete(int error);
+  // Called when the task has completed either because the task has run or
+  // it has been canceled.
+  void TaskComplete(int error);
 
   base::ThreadChecker thread_checker_;
 
diff --git a/components/update_client/update_client.cc b/components/update_client/update_client.cc
index ac1ac05..497fedb 100644
--- a/components/update_client/update_client.cc
+++ b/components/update_client/update_client.cc
@@ -68,7 +68,8 @@
     scoped_ptr<PingManager> ping_manager,
     UpdateChecker::Factory update_checker_factory,
     CrxDownloader::Factory crx_downloader_factory)
-    : config_(config),
+    : is_stopped_(false),
+      config_(config),
       ping_manager_(ping_manager.Pass()),
       update_engine_(
           new UpdateEngine(config,
@@ -76,16 +77,13 @@
                            crx_downloader_factory,
                            ping_manager_.get(),
                            base::Bind(&UpdateClientImpl::NotifyObservers,
-                                      base::Unretained(this)))) {
-}
+                                      base::Unretained(this)))) {}
 
 UpdateClientImpl::~UpdateClientImpl() {
   DCHECK(thread_checker_.CalledOnValidThread());
 
-  while (!task_queue_.empty()) {
-    delete task_queue_.front();
-    task_queue_.pop();
-  }
+  DCHECK(task_queue_.empty());
+  DCHECK(tasks_.empty());
 
   config_ = nullptr;
 }
@@ -150,9 +148,17 @@
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(completion_callback, error));
 
+  // Remove the task from the set of the running tasks. Only tasks handled by
+  // the update engine can be in this data structure.
   tasks_.erase(task);
+
+  // Delete the completed task. A task can be completed because the update
+  // engine has run it or because it has been canceled but never run.
   delete task;
 
+  if (is_stopped_)
+    return;
+
   // Pick up a task from the queue if the queue has pending tasks and no other
   // task is running.
   if (tasks_.empty() && !task_queue_.empty()) {
@@ -195,6 +201,31 @@
   return false;
 }
 
+void UpdateClientImpl::Stop() {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  is_stopped_ = true;
+
+  // In the current implementation it is sufficient to cancel the pending
+  // tasks only. The tasks that are run by the update engine will stop
+  // making progress naturally, as the main task runner stops running task
+  // actions. Upon the browser shutdown, the resources employed by the active
+  // tasks will leak, as the operating system kills the thread associated with
+  // the update engine task runner. Further refactoring may be needed in this
+  // area, to cancel the running tasks by canceling the current action update.
+  // This behavior would be expected, correct, and result in no resource leaks
+  // in all cases, in shutdown or not.
+  //
+  // Cancel the pending tasks. These tasks are safe to cancel and delete since
+  // they have not picked up by the update engine, and not shared with any
+  // task runner yet.
+  while (!task_queue_.empty()) {
+    const auto task(task_queue_.front());
+    task_queue_.pop();
+    task->Cancel();
+  }
+}
+
 scoped_refptr<UpdateClient> UpdateClientFactory(
     const scoped_refptr<Configurator>& config) {
   scoped_ptr<PingManager> ping_manager(new PingManager(*config));
diff --git a/components/update_client/update_client.h b/components/update_client/update_client.h
index e53b634..f5107d58 100644
--- a/components/update_client/update_client.h
+++ b/components/update_client/update_client.h
@@ -140,7 +140,9 @@
 struct CrxUpdateItem;
 
 enum Error {
+  ERROR_UPDATE_INVALID_ARGUMENT = -1,
   ERROR_UPDATE_IN_PROGRESS = 1,
+  ERROR_UPDATE_CANCELED = 2,
 };
 
 // Defines an interface for a generic CRX installer.
@@ -296,6 +298,12 @@
   // Returns true if the |id| is found in any running task.
   virtual bool IsUpdating(const std::string& id) const = 0;
 
+  // Cancels the queued updates and makes a best effort to stop updates in
+  // progress as soon as possible. Some updates may not be stopped, in which
+  // case, the updates will run to completion. Calling this function has no
+  // effect if updates are not currently executed or queued up.
+  virtual void Stop() = 0;
+
  protected:
   friend class base::RefCounted<UpdateClient>;
 
diff --git a/components/update_client/update_client_internal.h b/components/update_client/update_client_internal.h
index 0dc98be..6a5bf39 100644
--- a/components/update_client/update_client_internal.h
+++ b/components/update_client/update_client_internal.h
@@ -52,6 +52,7 @@
   bool GetCrxUpdateState(const std::string& id,
                          CrxUpdateItem* update_item) const override;
   bool IsUpdating(const std::string& id) const override;
+  void Stop() override;
 
  private:
   ~UpdateClientImpl() override;
@@ -65,12 +66,15 @@
 
   base::ThreadChecker thread_checker_;
 
+  // True is Stop method has been called.
+  bool is_stopped_;
+
   scoped_refptr<Configurator> config_;
 
   // Contains the tasks that are pending. In the current implementation,
   // only update tasks (background tasks) are queued up. These tasks are
-  // pending while they are in this queue. They are not being handled for
-  // the moment.
+  // pending while they are in this queue. They have not been picked up yet
+  // by the update engine.
   std::queue<Task*> task_queue_;
 
   // Contains all tasks in progress. These are the tasks that the update engine
@@ -86,12 +90,6 @@
 
   base::ObserverList<Observer> observer_list_;
 
-  // Used to post responses back to the main thread.
-  scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
-
-  // Used to execute blocking tasks.
-  scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
-
   DISALLOW_COPY_AND_ASSIGN(UpdateClientImpl);
 };
 
diff --git a/components/web_view/BUILD.gn b/components/web_view/BUILD.gn
index f387583..cb80c43 100644
--- a/components/web_view/BUILD.gn
+++ b/components/web_view/BUILD.gn
@@ -54,6 +54,7 @@
     "//components/clipboard/public/interfaces",
     "//components/devtools_service/public/cpp",
     "//components/devtools_service/public/interfaces",
+    "//components/mus/common",
     "//components/mus/public/cpp",
     "//components/mus/public/interfaces",
     "//components/resource_provider/public/interfaces",
diff --git a/components/web_view/DEPS b/components/web_view/DEPS
index 466e8918..32714a9 100644
--- a/components/web_view/DEPS
+++ b/components/web_view/DEPS
@@ -3,6 +3,7 @@
   "+components/devtools_service/public/cpp",
   "+components/devtools_service/public/interfaces",
   "+components/font_service/public/interfaces",
+  "+components/mus/common",
   "+components/mus/public",
   "+components/resource_provider/public/interfaces",
   "+mojo/application/public",
diff --git a/components/web_view/frame.h b/components/web_view/frame.h
index ab61f71..3fa2ff3 100644
--- a/components/web_view/frame.h
+++ b/components/web_view/frame.h
@@ -11,7 +11,7 @@
 #include "base/basictypes.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/time/time.h"
-#include "components/mus/public/cpp/types.h"
+#include "components/mus/common/types.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "components/web_view/public/interfaces/frame.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
diff --git a/content/browser/android/in_process/context_provider_in_process.cc b/content/browser/android/in_process/context_provider_in_process.cc
index fda13aa..71f8010 100644
--- a/content/browser/android/in_process/context_provider_in_process.cc
+++ b/content/browser/android/in_process/context_provider_in_process.cc
@@ -22,11 +22,11 @@
  public:
   explicit LostContextCallbackProxy(ContextProviderInProcess* provider)
       : provider_(provider) {
-    provider_->context3d_->setContextLostCallback(this);
+    provider_->WebContext3DImpl()->setContextLostCallback(this);
   }
 
   virtual ~LostContextCallbackProxy() {
-    provider_->context3d_->setContextLostCallback(NULL);
+    provider_->WebContext3DImpl()->setContextLostCallback(NULL);
   }
 
   virtual void onContextLost() {
@@ -49,10 +49,12 @@
 ContextProviderInProcess::ContextProviderInProcess(
     scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
     const std::string& debug_name)
-    : context3d_(context3d.Pass()),
-      debug_name_(debug_name) {
+    : debug_name_(debug_name) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  DCHECK(context3d_);
+  DCHECK(context3d);
+  gr_interface_ = skia::AdoptRef(new GrGLInterfaceForWebGraphicsContext3D(
+      context3d.Pass()));
+  DCHECK(gr_interface_->WebContext3D());
   context_thread_checker_.DetachFromThread();
 }
 
@@ -65,11 +67,20 @@
   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  return context3d_.get();
+  return WebContext3DImpl();
+}
+
+gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl*
+    ContextProviderInProcess::WebContext3DImpl() {
+  DCHECK(gr_interface_->WebContext3D());
+
+  return
+      static_cast<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl*>(
+          gr_interface_->WebContext3D());
 }
 
 bool ContextProviderInProcess::BindToCurrentThread() {
-  DCHECK(context3d_);
+  DCHECK(WebContext3DImpl());
 
   // This is called on the thread the context will be used.
   DCHECK(context_thread_checker_.CalledOnValidThread());
@@ -77,14 +88,15 @@
   if (lost_context_callback_proxy_)
     return true;
 
-  if (!context3d_->InitializeOnCurrentThread())
+  if (!WebContext3DImpl()->InitializeOnCurrentThread())
     return false;
 
+  gr_interface_->BindToCurrentThread();
   InitializeCapabilities();
 
   const std::string unique_context_name =
-      base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
-  context3d_->traceBeginCHROMIUM("gpu_toplevel",
+      base::StringPrintf("%s-%p", debug_name_.c_str(), WebContext3DImpl());
+  WebContext3DImpl()->traceBeginCHROMIUM("gpu_toplevel",
                                  unique_context_name.c_str());
 
   lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
@@ -96,9 +108,9 @@
 }
 
 void ContextProviderInProcess::InitializeCapabilities() {
-  capabilities_.gpu = context3d_->GetImplementation()->capabilities();
+  capabilities_.gpu = WebContext3DImpl()->GetImplementation()->capabilities();
 
-  size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
+  size_t mapped_memory_limit = WebContext3DImpl()->GetMappedMemoryLimit();
   capabilities_.max_transfer_buffer_usage_bytes =
       mapped_memory_limit ==
               WebGraphicsContext3DInProcessCommandBufferImpl::kNoLimit
@@ -114,21 +126,21 @@
 }
 
 ::gpu::gles2::GLES2Interface* ContextProviderInProcess::ContextGL() {
-  DCHECK(context3d_);
+  DCHECK(WebContext3DImpl());
   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  return context3d_->GetGLInterface();
+  return WebContext3DImpl()->GetGLInterface();
 }
 
 ::gpu::ContextSupport* ContextProviderInProcess::ContextSupport() {
-  DCHECK(context3d_);
+  DCHECK(WebContext3DImpl());
   if (!lost_context_callback_proxy_)
     return NULL;  // Not bound to anything.
 
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  return context3d_->GetContextSupport();
+  return WebContext3DImpl()->GetContextSupport();
 }
 
 class GrContext* ContextProviderInProcess::GrContext() {
@@ -138,7 +150,7 @@
   if (gr_context_)
     return gr_context_->get();
 
-  gr_context_.reset(new GrContextForWebGraphicsContext3D(context3d_.get()));
+  gr_context_.reset(new GrContextForWebGraphicsContext3D(gr_interface_));
   return gr_context_->get();
 }
 
@@ -151,7 +163,7 @@
 }
 
 void ContextProviderInProcess::SetupLock() {
-  context3d_->SetLock(&context_lock_);
+  WebContext3DImpl()->SetLock(&context_lock_);
 }
 
 base::Lock* ContextProviderInProcess::GetLock() {
diff --git a/content/browser/android/in_process/context_provider_in_process.h b/content/browser/android/in_process/context_provider_in_process.h
index 761caf0..81726d6 100644
--- a/content/browser/android/in_process/context_provider_in_process.h
+++ b/content/browser/android/in_process/context_provider_in_process.h
@@ -12,6 +12,7 @@
 #include "base/synchronization/lock.h"
 #include "base/threading/thread_checker.h"
 #include "cc/blink/context_provider_web_context.h"
+#include "skia/ext/refptr.h"
 
 namespace blink { class WebGraphicsContext3D; }
 
@@ -22,6 +23,7 @@
 namespace content {
 
 class GrContextForWebGraphicsContext3D;
+class GrGLInterfaceForWebGraphicsContext3D;
 
 class ContextProviderInProcess
     : NON_EXPORTED_BASE(public cc_blink::ContextProviderWebContext) {
@@ -41,6 +43,8 @@
   // cc_blink::ContextProviderWebContext:
   blink::WebGraphicsContext3D* WebContext3D() override;
 
+  gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl* WebContext3DImpl();
+
   // cc::ContextProvider:
   bool BindToCurrentThread() override;
   void DetachFromThread() override;
@@ -61,8 +65,7 @@
   base::ThreadChecker main_thread_checker_;
   base::ThreadChecker context_thread_checker_;
 
-  scoped_ptr<gpu_blink::WebGraphicsContext3DInProcessCommandBufferImpl>
-      context3d_;
+  skia::RefPtr<GrGLInterfaceForWebGraphicsContext3D> gr_interface_;
   scoped_ptr<GrContextForWebGraphicsContext3D> gr_context_;
 
   LostContextCallback lost_context_callback_;
diff --git a/content/browser/android/synchronous_compositor_host.cc b/content/browser/android/synchronous_compositor_host.cc
index 6880bd1..8117e08 100644
--- a/content/browser/android/synchronous_compositor_host.cc
+++ b/content/browser/android/synchronous_compositor_host.cc
@@ -10,6 +10,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/android/sync_compositor_messages.h"
 #include "content/public/browser/android/synchronous_compositor_client.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_view_host.h"
 #include "ipc/ipc_sender.h"
 
@@ -20,6 +21,8 @@
     SynchronousCompositorClient* client)
     : rwhva_(rwhva),
       client_(client),
+      ui_task_runner_(
+          BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)),
       routing_id_(rwhva_->GetRenderWidgetHost()->GetRoutingID()),
       sender_(rwhva_->GetRenderWidgetHost()),
       is_active_(false),
@@ -28,7 +31,8 @@
       need_animate_scroll_(false),
       need_invalidate_(false),
       need_begin_frame_(false),
-      did_activate_pending_tree_(false) {
+      did_activate_pending_tree_(false),
+      weak_ptr_factory_(this) {
   client_->DidInitializeCompositor(this);
 }
 
@@ -96,7 +100,7 @@
   if (bytes_limit_ == bytes_limit)
     return;
   bytes_limit_ = bytes_limit;
-  // TODO(boliu): Handle not in draw.
+  SendAsyncCompositorStateIfNeeded();
 }
 
 void SynchronousCompositorHost::DidChangeRootLayerScrollOffset(
@@ -104,7 +108,24 @@
   if (root_scroll_offset_ == root_offset)
     return;
   root_scroll_offset_ = root_offset;
-  // TODO(boliu): Handle async.
+  SendAsyncCompositorStateIfNeeded();
+}
+
+void SynchronousCompositorHost::SendAsyncCompositorStateIfNeeded() {
+  if (weak_ptr_factory_.HasWeakPtrs())
+    return;
+
+  ui_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&SynchronousCompositorHost::UpdateStateTask,
+                            weak_ptr_factory_.GetWeakPtr()));
+}
+
+void SynchronousCompositorHost::UpdateStateTask() {
+  SyncCompositorCommonBrowserParams common_browser_params;
+  PopulateCommonParams(&common_browser_params);
+  sender_->Send(
+      new SyncCompositorMsg_UpdateState(routing_id_, common_browser_params));
+  DCHECK(!weak_ptr_factory_.HasWeakPtrs());
 }
 
 void SynchronousCompositorHost::SetIsActive(bool is_active) {
@@ -175,6 +196,7 @@
   params->bytes_limit = bytes_limit_;
   params->root_scroll_offset = root_scroll_offset_;
   params->ack.resources.swap(returned_resources_);
+  weak_ptr_factory_.InvalidateWeakPtrs();
 }
 
 void SynchronousCompositorHost::ProcessCommonParams(
diff --git a/content/browser/android/synchronous_compositor_host.h b/content/browser/android/synchronous_compositor_host.h
index 0b741aa..15eed04 100644
--- a/content/browser/android/synchronous_compositor_host.h
+++ b/content/browser/android/synchronous_compositor_host.h
@@ -6,6 +6,8 @@
 #define CONTENT_BROWSER_ANDROID_SYNCHRONOUS_COMPOSITOR_HOST_H_
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
 #include "cc/output/compositor_frame.h"
 #include "content/browser/android/synchronous_compositor_base.h"
 #include "ui/gfx/geometry/scroll_offset.h"
@@ -59,9 +61,12 @@
   void UpdateFrameMetaData(const cc::CompositorFrameMetadata& frame_metadata);
   void OnOverScroll(const SyncCompositorCommonRendererParams& params,
                     const DidOverscrollParams& over_scroll_params);
+  void SendAsyncCompositorStateIfNeeded();
+  void UpdateStateTask();
 
   RenderWidgetHostViewAndroid* const rwhva_;
   SynchronousCompositorClient* const client_;
+  const scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
   const int routing_id_;
   IPC::Sender* const sender_;
 
@@ -79,6 +84,7 @@
   bool need_begin_frame_;
   bool did_activate_pending_tree_;
 
+  base::WeakPtrFactory<SynchronousCompositorHost> weak_ptr_factory_;
   DISALLOW_COPY_AND_ASSIGN(SynchronousCompositorHost);
 };
 
diff --git a/content/browser/android/web_contents_observer_proxy.cc b/content/browser/android/web_contents_observer_proxy.cc
index c04f926..923f5a6b 100644
--- a/content/browser/android/web_contents_observer_proxy.cc
+++ b/content/browser/android/web_contents_observer_proxy.cc
@@ -87,8 +87,10 @@
 void WebContentsObserverProxy::DidStopLoading() {
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj(java_observer_);
+  std::string url_string = web_contents()->GetLastCommittedURL().spec();
+  SetToBaseURLForDataURLIfNeeded(&url_string);
   ScopedJavaLocalRef<jstring> jstring_url(ConvertUTF8ToJavaString(
-      env, web_contents()->GetLastCommittedURL().spec()));
+      env, url_string));
   Java_WebContentsObserverProxy_didStopLoading(env, obj.obj(),
                                                jstring_url.obj());
 }
@@ -205,11 +207,7 @@
   ScopedJavaLocalRef<jobject> obj(java_observer_);
 
   std::string url_string = validated_url.spec();
-  NavigationEntry* entry =
-      web_contents()->GetController().GetLastCommittedEntry();
-  // Note that GetBaseURLForDataURL is only used by the Android WebView.
-  if (entry && !entry->GetBaseURLForDataURL().is_empty())
-    url_string = entry->GetBaseURLForDataURL().possibly_invalid_spec();
+  SetToBaseURLForDataURLIfNeeded(&url_string);
 
   ScopedJavaLocalRef<jstring> jstring_url(
       ConvertUTF8ToJavaString(env, url_string));
@@ -300,6 +298,15 @@
       env, obj.obj(), is_controllable, is_suspended);
 }
 
+void WebContentsObserverProxy::SetToBaseURLForDataURLIfNeeded(
+    std::string* url) {
+  NavigationEntry* entry =
+      web_contents()->GetController().GetLastCommittedEntry();
+  // Note that GetBaseURLForDataURL is only used by the Android WebView.
+  if (entry && !entry->GetBaseURLForDataURL().is_empty())
+    *url = entry->GetBaseURLForDataURL().possibly_invalid_spec();
+}
+
 bool RegisterWebContentsObserverProxy(JNIEnv* env) {
   return RegisterNativesImpl(env);
 }
diff --git a/content/browser/android/web_contents_observer_proxy.h b/content/browser/android/web_contents_observer_proxy.h
index bbce094..a366cfb 100644
--- a/content/browser/android/web_contents_observer_proxy.h
+++ b/content/browser/android/web_contents_observer_proxy.h
@@ -73,6 +73,7 @@
       NavigationController::ReloadType reload_type) override;
   void MediaSessionStateChanged(bool is_controllable,
                                 bool is_suspended) override;
+  void SetToBaseURLForDataURLIfNeeded(std::string* url);
 
   void DidFailLoadInternal(bool is_provisional_load,
                            bool is_main_frame,
diff --git a/content/browser/browser_child_process_host_impl.cc b/content/browser/browser_child_process_host_impl.cc
index 5ff5d814..c9a61c6 100644
--- a/content/browser/browser_child_process_host_impl.cc
+++ b/content/browser/browser_child_process_host_impl.cc
@@ -142,7 +142,7 @@
   AddFilter(new TraceMessageFilter(data_.id));
   AddFilter(new ProfilerMessageFilter(process_type));
   AddFilter(new HistogramMessageFilter);
-  AddFilter(new MemoryMessageFilter);
+  AddFilter(new MemoryMessageFilter(this, process_type));
 
   g_child_process_list.Get().push_back(this);
   GetContentClient()->browser()->BrowserChildProcessHostCreated(this);
diff --git a/content/browser/compositor/delegated_frame_host.cc b/content/browser/compositor/delegated_frame_host.cc
index c7c0b8e..b050f87 100644
--- a/content/browser/compositor/delegated_frame_host.cc
+++ b/content/browser/compositor/delegated_frame_host.cc
@@ -600,7 +600,7 @@
   if (result) {
     GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
     if (gl_helper)
-      sync_token = gpu::SyncToken(gl_helper->InsertSyncPoint());
+      gl_helper->GenerateSyncToken(&sync_token);
   }
   const bool lost_resource = !sync_token.HasData();
   release_callback->Run(sync_token, lost_resource);
@@ -735,7 +735,7 @@
   gpu::SyncToken sync_token;
   if (result) {
     GLHelper* gl_helper = ImageTransportFactory::GetInstance()->GetGLHelper();
-    sync_token = gpu::SyncToken(gl_helper->InsertSyncPoint());
+    gl_helper->GenerateSyncToken(&sync_token);
   }
   if (release_callback) {
     // A release callback means the texture came from the compositor, so there
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc
index 4a24c413..8c05e8b 100644
--- a/content/browser/download/save_package.cc
+++ b/content/browser/download/save_package.cc
@@ -1085,11 +1085,14 @@
     }
   }
 
+  base::FilePath directory = target_tree_node->IsMainFrame()
+                                 ? saved_main_directory_path_.BaseName()
+                                 : base::FilePath();
+
   // Ask target frame to serialize itself.
   RenderFrameHostImpl* target = target_tree_node->current_frame_host();
   target->Send(new FrameMsg_GetSerializedHtmlWithLocalLinks(
-      target->GetRoutingID(), saved_links, saved_file_paths,
-      saved_main_directory_path_.BaseName()));
+      target->GetRoutingID(), saved_links, saved_file_paths, directory));
 }
 
 // Process the serialized HTML content data of a specified frame
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc
index 8b00dfb..8270ea29 100644
--- a/content/browser/frame_host/frame_tree_node.cc
+++ b/content/browser/frame_host/frame_tree_node.cc
@@ -147,33 +147,28 @@
   if (SiteIsolationPolicy::AreCrossProcessFramesPossible())
     render_manager_.CreateProxiesForChildFrame(child.get());
 
-  children_.push_back(child.release());
+  children_.push_back(child.Pass());
 }
 
 void FrameTreeNode::RemoveChild(FrameTreeNode* child) {
-  std::vector<FrameTreeNode*>::iterator iter;
-  for (iter = children_.begin(); iter != children_.end(); ++iter) {
-    if ((*iter) == child)
-      break;
-  }
-
-  if (iter != children_.end()) {
-    // Subtle: we need to make sure the node is gone from the tree before
-    // observers are notified of its deletion.
-    scoped_ptr<FrameTreeNode> node_to_delete(*iter);
-    children_.weak_erase(iter);
-    node_to_delete.reset();
+  for (auto iter = children_.begin(); iter != children_.end(); ++iter) {
+    if (iter->get() == child) {
+      // Subtle: we need to make sure the node is gone from the tree before
+      // observers are notified of its deletion.
+      scoped_ptr<FrameTreeNode> node_to_delete(iter->Pass());
+      children_.erase(iter);
+      node_to_delete.reset();
+      return;
+    }
   }
 }
 
 void FrameTreeNode::ResetForNewProcess() {
   current_url_ = GURL();
 
-  // The children may not have been cleared if a cross-process navigation
-  // commits before the old process cleans everything up.  Make sure the child
-  // nodes get deleted before swapping to a new process.
-  ScopedVector<FrameTreeNode> old_children = children_.Pass();
-  old_children.clear();  // May notify observers.
+  // Remove child nodes from the tree, then delete them. This destruction
+  // operation will notify observers.
+  std::vector<scoped_ptr<FrameTreeNode>>().swap(children_);
 }
 
 void FrameTreeNode::SetOpener(FrameTreeNode* opener) {
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h
index bc1a9304..3d5d563e 100644
--- a/content/browser/frame_host/frame_tree_node.h
+++ b/content/browser/frame_host/frame_tree_node.h
@@ -6,11 +6,11 @@
 #define CONTENT_BROWSER_FRAME_HOST_FRAME_TREE_NODE_H_
 
 #include <string>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/frame_host/render_frame_host_manager.h"
 #include "content/common/content_export.h"
@@ -109,7 +109,7 @@
   void SetOpener(FrameTreeNode* opener);
 
   FrameTreeNode* child_at(size_t index) const {
-    return children_[index];
+    return children_[index].get();
   }
 
   const GURL& current_url() const {
@@ -266,7 +266,7 @@
   scoped_ptr<OpenerDestroyedObserver> opener_observer_;
 
   // The immediate children of this specific frame.
-  ScopedVector<FrameTreeNode> children_;
+  std::vector<scoped_ptr<FrameTreeNode>> children_;
 
   // Track the current frame's last committed URL.
   // TODO(creis): Consider storing a reference to the last committed
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index 87abff0..ce13a160 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -127,7 +127,7 @@
 // Configure all the NavigationEntries in entries for restore. This resets
 // the transition type to reload and makes sure the content state isn't empty.
 void ConfigureEntriesForRestore(
-    ScopedVector<NavigationEntryImpl>* entries,
+    std::vector<scoped_ptr<NavigationEntryImpl>>* entries,
     NavigationController::RestoreType type) {
   for (size_t i = 0; i < entries->size(); ++i) {
     // Use a transition type of reload so that we don't incorrectly increase
@@ -135,7 +135,7 @@
     (*entries)[i]->SetTransitionType(ui::PAGE_TRANSITION_RELOAD);
     (*entries)[i]->set_restore_type(ControllerRestoreTypeToEntryType(type));
     // NOTE(darin): This code is only needed for backwards compat.
-    SetPageStateIfEmpty((*entries)[i]);
+    SetPageStateIfEmpty((*entries)[i].get());
   }
 }
 
@@ -268,19 +268,20 @@
 void NavigationControllerImpl::Restore(
     int selected_navigation,
     RestoreType type,
-    ScopedVector<NavigationEntry>* entries) {
+    std::vector<scoped_ptr<NavigationEntry>>* entries) {
   // Verify that this controller is unused and that the input is valid.
   DCHECK(GetEntryCount() == 0 && !GetPendingEntry());
   DCHECK(selected_navigation >= 0 &&
          selected_navigation < static_cast<int>(entries->size()));
 
   needs_reload_ = true;
-  for (size_t i = 0; i < entries->size(); ++i) {
-    NavigationEntryImpl* entry =
-        NavigationEntryImpl::FromNavigationEntry((*entries)[i]);
-    entries_.push_back(entry);
-  }
-  entries->weak_clear();
+  entries_.reserve(entries->size());
+  for (auto& entry : *entries)
+    entries_.push_back(NavigationEntryImpl::FromNavigationEntry(entry.Pass()));
+
+  // At this point, the |entries| is full of empty scoped_ptrs, so it can be
+  // cleared out safely.
+  entries->clear();
 
   // And finish the restore.
   FinishRestore(selected_navigation, type);
@@ -422,13 +423,13 @@
 NavigationEntryImpl* NavigationControllerImpl::GetEntryWithPageID(
   SiteInstance* instance, int32 page_id) const {
   int index = GetEntryIndexWithPageID(instance, page_id);
-  return (index != -1) ? entries_[index] : nullptr;
+  return (index != -1) ? entries_[index].get() : nullptr;
 }
 
 NavigationEntryImpl*
 NavigationControllerImpl::GetEntryWithUniqueID(int nav_entry_id) const {
   int index = GetEntryIndexWithUniqueID(nav_entry_id);
-  return (index != -1) ? entries_[index] : nullptr;
+  return (index != -1) ? entries_[index].get() : nullptr;
 }
 
 void NavigationControllerImpl::LoadEntry(
@@ -452,7 +453,7 @@
 
 NavigationEntryImpl* NavigationControllerImpl::GetActiveEntry() const {
   if (transient_entry_index_ != -1)
-    return entries_[transient_entry_index_];
+    return entries_[transient_entry_index_].get();
   if (pending_entry_)
     return pending_entry_;
   return GetLastCommittedEntry();
@@ -460,7 +461,7 @@
 
 NavigationEntryImpl* NavigationControllerImpl::GetVisibleEntry() const {
   if (transient_entry_index_ != -1)
-    return entries_[transient_entry_index_];
+    return entries_[transient_entry_index_].get();
   // The pending entry is safe to return for new (non-history), browser-
   // initiated navigations.  Most renderer-initiated navigations should not
   // show the pending entry, to prevent URL spoof attacks.
@@ -502,7 +503,7 @@
 NavigationEntryImpl* NavigationControllerImpl::GetLastCommittedEntry() const {
   if (last_committed_entry_index_ == -1)
     return NULL;
-  return entries_[last_committed_entry_index_];
+  return entries_[last_committed_entry_index_].get();
 }
 
 bool NavigationControllerImpl::CanViewSource() const {
@@ -529,7 +530,7 @@
   if (index < 0 || index >= GetEntryCount())
     return nullptr;
 
-  return entries_[index];
+  return entries_[index].get();
 }
 
 NavigationEntryImpl* NavigationControllerImpl::GetEntryAtOffset(
@@ -1343,11 +1344,11 @@
 
 int NavigationControllerImpl::GetIndexOfEntry(
     const NavigationEntryImpl* entry) const {
-  const NavigationEntries::const_iterator i(std::find(
-      entries_.begin(),
-      entries_.end(),
-      entry));
-  return (i == entries_.end()) ? -1 : static_cast<int>(i - entries_.begin());
+  for (size_t i = 0; i < entries_.size(); ++i) {
+    if (entries_[i].get() == entry)
+      return i;
+  }
+  return -1;
 }
 
 // There are two general cases where a navigation is "in page":
@@ -1666,11 +1667,7 @@
   if (replace && current_size > 0) {
     int32 page_id = entry->GetPageID();
 
-    // ScopedVectors don't automatically delete the replaced value, so make sure
-    // the previous value gets deleted.
-    scoped_ptr<NavigationEntryImpl> old_entry(
-        entries_[last_committed_entry_index_]);
-    entries_[last_committed_entry_index_] = entry.release();
+    entries_[last_committed_entry_index_] = entry.Pass();
 
     // This is a new page ID, so we need everybody to know about it.
     delegate_->UpdateMaxPageID(page_id);
@@ -1752,7 +1749,7 @@
   // For session history navigations only the pending_entry_index_ is set.
   if (!pending_entry_) {
     CHECK_NE(pending_entry_index_, -1);
-    pending_entry_ = entries_[pending_entry_index_];
+    pending_entry_ = entries_[pending_entry_index_].get();
   }
 
   // Any renderer-side debug URLs or javascript: URLs should be ignored if the
@@ -1999,7 +1996,7 @@
 NavigationEntryImpl* NavigationControllerImpl::GetTransientEntry() const {
   if (transient_entry_index_ == -1)
     return NULL;
-  return entries_[transient_entry_index_];
+  return entries_[transient_entry_index_].get();
 }
 
 void NavigationControllerImpl::SetTransientEntry(
@@ -2010,7 +2007,7 @@
     index = last_committed_entry_index_ + 1;
   DiscardTransientEntry();
   entries_.insert(entries_.begin() + index,
-                  NavigationEntryImpl::FromNavigationEntry(entry.release()));
+                  NavigationEntryImpl::FromNavigationEntry(entry.Pass()));
   transient_entry_index_ = index;
   delegate_->NotifyNavigationStateChanged(INVALIDATE_TYPE_ALL);
 }
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index fe387b18d..680ba72 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -5,10 +5,11 @@
 #ifndef CONTENT_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_IMPL_H_
 #define CONTENT_BROWSER_FRAME_HOST_NAVIGATION_CONTROLLER_IMPL_H_
 
+#include <vector>
+
 #include "base/callback.h"
 #include "base/compiler_specific.h"
 #include "base/gtest_prod_util.h"
-#include "base/memory/scoped_vector.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "content/browser/frame_host/navigation_controller_delegate.h"
@@ -40,7 +41,7 @@
   void SetBrowserContext(BrowserContext* browser_context) override;
   void Restore(int selected_navigation,
                RestoreType type,
-               ScopedVector<NavigationEntry>* entries) override;
+               std::vector<scoped_ptr<NavigationEntry>>* entries) override;
   NavigationEntryImpl* GetActiveEntry() const override;
   NavigationEntryImpl* GetVisibleEntry() const override;
   int GetCurrentEntryIndex() const override;
@@ -352,9 +353,8 @@
   // The user browser context associated with this controller.
   BrowserContext* browser_context_;
 
-  // List of NavigationEntry for this tab
-  using NavigationEntries = ScopedVector<NavigationEntryImpl>;
-  NavigationEntries entries_;
+  // List of |NavigationEntry|s for this controller.
+  std::vector<scoped_ptr<NavigationEntryImpl>> entries_;
 
   // An entry we haven't gotten a response for yet.  This will be discarded
   // when we navigate again.  It's used only so we know what the currently
diff --git a/content/browser/frame_host/navigation_controller_impl_unittest.cc b/content/browser/frame_host/navigation_controller_impl_unittest.cc
index f1100395..1cc7803 100644
--- a/content/browser/frame_host/navigation_controller_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_unittest.cc
@@ -2762,7 +2762,7 @@
 TEST_F(NavigationControllerTest, RestoreNavigate) {
   // Create a NavigationController with a restored set of tabs.
   GURL url("http://foo");
-  ScopedVector<NavigationEntry> entries;
+  std::vector<scoped_ptr<NavigationEntry>> entries;
   scoped_ptr<NavigationEntry> entry =
       NavigationControllerImpl::CreateNavigationEntry(
           url, Referrer(), ui::PAGE_TRANSITION_RELOAD, false, std::string(),
@@ -2835,7 +2835,7 @@
 TEST_F(NavigationControllerTest, RestoreNavigateAfterFailure) {
   // Create a NavigationController with a restored set of tabs.
   GURL url("http://foo");
-  ScopedVector<NavigationEntry> entries;
+  std::vector<scoped_ptr<NavigationEntry>> entries;
   scoped_ptr<NavigationEntry> new_entry =
       NavigationControllerImpl::CreateNavigationEntry(
           url, Referrer(), ui::PAGE_TRANSITION_RELOAD, false, std::string(),
@@ -3282,7 +3282,8 @@
   // can show them in new tabs when it is safe.
   main_test_rfh()->SendRendererInitiatedNavigationRequest(url1, false);
   main_test_rfh()->PrepareForCommit();
-  navigator->DidStartProvisionalLoad(main_test_rfh(), url1);
+  navigator->DidStartProvisionalLoad(main_test_rfh(), url1,
+                                     base::TimeTicks::Now());
 
   // Simulate what happens if a BrowserURLHandler rewrites the URL, causing
   // the virtual URL to differ from the URL.
@@ -3296,7 +3297,8 @@
   // If the user clicks another link, we should replace the pending entry.
   main_test_rfh()->SendRendererInitiatedNavigationRequest(url2, false);
   main_test_rfh()->PrepareForCommit();
-  navigator->DidStartProvisionalLoad(main_test_rfh(), url2);
+  navigator->DidStartProvisionalLoad(main_test_rfh(), url2,
+                                     base::TimeTicks::Now());
   EXPECT_EQ(url2, controller.GetPendingEntry()->GetURL());
   EXPECT_EQ(url2, controller.GetPendingEntry()->GetVirtualURL());
 
@@ -3306,20 +3308,23 @@
   EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetVirtualURL());
 
   // We should not replace the pending entry for an error URL.
-  navigator->DidStartProvisionalLoad(main_test_rfh(), url1);
+  navigator->DidStartProvisionalLoad(main_test_rfh(), url1,
+                                     base::TimeTicks::Now());
   EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
-  navigator->DidStartProvisionalLoad(main_test_rfh(),
-                                     GURL(kUnreachableWebDataURL));
+  navigator->DidStartProvisionalLoad(
+      main_test_rfh(), GURL(kUnreachableWebDataURL), base::TimeTicks::Now());
   EXPECT_EQ(url1, controller.GetPendingEntry()->GetURL());
 
   // We should remember if the pending entry will replace the current one.
   // http://crbug.com/308444.
-  navigator->DidStartProvisionalLoad(main_test_rfh(), url1);
+  navigator->DidStartProvisionalLoad(main_test_rfh(), url1,
+                                     base::TimeTicks::Now());
   controller.GetPendingEntry()->set_should_replace_entry(true);
 
   main_test_rfh()->SendRendererInitiatedNavigationRequest(url2, false);
   main_test_rfh()->PrepareForCommit();
-  navigator->DidStartProvisionalLoad(main_test_rfh(), url2);
+  navigator->DidStartProvisionalLoad(main_test_rfh(), url2,
+                                     base::TimeTicks::Now());
   EXPECT_TRUE(controller.GetPendingEntry()->should_replace_entry());
   main_test_rfh()->SendNavigate(0, 0, false, url2);
   EXPECT_EQ(url2, controller.GetLastCommittedEntry()->GetURL());
@@ -4345,7 +4350,7 @@
   };
   const GURL kInitialUrl("http://site3.com");
 
-  ScopedVector<NavigationEntry> entries;
+  std::vector<scoped_ptr<NavigationEntry>> entries;
   for (size_t i = 0; i < arraysize(kRestoredUrls); ++i) {
     scoped_ptr<NavigationEntry> entry =
         NavigationControllerImpl::CreateNavigationEntry(
diff --git a/content/browser/frame_host/navigation_handle_impl.cc b/content/browser/frame_host/navigation_handle_impl.cc
index b1aace3..7ffc6b4 100644
--- a/content/browser/frame_host/navigation_handle_impl.cc
+++ b/content/browser/frame_host/navigation_handle_impl.cc
@@ -33,13 +33,16 @@
 // static
 scoped_ptr<NavigationHandleImpl> NavigationHandleImpl::Create(
     const GURL& url,
-    FrameTreeNode* frame_tree_node) {
+    FrameTreeNode* frame_tree_node,
+    const base::TimeTicks& navigation_start) {
   return scoped_ptr<NavigationHandleImpl>(
-      new NavigationHandleImpl(url, frame_tree_node));
+      new NavigationHandleImpl(url, frame_tree_node, navigation_start));
 }
 
-NavigationHandleImpl::NavigationHandleImpl(const GURL& url,
-                                           FrameTreeNode* frame_tree_node)
+NavigationHandleImpl::NavigationHandleImpl(
+    const GURL& url,
+    FrameTreeNode* frame_tree_node,
+    const base::TimeTicks& navigation_start)
     : url_(url),
       is_post_(false),
       has_user_gesture_(false),
@@ -51,7 +54,9 @@
       state_(INITIAL),
       is_transferring_(false),
       frame_tree_node_(frame_tree_node),
-      next_index_(0) {
+      next_index_(0),
+      navigation_start_(navigation_start) {
+  DCHECK(!navigation_start.is_null());
   // PlzNavigate
   // Initialize the ServiceWorkerNavigationHandle if it can be created for this
   // frame.
diff --git a/content/browser/frame_host/navigation_handle_impl.h b/content/browser/frame_host/navigation_handle_impl.h
index 6f46707..b0a7b9a 100644
--- a/content/browser/frame_host/navigation_handle_impl.h
+++ b/content/browser/frame_host/navigation_handle_impl.h
@@ -57,9 +57,14 @@
 // the RenderFrameHost still apply.
 class CONTENT_EXPORT NavigationHandleImpl : public NavigationHandle {
  public:
+  // |navigation_start| comes from the DidStartProvisionalLoad IPC, which tracks
+  // both renderer-initiated and browser-initiated navigation start.
+  // PlzNavigate: This value always comes from the CommonNavigationParams
+  // associated with this navigation.
   static scoped_ptr<NavigationHandleImpl> Create(
       const GURL& url,
-      FrameTreeNode* frame_tree_node);
+      FrameTreeNode* frame_tree_node,
+      const base::TimeTicks& navigation_start);
   ~NavigationHandleImpl() override;
 
   // NavigationHandle implementation:
@@ -90,6 +95,11 @@
       const GURL& new_referrer_url,
       bool new_is_external_protocol) override;
 
+  // The time the navigation started, recorded either in the renderer or browser
+  // process. Corresponds to Navigation Timing API.
+  // TODO(csharrison): Add this to the public class and mark this override.
+  const base::TimeTicks& navigation_start() { return navigation_start_; }
+
   NavigatorDelegate* GetDelegate() const;
 
   void set_net_error_code(net::Error net_error_code) {
@@ -162,7 +172,8 @@
   };
 
   NavigationHandleImpl(const GURL& url,
-                       FrameTreeNode* frame_tree_node);
+                       FrameTreeNode* frame_tree_node,
+                       const base::TimeTicks& navigation_start);
 
   NavigationThrottle::ThrottleCheckResult CheckWillStartRequest();
   NavigationThrottle::ThrottleCheckResult CheckWillRedirectRequest();
@@ -197,6 +208,9 @@
   // The index of the next throttle to check.
   size_t next_index_;
 
+  // The time this navigation started.
+  const base::TimeTicks navigation_start_;
+
   // This callback will be run when all throttle checks have been performed.
   ThrottleChecksFinishedCallback complete_callback_;
 
diff --git a/content/browser/frame_host/navigation_handle_impl_unittest.cc b/content/browser/frame_host/navigation_handle_impl_unittest.cc
index af6aced..614f17c 100644
--- a/content/browser/frame_host/navigation_handle_impl_unittest.cc
+++ b/content/browser/frame_host/navigation_handle_impl_unittest.cc
@@ -54,7 +54,7 @@
   void SetUp() override {
     RenderViewHostImplTestHarness::SetUp();
     test_handle_ = NavigationHandleImpl::Create(
-        GURL(), main_test_rfh()->frame_tree_node());
+        GURL(), main_test_rfh()->frame_tree_node(), base::TimeTicks::Now());
   }
 
   void TearDown() override {
diff --git a/content/browser/frame_host/navigation_request.cc b/content/browser/frame_host/navigation_request.cc
index f95e944..252d5472 100644
--- a/content/browser/frame_host/navigation_request.cc
+++ b/content/browser/frame_host/navigation_request.cc
@@ -218,7 +218,7 @@
 
 void NavigationRequest::CreateNavigationHandle() {
   navigation_handle_ = NavigationHandleImpl::Create(
-      common_params_.url, frame_tree_node_);
+      common_params_.url, frame_tree_node_, common_params_.navigation_start);
 }
 
 void NavigationRequest::TransferNavigationHandleOwnership(
diff --git a/content/browser/frame_host/navigator.h b/content/browser/frame_host/navigator.h
index e2f737d..1768310 100644
--- a/content/browser/frame_host/navigator.h
+++ b/content/browser/frame_host/navigator.h
@@ -53,8 +53,10 @@
   // Notifications coming from the RenderFrameHosts ----------------------------
 
   // The RenderFrameHostImpl started a provisional load.
-  virtual void DidStartProvisionalLoad(RenderFrameHostImpl* render_frame_host,
-                                       const GURL& url) {};
+  virtual void DidStartProvisionalLoad(
+      RenderFrameHostImpl* render_frame_host,
+      const GURL& url,
+      const base::TimeTicks& navigation_start) {};
 
   // The RenderFrameHostImpl has failed a provisional load.
   virtual void DidFailProvisionalLoadWithError(
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index 788c23d..44bc5a8 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -119,7 +119,8 @@
 
 void NavigatorImpl::DidStartProvisionalLoad(
     RenderFrameHostImpl* render_frame_host,
-    const GURL& url) {
+    const GURL& url,
+    const base::TimeTicks& navigation_start) {
   bool is_main_frame = render_frame_host->frame_tree_node()->IsMainFrame();
   bool is_error_page = (url.spec() == kUnreachableWebDataURL);
   bool is_iframe_srcdoc = (url.spec() == kAboutSrcDocURL);
@@ -160,7 +161,7 @@
   }
 
   render_frame_host->SetNavigationHandle(NavigationHandleImpl::Create(
-      validated_url, render_frame_host->frame_tree_node()));
+      validated_url, render_frame_host->frame_tree_node(), navigation_start));
 }
 
 void NavigatorImpl::DidFailProvisionalLoadWithError(
diff --git a/content/browser/frame_host/navigator_impl.h b/content/browser/frame_host/navigator_impl.h
index 8b52dfb..775b16f 100644
--- a/content/browser/frame_host/navigator_impl.h
+++ b/content/browser/frame_host/navigator_impl.h
@@ -36,8 +36,10 @@
   // Navigator implementation.
   NavigatorDelegate* GetDelegate() override;
   NavigationController* GetController() override;
-  void DidStartProvisionalLoad(RenderFrameHostImpl* render_frame_host,
-                               const GURL& url) override;
+  void DidStartProvisionalLoad(
+      RenderFrameHostImpl* render_frame_host,
+      const GURL& url,
+      const base::TimeTicks& navigation_start) override;
   void DidFailProvisionalLoadWithError(
       RenderFrameHostImpl* render_frame_host,
       const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params)
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 2253381..9a8810b3 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -472,8 +472,8 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_AddMessageToConsole, OnAddMessageToConsole)
     IPC_MESSAGE_HANDLER(FrameHostMsg_Detach, OnDetach)
     IPC_MESSAGE_HANDLER(FrameHostMsg_FrameFocused, OnFrameFocused)
-    IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoadForFrame,
-                        OnDidStartProvisionalLoadForFrame)
+    IPC_MESSAGE_HANDLER(FrameHostMsg_DidStartProvisionalLoad,
+                        OnDidStartProvisionalLoad)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailProvisionalLoadWithError,
                         OnDidFailProvisionalLoadWithError)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidFailLoadWithError,
@@ -816,9 +816,11 @@
   delegate_->DocumentOnLoadCompleted(this);
 }
 
-void RenderFrameHostImpl::OnDidStartProvisionalLoadForFrame(const GURL& url) {
-  frame_tree_node_->navigator()->DidStartProvisionalLoad(
-      this, url);
+void RenderFrameHostImpl::OnDidStartProvisionalLoad(
+    const GURL& url,
+    const base::TimeTicks& navigation_start) {
+  frame_tree_node_->navigator()->DidStartProvisionalLoad(this, url,
+                                                         navigation_start);
 }
 
 void RenderFrameHostImpl::OnDidFailProvisionalLoadWithError(
@@ -958,7 +960,7 @@
   // message.
   if (!navigation_handle_) {
     navigation_handle_ = NavigationHandleImpl::Create(
-        validated_params.url, frame_tree_node_);
+        validated_params.url, frame_tree_node_, base::TimeTicks::Now());
   }
 
   accessibility_reset_count_ = 0;
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 41f0bce..cbefae8 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -515,7 +515,9 @@
   void OnDocumentOnLoadCompleted(
       FrameMsg_UILoadMetricsReportType::Value report_type,
       base::TimeTicks ui_timestamp);
-  void OnDidStartProvisionalLoadForFrame(const GURL& url);
+  void OnDidStartProvisionalLoad(
+      const GURL& url,
+      const base::TimeTicks& navigation_start);
   void OnDidFailProvisionalLoadWithError(
       const FrameHostMsg_DidFailProvisionalLoadWithError_Params& params);
   void OnDidFailLoadWithError(
diff --git a/content/browser/gpu/gpu_ipc_browsertests.cc b/content/browser/gpu/gpu_ipc_browsertests.cc
index 7154c2ee..1a09b24 100644
--- a/content/browser/gpu/gpu_ipc_browsertests.cc
+++ b/content/browser/gpu/gpu_ipc_browsertests.cc
@@ -13,6 +13,9 @@
 #include "content/public/common/content_switches.h"
 #include "content/public/test/content_browser_test.h"
 #include "gpu/blink/webgraphicscontext3d_in_process_command_buffer_impl.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GrContext.h"
 #include "ui/gl/gl_switches.h"
 
 namespace {
@@ -194,6 +197,52 @@
 }
 #endif
 
+// Test fails on Windows because GPU Channel set-up fails.
+// Mac only fails GPU set-up on MacOS 10.6, but we have no version-specific
+// macros for disabling tests.
+#if !defined(OS_WIN) && !defined(OS_MACOSX)
+#define MAYBE_GrContextKeepsGpuChannelAlive GrContextKeepsGpuChannelAlive
+#else
+#define MAYBE_GrContextKeepsGpuChannelAlive \
+    DISABLED_GrContextKeepsGpuChannelAlive
+#endif
+IN_PROC_BROWSER_TEST_F(BrowserGpuChannelHostFactoryTest,
+                       MAYBE_GrContextKeepsGpuChannelAlive) {
+  // Test for crbug.com/551143
+  // This test verifies that holding a reference to the GrContext created by
+  // a ContextProviderCommandBuffer will keep the gpu channel alive after the
+  // provider has been destroyed. Without this behavior, user code would have
+  // to be careful to destroy objects in the right order to avoid using freed
+  // memory as a function pointer in the GrContext's GrGLInterface instance.
+  DCHECK(!IsChannelEstablished());
+  EstablishAndWait();
+
+  // Step 2: verify that holding onto the provider's GrContext will
+  // retain the host after provider is destroyed.
+  scoped_refptr<ContextProviderCommandBuffer> provider =
+      ContextProviderCommandBuffer::Create(CreateContext(),
+                                           OFFSCREEN_CONTEXT_FOR_TESTING);
+  EXPECT_TRUE(provider->BindToCurrentThread());
+
+  skia::RefPtr<GrContext> gr_context = skia::SharePtr(provider->GrContext());
+  provider = nullptr;
+
+  SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
+  skia::RefPtr<SkSurface> surface = skia::AdoptRef(SkSurface::NewRenderTarget(
+      gr_context.get(), SkSurface::kNo_Budgeted, info));
+  gr_context = nullptr;
+
+  // use the canvas after the provider and grcontext have been locally
+  // unref'ed. This should work just fine thanks to SkSurface_Gpu ref'ing
+  // the GrContext, which is ref'ing the GrGLInterfaceForWebGraphicsContext3D,
+  // which owns the commandbuffer instance.
+  SkPaint greenFillPaint;
+  greenFillPaint.setColor(SK_ColorGREEN);
+  greenFillPaint.setStyle(SkPaint::kFill_Style);
+  // Passes by not crashing
+  surface->getCanvas()->drawRect(SkRect::MakeWH(100, 100), greenFillPaint);
+}
+
 // Test fails on Chromeos + Mac, flaky on Windows because UI Compositor
 // establishes a GPU channel.
 #if defined(OS_LINUX) && !defined(OS_CHROMEOS)
diff --git a/content/browser/memory/memory_message_filter.cc b/content/browser/memory/memory_message_filter.cc
index 9a792d8..110f839 100644
--- a/content/browser/memory/memory_message_filter.cc
+++ b/content/browser/memory/memory_message_filter.cc
@@ -9,8 +9,20 @@
 
 namespace content {
 
-MemoryMessageFilter::MemoryMessageFilter()
-    : BrowserMessageFilter(MemoryMsgStart) {}
+MemoryMessageFilter::MemoryMessageFilter(
+    const BrowserChildProcessHost* child_process_host,
+    ProcessType process_type)
+    : BrowserMessageFilter(MemoryMsgStart),
+      process_host_(child_process_host),
+      process_type_(process_type) {
+  DCHECK_NE(process_type_, PROCESS_TYPE_RENDERER);
+}
+
+MemoryMessageFilter::MemoryMessageFilter(
+    const RenderProcessHost* render_process_host)
+    : BrowserMessageFilter(MemoryMsgStart),
+      process_host_(render_process_host),
+      process_type_(PROCESS_TYPE_RENDERER) {}
 
 MemoryMessageFilter::~MemoryMessageFilter() {}
 
diff --git a/content/browser/memory/memory_message_filter.h b/content/browser/memory/memory_message_filter.h
index c3fd30f..7567b37 100644
--- a/content/browser/memory/memory_message_filter.h
+++ b/content/browser/memory/memory_message_filter.h
@@ -8,14 +8,20 @@
 #include "base/memory/memory_pressure_listener.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/browser_message_filter.h"
+#include "content/public/common/process_type.h"
 
 namespace content {
 
+class BrowserChildProcessHost;
+class RenderProcessHost;
+
 // This class sends memory messages from the browser process.
 // See also: child_memory_message_filter.h
 class CONTENT_EXPORT MemoryMessageFilter : public BrowserMessageFilter {
  public:
-  MemoryMessageFilter();
+  MemoryMessageFilter(const BrowserChildProcessHost* child_process_host,
+                      ProcessType process_type);
+  MemoryMessageFilter(const RenderProcessHost* render_process_host);
 
   // BrowserMessageFilter implementation.
   void OnFilterAdded(IPC::Sender* sender) override;
@@ -29,9 +35,21 @@
       base::MemoryPressureListener::MemoryPressureLevel level);
 
  protected:
+  friend class MemoryPressureController;
+
   ~MemoryMessageFilter() override;
 
+  const void* process_host() const { return process_host_; }
+  ProcessType process_type() const { return process_type_; }
+
  private:
+  // The untyped process host and ProcessType associated with this filter
+  // instance. The process host is stored as untyped because it is only used as
+  // a key in MemoryPressureController; at no point is it ever deferenced to
+  // invoke any members on a process host.
+  const void* process_host_;
+  ProcessType process_type_;
+
   DISALLOW_COPY_AND_ASSIGN(MemoryMessageFilter);
 };
 
diff --git a/content/browser/memory/memory_pressure_controller.cc b/content/browser/memory/memory_pressure_controller.cc
index 67f31b4a..11cdbe5 100644
--- a/content/browser/memory/memory_pressure_controller.cc
+++ b/content/browser/memory/memory_pressure_controller.cc
@@ -20,7 +20,10 @@
 
   // Add the message filter to the set of all memory message filters and check
   // that it wasn't there beforehand.
-  const bool success = memory_message_filters_.insert(filter).second;
+  const bool success =
+      memory_message_filters_.insert(
+                                 std::make_pair(filter->process_host(), filter))
+          .second;
   DCHECK(success);
 
   // There's no need to send a message to the child process if memory pressure
@@ -33,10 +36,12 @@
     MemoryMessageFilter* filter) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
-  // Remove the message filter from the set of all memory message filters and
-  // check that it was there beforehand.
-  const bool success = memory_message_filters_.erase(filter) == 1u;
-  DCHECK(success);
+  // Remove the message filter from the set of all memory message filters,
+  // ensuring that it was there beforehand.
+  auto it = memory_message_filters_.find(filter->process_host());
+  DCHECK(it != memory_message_filters_.end());
+  DCHECK_EQ(filter, it->second);
+  memory_message_filters_.erase(it);
 }
 
 // static
@@ -63,9 +68,8 @@
   base::MemoryPressureListener::SetNotificationsSuppressed(suppressed);
 
   // Enable/disable suppressing memory notifications in all child processes.
-  for (const scoped_refptr<MemoryMessageFilter>& filter :
-       memory_message_filters_)
-    filter->SendSetPressureNotificationsSuppressed(suppressed);
+  for (const auto& filter_pair : memory_message_filters_)
+    filter_pair.second->SendSetPressureNotificationsSuppressed(suppressed);
 }
 
 void MemoryPressureController::SimulatePressureNotificationInAllProcesses(
@@ -87,9 +91,44 @@
   base::MemoryPressureListener::SimulatePressureNotification(level);
 
   // Simulate memory pressure notification in all child processes.
-  for (const scoped_refptr<MemoryMessageFilter>& filter :
-       memory_message_filters_)
-    filter->SendSimulatePressureNotification(level);
+  for (const auto& filter_pair : memory_message_filters_)
+    filter_pair.second->SendSimulatePressureNotification(level);
+}
+
+void MemoryPressureController::SendPressureNotification(
+    const BrowserChildProcessHost* child_process_host,
+    base::MemoryPressureListener::MemoryPressureLevel level) {
+  SendPressureNotificationImpl(child_process_host, level);
+}
+
+void MemoryPressureController::SendPressureNotification(
+    const RenderProcessHost* render_process_host,
+    base::MemoryPressureListener::MemoryPressureLevel level) {
+  SendPressureNotificationImpl(render_process_host, level);
+}
+
+void MemoryPressureController::SendPressureNotificationImpl(
+    const void* child_process_host,
+    base::MemoryPressureListener::MemoryPressureLevel level) {
+  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
+    // Note that passing base::Unretained(this) is safe here because the
+    // controller is a leaky singleton. It's also safe to pass an untyped
+    // child process pointer as the address is only used as a key for lookup in
+    // a map; at no point is it dereferenced.
+    BrowserThread::PostTask(
+        BrowserThread::IO, FROM_HERE,
+        base::Bind(&MemoryPressureController::SendPressureNotificationImpl,
+                   base::Unretained(this), child_process_host, level));
+    return;
+  }
+
+  if (base::MemoryPressureListener::AreNotificationsSuppressed())
+    return;
+
+  // Find the appropriate message filter and dispatch the message.
+  auto it = memory_message_filters_.find(child_process_host);
+  if (it != memory_message_filters_.end())
+    it->second->SendPressureNotification(level);
 }
 
 }  // namespace content
diff --git a/content/browser/memory/memory_pressure_controller.h b/content/browser/memory/memory_pressure_controller.h
index 934f847..b315ad3 100644
--- a/content/browser/memory/memory_pressure_controller.h
+++ b/content/browser/memory/memory_pressure_controller.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_BROWSER_MEMORY_MEMORY_PRESSURE_CONTROLLER_H_
 #define CONTENT_BROWSER_MEMORY_MEMORY_PRESSURE_CONTROLLER_H_
 
-#include <set>
+#include <map>
 
 #include "base/callback.h"
 #include "base/memory/memory_pressure_listener.h"
@@ -14,7 +14,9 @@
 
 namespace content {
 
+class BrowserChildProcessHost;
 class MemoryMessageFilter;
+class RenderProcessHost;
 
 class CONTENT_EXPORT MemoryPressureController {
  public:
@@ -26,6 +28,12 @@
   void SetPressureNotificationsSuppressedInAllProcesses(bool suppressed);
   void SimulatePressureNotificationInAllProcesses(
       base::MemoryPressureListener::MemoryPressureLevel level);
+  void SendPressureNotification(
+      const BrowserChildProcessHost* child_process_host,
+      base::MemoryPressureListener::MemoryPressureLevel level);
+  void SendPressureNotification(
+      const RenderProcessHost* render_process_host,
+      base::MemoryPressureListener::MemoryPressureLevel level);
 
   // This method can be called from any thread.
   static MemoryPressureController* GetInstance();
@@ -38,10 +46,16 @@
 
   MemoryPressureController();
 
-  // Set of all memory message filters in the browser process. Always accessed
-  // on the IO thread.
-  typedef std::set<scoped_refptr<MemoryMessageFilter>> MemoryMessageFilterSet;
-  MemoryMessageFilterSet memory_message_filters_;
+  // Implementation of the various SendPressureNotification methods.
+  void SendPressureNotificationImpl(
+      const void* child_process_host,
+      base::MemoryPressureListener::MemoryPressureLevel level);
+
+  // Map from untyped process host pointers to the associated memory message
+  // filters in the browser process. Always accessed on the IO thread.
+  typedef std::map<const void*, scoped_refptr<MemoryMessageFilter>>
+      MemoryMessageFilterMap;
+  MemoryMessageFilterMap memory_message_filters_;
 
   DISALLOW_COPY_AND_ASSIGN(MemoryPressureController);
 };
diff --git a/content/browser/memory/memory_pressure_controller_browsertest.cc b/content/browser/memory/memory_pressure_controller_browsertest.cc
index c0d4069..5b08a66 100644
--- a/content/browser/memory/memory_pressure_controller_browsertest.cc
+++ b/content/browser/memory/memory_pressure_controller_browsertest.cc
@@ -38,8 +38,25 @@
   return level == base::get<0>(param);
 }
 
+MATCHER_P(IsPressureMessage, level, "") {
+  // Ensure that the message is deleted upon return.
+  scoped_ptr<IPC::Message> message(arg);
+  if (message == nullptr)
+    return false;
+  MemoryMsg_PressureNotification::Param param;
+  if (!MemoryMsg_PressureNotification::Read(message.get(), &param))
+    return false;
+  return level == base::get<0>(param);
+}
+
 class MemoryMessageFilterForTesting : public MemoryMessageFilter {
  public:
+  // Use this object itself as a fake RenderProcessHost pointer. The address is
+  // only used for looking up the message filter in the controller and is never
+  // actually dereferenced, so this is safe.
+  MemoryMessageFilterForTesting()
+      : MemoryMessageFilter(reinterpret_cast<RenderProcessHost*>(this)) {}
+
   MOCK_METHOD1(Send, bool(IPC::Message* message));
 
   void Add() {
@@ -91,8 +108,21 @@
         ->SimulatePressureNotificationInAllProcesses(level);
     RunAllPendingInMessageLoop(BrowserThread::IO);
   }
+
+  void SendPressureNotificationAndWait(
+      const void* fake_process_host,
+      base::MemoryPressureListener::MemoryPressureLevel level) {
+    MemoryPressureController::GetInstance()->SendPressureNotification(
+        reinterpret_cast<const RenderProcessHost*>(fake_process_host), level);
+    RunAllPendingInMessageLoop(BrowserThread::IO);
+  }
 };
 
+const auto MEMORY_PRESSURE_LEVEL_MODERATE =
+    base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
+const auto MEMORY_PRESSURE_LEVEL_CRITICAL =
+    base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
+
 IN_PROC_BROWSER_TEST_F(MemoryPressureControllerBrowserTest,
                        SetPressureNotificationsSuppressedInAllProcesses) {
   scoped_refptr<MemoryMessageFilterForTesting> filter1(
@@ -108,6 +138,7 @@
   EXPECT_CALL(*filter2, Send(testing::_)).Times(0);
   filter1->Add();
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
+  testing::Mock::VerifyAndClearExpectations(this);
 
   // Enable suppressing memory pressure notifications in all processes. The
   // first filter should send a message.
@@ -115,12 +146,22 @@
   EXPECT_CALL(*filter2, Send(testing::_)).Times(0);
   SetPressureNotificationsSuppressedInAllProcessesAndWait(true);
   EXPECT_TRUE(base::MemoryPressureListener::AreNotificationsSuppressed());
+  testing::Mock::VerifyAndClearExpectations(this);
 
   // Add the second filter. It should send a message because notifications are
   // suppressed.
   EXPECT_CALL(*filter1, Send(testing::_)).Times(0);
   EXPECT_CALL(*filter2, Send(IsSetSuppressedMessage(true))).Times(1);
   filter2->Add();
+  testing::Mock::VerifyAndClearExpectations(this);
+
+  // Send a memory pressure event to the first child process. No messages should
+  // be sent as the notifications are suppressed.
+  EXPECT_CALL(*filter1, Send(testing::_)).Times(0);
+  EXPECT_CALL(*filter2, Send(testing::_)).Times(0);
+  SendPressureNotificationAndWait(filter1.get(),
+                                  MEMORY_PRESSURE_LEVEL_MODERATE);
+  testing::Mock::VerifyAndClearExpectations(this);
 
   // Disable suppressing memory pressure notifications in all processes. Both
   // filters should send a message.
@@ -128,11 +169,30 @@
   EXPECT_CALL(*filter2, Send(IsSetSuppressedMessage(false))).Times(1);
   SetPressureNotificationsSuppressedInAllProcessesAndWait(false);
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
+  testing::Mock::VerifyAndClearExpectations(this);
+
+  // Send a memory pressure event to the first child process. A message should
+  // be received as messages are not being suppressed.
+  EXPECT_CALL(*filter1, Send(IsPressureMessage(MEMORY_PRESSURE_LEVEL_MODERATE)))
+      .Times(1);
+  EXPECT_CALL(*filter2, Send(testing::_)).Times(0);
+  SendPressureNotificationAndWait(filter1.get(),
+                                  MEMORY_PRESSURE_LEVEL_MODERATE);
+  testing::Mock::VerifyAndClearExpectations(this);
+
+  // Send a memory pressure event to a non-existing child process. No message
+  // should be sent.
+  EXPECT_CALL(*filter1, Send(testing::_)).Times(0);
+  EXPECT_CALL(*filter2, Send(testing::_)).Times(0);
+  SendPressureNotificationAndWait(reinterpret_cast<const void*>(0xF005BA11),
+                                  MEMORY_PRESSURE_LEVEL_MODERATE);
+  testing::Mock::VerifyAndClearExpectations(this);
 
   // Remove the first filter. No messages should be sent.
   EXPECT_CALL(*filter1, Send(testing::_)).Times(0);
   EXPECT_CALL(*filter2, Send(testing::_)).Times(0);
   filter1->Remove();
+  testing::Mock::VerifyAndClearExpectations(this);
 
   // Enable suppressing memory pressure notifications in all processes. The
   // second filter should send a message.
@@ -140,6 +200,7 @@
   EXPECT_CALL(*filter2, Send(IsSetSuppressedMessage(true))).Times(1);
   SetPressureNotificationsSuppressedInAllProcessesAndWait(true);
   EXPECT_TRUE(base::MemoryPressureListener::AreNotificationsSuppressed());
+  testing::Mock::VerifyAndClearExpectations(this);
 
   // Remove the second filter and disable suppressing memory pressure
   // notifications in all processes. No messages should be sent.
@@ -148,15 +209,11 @@
   filter2->Remove();
   SetPressureNotificationsSuppressedInAllProcessesAndWait(false);
   EXPECT_FALSE(base::MemoryPressureListener::AreNotificationsSuppressed());
+  testing::Mock::VerifyAndClearExpectations(this);
 }
 
 IN_PROC_BROWSER_TEST_F(MemoryPressureControllerBrowserTest,
                        SimulatePressureNotificationInAllProcesses) {
-  const auto MEMORY_PRESSURE_LEVEL_MODERATE =
-      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE;
-  const auto MEMORY_PRESSURE_LEVEL_CRITICAL =
-      base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL;
-
   scoped_refptr<MemoryMessageFilterForTesting> filter(
       new MemoryMessageFilterForTesting);
   scoped_ptr<base::MemoryPressureListener> listener(
@@ -168,17 +225,26 @@
 
   filter->Add();
 
+  // Send a memory pressure event to the first child process. It should send a
+  // pressure notification message.
+  EXPECT_CALL(*filter, Send(IsPressureMessage(MEMORY_PRESSURE_LEVEL_MODERATE)))
+      .Times(1);
+  SendPressureNotificationAndWait(filter.get(), MEMORY_PRESSURE_LEVEL_MODERATE);
+  testing::Mock::VerifyAndClearExpectations(this);
+
   EXPECT_CALL(*filter, Send(IsSimulateMessage(MEMORY_PRESSURE_LEVEL_CRITICAL)))
       .Times(1);
   EXPECT_CALL(*this, OnMemoryPressure(MEMORY_PRESSURE_LEVEL_CRITICAL)).Times(1);
   SimulatePressureNotificationInAllProcessesAndWait(
       MEMORY_PRESSURE_LEVEL_CRITICAL);
   RunAllPendingInMessageLoop();  // Wait for the listener to run.
+  testing::Mock::VerifyAndClearExpectations(this);
 
   // Enable suppressing memory pressure notifications in all processes. This
   // should have no impact on simulating memory pressure notifications.
   EXPECT_CALL(*filter, Send(IsSetSuppressedMessage(true))).Times(1);
   SetPressureNotificationsSuppressedInAllProcessesAndWait(true);
+  testing::Mock::VerifyAndClearExpectations(this);
 
   EXPECT_CALL(*filter, Send(IsSimulateMessage(MEMORY_PRESSURE_LEVEL_MODERATE)))
       .Times(1);
@@ -186,11 +252,13 @@
   SimulatePressureNotificationInAllProcessesAndWait(
       MEMORY_PRESSURE_LEVEL_MODERATE);
   RunAllPendingInMessageLoop();  // Wait for the listener to run.
+  testing::Mock::VerifyAndClearExpectations(this);
 
   // Disable suppressing memory pressure notifications in all processes. This
   // should have no impact on simulating memory pressure notifications.
   EXPECT_CALL(*filter, Send(IsSetSuppressedMessage(false))).Times(1);
   SetPressureNotificationsSuppressedInAllProcessesAndWait(false);
+  testing::Mock::VerifyAndClearExpectations(this);
 
   EXPECT_CALL(*filter, Send(IsSimulateMessage(MEMORY_PRESSURE_LEVEL_MODERATE)))
       .Times(1);
@@ -198,6 +266,7 @@
   SimulatePressureNotificationInAllProcessesAndWait(
       MEMORY_PRESSURE_LEVEL_MODERATE);
   RunAllPendingInMessageLoop();  // Wait for the listener to run.
+  testing::Mock::VerifyAndClearExpectations(this);
 
   filter->Remove();
 }
diff --git a/content/browser/renderer_host/media/video_capture_controller_unittest.cc b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
index 1d8facee..27eb172 100644
--- a/content/browser/renderer_host/media/video_capture_controller_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_controller_unittest.cc
@@ -534,8 +534,8 @@
                                      media::PIXEL_STORAGE_TEXTURE);
     ASSERT_TRUE(buffer.get());
 #if !defined(OS_ANDROID)
-    mailbox_synctokens[i] = gpu::SyncToken(
-        ImageTransportFactory::GetInstance()->GetGLHelper()->InsertSyncPoint());
+    ImageTransportFactory::GetInstance()->GetGLHelper()->GenerateSyncToken(
+        &mailbox_synctokens[i]);
 #endif
     device_->OnIncomingCapturedVideoFrame(
         buffer.Pass(),
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 5e8fbf0..75334a2 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -988,7 +988,7 @@
   if (browser_command_line.HasSwitch(switches::kEnableMemoryBenchmarking))
     AddFilter(new MemoryBenchmarkMessageFilter());
 #endif
-  AddFilter(new MemoryMessageFilter());
+  AddFilter(new MemoryMessageFilter(this));
   AddFilter(new PushMessagingMessageFilter(
       GetID(), storage_partition_impl_->GetServiceWorkerContext()));
   // TODO(mfomitchev): Screen Orientation APIs on Aura - crbug.com/546719.
@@ -1279,6 +1279,7 @@
   // Propagate the following switches to the renderer command line (along
   // with any associated values) if present in the browser command line.
   static const char* const kSwitchNames[] = {
+    switches::kAgcStartupMinVolume,
     switches::kAllowLoopbackInPeerConnection,
     switches::kAudioBufferSize,
     switches::kBlinkPlatformLogChannels,
diff --git a/content/browser/renderer_host/render_widget_host_view_android.cc b/content/browser/renderer_host/render_widget_host_view_android.cc
index adc7f87..abb3ff1 100644
--- a/content/browser/renderer_host/render_widget_host_view_android.cc
+++ b/content/browser/renderer_host/render_widget_host_view_android.cc
@@ -249,7 +249,7 @@
   if (result) {
     GLHelper* gl_helper = GetPostReadbackGLHelper();
     if (gl_helper)
-      sync_token = gpu::SyncToken(gl_helper->InsertSyncPoint());
+      gl_helper->GenerateSyncToken(&sync_token);
   }
   const bool lost_resource = !sync_token.HasData();
   release_callback->Run(sync_token, lost_resource);
diff --git a/content/browser/renderer_host/text_input_client_mac.h b/content/browser/renderer_host/text_input_client_mac.h
index 84539e5..4f03a93 100644
--- a/content/browser/renderer_host/text_input_client_mac.h
+++ b/content/browser/renderer_host/text_input_client_mac.h
@@ -57,9 +57,6 @@
   //
   // Returns NSNotFound if the request times out or is not completed.
   NSUInteger GetCharacterIndexAtPoint(RenderWidgetHost* rwh, gfx::Point point);
-  // Returns nil if the request times out or is completed.
-  NSAttributedString* GetAttributedSubstringFromRange(
-      RenderWidgetHost* rwh, NSRange range);
   // Returns NSZeroRect if the request times out or is not completed. The result
   // is in WebKit coordinates.
   NSRect GetFirstRectForRange(RenderWidgetHost* rwh, NSRange range);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index bb9f32a..34b20cb 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -3853,6 +3853,78 @@
                                  grandchild->current_url().spec());
 }
 
+// Check that document.hasFocus() works properly with out-of-process iframes.
+// The test builds a page with four cross-site frames and then focuses them one
+// by one, checking the value of document.hasFocus() in all frames.  For any
+// given focused frame, document.hasFocus() should return true for that frame
+// and all its ancestor frames.
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DocumentHasFocus) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(b(c),d)"));
+  EXPECT_TRUE(NavigateToURL(shell(), main_url));
+
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+
+  EXPECT_EQ(
+      " Site A ------------ proxies for B C D\n"
+      "   |--Site B ------- proxies for A C D\n"
+      "   |    +--Site C -- proxies for A B D\n"
+      "   +--Site D ------- proxies for A B C\n"
+      "Where A = http://a.com/\n"
+      "      B = http://b.com/\n"
+      "      C = http://c.com/\n"
+      "      D = http://d.com/",
+      DepictFrameTree(root));
+
+  FrameTreeNode* child1 = root->child_at(0);
+  FrameTreeNode* child2 = root->child_at(1);
+  FrameTreeNode* grandchild = root->child_at(0)->child_at(0);
+
+  // Helper function to check document.hasFocus() for a given frame.
+  auto document_has_focus = [](FrameTreeNode* node) {
+    bool hasFocus = false;
+    EXPECT_TRUE(ExecuteScriptAndExtractBool(
+        node->current_frame_host(),
+        "window.domAutomationController.send(document.hasFocus())",
+        &hasFocus));
+    return hasFocus;
+  };
+
+  // The main frame should be focused to start with.
+  EXPECT_EQ(root, root->frame_tree()->GetFocusedFrame());
+
+  EXPECT_TRUE(document_has_focus(root));
+  EXPECT_FALSE(document_has_focus(child1));
+  EXPECT_FALSE(document_has_focus(grandchild));
+  EXPECT_FALSE(document_has_focus(child2));
+
+  FocusFrame(child1);
+  EXPECT_EQ(child1, root->frame_tree()->GetFocusedFrame());
+
+  EXPECT_TRUE(document_has_focus(root));
+  EXPECT_TRUE(document_has_focus(child1));
+  EXPECT_FALSE(document_has_focus(grandchild));
+  EXPECT_FALSE(document_has_focus(child2));
+
+  FocusFrame(grandchild);
+  EXPECT_EQ(grandchild, root->frame_tree()->GetFocusedFrame());
+
+  EXPECT_TRUE(document_has_focus(root));
+  EXPECT_TRUE(document_has_focus(child1));
+  EXPECT_TRUE(document_has_focus(grandchild));
+  EXPECT_FALSE(document_has_focus(child2));
+
+  FocusFrame(child2);
+  EXPECT_EQ(child2, root->frame_tree()->GetFocusedFrame());
+
+  EXPECT_TRUE(document_has_focus(root));
+  EXPECT_FALSE(document_has_focus(child1));
+  EXPECT_FALSE(document_has_focus(grandchild));
+  EXPECT_TRUE(document_has_focus(child2));
+}
+
 // There are no cursors on Android.
 #if !defined(OS_ANDROID)
 class CursorMessageFilter : public content::BrowserMessageFilter {
diff --git a/content/browser/tracing/OWNERS b/content/browser/tracing/OWNERS
index 73bcad3..a7ae202 100644
--- a/content/browser/tracing/OWNERS
+++ b/content/browser/tracing/OWNERS
@@ -1,3 +1,4 @@
-nduca@chromium.org
 dsinclair@chromium.org
+nduca@chromium.org
+oysteine@chromium.org
 simonhatch@chromium.org
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc
index 2e38619c..186b066 100644
--- a/content/browser/web_contents/web_contents_impl_unittest.cc
+++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -838,7 +838,7 @@
   // SiteInstance.
   browser_client.set_assign_site_for_url(false);
   const GURL native_url("non-site-url://stuffandthings");
-  ScopedVector<NavigationEntry> entries;
+  std::vector<scoped_ptr<NavigationEntry>> entries;
   scoped_ptr<NavigationEntry> new_entry =
       NavigationControllerImpl::CreateNavigationEntry(
           native_url, Referrer(), ui::PAGE_TRANSITION_LINK, false,
@@ -888,7 +888,7 @@
   // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
   browser_client.set_assign_site_for_url(true);
   const GURL regular_url("http://www.yahoo.com");
-  ScopedVector<NavigationEntry> entries;
+  std::vector<scoped_ptr<NavigationEntry>> entries;
   scoped_ptr<NavigationEntry> new_entry =
       NavigationControllerImpl::CreateNavigationEntry(
           regular_url, Referrer(), ui::PAGE_TRANSITION_LINK, false,
diff --git a/content/child/memory/child_memory_message_filter.cc b/content/child/memory/child_memory_message_filter.cc
index c824c5a..91e6849 100644
--- a/content/child/memory/child_memory_message_filter.cc
+++ b/content/child/memory/child_memory_message_filter.cc
@@ -19,6 +19,7 @@
                         OnSetPressureNotificationsSuppressed)
     IPC_MESSAGE_HANDLER(MemoryMsg_SimulatePressureNotification,
                         OnSimulatePressureNotification)
+    IPC_MESSAGE_HANDLER(MemoryMsg_PressureNotification, OnPressureNotification)
     IPC_MESSAGE_UNHANDLED(handled = false)
   IPC_END_MESSAGE_MAP()
   return handled;
diff --git a/content/child/resource_dispatcher.cc b/content/child/resource_dispatcher.cc
index f9eae9a..92a0962 100644
--- a/content/child/resource_dispatcher.cc
+++ b/content/child/resource_dispatcher.cc
@@ -101,12 +101,6 @@
     return true;
   }
 
-  // TODO(erikchen): Temporary debugging for http://crbug.com/550938.
-  if (message.type() == ResourceMsg_SetDataBuffer::ID)
-    request_info->has_received_buffer = true;
-  if (message.type() == ResourceMsg_DataReceived::ID)
-    CHECK(request_info->has_received_buffer);
-
   if (request_info->is_deferred) {
     request_info->deferred_message_queue.push_back(new IPC::Message(message));
     return true;
@@ -198,7 +192,6 @@
 
   request_info->buffer.reset(
       new base::SharedMemory(shm_handle, true));  // read only
-  request_info->has_processed_buffer = true;
   request_info->received_data_factory =
       make_scoped_refptr(new SharedMemoryReceivedDataFactory(
           message_sender_, request_id, request_info->buffer));
@@ -231,11 +224,6 @@
   PendingRequestInfo* request_info = GetPendingRequestInfo(request_id);
   bool send_ack = true;
   if (request_info && data_length > 0) {
-    // TODO(erikchen): Temporary debugging. http://crbug.com/550938.
-    CHECK(request_info->has_processed_buffer);
-    CHECK(!request_info->has_destroyed_buffer);
-    CHECK(request_info->buffer.get());
-
     CHECK(base::SharedMemory::IsHandleValid(request_info->buffer->handle()));
     CHECK_GE(request_info->buffer_size, data_offset + data_length);
 
@@ -354,7 +342,6 @@
     return;
   request_info->completion_time = ConsumeIOTimestamp();
   request_info->buffer.reset();
-  request_info->has_destroyed_buffer = true;
   if (request_info->received_data_factory)
     request_info->received_data_factory->Stop();
   request_info->received_data_factory = nullptr;
@@ -517,10 +504,7 @@
       frame_origin(frame_origin),
       response_url(request_url),
       download_to_file(download_to_file),
-      request_start(base::TimeTicks::Now()),
-      has_received_buffer(false),
-      has_processed_buffer(false),
-      has_destroyed_buffer(false) {
+      request_start(base::TimeTicks::Now()) {
 }
 
 ResourceDispatcher::PendingRequestInfo::~PendingRequestInfo() {
diff --git a/content/child/resource_dispatcher.h b/content/child/resource_dispatcher.h
index 604c636..05500f5 100644
--- a/content/child/resource_dispatcher.h
+++ b/content/child/resource_dispatcher.h
@@ -173,11 +173,6 @@
     scoped_refptr<SharedMemoryReceivedDataFactory> received_data_factory;
     linked_ptr<SiteIsolationResponseMetaData> site_isolation_metadata;
     int buffer_size;
-
-    // TODO(erikchen): Temporary debugging for http://crbug.com/550938.
-    bool has_received_buffer;
-    bool has_processed_buffer;
-    bool has_destroyed_buffer;
   };
   typedef base::hash_map<int, PendingRequestInfo> PendingRequestList;
 
diff --git a/content/common/android/sync_compositor_messages.h b/content/common/android/sync_compositor_messages.h
index d779f25..0326c6b 100644
--- a/content/common/android/sync_compositor_messages.h
+++ b/content/common/android/sync_compositor_messages.h
@@ -124,6 +124,9 @@
                            content::SyncCompositorCommonRendererParams,
                            cc::CompositorFrame)
 
+IPC_MESSAGE_ROUTED1(SyncCompositorMsg_UpdateState,
+                    content::SyncCompositorCommonBrowserParams)
+
 IPC_MESSAGE_ROUTED1(SyncCompositorHostMsg_UpdateState,
                     content::SyncCompositorCommonRendererParams)
 
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 945d3587..8ea66254 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -759,8 +759,9 @@
 IPC_MESSAGE_ROUTED0(FrameHostMsg_FrameFocused)
 
 // Sent when the renderer starts a provisional load for a frame.
-IPC_MESSAGE_ROUTED1(FrameHostMsg_DidStartProvisionalLoadForFrame,
-                    GURL /* url */)
+IPC_MESSAGE_ROUTED2(FrameHostMsg_DidStartProvisionalLoad,
+                    GURL /* url */,
+                    base::TimeTicks /* navigation_start */);
 
 // Sent when the renderer fails a provisional load with an error.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_DidFailProvisionalLoadWithError,
diff --git a/content/common/gpu/client/context_provider_command_buffer.cc b/content/common/gpu/client/context_provider_command_buffer.cc
index 7b16a02..ba1baa9 100644
--- a/content/common/gpu/client/context_provider_command_buffer.cc
+++ b/content/common/gpu/client/context_provider_command_buffer.cc
@@ -21,11 +21,11 @@
  public:
   explicit LostContextCallbackProxy(ContextProviderCommandBuffer* provider)
       : provider_(provider) {
-    provider_->context3d_->setContextLostCallback(this);
+    provider_->WebContext3DNoChecks()->setContextLostCallback(this);
   }
 
   ~LostContextCallbackProxy() override {
-    provider_->context3d_->setContextLostCallback(NULL);
+    provider_->WebContext3DNoChecks()->setContextLostCallback(NULL);
   }
 
   void onContextLost() override { provider_->OnLostContext(); }
@@ -47,11 +47,12 @@
 ContextProviderCommandBuffer::ContextProviderCommandBuffer(
     scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d,
     CommandBufferContextType type)
-    : context3d_(context3d.Pass()),
-      context_type_(type),
+    : context_type_(type),
       debug_name_(CommandBufferContextTypeToString(type)) {
+  gr_interface_ = skia::AdoptRef(new GrGLInterfaceForWebGraphicsContext3D(
+      context3d.Pass()));
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  DCHECK(context3d_);
+  DCHECK(gr_interface_->WebContext3D());
   context_thread_checker_.DetachFromThread();
 }
 
@@ -60,41 +61,52 @@
          context_thread_checker_.CalledOnValidThread());
 
   // Destroy references to the context3d_ before leaking it.
-  if (context3d_->GetCommandBufferProxy())
-    context3d_->GetCommandBufferProxy()->SetLock(nullptr);
+  if (WebContext3DNoChecks()->GetCommandBufferProxy())
+    WebContext3DNoChecks()->GetCommandBufferProxy()->SetLock(nullptr);
   lost_context_callback_proxy_.reset();
 }
 
 
 CommandBufferProxyImpl* ContextProviderCommandBuffer::GetCommandBufferProxy() {
-  return context3d_->GetCommandBufferProxy();
+  return WebContext3D()->GetCommandBufferProxy();
 }
 
 WebGraphicsContext3DCommandBufferImpl*
 ContextProviderCommandBuffer::WebContext3D() {
-  DCHECK(context3d_);
+  DCHECK(gr_interface_);
+  DCHECK(gr_interface_->WebContext3D());
   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
   DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  return context3d_.get();
+  return WebContext3DNoChecks();
+}
+
+WebGraphicsContext3DCommandBufferImpl*
+    ContextProviderCommandBuffer::WebContext3DNoChecks() {
+  DCHECK(gr_interface_);
+  return static_cast<WebGraphicsContext3DCommandBufferImpl*>(
+      gr_interface_->WebContext3D());
 }
 
 bool ContextProviderCommandBuffer::BindToCurrentThread() {
   // This is called on the thread the context will be used.
   DCHECK(context_thread_checker_.CalledOnValidThread());
+  DCHECK(gr_interface_ && gr_interface_->WebContext3D());
 
   if (lost_context_callback_proxy_)
     return true;
 
-  context3d_->SetContextType(context_type_);
-  if (!context3d_->InitializeOnCurrentThread())
+  WebContext3DNoChecks()->SetContextType(context_type_);
+  if (!WebContext3DNoChecks()->InitializeOnCurrentThread())
     return false;
 
+  gr_interface_->BindToCurrentThread();
   InitializeCapabilities();
 
   std::string unique_context_name =
-      base::StringPrintf("%s-%p", debug_name_.c_str(), context3d_.get());
-  context3d_->traceBeginCHROMIUM("gpu_toplevel", unique_context_name.c_str());
+      base::StringPrintf("%s-%p", debug_name_.c_str(), WebContext3DNoChecks());
+  WebContext3DNoChecks()->traceBeginCHROMIUM("gpu_toplevel",
+                                             unique_context_name.c_str());
 
   lost_context_callback_proxy_.reset(new LostContextCallbackProxy(this));
   return true;
@@ -105,15 +117,13 @@
 }
 
 gpu::gles2::GLES2Interface* ContextProviderCommandBuffer::ContextGL() {
-  DCHECK(context3d_);
   DCHECK(lost_context_callback_proxy_);  // Is bound to thread.
-  DCHECK(context_thread_checker_.CalledOnValidThread());
 
-  return context3d_->GetImplementation();
+  return WebContext3DNoChecks()->GetImplementation();
 }
 
 gpu::ContextSupport* ContextProviderCommandBuffer::ContextSupport() {
-  return context3d_->GetContextSupport();
+  return WebContext3D()->GetContextSupport();
 }
 
 class GrContext* ContextProviderCommandBuffer::GrContext() {
@@ -123,7 +133,7 @@
   if (gr_context_)
     return gr_context_->get();
 
-  gr_context_.reset(new GrContextForWebGraphicsContext3D(context3d_.get()));
+  gr_context_.reset(new GrContextForWebGraphicsContext3D(gr_interface_));
 
   // If GlContext is already lost, also abandon the new GrContext.
   if (gr_context_->get() &&
@@ -142,8 +152,7 @@
 }
 
 void ContextProviderCommandBuffer::SetupLock() {
-  DCHECK(context3d_);
-  context3d_->GetCommandBufferProxy()->SetLock(&context_lock_);
+  WebContext3D()->GetCommandBufferProxy()->SetLock(&context_lock_);
 }
 
 base::Lock* ContextProviderCommandBuffer::GetLock() {
@@ -176,9 +185,9 @@
 
 void ContextProviderCommandBuffer::InitializeCapabilities() {
   Capabilities caps;
-  caps.gpu = context3d_->GetImplementation()->capabilities();
+  caps.gpu = WebContext3DNoChecks()->GetImplementation()->capabilities();
 
-  size_t mapped_memory_limit = context3d_->GetMappedMemoryLimit();
+  size_t mapped_memory_limit = WebContext3DNoChecks()->GetMappedMemoryLimit();
   caps.max_transfer_buffer_usage_bytes =
       mapped_memory_limit == WebGraphicsContext3DCommandBufferImpl::kNoLimit
       ? std::numeric_limits<size_t>::max() : mapped_memory_limit;
diff --git a/content/common/gpu/client/context_provider_command_buffer.h b/content/common/gpu/client/context_provider_command_buffer.h
index 3e67234..7444f35 100644
--- a/content/common/gpu/client/context_provider_command_buffer.h
+++ b/content/common/gpu/client/context_provider_command_buffer.h
@@ -14,10 +14,12 @@
 #include "content/common/content_export.h"
 #include "content/common/gpu/client/command_buffer_metrics.h"
 #include "content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.h"
+#include "skia/ext/refptr.h"
 
 namespace content {
 
 class GrContextForWebGraphicsContext3D;
+class GrGLInterfaceForWebGraphicsContext3D;
 
 // Implementation of cc::ContextProvider that provides a
 // WebGraphicsContext3DCommandBufferImpl context and a GrContext.
@@ -56,12 +58,13 @@
   void OnLostContext();
 
  private:
+  WebGraphicsContext3DCommandBufferImpl* WebContext3DNoChecks();
   void InitializeCapabilities();
 
   base::ThreadChecker main_thread_checker_;
   base::ThreadChecker context_thread_checker_;
 
-  scoped_ptr<WebGraphicsContext3DCommandBufferImpl> context3d_;
+  skia::RefPtr<GrGLInterfaceForWebGraphicsContext3D> gr_interface_;
   scoped_ptr<GrContextForWebGraphicsContext3D> gr_context_;
 
   cc::ContextProvider::Capabilities capabilities_;
@@ -73,6 +76,7 @@
   base::Lock context_lock_;
 
   class LostContextCallbackProxy;
+  friend class LostContextCallbackProxy;
   scoped_ptr<LostContextCallbackProxy> lost_context_callback_proxy_;
 };
 
diff --git a/content/common/gpu/client/gl_helper.cc b/content/common/gpu/client/gl_helper.cc
index 33c9521c..5639cb21 100644
--- a/content/common/gpu/client/gl_helper.cc
+++ b/content/common/gpu/client/gl_helper.cc
@@ -952,8 +952,6 @@
   gl_->DeleteTextures(1, &texture_id);
 }
 
-uint32 GLHelper::InsertSyncPoint() { return gl_->InsertSyncPointCHROMIUM(); }
-
 void GLHelper::GenerateSyncToken(gpu::SyncToken* sync_token) {
   const uint64_t fence_sync = gl_->InsertFenceSyncCHROMIUM();
   gl_->ShallowFlushCHROMIUM();
@@ -969,8 +967,11 @@
   gpu::Mailbox mailbox;
   gl_->GenMailboxCHROMIUM(mailbox.name);
   gl_->ProduceTextureDirectCHROMIUM(texture_id, GL_TEXTURE_2D, mailbox.name);
-  return gpu::MailboxHolder(mailbox, gpu::SyncToken(InsertSyncPoint()),
-                            GL_TEXTURE_2D);
+
+  gpu::SyncToken sync_token;
+  GenerateSyncToken(&sync_token);
+
+  return gpu::MailboxHolder(mailbox, sync_token, GL_TEXTURE_2D);
 }
 
 GLuint GLHelper::ConsumeMailboxToTexture(const gpu::Mailbox& mailbox,
diff --git a/content/common/gpu/client/gl_helper.h b/content/common/gpu/client/gl_helper.h
index c8224d4..2c8b48ba 100644
--- a/content/common/gpu/client/gl_helper.h
+++ b/content/common/gpu/client/gl_helper.h
@@ -244,9 +244,6 @@
   // Deletes a texture.
   void DeleteTexture(GLuint texture_id);
 
-  // Insert a sync point into the GL command buffer.
-  uint32 InsertSyncPoint();
-
   // Inserts a fence sync, flushes, and generates a sync token.
   void GenerateSyncToken(gpu::SyncToken* sync_token);
 
diff --git a/content/common/gpu/client/gpu_video_decode_accelerator_host.cc b/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
index 41a4dbc..a329dcc 100644
--- a/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
+++ b/content/common/gpu/client/gpu_video_decode_accelerator_host.cc
@@ -46,6 +46,8 @@
   DCHECK(CalledOnValidThread());
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAcceleratorHost, msg)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_CdmAttached,
+                        OnCdmAttached)
     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed,
                         OnBitstreamBufferProcessed)
     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers,
@@ -104,6 +106,13 @@
   return true;
 }
 
+void GpuVideoDecodeAcceleratorHost::SetCdm(int cdm_id) {
+  DCHECK(CalledOnValidThread());
+  if (!channel_)
+    return;
+  Send(new AcceleratedVideoDecoderMsg_SetCdm(decoder_route_id_, cdm_id));
+}
+
 void GpuVideoDecodeAcceleratorHost::Decode(
     const media::BitstreamBuffer& bitstream_buffer) {
   DCHECK(CalledOnValidThread());
@@ -209,6 +218,12 @@
   }
 }
 
+void GpuVideoDecodeAcceleratorHost::OnCdmAttached(bool success) {
+  DCHECK(CalledOnValidThread());
+  if (client_)
+    client_->NotifyCdmAttached(success);
+}
+
 void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
     int32 bitstream_buffer_id) {
   DCHECK(CalledOnValidThread());
diff --git a/content/common/gpu/client/gpu_video_decode_accelerator_host.h b/content/common/gpu/client/gpu_video_decode_accelerator_host.h
index d82da072..9f9e8e2 100644
--- a/content/common/gpu/client/gpu_video_decode_accelerator_host.h
+++ b/content/common/gpu/client/gpu_video_decode_accelerator_host.h
@@ -36,6 +36,7 @@
 
   // media::VideoDecodeAccelerator implementation.
   bool Initialize(media::VideoCodecProfile profile, Client* client) override;
+  void SetCdm(int cdm_id) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& buffers) override;
@@ -58,6 +59,7 @@
 
   // IPC handlers, proxying media::VideoDecodeAccelerator::Client for the GPU
   // process.  Should not be called directly.
+  void OnCdmAttached(bool success);
   void OnBitstreamBufferProcessed(int32 bitstream_buffer_id);
   void OnProvidePictureBuffer(uint32 num_requested_buffers,
                               const gfx::Size& dimensions,
diff --git a/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc b/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc
index 970ec38..73c39ea 100644
--- a/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc
+++ b/content/common/gpu/client/grcontext_for_webgraphicscontext3d.cc
@@ -8,8 +8,8 @@
 #include "base/trace_event/trace_event.h"
 #include "gpu/blink/webgraphicscontext3d_impl.h"
 #include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h"
 #include "third_party/skia/include/gpu/GrContext.h"
-#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
 
 using gpu_blink::WebGraphicsContext3DImpl;
 
@@ -32,32 +32,28 @@
     LAZY_INSTANCE_INITIALIZER;
 
 void BindWebGraphicsContext3DGLContextCallback(const GrGLInterface* interface) {
-  gles2::SetGLContext(reinterpret_cast<WebGraphicsContext3DImpl*>(
-                          interface->fCallbackData)->GetGLInterface());
+  gles2::SetGLContext(static_cast<const GrGLInterfaceForWebGraphicsContext3D*>(
+                          interface)->WebContext3D()->GetGLInterface());
 }
 
 }  // namespace anonymous
 
 GrContextForWebGraphicsContext3D::GrContextForWebGraphicsContext3D(
-    WebGraphicsContext3DImpl* context3d) {
-  if (!context3d)
+    skia::RefPtr<GrGLInterfaceForWebGraphicsContext3D> gr_interface) {
+  if (!gr_interface || !gr_interface->WebContext3D())
     return;
 
   // Ensure the gles2 library is initialized first in a thread safe way.
   g_gles2_initializer.Get();
-  gles2::SetGLContext(context3d->GetGLInterface());
-  skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(
-      context3d->createGrGLInterface());
-  if (!interface)
-    return;
+  gles2::SetGLContext(gr_interface->WebContext3D()->GetGLInterface());
 
-  interface->fCallback = BindWebGraphicsContext3DGLContextCallback;
-  interface->fCallbackData =
-      reinterpret_cast<GrGLInterfaceCallbackData>(context3d);
+  skia_bindings::InitCommandBufferSkiaGLBinding(gr_interface.get());
+
+  gr_interface->fCallback = BindWebGraphicsContext3DGLContextCallback;
 
   gr_context_ = skia::AdoptRef(GrContext::Create(
       kOpenGL_GrBackend,
-      reinterpret_cast<GrBackendContext>(interface.get())));
+      reinterpret_cast<GrBackendContext>(gr_interface.get())));
   if (gr_context_) {
     // The limit of the number of GPU resources we hold in the GrContext's
     // GPU cache.
@@ -87,4 +83,22 @@
   }
 }
 
+GrGLInterfaceForWebGraphicsContext3D::GrGLInterfaceForWebGraphicsContext3D(
+    scoped_ptr<gpu_blink::WebGraphicsContext3DImpl> context3d)
+    : context3d_(context3d.Pass()) {
+}
+
+void GrGLInterfaceForWebGraphicsContext3D::BindToCurrentThread() {
+  context_thread_checker_.DetachFromThread();
+}
+
+GrGLInterfaceForWebGraphicsContext3D::~GrGLInterfaceForWebGraphicsContext3D() {
+  DCHECK(context_thread_checker_.CalledOnValidThread());
+#if !defined(NDEBUG)
+  // Set all the function pointers to zero, in order to crash if function
+  // pointers are used after free.
+  memset(&fFunctions, 0, sizeof(GrGLInterface::Functions));
+#endif
+}
+
 }  // namespace content
diff --git a/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h b/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h
index 8d0a2ea..7597f90 100644
--- a/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h
+++ b/content/common/gpu/client/grcontext_for_webgraphicscontext3d.h
@@ -6,7 +6,10 @@
 #define CONTENT_COMMON_GPU_CLIENT_GRCONTEXT_FOR_WEBGRAPHICSCONTEXT3D_H_
 
 #include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "skia/ext/refptr.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
 
 class GrContext;
 
@@ -16,13 +19,35 @@
 
 namespace content {
 
+// Wrap WebGraphicsContext3DImpl into a GrGLInterface object, which allows
+// the WebGraphicsContext3DImpl to be jointly refcounted (indirectly)
+// by the GrContext and the context provider. This makes it legal for the
+// GrContext to be invoked when it outlives the context provider that created
+// it. By doing this we no longer have to worry about use after free errors
+// caused a lack of consideration for object destruction order.
+class GrGLInterfaceForWebGraphicsContext3D final : public GrGLInterface {
+ public:
+  GrGLInterfaceForWebGraphicsContext3D(
+      scoped_ptr<gpu_blink::WebGraphicsContext3DImpl> context3d);
+  ~GrGLInterfaceForWebGraphicsContext3D() final;
+
+  void BindToCurrentThread();
+
+  gpu_blink::WebGraphicsContext3DImpl* WebContext3D() const {
+    return context3d_.get();
+  }
+ private:
+  base::ThreadChecker context_thread_checker_;
+  scoped_ptr<gpu_blink::WebGraphicsContext3DImpl> context3d_;
+};
+
 // This class binds an offscreen GrContext to an offscreen context3d. The
 // context3d is used by the GrContext so must be valid as long as this class
 // is alive.
 class GrContextForWebGraphicsContext3D {
  public:
   explicit GrContextForWebGraphicsContext3D(
-      gpu_blink::WebGraphicsContext3DImpl* context3d);
+      skia::RefPtr<GrGLInterfaceForWebGraphicsContext3D> context3d);
   virtual ~GrContextForWebGraphicsContext3D();
 
   GrContext* get() { return gr_context_.get(); }
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h
index a9c84a4..91803c260 100644
--- a/content/common/gpu/gpu_messages.h
+++ b/content/common/gpu/gpu_messages.h
@@ -678,12 +678,15 @@
 // Accelerated Video Decoder Messages
 // These messages are sent from Renderer process to GPU process.
 
+// Set a CDM on the decoder to handle encrypted buffers.
+IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_SetCdm,
+                    int32_t) /* CDM ID */
+
 // Send input buffer for decoding.
 IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderMsg_Decode,
                     AcceleratedVideoDecoderMsg_Decode_Params)
 
-// Sent from Renderer process to the GPU process to give the texture IDs for
-// the textures the decoder will use for output.
+// Give the texture IDs for the textures the decoder will use for output.
 IPC_MESSAGE_ROUTED2(AcceleratedVideoDecoderMsg_AssignPictureBuffers,
                     std::vector<int32>,  /* Picture buffer ID */
                     std::vector<uint32>) /* Texture ID */
@@ -708,6 +711,10 @@
 // Inform AcceleratedVideoDecoderHost that AcceleratedVideoDecoder has been
 // created.
 
+// Notify the CDM setting result.
+IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_CdmAttached,
+                    bool) /* success */
+
 // Accelerated video decoder has consumed input buffer from transfer buffer.
 IPC_MESSAGE_ROUTED1(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed,
                     int32) /* Processed buffer ID */
diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc
index 67b1259..8a0f7db1 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.cc
+++ b/content/common/gpu/media/android_video_decode_accelerator.cc
@@ -138,6 +138,12 @@
   return true;
 }
 
+void AndroidVideoDecodeAccelerator::SetCdm(int /* cdm_id */) {
+  // TODO(xhwang): Implement CDM setting here.
+  NOTIMPLEMENTED();
+  NotifyCdmAttached(false);
+}
+
 void AndroidVideoDecodeAccelerator::DoIOTask() {
   DCHECK(thread_checker_.CalledOnValidThread());
   TRACE_EVENT0("media", "AVDA::DoIOTask");
@@ -583,6 +589,10 @@
   state_ = ERROR;
 }
 
+void AndroidVideoDecodeAccelerator::NotifyCdmAttached(bool success) {
+  client_->NotifyCdmAttached(success);
+}
+
 void AndroidVideoDecodeAccelerator::NotifyPictureReady(
     const media::Picture& picture) {
   client_->PictureReady(picture);
diff --git a/content/common/gpu/media/android_video_decode_accelerator.h b/content/common/gpu/media/android_video_decode_accelerator.h
index 75ed7853..8384bc8 100644
--- a/content/common/gpu/media/android_video_decode_accelerator.h
+++ b/content/common/gpu/media/android_video_decode_accelerator.h
@@ -94,8 +94,9 @@
 
   ~AndroidVideoDecodeAccelerator() override;
 
-  // Does not take ownership of |client| which must outlive |*this|.
+  // media::VideoDecodeAccelerator implementation:
   bool Initialize(media::VideoCodecProfile profile, Client* client) override;
+  void SetCdm(int cdm_id) override;
   void Decode(const media::BitstreamBuffer& bitstream_buffer) override;
   void AssignPictureBuffers(
       const std::vector<media::PictureBuffer>& buffers) override;
@@ -105,7 +106,7 @@
   void Destroy() override;
   bool CanDecodeOnIOThread() override;
 
-  // AndroidVideoDecodeStateProvider
+  // AVDAStateProvider implementation:
   const gfx::Size& GetSize() const override;
   const base::ThreadChecker& ThreadChecker() const override;
   base::WeakPtr<gpu::gles2::GLES2Decoder> GetGlDecoder() const override;
@@ -146,6 +147,9 @@
   // Requests picture buffers from the client.
   void RequestPictureBuffers();
 
+  // Notifies the client of the CDM setting result.
+  void NotifyCdmAttached(bool success);
+
   // Notifies the client about the availability of a picture.
   void NotifyPictureReady(const media::Picture& picture);
 
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.cc b/content/common/gpu/media/gpu_video_decode_accelerator.cc
index 302caea..ed4d179 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.cc
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.cc
@@ -151,12 +151,46 @@
   DCHECK(!video_decode_accelerator_);
 }
 
+// static
+gpu::VideoDecodeAcceleratorSupportedProfiles
+GpuVideoDecodeAccelerator::GetSupportedProfiles() {
+  media::VideoDecodeAccelerator::SupportedProfiles profiles;
+  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
+  if (cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
+    return gpu::VideoDecodeAcceleratorSupportedProfiles();
+
+  // Query supported profiles for each VDA. The order of querying VDAs should
+  // be the same as the order of initializing VDAs. Then the returned profile
+  // can be initialized by corresponding VDA successfully.
+#if defined(OS_WIN)
+  profiles = DXVAVideoDecodeAccelerator::GetSupportedProfiles();
+#elif defined(OS_CHROMEOS)
+  media::VideoDecodeAccelerator::SupportedProfiles vda_profiles;
+#if defined(USE_V4L2_CODEC)
+  vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles();
+  GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
+  vda_profiles = V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles();
+  GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
+#endif
+#if defined(ARCH_CPU_X86_FAMILY)
+  vda_profiles = VaapiVideoDecodeAccelerator::GetSupportedProfiles();
+  GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
+#endif
+#elif defined(OS_MACOSX)
+  profiles = VTVideoDecodeAccelerator::GetSupportedProfiles();
+#elif defined(OS_ANDROID)
+  profiles = AndroidVideoDecodeAccelerator::GetSupportedProfiles();
+#endif
+  return GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeProfiles(profiles);
+}
+
 bool GpuVideoDecodeAccelerator::OnMessageReceived(const IPC::Message& msg) {
   if (!video_decode_accelerator_)
     return false;
 
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAccelerator, msg)
+    IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_SetCdm, OnSetCdm)
     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_Decode, OnDecode)
     IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderMsg_AssignPictureBuffers,
                         OnAssignPictureBuffers)
@@ -170,6 +204,12 @@
   return handled;
 }
 
+void GpuVideoDecodeAccelerator::NotifyCdmAttached(bool success) {
+  if (!Send(new AcceleratedVideoDecoderHostMsg_CdmAttached(host_route_id_,
+                                                           success)))
+    DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_CdmAttached) failed";
+}
+
 void GpuVideoDecodeAccelerator::ProvidePictureBuffers(
     uint32 requested_num_of_buffers,
     const gfx::Size& dimensions,
@@ -225,6 +265,26 @@
   }
 }
 
+void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
+    int32 bitstream_buffer_id) {
+  if (!Send(new AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed(
+          host_route_id_, bitstream_buffer_id))) {
+    DLOG(ERROR)
+        << "Send(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed) "
+        << "failed";
+  }
+}
+
+void GpuVideoDecodeAccelerator::NotifyFlushDone() {
+  if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_)))
+    DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed";
+}
+
+void GpuVideoDecodeAccelerator::NotifyResetDone() {
+  if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_)))
+    DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed";
+}
+
 void GpuVideoDecodeAccelerator::NotifyError(
     media::VideoDecodeAccelerator::Error error) {
   if (!Send(new AcceleratedVideoDecoderHostMsg_ErrorNotification(
@@ -234,10 +294,38 @@
   }
 }
 
+void GpuVideoDecodeAccelerator::OnWillDestroyStub() {
+  // The stub is going away, so we have to stop and destroy VDA here, before
+  // returning, because the VDA may need the GL context to run and/or do its
+  // cleanup. We cannot destroy the VDA before the IO thread message filter is
+  // removed however, since we cannot service incoming messages with VDA gone.
+  // We cannot simply check for existence of VDA on IO thread though, because
+  // we don't want to synchronize the IO thread with the ChildThread.
+  // So we have to wait for the RemoveFilter callback here instead and remove
+  // the VDA after it arrives and before returning.
+  if (filter_) {
+    stub_->channel()->RemoveFilter(filter_.get());
+    filter_removed_.Wait();
+  }
+
+  stub_->channel()->RemoveRoute(host_route_id_);
+  stub_->RemoveDestructionObserver(this);
+
+  video_decode_accelerator_.reset();
+  delete this;
+}
+
+bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) {
+  if (filter_ && io_task_runner_->BelongsToCurrentThread())
+    return filter_->SendOnIOThread(message);
+  DCHECK(child_task_runner_->BelongsToCurrentThread());
+  return stub_->channel()->Send(message);
+}
+
 void GpuVideoDecodeAccelerator::Initialize(
     const media::VideoCodecProfile profile,
     IPC::Message* init_done_msg) {
-  DCHECK(!video_decode_accelerator_.get());
+  DCHECK(!video_decode_accelerator_);
 
   if (!stub_->channel()->AddRoute(host_route_id_, this)) {
     DLOG(ERROR) << "Initialize(): failed to add route";
@@ -397,44 +485,16 @@
   return decoder.Pass();
 }
 
-// static
-gpu::VideoDecodeAcceleratorSupportedProfiles
-GpuVideoDecodeAccelerator::GetSupportedProfiles() {
-  media::VideoDecodeAccelerator::SupportedProfiles profiles;
-  const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
-  if (cmd_line->HasSwitch(switches::kDisableAcceleratedVideoDecode))
-    return gpu::VideoDecodeAcceleratorSupportedProfiles();
-
-  // Query supported profiles for each VDA. The order of querying VDAs should
-  // be the same as the order of initializing VDAs. Then the returned profile
-  // can be initialized by corresponding VDA successfully.
-#if defined(OS_WIN)
-  profiles = DXVAVideoDecodeAccelerator::GetSupportedProfiles();
-#elif defined(OS_CHROMEOS)
-  media::VideoDecodeAccelerator::SupportedProfiles vda_profiles;
-#if defined(USE_V4L2_CODEC)
-  vda_profiles = V4L2VideoDecodeAccelerator::GetSupportedProfiles();
-  GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
-  vda_profiles = V4L2SliceVideoDecodeAccelerator::GetSupportedProfiles();
-  GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
-#endif
-#if defined(ARCH_CPU_X86_FAMILY)
-  vda_profiles = VaapiVideoDecodeAccelerator::GetSupportedProfiles();
-  GpuVideoAcceleratorUtil::InsertUniqueDecodeProfiles(vda_profiles, &profiles);
-#endif
-#elif defined(OS_MACOSX)
-  profiles = VTVideoDecodeAccelerator::GetSupportedProfiles();
-#elif defined(OS_ANDROID)
-  profiles = AndroidVideoDecodeAccelerator::GetSupportedProfiles();
-#endif
-  return GpuVideoAcceleratorUtil::ConvertMediaToGpuDecodeProfiles(profiles);
+void GpuVideoDecodeAccelerator::OnSetCdm(int cdm_id) {
+  DCHECK(video_decode_accelerator_);
+  video_decode_accelerator_->SetCdm(cdm_id);
 }
 
 // Runs on IO thread if video_decode_accelerator_->CanDecodeOnIOThread() is
 // true, otherwise on the main thread.
 void GpuVideoDecodeAccelerator::OnDecode(
     const AcceleratedVideoDecoderMsg_Decode_Params& params) {
-  DCHECK(video_decode_accelerator_.get());
+  DCHECK(video_decode_accelerator_);
   if (params.bitstream_buffer_id < 0) {
     DLOG(ERROR) << "BitstreamBuffer id " << params.bitstream_buffer_id
                 << " out of range";
@@ -535,22 +595,22 @@
 
 void GpuVideoDecodeAccelerator::OnReusePictureBuffer(
     int32 picture_buffer_id) {
-  DCHECK(video_decode_accelerator_.get());
+  DCHECK(video_decode_accelerator_);
   video_decode_accelerator_->ReusePictureBuffer(picture_buffer_id);
 }
 
 void GpuVideoDecodeAccelerator::OnFlush() {
-  DCHECK(video_decode_accelerator_.get());
+  DCHECK(video_decode_accelerator_);
   video_decode_accelerator_->Flush();
 }
 
 void GpuVideoDecodeAccelerator::OnReset() {
-  DCHECK(video_decode_accelerator_.get());
+  DCHECK(video_decode_accelerator_);
   video_decode_accelerator_->Reset();
 }
 
 void GpuVideoDecodeAccelerator::OnDestroy() {
-  DCHECK(video_decode_accelerator_.get());
+  DCHECK(video_decode_accelerator_);
   OnWillDestroyStub();
 }
 
@@ -560,47 +620,6 @@
   filter_removed_.Signal();
 }
 
-void GpuVideoDecodeAccelerator::NotifyEndOfBitstreamBuffer(
-    int32 bitstream_buffer_id) {
-  if (!Send(new AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed(
-          host_route_id_, bitstream_buffer_id))) {
-    DLOG(ERROR)
-        << "Send(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed) "
-        << "failed";
-  }
-}
-
-void GpuVideoDecodeAccelerator::NotifyFlushDone() {
-  if (!Send(new AcceleratedVideoDecoderHostMsg_FlushDone(host_route_id_)))
-    DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_FlushDone) failed";
-}
-
-void GpuVideoDecodeAccelerator::NotifyResetDone() {
-  if (!Send(new AcceleratedVideoDecoderHostMsg_ResetDone(host_route_id_)))
-    DLOG(ERROR) << "Send(AcceleratedVideoDecoderHostMsg_ResetDone) failed";
-}
-
-void GpuVideoDecodeAccelerator::OnWillDestroyStub() {
-  // The stub is going away, so we have to stop and destroy VDA here, before
-  // returning, because the VDA may need the GL context to run and/or do its
-  // cleanup. We cannot destroy the VDA before the IO thread message filter is
-  // removed however, since we cannot service incoming messages with VDA gone.
-  // We cannot simply check for existence of VDA on IO thread though, because
-  // we don't want to synchronize the IO thread with the ChildThread.
-  // So we have to wait for the RemoveFilter callback here instead and remove
-  // the VDA after it arrives and before returning.
-  if (filter_.get()) {
-    stub_->channel()->RemoveFilter(filter_.get());
-    filter_removed_.Wait();
-  }
-
-  stub_->channel()->RemoveRoute(host_route_id_);
-  stub_->RemoveDestructionObserver(this);
-
-  video_decode_accelerator_.reset();
-  delete this;
-}
-
 void GpuVideoDecodeAccelerator::SetTextureCleared(
     const media::Picture& picture) {
   DCHECK(child_task_runner_->BelongsToCurrentThread());
@@ -619,13 +638,6 @@
   uncleared_textures_.erase(it);
 }
 
-bool GpuVideoDecodeAccelerator::Send(IPC::Message* message) {
-  if (filter_.get() && io_task_runner_->BelongsToCurrentThread())
-    return filter_->SendOnIOThread(message);
-  DCHECK(child_task_runner_->BelongsToCurrentThread());
-  return stub_->channel()->Send(message);
-}
-
 void GpuVideoDecodeAccelerator::SendCreateDecoderReply(IPC::Message* message,
                                                        bool succeeded) {
   GpuCommandBufferMsg_CreateVideoDecoder::WriteReplyParams(message, succeeded);
diff --git a/content/common/gpu/media/gpu_video_decode_accelerator.h b/content/common/gpu/media/gpu_video_decode_accelerator.h
index 2b2c3b7f..ad1e142f 100644
--- a/content/common/gpu/media/gpu_video_decode_accelerator.h
+++ b/content/common/gpu/media/gpu_video_decode_accelerator.h
@@ -38,19 +38,25 @@
       GpuCommandBufferStub* stub,
       const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner);
 
+  // Static query for supported profiles. This query calls the appropriate
+  // platform-specific version. The returned supported profiles vector will
+  // not contain duplicates.
+  static gpu::VideoDecodeAcceleratorSupportedProfiles GetSupportedProfiles();
+
   // IPC::Listener implementation.
   bool OnMessageReceived(const IPC::Message& message) override;
 
   // media::VideoDecodeAccelerator::Client implementation.
+  void NotifyCdmAttached(bool success) override;
   void ProvidePictureBuffers(uint32 requested_num_of_buffers,
                              const gfx::Size& dimensions,
                              uint32 texture_target) override;
   void DismissPictureBuffer(int32 picture_buffer_id) override;
   void PictureReady(const media::Picture& picture) override;
-  void NotifyError(media::VideoDecodeAccelerator::Error error) override;
   void NotifyEndOfBitstreamBuffer(int32 bitstream_buffer_id) override;
   void NotifyFlushDone() override;
   void NotifyResetDone() override;
+  void NotifyError(media::VideoDecodeAccelerator::Error error) override;
 
   // GpuCommandBufferStub::DestructionObserver implementation.
   void OnWillDestroyStub() override;
@@ -65,11 +71,6 @@
   void Initialize(const media::VideoCodecProfile profile,
                   IPC::Message* init_done_msg);
 
-  // Static query for supported profiles. This query calls the appropriate
-  // platform-specific version. The returned supported profiles vector will
-  // not contain duplicates.
-  static gpu::VideoDecodeAcceleratorSupportedProfiles GetSupportedProfiles();
-
  private:
   typedef scoped_ptr<media::VideoDecodeAccelerator>(
       GpuVideoDecodeAccelerator::*CreateVDAFp)();
@@ -88,6 +89,7 @@
   ~GpuVideoDecodeAccelerator() override;
 
   // Handlers for IPC messages.
+  void OnSetCdm(int cdm_id);
   void OnDecode(const AcceleratedVideoDecoderMsg_Decode_Params& params);
   void OnAssignPictureBuffers(const std::vector<int32>& buffer_ids,
                               const std::vector<uint32>& texture_ids);
diff --git a/content/common/gpu/media/video_encode_accelerator_unittest.cc b/content/common/gpu/media/video_encode_accelerator_unittest.cc
index 1775614..0f80d07 100644
--- a/content/common/gpu/media/video_encode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_encode_accelerator_unittest.cc
@@ -27,6 +27,7 @@
 #include "content/common/gpu/media/video_accelerator_unittest_helpers.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/bitstream_buffer.h"
+#include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_util.h"
 #include "media/base/test_data_util.h"
@@ -670,8 +671,9 @@
     LOG_ASSERT(0) << "Invalid profile " << profile_;
 
   decoder_->Initialize(
-      config, false, base::Bind(&VideoFrameQualityValidator::InitializeCB,
-                                base::Unretained(this)),
+      config, false, media::SetCdmReadyCB(),
+      base::Bind(&VideoFrameQualityValidator::InitializeCB,
+                 base::Unretained(this)),
       base::Bind(&VideoFrameQualityValidator::VerifyOutputFrame,
                  base::Unretained(this)));
 }
diff --git a/content/content_shell.gypi b/content/content_shell.gypi
index 637b557..cc30c8f 100644
--- a/content/content_shell.gypi
+++ b/content/content_shell.gypi
@@ -101,8 +101,6 @@
         'shell/app/shell_main_delegate_mac.mm',
         'shell/browser/blink_test_controller.cc',
         'shell/browser/blink_test_controller.h',
-        'shell/browser/ipc_echo_message_filter.cc',
-        'shell/browser/ipc_echo_message_filter.h',
         'shell/browser/layout_test/layout_test_android.cc',
         'shell/browser/layout_test/layout_test_android.h',
         'shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc',
@@ -210,8 +208,6 @@
         'shell/common/shell_test_configuration.h',
         'shell/common/v8_breakpad_support_win.cc',
         'shell/common/v8_breakpad_support_win.h',
-        'shell/renderer/ipc_echo.cc',
-        'shell/renderer/ipc_echo.h',
         'shell/renderer/layout_test/blink_test_helpers.cc',
         'shell/renderer/layout_test/blink_test_helpers.h',
         'shell/renderer/layout_test/blink_test_runner.cc',
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index 34bf7e6..90fac7e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -25,8 +25,6 @@
 import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.provider.Browser;
-import android.text.Editable;
-import android.text.Selection;
 import android.text.TextUtils;
 import android.util.Pair;
 import android.util.TypedValue;
@@ -61,11 +59,9 @@
 import org.chromium.content.browser.accessibility.captioning.CaptioningBridgeFactory;
 import org.chromium.content.browser.accessibility.captioning.SystemCaptioningBridge;
 import org.chromium.content.browser.accessibility.captioning.TextTrackSettings;
-import org.chromium.content.browser.input.AdapterInputConnection;
 import org.chromium.content.browser.input.FloatingPastePopupMenu;
 import org.chromium.content.browser.input.GamepadList;
 import org.chromium.content.browser.input.ImeAdapter;
-import org.chromium.content.browser.input.ImeAdapter.AdapterInputConnectionFactory;
 import org.chromium.content.browser.input.InputMethodManagerWrapper;
 import org.chromium.content.browser.input.JoystickScrollProvider;
 import org.chromium.content.browser.input.LegacyPastePopupMenu;
@@ -478,8 +474,6 @@
 
     // Only valid when focused on a text / password field.
     private ImeAdapter mImeAdapter;
-    private ImeAdapter.AdapterInputConnectionFactory mAdapterInputConnectionFactory;
-    private AdapterInputConnection mInputConnection;
 
     // Lazily created paste popup menu, triggered either via long press in an
     // editable region or from tapping the insertion handle.
@@ -569,12 +563,6 @@
     private SmartClipDataListener mSmartClipDataListener = null;
     private final ObserverList<ContainerViewObserver> mContainerViewObservers;
 
-    // This holds the state of editable text (e.g. contents of <input>, contenteditable) of
-    // a focused element.
-    // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new
-    //  state must be reflected to this to keep consistency.
-    private final Editable mEditable;
-
     /**
      * PID used to indicate an invalid render process.
      */
@@ -623,7 +611,6 @@
      */
     public ContentViewCore(Context context) {
         mContext = context;
-        mAdapterInputConnectionFactory = new AdapterInputConnectionFactory();
         mRenderCoordinates = new RenderCoordinates();
         mJoystickScrollProvider = new JoystickScrollProvider(this);
         float deviceScaleFactor = getContext().getResources().getDisplayMetrics().density;
@@ -639,8 +626,6 @@
         mGestureStateListeners = new ObserverList<GestureStateListener>();
         mGestureStateListenersIterator = mGestureStateListeners.rewindableIterator();
 
-        mEditable = Editable.Factory.getInstance().newEditable("");
-        Selection.setSelection(mEditable, 0);
         mContainerViewObservers = new ObserverList<ContainerViewObserver>();
         // Deep copy newConfig so that we can notice the difference.
         mCurrentConfig = new Configuration(getContext().getResources().getConfiguration());
@@ -721,19 +706,9 @@
         return mImeAdapter;
     }
 
-    @VisibleForTesting
-    public void setAdapterInputConnectionFactory(AdapterInputConnectionFactory factory) {
-        mAdapterInputConnectionFactory = factory;
-    }
-
-    @VisibleForTesting
-    public AdapterInputConnection getInputConnectionForTest() {
-        return mInputConnection;
-    }
-
     private ImeAdapter createImeAdapter() {
-        return new ImeAdapter(new InputMethodManagerWrapper(mContext),
-                new ImeAdapter.ImeAdapterDelegate() {
+        return new ImeAdapter(
+                new InputMethodManagerWrapper(mContext), new ImeAdapter.ImeAdapterDelegate() {
                     @Override
                     public void onImeEvent() {
                         mPopupZoomer.hide(true);
@@ -796,8 +771,7 @@
                             }
                         };
                     }
-                }
-        );
+                });
     }
 
     /**
@@ -840,7 +814,7 @@
     }
 
     @VisibleForTesting
-    void createContentViewAndroidDelegate() {
+    public void createContentViewAndroidDelegate() {
         mViewAndroidDelegate = new ContentViewAndroidDelegate(mContainerView, mRenderCoordinates);
     }
 
@@ -868,7 +842,6 @@
             if (mContainerView != null) {
                 assert mOverscrollRefreshHandler == null;
                 mPastePopupMenu = null;
-                mInputConnection = null;
                 hidePopupsAndClearSelection();
             }
 
@@ -1452,17 +1425,6 @@
         hidePopups();
     }
 
-    private void clearUserSelection() {
-        if (mFocusedNodeEditable) {
-            if (mInputConnection != null) {
-                int selectionEnd = Selection.getSelectionEnd(mEditable);
-                mInputConnection.setSelection(selectionEnd, selectionEnd);
-            }
-        } else if (mWebContents != null) {
-            mWebContents.unselect();
-        }
-    }
-
     private void hidePopups() {
         hideSelectActionMode();
         hidePastePopup();
@@ -1540,37 +1502,7 @@
      * @see View#onCreateInputConnection(EditorInfo)
      */
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
-        // Android View framework will check whether the user can compose text by calling this
-        // function at view attachment. Especially in the case of hardware keyboard, connection can
-        // be made regardless of whether we have called showSoftInput(), and therefore we need
-        // to check the availability ourselves here.
-        // If we return null here, hardware keyboard will not be connected through input connection,
-        // but key events will go through View#dispatchKeyEvent(), and the user won't get any
-        // recommendation from text composition, which is what we expect.
-        if (!mImeAdapter.canCreateInputConnection()) {
-            mInputConnection = null;
-            return null;
-        }
-
-        if (!mImeAdapter.hasTextInputType()) {
-            // Although onCheckIsTextEditor will return false in this case, the EditorInfo
-            // is still used by the InputMethodService. Need to make sure the IME doesn't
-            // enter fullscreen mode.
-            outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
-        }
-        mInputConnection = mAdapterInputConnectionFactory.get(mContainerView, mImeAdapter,
-                mEditable, outAttrs);
-        return mInputConnection;
-    }
-
-    @VisibleForTesting
-    public AdapterInputConnection getAdapterInputConnectionForTest() {
-        return mInputConnection;
-    }
-
-    @VisibleForTesting
-    public Editable getEditableForTest() {
-        return mEditable;
+        return mImeAdapter.onCreateInputConnection(outAttrs);
     }
 
     /**
@@ -1692,7 +1624,7 @@
                 // Clear the selection. The selection is cleared on destroying IME
                 // and also here since we may receive destroy first, for example
                 // when focus is lost in webview.
-                clearUserSelection();
+                clearSelection();
             }
         }
         if (mNativeContentViewCore != 0) nativeSetFocus(mNativeContentViewCore, gainFocus);
@@ -2147,7 +2079,7 @@
                     mActionMode = null;
                     if (mUnselectAllOnActionModeDismiss) {
                         dismissTextHandles();
-                        clearUserSelection();
+                        clearSelection();
                     }
                     if (!supportsFloatingActionMode()) {
                         getContentViewClient().onContextualActionBarHidden();
@@ -2264,11 +2196,16 @@
     }
 
     /**
-     * Clears the current text selection.
+     * Clears the current text selection. Note that we will try to move cursor to selection
+     * end if applicable.
      */
     public void clearSelection() {
-        // This method can be called during shutdown, guard against null accordingly.
-        if (mWebContents != null) mWebContents.unselect();
+        if (mFocusedNodeEditable) {
+            mImeAdapter.moveCursorToSelectionEnd();
+        } else {
+            // This method can be called during shutdown, guard against null accordingly.
+            if (mWebContents != null) mWebContents.unselect();
+        }
     }
 
     /**
@@ -2482,11 +2419,8 @@
             mImeAdapter.attach(nativeImeAdapterAndroid);
             mImeAdapter.updateKeyboardVisibility(
                     textInputType, textInputFlags, showImeIfNeeded);
-
-            if (mInputConnection != null) {
-                mInputConnection.updateState(text, selectionStart, selectionEnd, compositionStart,
-                        compositionEnd, isNonImeChange);
-            }
+            mImeAdapter.updateState(text, selectionStart, selectionEnd, compositionStart,
+                    compositionEnd, isNonImeChange);
 
             if (mActionMode != null) {
                 final boolean actionModeConfigurationChanged =
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
index 13a48f8..2376c47e 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/AdapterInputConnection.java
@@ -36,9 +36,7 @@
     public static final int INVALID_SELECTION = -1;
     public static final int INVALID_COMPOSITION = -1;
 
-    private final View mInternalView;
     private final ImeAdapter mImeAdapter;
-    private final Editable mEditable;
 
     private boolean mSingleLine;
     private int mNumNestedBatchEdits = 0;
@@ -50,13 +48,11 @@
     private int mLastUpdateCompositionEnd = INVALID_COMPOSITION;
 
     @VisibleForTesting
-    AdapterInputConnection(
-            View view, ImeAdapter imeAdapter, Editable editable, EditorInfo outAttrs) {
+    AdapterInputConnection(View view, ImeAdapter imeAdapter, int initialSelStart, int initialSelEnd,
+            EditorInfo outAttrs) {
         super(view, true);
-        mInternalView = view;
         mImeAdapter = imeAdapter;
         mImeAdapter.setInputConnection(this);
-        mEditable = editable;
 
         mSingleLine = true;
         outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN
@@ -132,13 +128,11 @@
             outAttrs.inputType |= InputType.TYPE_TEXT_FLAG_CAP_SENTENCES;
         }
 
-        outAttrs.initialSelStart = Selection.getSelectionStart(mEditable);
-        outAttrs.initialSelEnd = Selection.getSelectionEnd(mEditable);
+        outAttrs.initialSelStart = initialSelStart;
+        outAttrs.initialSelEnd = initialSelEnd;
         mLastUpdateSelectionStart = outAttrs.initialSelStart;
         mLastUpdateSelectionEnd = outAttrs.initialSelEnd;
         Log.d(TAG, "Constructor called with outAttrs: %s", dumpEditorInfo(outAttrs));
-
-        Selection.setSelection(mEditable, outAttrs.initialSelStart, outAttrs.initialSelEnd);
     }
 
     private static String dumpEditorInfo(EditorInfo editorInfo) {
@@ -191,17 +185,19 @@
         compositionStart = Math.min(compositionStart, text.length());
         compositionEnd = Math.min(compositionEnd, text.length());
 
-        String prevText = mEditable.toString();
+        Editable editable = getEditableInternal();
+
+        String prevText = editable.toString();
         boolean textUnchanged = prevText.equals(text);
 
         if (!textUnchanged) {
-            mEditable.replace(0, mEditable.length(), text);
+            editable.replace(0, editable.length(), text);
         }
 
-        Selection.setSelection(mEditable, selectionStart, selectionEnd);
+        Selection.setSelection(editable, selectionStart, selectionEnd);
 
         if (compositionStart == compositionEnd) {
-            removeComposingSpans(mEditable);
+            removeComposingSpans(editable);
         } else {
             super.setComposingRegion(compositionStart, compositionEnd);
         }
@@ -209,12 +205,17 @@
     }
 
     /**
-     * @return Editable object which contains the state of current focused editable element.
+     * @see BaseInputConnection#getEditable()
      */
     @Override
     public Editable getEditable() {
-        Log.d(TAG, "getEditable: %s", dumpEditable(mEditable));
-        return mEditable;
+        Editable editable = getEditableInternal();
+        Log.d(TAG, "getEditable: %s", dumpEditable(editable));
+        return editable;
+    }
+
+    private Editable getEditableInternal() {
+        return mImeAdapter.getEditable();
     }
 
     /**
@@ -223,10 +224,11 @@
      */
     private void updateSelectionIfRequired() {
         if (mNumNestedBatchEdits != 0) return;
-        int selectionStart = Selection.getSelectionStart(mEditable);
-        int selectionEnd = Selection.getSelectionEnd(mEditable);
-        int compositionStart = getComposingSpanStart(mEditable);
-        int compositionEnd = getComposingSpanEnd(mEditable);
+        Editable editable = getEditableInternal();
+        int selectionStart = Selection.getSelectionStart(editable);
+        int selectionEnd = Selection.getSelectionEnd(editable);
+        int compositionStart = getComposingSpanStart(editable);
+        int compositionEnd = getComposingSpanEnd(editable);
         // Avoid sending update if we sent an exact update already previously.
         if (mLastUpdateSelectionStart == selectionStart
                 && mLastUpdateSelectionEnd == selectionEnd
@@ -238,8 +240,7 @@
                 compositionStart, compositionEnd);
         // updateSelection should be called every time the selection or composition changes
         // if it happens not within a batch edit, or at the end of each top level batch edit.
-        getInputMethodManagerWrapper().updateSelection(
-                mInternalView, selectionStart, selectionEnd, compositionStart, compositionEnd);
+        mImeAdapter.updateSelection(selectionStart, selectionEnd, compositionStart, compositionEnd);
         mLastUpdateSelectionStart = selectionStart;
         mLastUpdateSelectionEnd = selectionEnd;
         mLastUpdateCompositionStart = compositionStart;
@@ -295,11 +296,12 @@
     @Override
     public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
         Log.d(TAG, "getExtractedText");
+        Editable editable = getEditableInternal();
         ExtractedText et = new ExtractedText();
-        et.text = mEditable.toString();
-        et.partialEndOffset = mEditable.length();
-        et.selectionStart = Selection.getSelectionStart(mEditable);
-        et.selectionEnd = Selection.getSelectionEnd(mEditable);
+        et.text = editable.toString();
+        et.partialEndOffset = editable.length();
+        et.selectionStart = Selection.getSelectionStart(editable);
+        et.selectionEnd = Selection.getSelectionEnd(editable);
         et.flags = mSingleLine ? ExtractedText.FLAG_SINGLE_LINE : 0;
         return et;
     }
@@ -354,21 +356,20 @@
             finishComposingText();
         }
 
-        int originalBeforeLength = beforeLength;
-        int originalAfterLength = afterLength;
-        int selectionStart = Selection.getSelectionStart(mEditable);
-        int selectionEnd = Selection.getSelectionEnd(mEditable);
+        Editable editable = getEditableInternal();
+        int selectionStart = Selection.getSelectionStart(editable);
+        int selectionEnd = Selection.getSelectionEnd(editable);
         int availableBefore = selectionStart;
-        int availableAfter = mEditable.length() - selectionEnd;
+        int availableAfter = editable.length() - selectionEnd;
         beforeLength = Math.min(beforeLength, availableBefore);
         afterLength = Math.min(afterLength, availableAfter);
 
         // Adjust these values even before calling super.deleteSurroundingText() to be consistent
         // with the super class.
-        if (isIndexBetweenUtf16SurrogatePair(mEditable, selectionStart - beforeLength)) {
+        if (isIndexBetweenUtf16SurrogatePair(editable, selectionStart - beforeLength)) {
             beforeLength += 1;
         }
-        if (isIndexBetweenUtf16SurrogatePair(mEditable, selectionEnd + afterLength)) {
+        if (isIndexBetweenUtf16SurrogatePair(editable, selectionEnd + afterLength)) {
             afterLength += 1;
         }
 
@@ -442,20 +443,21 @@
     }
 
     /**
-     * Update the mEditable state to reflect what Blink will do in response to the KeyDown
-     * for a unicode-mapped key event.
+     * Update the Editable to reflect what Blink will do in response to the KeyDown for a
+     * unicode-mapped key event.
      * @param unicodeChar The Unicode character to update selection with.
      */
     private void replaceSelectionWithUnicodeChar(int unicodeChar) {
         if (unicodeChar == 0) return;
-        int selectionStart = Selection.getSelectionStart(mEditable);
-        int selectionEnd = Selection.getSelectionEnd(mEditable);
+        Editable editable = getEditableInternal();
+        int selectionStart = Selection.getSelectionStart(editable);
+        int selectionEnd = Selection.getSelectionEnd(editable);
         if (selectionStart > selectionEnd) {
             int temp = selectionStart;
             selectionStart = selectionEnd;
             selectionEnd = temp;
         }
-        mEditable.replace(selectionStart, selectionEnd, Character.toString((char) unicodeChar));
+        editable.replace(selectionStart, selectionEnd, Character.toString((char) unicodeChar));
         updateSelectionIfRequired();
     }
 
@@ -467,7 +469,8 @@
         Log.d(TAG, "finishComposingText");
         mPendingAccent = 0;
 
-        if (getComposingSpanStart(mEditable) == getComposingSpanEnd(mEditable)) {
+        if (getComposingSpanStart(getEditableInternal())
+                == getComposingSpanEnd(getEditableInternal())) {
             return true;
         }
 
@@ -484,7 +487,7 @@
     @Override
     public boolean setSelection(int start, int end) {
         Log.d(TAG, "setSelection [%d %d]", start, end);
-        int textLength = mEditable.length();
+        int textLength = getEditableInternal().length();
         if (start < 0 || end < 0 || start > textLength || end > textLength) return true;
         super.setSelection(start, end);
         updateSelectionIfRequired();
@@ -492,12 +495,10 @@
     }
 
     /**
-     * Informs the InputMethodManager and InputMethodSession (i.e. the IME) that the text
-     * state is no longer what the IME has and that it needs to be updated.
+     * Call this when restartInput() is called.
      */
-    void restartInput() {
-        Log.d(TAG, "restartInput");
-        getInputMethodManagerWrapper().restartInput(mInternalView);
+    void onRestartInput() {
+        Log.d(TAG, "onRestartInput");
         mNumNestedBatchEdits = 0;
         mPendingAccent = 0;
     }
@@ -508,7 +509,8 @@
     @Override
     public boolean setComposingRegion(int start, int end) {
         Log.d(TAG, "setComposingRegion [%d %d]", start, end);
-        int textLength = mEditable.length();
+        Editable editable = getEditableInternal();
+        int textLength = editable.length();
         int a = Math.min(start, end);
         int b = Math.max(start, end);
         if (a < 0) a = 0;
@@ -517,7 +519,7 @@
         if (b > textLength) b = textLength;
 
         if (a == b) {
-            removeComposingSpans(mEditable);
+            removeComposingSpans(editable);
         } else {
             super.setComposingRegion(a, b);
         }
@@ -525,15 +527,11 @@
 
         CharSequence regionText = null;
         if (b > a) {
-            regionText = mEditable.subSequence(a, b);
+            regionText = editable.subSequence(a, b);
         }
         return mImeAdapter.setComposingRegion(regionText, a, b);
     }
 
-    private InputMethodManagerWrapper getInputMethodManagerWrapper() {
-        return mImeAdapter.getInputMethodManagerWrapper();
-    }
-
     @VisibleForTesting
     static class ImeState {
         public final String text;
@@ -554,11 +552,12 @@
 
     @VisibleForTesting
     ImeState getImeStateForTesting() {
-        String text = mEditable.toString();
-        int selectionStart = Selection.getSelectionStart(mEditable);
-        int selectionEnd = Selection.getSelectionEnd(mEditable);
-        int compositionStart = getComposingSpanStart(mEditable);
-        int compositionEnd = getComposingSpanEnd(mEditable);
+        Editable editable = getEditableInternal();
+        String text = editable.toString();
+        int selectionStart = Selection.getSelectionStart(editable);
+        int selectionEnd = Selection.getSelectionEnd(editable);
+        int compositionStart = getComposingSpanStart(editable);
+        int compositionEnd = getComposingSpanEnd(editable);
         return new ImeState(text, selectionStart, selectionEnd, compositionStart, compositionEnd);
     }
 }
diff --git a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
index c53070a..159aa7b 100644
--- a/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
+++ b/content/public/android/java/src/org/chromium/content/browser/input/ImeAdapter.java
@@ -8,6 +8,7 @@
 import android.os.ResultReceiver;
 import android.os.SystemClock;
 import android.text.Editable;
+import android.text.Selection;
 import android.text.SpannableString;
 import android.text.style.BackgroundColorSpan;
 import android.text.style.CharacterStyle;
@@ -90,8 +91,15 @@
     private long mNativeImeAdapterAndroid;
     private InputMethodManagerWrapper mInputMethodManagerWrapper;
     private AdapterInputConnection mInputConnection;
+    private AdapterInputConnectionFactory mInputConnectionFactory;
     private final ImeAdapterDelegate mViewEmbedder;
 
+    // This holds the state of editable text (e.g. contents of <input>, contenteditable) of
+    // a focused element.
+    // Every time the user, IME, javascript (Blink), autofill etc. modifies the content, the new
+    // state must be reflected to this to keep consistency.
+    private final Editable mEditable;
+
     private int mTextInputType = TextInputType.NONE;
     private int mTextInputFlags;
 
@@ -103,19 +111,48 @@
     public ImeAdapter(InputMethodManagerWrapper wrapper, ImeAdapterDelegate embedder) {
         mInputMethodManagerWrapper = wrapper;
         mViewEmbedder = embedder;
+        mInputConnectionFactory = new AdapterInputConnectionFactory();
+        mEditable = Editable.Factory.getInstance().newEditable("");
+        Selection.setSelection(mEditable, 0);
     }
 
     /**
      * Default factory for AdapterInputConnection classes.
      */
     public static class AdapterInputConnectionFactory {
-        public AdapterInputConnection get(View view, ImeAdapter imeAdapter,
-                Editable editable, EditorInfo outAttrs) {
-            return new AdapterInputConnection(view, imeAdapter, editable, outAttrs);
+        public AdapterInputConnection get(View view, ImeAdapter imeAdapter, int initialSelStart,
+                int initialSelEnd, EditorInfo outAttrs) {
+            return new AdapterInputConnection(
+                    view, imeAdapter, initialSelStart, initialSelEnd, outAttrs);
         }
     }
 
     /**
+     * @see View#onCreateInputConnection(EditorInfo)
+     */
+    public AdapterInputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        // Without this line, some third-party IMEs will try to compose text even when
+        // not on an editable node. Even when we return null here, key events can still go through
+        // ImeAdapter#dispatchKeyEvent().
+        if (mTextInputType == TextInputType.NONE) {
+            mInputConnection = null;
+            return null;
+        }
+
+        if (!isTextInputType(mTextInputType)) {
+            // Although onCheckIsTextEditor will return false in this case, the EditorInfo
+            // is still used by the InputMethodService. Need to make sure the IME doesn't
+            // enter fullscreen mode.
+            outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_FULLSCREEN;
+        }
+        int initialSelStart = Selection.getSelectionStart(mEditable);
+        int initialSelEnd = outAttrs.initialSelEnd = Selection.getSelectionEnd(mEditable);
+        mInputConnection = mInputConnectionFactory.get(
+                mViewEmbedder.getAttachedView(), this, initialSelStart, initialSelEnd, outAttrs);
+        return mInputConnection;
+    }
+
+    /**
      * Overrides the InputMethodManagerWrapper that ImeAdapter uses to make calls to
      * InputMethodManager.
      * @param immw InputMethodManagerWrapper that should be used to call InputMethodManager.
@@ -134,6 +171,11 @@
         return mInputMethodManagerWrapper;
     }
 
+    @VisibleForTesting
+    void setInputConnectionFactory(AdapterInputConnectionFactory factory) {
+        mInputConnectionFactory = factory;
+    }
+
     /**
      * Set the current active InputConnection when a new InputConnection is constructed.
      * @param inputConnection The input connection that is currently used with IME.
@@ -143,6 +185,21 @@
     }
 
     /**
+     * Get the current input connection for testing purposes.
+     */
+    @VisibleForTesting
+    public AdapterInputConnection getInputConnectionForTest() {
+        return mInputConnection;
+    }
+
+    /**
+     * @return The Editable instance that will be shared across AdapterInputConnection instances.
+     */
+    Editable getEditable() {
+        return mEditable;
+    }
+
+    /**
      * Should be used only by AdapterInputConnection.
      * @return The input type of currently focused element.
      */
@@ -198,9 +255,7 @@
         if (mTextInputType != textInputType) {
             mTextInputType = textInputType;
             // No need to restart if we are going to hide anyways.
-            if (textInputType != TextInputType.NONE) {
-                mInputMethodManagerWrapper.restartInput(mViewEmbedder.getAttachedView());
-            }
+            if (textInputType != TextInputType.NONE) restartInput();
         }
 
         // There is no API for us to get notified of user's dismissal of keyboard.
@@ -213,6 +268,28 @@
     }
 
     /**
+     * Updates internal representation of the text being edited and its selection and composition
+     * properties.
+     *
+     * @param text The String contents of the field being edited.
+     * @param selectionStart The character offset of the selection start, or the caret position if
+     *                       there is no selection.
+     * @param selectionEnd The character offset of the selection end, or the caret position if there
+     *                     is no selection.
+     * @param compositionStart The character offset of the composition start, or -1 if there is no
+     *                         composition.
+     * @param compositionEnd The character offset of the composition end, or -1 if there is no
+     *                       selection.
+     * @param isNonImeChange True when the update was caused by non-IME (e.g. Javascript).
+     */
+    public void updateState(String text, int selectionStart, int selectionEnd, int compositionStart,
+            int compositionEnd, boolean isNonImeChange) {
+        if (mInputConnection == null) return;
+        mInputConnection.updateState(text, selectionStart, selectionEnd, compositionStart,
+                compositionEnd, isNonImeChange);
+    }
+
+    /**
      * Attaches the imeAdapter to its native counterpart. This is needed to start forwarding
      * keyboard events to WebKit.
      * @param nativeImeAdapter The pointer to the native ImeAdapter object.
@@ -231,7 +308,7 @@
     /**
      * Show soft keyboard only if it is the current keyboard configuration.
      */
-    public void showSoftKeyboard() {
+    private void showSoftKeyboard() {
         Log.d(TAG, "showSoftKeyboard");
         mInputMethodManagerWrapper.showSoftInput(
                 mViewEmbedder.getAttachedView(), 0, mViewEmbedder.getNewShowKeyboardReceiver());
@@ -244,7 +321,7 @@
     /**
      * Hide soft keyboard.
      */
-    public void hideKeyboard() {
+    private void hideKeyboard() {
         Log.d(TAG, "hideKeyboard");
         View view = mViewEmbedder.getAttachedView();
         if (mInputMethodManagerWrapper.isActive(view)) {
@@ -252,8 +329,9 @@
             // and ImeAdapter even after input method goes away and result gets received.
             mInputMethodManagerWrapper.hideSoftInputFromWindow(view.getWindowToken(), 0, null);
         }
+        // Detach input connection by returning null from onCreateInputConnection().
         if (mTextInputType == TextInputType.NONE && mInputConnection != null) {
-            mInputConnection.restartInput();
+            restartInput();
         }
     }
 
@@ -263,7 +341,7 @@
     public void onKeyboardConfigurationChanged() {
         Log.d(TAG, "onKeyboardConfigurationChanged: mTextInputType [%d]", mTextInputType);
         if (mTextInputType != TextInputType.NONE) {
-            mInputMethodManagerWrapper.restartInput(mViewEmbedder.getAttachedView());
+            restartInput();
             // By default, we show soft keyboard on keyboard changes. This is useful
             // when the user switches from hardware keyboard to software keyboard.
             // TODO(changwan): check if we can skip this for hardware keyboard configurations.
@@ -281,11 +359,14 @@
     }
 
     /**
-     * @return Whether input can be shown on the current focus (e.g. on an input box
-     *         or on a contenteditable).
+     * Move cursor to the end of the current selection.
      */
-    public boolean canCreateInputConnection() {
-        return mTextInputType != TextInputType.NONE;
+    public void moveCursorToSelectionEnd() {
+        Log.d(TAG, "movecursorToEnd");
+        if (mInputConnection != null) {
+            int selectionEnd = Selection.getSelectionEnd(mEditable);
+            mInputConnection.setSelection(selectionEnd, selectionEnd);
+        }
     }
 
     @VisibleForTesting
@@ -311,6 +392,28 @@
     }
 
     /**
+     * Update selection to input method manager.
+     *
+     * @param selectionStart The selection start.
+     * @param selectionEnd The selection end.
+     * @param compositionStart The composition start.
+     * @param compositionEnd The composition end.
+     */
+    void updateSelection(
+            int selectionStart, int selectionEnd, int compositionStart, int compositionEnd) {
+        mInputMethodManagerWrapper.updateSelection(mViewEmbedder.getAttachedView(), selectionStart,
+                selectionEnd, compositionStart, compositionEnd);
+    }
+
+    /**
+     * Restart input (finish composition and change EditorInfo, such as input type).
+     */
+    void restartInput() {
+        mInputMethodManagerWrapper.restartInput(mViewEmbedder.getAttachedView());
+        if (mInputConnection != null) mInputConnection.onRestartInput();
+    }
+
+    /**
      * @see BaseInputConnection#performContextMenuAction(int)
      */
     boolean performContextMenuAction(int id) {
@@ -441,7 +544,7 @@
     private void focusedNodeChanged(boolean isEditable) {
         Log.d(TAG, "focusedNodeChanged: isEditable [%b]", isEditable);
         if (mTextInputType != TextInputType.NONE && mInputConnection != null && isEditable) {
-            mInputConnection.restartInput();
+            restartInput();
         }
     }
 
@@ -468,7 +571,7 @@
     @CalledByNative
     private void cancelComposition() {
         Log.d(TAG, "cancelComposition");
-        if (mInputConnection != null) mInputConnection.restartInput();
+        if (mInputConnection != null) restartInput();
     }
 
     @CalledByNative
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index f165310..e43c084 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -100,7 +100,8 @@
     void selectAll();
 
     /**
-     * Clear the selection.
+     * Clear the selection. This includes the cursor which is a zero-sized selection, and keyboard
+     * will be hidden as a result.
      */
     void unselect();
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
index c9661f0d..a7beabc 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
@@ -412,6 +412,29 @@
     }
 
     @SmallTest
+    @Feature({"TextSelection", "TextInput"})
+    public void testCursorPositionAfterHidingActionMode() throws Exception {
+        DOMUtils.longPressNode(this, mContentViewCore, "textarea");
+        assertWaitForSelectActionBarVisible(true);
+        assertTrue(mContentViewCore.hasSelection());
+        assertNotNull(mContentViewCore.getSelectActionHandler());
+        selectActionBarSelectAll();
+        assertTrue(mContentViewCore.hasSelection());
+        assertWaitForSelectActionBarVisible(true);
+        assertEquals(mContentViewCore.getSelectedText(), "SampleTextArea");
+        hideSelectActionMode();
+        assertWaitForSelectActionBarVisible(false);
+        assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return "SampleTextArea".equals(mContentViewCore.getImeAdapterForTest()
+                        .getInputConnectionForTest()
+                        .getTextBeforeCursor(50, 0));
+            }
+        }));
+    }
+
+    @SmallTest
     @Feature({"TextSelection"})
     public void testSelectActionBarPlainTextPaste() throws Exception {
         copyStringToClipboard("SampleTextToCopy");
@@ -562,6 +585,15 @@
         });
     }
 
+    private void hideSelectActionMode() {
+        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
+            @Override
+            public void run() {
+                mContentViewCore.hideSelectActionMode();
+            }
+        });
+    }
+
     private void assertClipboardContents(final Context context, final String expectedContents)
             throws InterruptedException {
         assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/AdapterInputConnectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/AdapterInputConnectionTest.java
index 0694de03..636129f 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/AdapterInputConnectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/AdapterInputConnectionTest.java
@@ -9,13 +9,11 @@
 import android.os.ResultReceiver;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.text.Editable;
 import android.view.View;
 import android.view.inputmethod.EditorInfo;
 
 import org.chromium.base.test.util.Feature;
 import org.chromium.content.browser.input.AdapterInputConnection.ImeState;
-import org.chromium.content.browser.input.ImeAdapter.ImeAdapterDelegate;
 import org.chromium.content_shell_apk.ContentShellTestBase;
 
 import java.util.ArrayList;
@@ -27,7 +25,6 @@
 
     private AdapterInputConnection mConnection;
     private TestInputMethodManagerWrapper mWrapper;
-    private Editable mEditable;
     private TestImeAdapter mImeAdapter;
 
     @Override
@@ -37,9 +34,8 @@
         assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
         mWrapper = new TestInputMethodManagerWrapper(getActivity());
         mImeAdapter = new TestImeAdapter(mWrapper, new TestImeAdapterDelegate());
-        mEditable = Editable.Factory.getInstance().newEditable("");
         mConnection = new AdapterInputConnection(
-                getContentViewCore().getContainerView(), mImeAdapter, mEditable, new EditorInfo());
+                getContentViewCore().getContainerView(), mImeAdapter, 0, 0, new EditorInfo());
     }
 
     @SmallTest
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
index b21ec85..bbb1878 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -11,8 +11,6 @@
 import android.content.res.Configuration;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.text.Editable;
-import android.text.Selection;
 import android.text.TextUtils;
 import android.view.KeyEvent;
 import android.view.View;
@@ -79,7 +77,7 @@
         getImeAdapter().setInputMethodManagerWrapperForTest(mInputMethodManagerWrapper);
         assertEquals(0, mInputMethodManagerWrapper.getShowSoftInputCounter());
         mConnectionFactory = new TestAdapterInputConnectionFactory();
-        mContentViewCore.setAdapterInputConnectionFactory(mConnectionFactory);
+        getImeAdapter().setInputConnectionFactory(mConnectionFactory);
 
         mCallbackContainer = new TestCallbackHelperContainer(mContentViewCore);
         // TODO(aurimas) remove this wait once crbug.com/179511 is fixed.
@@ -194,13 +192,15 @@
         // showSoftInput() on input_text. restartInput() on input_number1 due to focus change,
         // and restartInput() on input_text later.
         // TODO(changwan): reduce unnecessary restart input.
-        waitForKeyboardStates(3, 1, 5, new Integer[] {TextInputType.NUMBER, TextInputType.NUMBER,
-                TextInputType.NUMBER, TextInputType.TEXT});
+        waitForKeyboardStates(3, 1, 5, new Integer[] {
+                TextInputType.NUMBER, TextInputType.NUMBER, TextInputType.NUMBER,
+                TextInputType.TEXT});
 
         focusElement("input_radio", false);
         // hideSoftInput(), restartInput()
-        waitForKeyboardStates(3, 2, 6, new Integer[] {TextInputType.NUMBER, TextInputType.NUMBER,
-                TextInputType.NUMBER, TextInputType.TEXT});
+        waitForKeyboardStates(3, 2, 6, new Integer[] {
+                TextInputType.NUMBER, TextInputType.NUMBER, TextInputType.NUMBER,
+                TextInputType.TEXT});
     }
 
     private void waitForKeyboardStates(int show, int hide, int restart, Integer[] history)
@@ -255,7 +255,7 @@
         selectAll();
         copy();
         assertWaitForKeyboardStatus(true);
-        assertEquals(11, Selection.getSelectionEnd(mContentViewCore.getEditableForTest()));
+        assertEquals(11, mInputMethodManagerWrapper.getSelection().end());
     }
 
     @SmallTest
@@ -373,20 +373,30 @@
         setComposingText("a", 1);
         waitForKeyboardStates(1, 0, 1, new Integer[] {TextInputType.TEXT});
         detachPhysicalKeyboard();
+        assertWaitForKeyboardStatus(true);
         // Now we really show soft keyboard. We also call restartInput when configuration changes.
         waitForKeyboardStates(2, 0, 2, new Integer[] {TextInputType.TEXT, TextInputType.TEXT});
 
-        // Reload the page, then the focus will be lost.
+        // Reload the page, then focus will be lost and keyboard should be hidden.
         getInstrumentation().runOnMainSync(new Runnable() {
             @Override
             public void run() {
                 getActivity().getActiveShell().loadUrl(DATA_URL);
             }
         });
+        // Depending on the timing, hideSoftInput and restartInput call counts may vary here
+        // because render widget gets restarted. But the end result should be the same.
+        assertWaitForKeyboardStatus(false);
 
         detachPhysicalKeyboard();
+
         // We should not show soft keyboard here because focus has been lost.
-        waitForKeyboardStates(2, 1, 2, new Integer[] {TextInputType.TEXT, TextInputType.TEXT});
+        assertFalse(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
+            @Override
+            public boolean isSatisfied() {
+                return mInputMethodManagerWrapper.isShowWithoutHideOutstanding();
+            }
+        }));
     }
 
     @SmallTest
@@ -932,7 +942,7 @@
         ThreadUtils.runOnUiThreadBlocking(new Runnable() {
             @Override
             public void run() {
-                mConnection.restartInput();
+                mImeAdapter.restartInput();
             }
         });
         // We don't do anything when input gets restarted. But we depend on Android's
@@ -958,8 +968,9 @@
         assertTrue(CriteriaHelper.pollForUIThreadCriteria(new Criteria() {
             @Override
             public boolean isSatisfied() {
+                boolean hasConnection = getAdapterInputConnection() != null;
                 return show == mInputMethodManagerWrapper.isShowWithoutHideOutstanding()
-                        && (!show || getAdapterInputConnection() != null);
+                        && show == hasConnection;
             }
         }));
     }
@@ -1044,7 +1055,7 @@
     }
 
     private AdapterInputConnection getAdapterInputConnection() {
-        return mContentViewCore.getInputConnectionForTest();
+        return mContentViewCore.getImeAdapterForTest().getInputConnectionForTest();
     }
 
     private void copy() {
@@ -1205,11 +1216,11 @@
         private final List<Integer> mTextInputTypeList = new ArrayList<>();
 
         @Override
-        public AdapterInputConnection get(View view, ImeAdapter imeAdapter,
-                Editable editable, EditorInfo outAttrs) {
+        public AdapterInputConnection get(View view, ImeAdapter imeAdapter, int initialSelStart,
+                int initialSelEnd, EditorInfo outAttrs) {
             mTextInputTypeList.add(imeAdapter.getTextInputType());
             return new TestAdapterInputConnection(
-                    mImeStateList, view, imeAdapter, editable, outAttrs);
+                    mImeStateList, view, imeAdapter, initialSelStart, initialSelEnd, outAttrs);
         }
 
         public List<TestImeState> getImeStateList() {
@@ -1231,8 +1242,9 @@
         private final List<TestImeState> mImeStateList;
 
         public TestAdapterInputConnection(List<TestImeState> imeStateList, View view,
-                ImeAdapter imeAdapter, Editable editable, EditorInfo outAttrs) {
-            super(view, imeAdapter, editable, outAttrs);
+                ImeAdapter imeAdapter, int initialSelStart, int initialSelEnd,
+                EditorInfo outAttrs) {
+            super(view, imeAdapter, initialSelStart, initialSelEnd, outAttrs);
             mImeStateList = imeStateList;
         }
 
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreInputConnectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/RecreateInputConnectionTest.java
similarity index 70%
rename from content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreInputConnectionTest.java
rename to content/public/android/javatests/src/org/chromium/content/browser/input/RecreateInputConnectionTest.java
index d8d9f31..4083a46 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreInputConnectionTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/RecreateInputConnectionTest.java
@@ -2,14 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.content.browser;
+package org.chromium.content.browser.input;
 
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.inputmethod.EditorInfo;
 
-import org.chromium.content.browser.input.AdapterInputConnection;
-import org.chromium.content.browser.input.ImeAdapter;
-import org.chromium.content.browser.input.InputMethodManagerWrapper;
+import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.test.util.TestInputMethodManagerWrapper;
 import org.chromium.content_shell_apk.ContentShellTestBase;
 import org.chromium.ui.base.ime.TextInputType;
@@ -17,14 +15,15 @@
 /**
  * Tests that when InputConnection is recreated, the text is still retained.
  */
-public class ContentViewCoreInputConnectionTest extends ContentShellTestBase {
+public class RecreateInputConnectionTest extends ContentShellTestBase {
     private ContentViewCore mContentViewCore;
     private TestImeAdapter mImeAdapter;
     private TestInputMethodManagerWrapper mInputMethodManagerWrapper;
 
     private static class TestImeAdapter extends ImeAdapter {
-        public TestImeAdapter(InputMethodManagerWrapper immw) {
-            super(immw, null);
+        public TestImeAdapter(
+                InputMethodManagerWrapper immw, ImeAdapterDelegate imeAdapterDelegate) {
+            super(immw, imeAdapterDelegate);
         }
         @Override
         public boolean hasTextInputType() {
@@ -36,13 +35,14 @@
     public void setUp() throws Exception {
         super.setUp();
         mContentViewCore = new ContentViewCore(getActivity());
-        mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentViewCore);
-        mImeAdapter = new TestImeAdapter(mInputMethodManagerWrapper);
-        mImeAdapter.setInputMethodManagerWrapperForTest(new TestInputMethodManagerWrapper(
-                mContentViewCore));
-        mContentViewCore.setImeAdapterForTest(mImeAdapter);
         mContentViewCore.createContentViewAndroidDelegate();
         mContentViewCore.setContainerView(getActivity().getActiveShell().getContentView());
+        mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentViewCore);
+        mImeAdapter = new TestImeAdapter(mInputMethodManagerWrapper,
+                new TestImeAdapterDelegate(mContentViewCore.getContainerView()));
+        mImeAdapter.setInputMethodManagerWrapperForTest(
+                new TestInputMethodManagerWrapper(mContentViewCore));
+        mContentViewCore.setImeAdapterForTest(mImeAdapter);
     }
 
     /**
@@ -56,17 +56,17 @@
 
         mImeAdapter.setInputTypeForTest(TextInputType.TEXT);
         mContentViewCore.onCreateInputConnection(info);
-        AdapterInputConnection adapter = mContentViewCore.getAdapterInputConnectionForTest();
-        adapter.updateState("Is this text restored?", 0, 0, 0, 0, true);
+        AdapterInputConnection inputConnection = mImeAdapter.getInputConnectionForTest();
+        inputConnection.updateState("Is this text restored?", 0, 0, 0, 0, true);
 
-        String text = mContentViewCore.getEditableForTest().toString();
+        String text = mContentViewCore.getImeAdapterForTest().getEditable().toString();
         assertEquals("Check if the initial text is stored.", "Is this text restored?", text);
 
         // Create a new InputConnection.
         EditorInfo info2 = new EditorInfo();
         mContentViewCore.onCreateInputConnection(info2);
 
-        String newtext = mContentViewCore.getEditableForTest().toString();
+        String newtext = mContentViewCore.getImeAdapterForTest().getEditable().toString();
         assertEquals("Check if the string is restored.", "Is this text restored?", newtext);
     }
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/TestImeAdapterDelegate.java b/content/public/android/javatests/src/org/chromium/content/browser/input/TestImeAdapterDelegate.java
index f59a101..f3c5073 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/input/TestImeAdapterDelegate.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/input/TestImeAdapterDelegate.java
@@ -13,6 +13,16 @@
  * An empty ImeAdapterDelegate used for testing.
  */
 public class TestImeAdapterDelegate implements ImeAdapterDelegate {
+    private final View mView;
+
+    public TestImeAdapterDelegate() {
+        this(null);
+    }
+
+    public TestImeAdapterDelegate(View view) {
+        mView = view;
+    }
+
     @Override
     public void onImeEvent() {}
 
@@ -26,7 +36,7 @@
 
     @Override
     public View getAttachedView() {
-        return null;
+        return mView;
     }
 
     @Override
diff --git a/content/public/browser/navigation_controller.h b/content/public/browser/navigation_controller.h
index af1b3b9..ac52ae13 100644
--- a/content/public/browser/navigation_controller.h
+++ b/content/public/browser/navigation_controller.h
@@ -10,7 +10,6 @@
 #include <vector>
 
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
 #include "content/common/content_export.h"
 #include "content/public/browser/global_request_id.h"
@@ -227,7 +226,7 @@
   // restore.
   virtual void Restore(int selected_navigation,
                        RestoreType type,
-                       ScopedVector<NavigationEntry>* entries) = 0;
+                       std::vector<scoped_ptr<NavigationEntry>>* entries) = 0;
 
   // Entries -------------------------------------------------------------------
 
diff --git a/content/public/browser/navigation_handle.cc b/content/public/browser/navigation_handle.cc
index 0df5535..fa67249 100644
--- a/content/public/browser/navigation_handle.cc
+++ b/content/public/browser/navigation_handle.cc
@@ -24,7 +24,8 @@
     RenderFrameHost* render_frame_host) {
   scoped_ptr<NavigationHandleImpl> handle_impl = NavigationHandleImpl::Create(
       url,
-      static_cast<RenderFrameHostImpl*>(render_frame_host)->frame_tree_node());
+      static_cast<RenderFrameHostImpl*>(render_frame_host)->frame_tree_node(),
+      base::TimeTicks::Now());
   return scoped_ptr<NavigationHandle>(handle_impl.Pass());
 }
 
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index de9415a0..c449382 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -10,6 +10,13 @@
 // have an effect. 0 disables MSAA.
 const char kAcceleratedCanvas2dMSAASampleCount[] = "canvas-msaa-sample-count";
 
+// Override the default minimum starting volume of the Automatic Gain Control
+// algorithm in WebRTC used with audio tracks from getUserMedia.
+// The valid range is 12-255. Values outside that range will be clamped
+// to the lowest or highest valid value inside WebRTC.
+// TODO(tommi): Remove this switch when crbug.com/555577 is fixed.
+const char kAgcStartupMinVolume[] = "agc-startup-min-volume";
+
 // By default, file:// URIs cannot read other file:// URIs. This is an
 // override for developers who need the old behavior for testing.
 const char kAllowFileAccessFromFiles[]      = "allow-file-access-from-files";
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 48c465c..9bd5dbd 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -15,6 +15,7 @@
 // All switches in alphabetical order. The switches should be documented
 // alongside the definition of their values in the .cc file.
 CONTENT_EXPORT extern const char kAcceleratedCanvas2dMSAASampleCount[];
+CONTENT_EXPORT extern const char kAgcStartupMinVolume[];
 CONTENT_EXPORT extern const char kAllowFileAccessFromFiles[];
 CONTENT_EXPORT extern const char kAllowLoopbackInPeerConnection[];
 CONTENT_EXPORT extern const char kAllowNoSandboxJob[];
diff --git a/content/public/test/test_navigation_observer.cc b/content/public/test/test_navigation_observer.cc
index 267dedf2..671cde1 100644
--- a/content/public/test/test_navigation_observer.cc
+++ b/content/public/test/test_navigation_observer.cc
@@ -50,8 +50,8 @@
                                        const GURL& validated_url,
                                        bool is_error_page,
                                        bool is_iframe_srcdoc) override {
-    parent_->OnDidStartProvisionalLoadForFrame(
-        render_frame_host, validated_url, is_error_page, is_iframe_srcdoc);
+    parent_->OnDidStartProvisionalLoad(render_frame_host, validated_url,
+                                       is_error_page, is_iframe_srcdoc);
   }
 
   void DidFailProvisionalLoad(
@@ -172,7 +172,7 @@
   }
 }
 
-void TestNavigationObserver::OnDidStartProvisionalLoadForFrame(
+void TestNavigationObserver::OnDidStartProvisionalLoad(
     RenderFrameHost* render_frame_host,
     const GURL& validated_url,
     bool is_error_page,
diff --git a/content/public/test/test_navigation_observer.h b/content/public/test/test_navigation_observer.h
index 31a94d6..007e6c67 100644
--- a/content/public/test/test_navigation_observer.h
+++ b/content/public/test/test_navigation_observer.h
@@ -62,10 +62,10 @@
   void OnDidAttachInterstitialPage(WebContents* web_contents);
   void OnDidStartLoading(WebContents* web_contents);
   void OnDidStopLoading(WebContents* web_contents);
-  void OnDidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host,
-                                         const GURL& validated_url,
-                                         bool is_error_page,
-                                         bool is_iframe_srcdoc);
+  void OnDidStartProvisionalLoad(RenderFrameHost* render_frame_host,
+                                 const GURL& validated_url,
+                                 bool is_error_page,
+                                 bool is_iframe_srcdoc);
   void OnDidFailProvisionalLoad(RenderFrameHost* render_frame_host,
                                 const GURL& validated_url,
                                 int error_code,
diff --git a/content/renderer/accessibility/blink_ax_tree_source.cc b/content/renderer/accessibility/blink_ax_tree_source.cc
index f595172..514c5af 100644
--- a/content/renderer/accessibility/blink_ax_tree_source.cc
+++ b/content/renderer/accessibility/blink_ax_tree_source.cc
@@ -146,7 +146,7 @@
 
   const WebDocumentType& doctype = document.doctype();
   if (!doctype.isNull())
-    tree_data.doctype = UTF16ToUTF8(base::StringPiece16(doctype.name()));
+    tree_data.doctype = doctype.name().utf8();
 
   WebAXObject anchor_object, focus_object;
   int anchor_offset, focus_offset;
@@ -263,17 +263,13 @@
   dst->state = AXStateFromBlink(src);
   dst->location = src.boundingBoxRect();
   dst->id = src.axID();
-  std::string name = UTF16ToUTF8(base::StringPiece16(src.deprecatedTitle()));
+  std::string name = src.deprecatedTitle().utf8();
 
   std::string value;
   if (src.valueDescription().length()) {
-    dst->AddStringAttribute(ui::AX_ATTR_VALUE,
-                            UTF16ToUTF8(base::StringPiece16(
-                                src.valueDescription())));
+    dst->AddStringAttribute(ui::AX_ATTR_VALUE, src.valueDescription().utf8());
   } else {
-    dst->AddStringAttribute(
-        ui::AX_ATTR_VALUE,
-        UTF16ToUTF8(base::StringPiece16(src.stringValue())));
+    dst->AddStringAttribute(ui::AX_ATTR_VALUE, src.stringValue().utf8());
   }
 
   if (dst->role == ui::AX_ROLE_COLOR_WELL)
@@ -298,7 +294,7 @@
   if (src.invalidState() == blink::WebAXInvalidStateOther) {
     dst->AddStringAttribute(
         ui::AX_ATTR_ARIA_INVALID_VALUE,
-        UTF16ToUTF8(base::StringPiece16(src.ariaInvalidValue())));
+        src.ariaInvalidValue().utf8());
   }
 
   if (src.textDirection()) {
@@ -337,18 +333,16 @@
   }
 
   if (src.accessKey().length()) {
-    dst->AddStringAttribute(ui::AX_ATTR_ACCESS_KEY,
-    UTF16ToUTF8(base::StringPiece16(src.accessKey())));
+    dst->AddStringAttribute(ui::AX_ATTR_ACCESS_KEY, src.accessKey().utf8());
   }
 
-  if (src.actionVerb().length())
-    dst->AddStringAttribute(
-        ui::AX_ATTR_ACTION,
-        UTF16ToUTF8(base::StringPiece16(src.actionVerb())));
+  if (src.actionVerb().length()) {
+    dst->AddStringAttribute(ui::AX_ATTR_ACTION, src.actionVerb().utf8());
+  }
   if (src.ariaAutoComplete().length())
     dst->AddStringAttribute(
         ui::AX_ATTR_AUTO_COMPLETE,
-        UTF16ToUTF8(base::StringPiece16(src.ariaAutoComplete())));
+        src.ariaAutoComplete().utf8());
   if (src.isAriaReadOnly())
     dst->AddBoolAttribute(ui::AX_ATTR_ARIA_READONLY, true);
   if (src.isButtonStateMixed())
@@ -358,27 +352,24 @@
   if (src.deprecatedAccessibilityDescription().length()) {
     dst->AddStringAttribute(
         ui::AX_ATTR_DESCRIPTION,
-        UTF16ToUTF8(base::StringPiece16(
-            src.deprecatedAccessibilityDescription())));
+        src.deprecatedAccessibilityDescription().utf8());
   }
   if (src.hasComputedStyle()) {
     dst->AddStringAttribute(
         ui::AX_ATTR_DISPLAY,
-        UTF16ToUTF8(base::StringPiece16(src.computedStyleDisplay())));
+        src.computedStyleDisplay().utf8());
   }
   if (src.deprecatedHelpText().length())
-    dst->AddStringAttribute(
-        ui::AX_ATTR_HELP,
-        UTF16ToUTF8(base::StringPiece16((src.deprecatedHelpText()))));
+    dst->AddStringAttribute(ui::AX_ATTR_HELP, src.deprecatedHelpText().utf8());
   if (src.deprecatedPlaceholder().length()) {
     dst->AddStringAttribute(
         ui::AX_ATTR_PLACEHOLDER,
-        UTF16ToUTF8(base::StringPiece16(src.deprecatedPlaceholder())));
+        src.deprecatedPlaceholder().utf8());
   }
   if (src.keyboardShortcut().length()) {
     dst->AddStringAttribute(
         ui::AX_ATTR_SHORTCUT,
-        UTF16ToUTF8(base::StringPiece16(src.keyboardShortcut())));
+        src.keyboardShortcut().utf8());
   }
   if (!src.deprecatedTitleUIElement().isDetached()) {
     dst->AddIntAttribute(ui::AX_ATTR_TITLE_UI_ELEMENT,
@@ -428,13 +419,11 @@
     // a WebElement method that returns the original lower cased tagName.
     dst->AddStringAttribute(
         ui::AX_ATTR_HTML_TAG,
-        base::ToLowerASCII(UTF16ToUTF8(
-            base::StringPiece16(element.tagName()))));
+        base::ToLowerASCII(element.tagName().utf8()));
     for (unsigned i = 0; i < element.attributeCount(); ++i) {
-      std::string name = base::ToLowerASCII(UTF16ToUTF8(
-          base::StringPiece16(element.attributeLocalName(i))));
-      std::string value =
-          UTF16ToUTF8(base::StringPiece16(element.attributeValue(i)));
+      std::string name = base::ToLowerASCII(
+          element.attributeLocalName(i).utf8());
+      std::string value = element.attributeValue(i).utf8();
       dst->html_attributes.push_back(std::make_pair(name, value));
     }
 
@@ -457,7 +446,7 @@
     if (element.hasAttribute("role")) {
       dst->AddStringAttribute(
           ui::AX_ATTR_ROLE,
-          UTF16ToUTF8(base::StringPiece16(element.getAttribute("role"))));
+          element.getAttribute("role").utf8());
     } else {
       std::string role = GetEquivalentAriaRoleString(dst->role);
       if (!role.empty())
@@ -497,21 +486,21 @@
     if (!src.liveRegionStatus().isEmpty()) {
       dst->AddStringAttribute(
           ui::AX_ATTR_LIVE_STATUS,
-          UTF16ToUTF8(base::StringPiece16(src.liveRegionStatus())));
+          src.liveRegionStatus().utf8());
     }
     dst->AddStringAttribute(
         ui::AX_ATTR_LIVE_RELEVANT,
-        UTF16ToUTF8(base::StringPiece16(src.liveRegionRelevant())));
+        src.liveRegionRelevant().utf8());
     dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_ATOMIC,
                           src.containerLiveRegionAtomic());
     dst->AddBoolAttribute(ui::AX_ATTR_CONTAINER_LIVE_BUSY,
                           src.containerLiveRegionBusy());
     dst->AddStringAttribute(
         ui::AX_ATTR_CONTAINER_LIVE_STATUS,
-        UTF16ToUTF8(base::StringPiece16(src.containerLiveRegionStatus())));
+        src.containerLiveRegionStatus().utf8());
     dst->AddStringAttribute(
         ui::AX_ATTR_CONTAINER_LIVE_RELEVANT,
-        UTF16ToUTF8(base::StringPiece16(src.containerLiveRegionRelevant())));
+        src.containerLiveRegionRelevant().utf8());
   }
 
   if (dst->role == ui::AX_ROLE_PROGRESS_INDICATOR ||
@@ -530,7 +519,7 @@
     dst->AddStringAttribute(ui::AX_ATTR_HTML_TAG, "#document");
     const WebDocument& document = src.document();
     if (name.empty())
-      name = UTF16ToUTF8(base::StringPiece16(document.title()));
+      name = document.title().utf8();
   }
 
   if (dst->role == ui::AX_ROLE_TABLE) {
diff --git a/content/renderer/android/synchronous_compositor_proxy.cc b/content/renderer/android/synchronous_compositor_proxy.cc
index b8ae7ca2..bd9fb355 100644
--- a/content/renderer/android/synchronous_compositor_proxy.cc
+++ b/content/renderer/android/synchronous_compositor_proxy.cc
@@ -147,6 +147,7 @@
     IPC_MESSAGE_HANDLER(SyncCompositorMsg_BeginFrame, BeginFrame)
     IPC_MESSAGE_HANDLER(SyncCompositorMsg_ComputeScroll, OnComputeScroll)
     IPC_MESSAGE_HANDLER(SyncCompositorMsg_DemandDrawHw, DemandDrawHw)
+    IPC_MESSAGE_HANDLER(SyncCompositorMsg_UpdateState, ProcessCommonParams)
   IPC_END_MESSAGE_MAP()
 }
 
diff --git a/content/renderer/bluetooth/bluetooth_dispatcher.cc b/content/renderer/bluetooth/bluetooth_dispatcher.cc
index 5687bf7..5f10eed 100644
--- a/content/renderer/bluetooth/bluetooth_dispatcher.cc
+++ b/content/renderer/bluetooth/bluetooth_dispatcher.cc
@@ -253,12 +253,13 @@
 
 void BluetoothDispatcher::writeValue(
     const blink::WebString& characteristic_instance_id,
-    const std::vector<uint8_t>& value,
+    const blink::WebVector<uint8_t>& value,
     blink::WebBluetoothWriteValueCallbacks* callbacks) {
   int request_id = pending_write_value_requests_.Add(callbacks);
 
   Send(new BluetoothHostMsg_WriteValue(
-      CurrentWorkerId(), request_id, characteristic_instance_id.utf8(), value));
+      CurrentWorkerId(), request_id, characteristic_instance_id.utf8(),
+      std::vector<uint8_t>(value.begin(), value.end())));
 }
 
 void BluetoothDispatcher::startNotifications(
diff --git a/content/renderer/bluetooth/bluetooth_dispatcher.h b/content/renderer/bluetooth/bluetooth_dispatcher.h
index f27d7d65..ff6a0751 100644
--- a/content/renderer/bluetooth/bluetooth_dispatcher.h
+++ b/content/renderer/bluetooth/bluetooth_dispatcher.h
@@ -75,7 +75,7 @@
   void readValue(const blink::WebString& characteristic_instance_id,
                  blink::WebBluetoothReadValueCallbacks* callbacks);
   void writeValue(const blink::WebString& characteristic_instance_id,
-                  const std::vector<uint8_t>& value,
+                  const blink::WebVector<uint8_t>& value,
                   blink::WebBluetoothWriteValueCallbacks*);
   void startNotifications(const blink::WebString& characteristic_instance_id,
                           blink::WebBluetoothGATTCharacteristic* delegate,
diff --git a/content/renderer/bluetooth/web_bluetooth_impl.cc b/content/renderer/bluetooth/web_bluetooth_impl.cc
index 7c813c2..92d035b 100644
--- a/content/renderer/bluetooth/web_bluetooth_impl.cc
+++ b/content/renderer/bluetooth/web_bluetooth_impl.cc
@@ -56,7 +56,7 @@
 
 void WebBluetoothImpl::writeValue(
     const blink::WebString& characteristic_instance_id,
-    const std::vector<uint8_t>& value,
+    const blink::WebVector<uint8_t>& value,
     blink::WebBluetoothWriteValueCallbacks* callbacks) {
   GetDispatcher()->writeValue(characteristic_instance_id, value, callbacks);
 }
diff --git a/content/renderer/bluetooth/web_bluetooth_impl.h b/content/renderer/bluetooth/web_bluetooth_impl.h
index 470c1836..f475c00 100644
--- a/content/renderer/bluetooth/web_bluetooth_impl.h
+++ b/content/renderer/bluetooth/web_bluetooth_impl.h
@@ -47,7 +47,7 @@
   void readValue(const blink::WebString& characteristic_instance_id,
                  blink::WebBluetoothReadValueCallbacks* callbacks) override;
   void writeValue(const blink::WebString& characteristic_instance_id,
-                  const std::vector<uint8_t>& value,
+                  const blink::WebVector<uint8_t>& value,
                   blink::WebBluetoothWriteValueCallbacks*) override;
   void startNotifications(const blink::WebString& characteristic_instance_id,
                           blink::WebBluetoothGATTCharacteristic* characteristic,
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index ee42edff..64194686 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -692,7 +692,7 @@
     const blink::WebLayer* outerViewportScrollLayer) {
   layer_tree_host_->RegisterViewportLayers(
       // TODO(bokan): This check can probably be removed now, but it looks
-      // like overscroll elasticity may still be NULL until PinchViewport
+      // like overscroll elasticity may still be NULL until VisualViewport
       // registers its layers.
       // The scroll elasticity layer will only exist when using pinch virtual
       // viewports.
@@ -704,7 +704,7 @@
       static_cast<const cc_blink::WebLayerImpl*>(innerViewportScrollLayer)
           ->layer(),
       // TODO(bokan): This check can probably be removed now, but it looks
-      // like overscroll elasticity may still be NULL until PinchViewport
+      // like overscroll elasticity may still be NULL until VisualViewport
       // registers its layers.
       // The outer viewport layer will only exist when using pinch virtual
       // viewports.
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index 9b4d312c..1f45238a 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -520,10 +520,9 @@
   DCHECK(!set_cdm_ready_cb_.is_null());
 
   audio_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
-      media_task_runner_, media_log_, set_cdm_ready_cb_,
-      waiting_for_decryption_key_cb_));
+      media_task_runner_, media_log_, waiting_for_decryption_key_cb_));
   audio_decrypting_demuxer_stream_->Initialize(
-      audio_stream_,
+      audio_stream_, set_cdm_ready_cb_,
       base::Bind(&MediaSourceDelegate::OnAudioDecryptingDemuxerStreamInitDone,
                  media_weak_factory_.GetWeakPtr()));
 }
@@ -534,10 +533,9 @@
   DCHECK(!set_cdm_ready_cb_.is_null());
 
   video_decrypting_demuxer_stream_.reset(new media::DecryptingDemuxerStream(
-      media_task_runner_, media_log_, set_cdm_ready_cb_,
-      waiting_for_decryption_key_cb_));
+      media_task_runner_, media_log_, waiting_for_decryption_key_cb_));
   video_decrypting_demuxer_stream_->Initialize(
-      video_stream_,
+      video_stream_, set_cdm_ready_cb_,
       base::Bind(&MediaSourceDelegate::OnVideoDecryptingDemuxerStreamInitDone,
                  media_weak_factory_.GetWeakPtr()));
 }
diff --git a/content/renderer/media/media_stream_audio_processor.cc b/content/renderer/media/media_stream_audio_processor.cc
index c736696b3..5e4c1c0 100644
--- a/content/renderer/media/media_stream_audio_processor.cc
+++ b/content/renderer/media/media_stream_audio_processor.cc
@@ -7,6 +7,7 @@
 #include "base/command_line.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/trace_event/trace_event.h"
 #include "content/public/common/content_switches.h"
 #include "content/renderer/media/media_stream_audio_processor_options.h"
@@ -107,6 +108,17 @@
   return (group_name == "Enabled" || group_name == "DefaultEnabled");
 }
 
+// Checks if the default minimum starting volume value for the AGC is overridden
+// on the command line.
+bool GetStartupMinVolumeForAgc(int* startup_min_volume) {
+  DCHECK(startup_min_volume);
+  std::string min_volume_str(
+      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+          switches::kAgcStartupMinVolume));
+  return !min_volume_str.empty() &&
+         base::StringToInt(min_volume_str, startup_min_volume);
+}
+
 }  // namespace
 
 // Wraps AudioBus to provide access to the array of channel pointers, since this
@@ -528,6 +540,16 @@
         new webrtc::Beamforming(geometry.size() > 1, geometry));
   }
 
+  // If the experimental AGC is enabled, check for overridden config params.
+  if (audio_constraints.GetProperty(
+          MediaAudioConstraints::kGoogExperimentalAutoGainControl)) {
+    int startup_min_volume = 0;
+    if (GetStartupMinVolumeForAgc(&startup_min_volume)) {
+      config.Set<webrtc::ExperimentalAgc>(
+          new webrtc::ExperimentalAgc(true, startup_min_volume));
+    }
+  }
+
   // Create and configure the webrtc::AudioProcessing.
   audio_processing_.reset(webrtc::AudioProcessing::Create(config));
 
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 193ab945..6dfe0d9f 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -796,10 +796,8 @@
     blink::WebRTCPeerConnectionHandlerClient* client,
     PeerConnectionDependencyFactory* dependency_factory)
     : client_(client),
-      is_closed_(false),
       dependency_factory_(dependency_factory),
       weak_factory_(this) {
-  CHECK(client_),
   g_peer_connection_handlers.Get().insert(this);
 }
 
@@ -819,13 +817,13 @@
 
 // static
 void RTCPeerConnectionHandler::DestructAllHandlers() {
-  // Copy g_peer_connection_handlers since releasePeerConnectionHandler will
-  // remove an item.
   std::set<RTCPeerConnectionHandler*> handlers(
       g_peer_connection_handlers.Get().begin(),
       g_peer_connection_handlers.Get().end());
-  for (auto* handler : handlers)
-    handler->client_->releasePeerConnectionHandler();
+  for (auto handler : handlers) {
+    if (handler->client_)
+      handler->client_->releasePeerConnectionHandler();
+  }
 }
 
 // static
@@ -1311,7 +1309,7 @@
 
 void RTCPeerConnectionHandler::CloseClientPeerConnection() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (!is_closed_)
+  if (client_)
     client_->closePeerConnection();
 }
 
@@ -1382,7 +1380,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "RTCPeerConnectionHandler::stop";
 
-  if (!is_closed_ || !native_peer_connection_.get())
+  if (!client_ || !native_peer_connection_.get())
     return;  // Already stopped.
 
   if (peer_connection_tracker_)
@@ -1390,8 +1388,9 @@
 
   native_peer_connection_->Close();
 
-  // This object may no longer forward call backs to blink.
-  is_closed_ = true;
+  // The client_ pointer is not considered valid after this point and no further
+  // callbacks must be made.
+  client_ = nullptr;
 }
 
 void RTCPeerConnectionHandler::OnSignalingChange(
@@ -1403,7 +1402,7 @@
       GetWebKitSignalingState(new_state);
   if (peer_connection_tracker_)
     peer_connection_tracker_->TrackSignalingStateChange(this, state);
-  if (!is_closed_)
+  if (client_)
     client_->didChangeSignalingState(state);
 }
 
@@ -1439,7 +1438,7 @@
       GetWebKitIceConnectionState(new_state);
   if (peer_connection_tracker_)
     peer_connection_tracker_->TrackIceConnectionStateChange(this, state);
-  if (!is_closed_)
+  if(client_)
     client_->didChangeICEConnectionState(state);
 }
 
@@ -1452,7 +1451,7 @@
   if (new_state == webrtc::PeerConnectionInterface::kIceGatheringComplete) {
     // If ICE gathering is completed, generate a NULL ICE candidate,
     // to signal end of candidates.
-    if (!is_closed_) {
+    if (client_) {
       blink::WebRTCICECandidate null_candidate;
       client_->didGenerateICECandidate(null_candidate);
     }
@@ -1509,7 +1508,7 @@
 
   track_metrics_.AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM,
                            s->webrtc_stream().get());
-  if (!is_closed_)
+  if (client_)
     client_->didAddRemoteStream(s->webkit_stream());
 }
 
@@ -1537,7 +1536,7 @@
         this, webkit_stream, PeerConnectionTracker::SOURCE_REMOTE);
   }
 
-  if (!is_closed_)
+  if (client_)
     client_->didRemoveRemoteStream(webkit_stream);
 }
 
@@ -1551,7 +1550,7 @@
         this, handler->channel().get(), PeerConnectionTracker::SOURCE_REMOTE);
   }
 
-  if (!is_closed_)
+  if (client_)
     client_->didAddRemoteDataChannel(handler.release());
 }
 
@@ -1580,7 +1579,7 @@
       NOTREACHED();
     }
   }
-  if (!is_closed_)
+  if (client_)
     client_->didGenerateICECandidate(web_candidate);
 }
 
diff --git a/content/renderer/media/rtc_peer_connection_handler.h b/content/renderer/media/rtc_peer_connection_handler.h
index fa45d6a..8e8af25 100644
--- a/content/renderer/media/rtc_peer_connection_handler.h
+++ b/content/renderer/media/rtc_peer_connection_handler.h
@@ -225,14 +225,8 @@
 
   base::ThreadChecker thread_checker_;
 
-  // |client_| is a weak pointer to the blink object (blink::RTCPeerConnection)
-  // that owns this object.
-  // It is valid for the lifetime of this object.
-  blink::WebRTCPeerConnectionHandlerClient* const client_;
-  // True if this PeerConnection has been closed.
-  // After the PeerConnection has been closed, this object may no longer
-  // forward callbacks to blink.
-  bool is_closed_;
+  // |client_| is a weak pointer, and is valid until stop() has returned.
+  blink::WebRTCPeerConnectionHandlerClient* client_;
 
   // |dependency_factory_| is a raw pointer, and is valid for the lifetime of
   // RenderThreadImpl.
diff --git a/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
index 88fad70a..6cbdd1db 100644
--- a/content/renderer/media/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
@@ -334,11 +334,6 @@
   pc_handler_.reset(NULL);
 }
 
-TEST_F(RTCPeerConnectionHandlerTest, DestructAllHandlers) {
-  EXPECT_CALL(*mock_client_.get(), releasePeerConnectionHandler())
-      .Times(1);
-  RTCPeerConnectionHandler::DestructAllHandlers();
-}
 TEST_F(RTCPeerConnectionHandlerTest, CreateOffer) {
   blink::WebRTCSessionDescriptionRequest request;
   blink::WebMediaConstraints options;
diff --git a/content/renderer/media/rtc_video_decoder.cc b/content/renderer/media/rtc_video_decoder.cc
index a9d1af5..2381c77 100644
--- a/content/renderer/media/rtc_video_decoder.cc
+++ b/content/renderer/media/rtc_video_decoder.cc
@@ -38,24 +38,6 @@
 // Maximum number of pending WebRTC buffers that are waiting for shared memory.
 static const size_t kMaxNumOfPendingBuffers = 8;
 
-// A shared memory segment and its allocated size. This class has the ownership
-// of |shm|.
-class RTCVideoDecoder::SHMBuffer {
- public:
-  SHMBuffer(scoped_ptr<base::SharedMemory> shm, size_t size);
-  ~SHMBuffer();
-  scoped_ptr<base::SharedMemory> const shm;
-  const size_t size;
-};
-
-RTCVideoDecoder::SHMBuffer::SHMBuffer(scoped_ptr<base::SharedMemory> shm,
-                                      size_t size)
-    : shm(shm.Pass()), size(size) {
-}
-
-RTCVideoDecoder::SHMBuffer::~SHMBuffer() {
-}
-
 RTCVideoDecoder::BufferData::BufferData(int32 bitstream_buffer_id,
                                         uint32_t timestamp,
                                         size_t size,
@@ -76,7 +58,7 @@
       decoder_texture_target_(0),
       next_picture_buffer_id_(0),
       state_(UNINITIALIZED),
-      decode_complete_callback_(NULL),
+      decode_complete_callback_(nullptr),
       num_shm_buffers_(0),
       next_bitstream_buffer_id_(0),
       reset_bitstream_buffer_id_(ID_INVALID),
@@ -126,12 +108,11 @@
                  profile,
                  &waiter));
   waiter.Wait();
-  // vda can be NULL if the codec is not supported.
-  if (decoder->vda_ != NULL) {
+  // |decoder->vda_| is nullptr if the codec is not supported.
+  if (decoder->vda_)
     decoder->state_ = INITIALIZED;
-  } else {
+  else
     factories->GetTaskRunner()->DeleteSoon(FROM_HERE, decoder.release());
-  }
   return decoder.Pass();
 }
 
@@ -164,7 +145,7 @@
 
   base::AutoLock auto_lock(lock_);
 
-  if (state_ == UNINITIALIZED || decode_complete_callback_ == NULL) {
+  if (state_ == UNINITIALIZED || !decode_complete_callback_) {
     LOG(ERROR) << "The decoder has not initialized.";
     return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
   }
@@ -193,8 +174,8 @@
 
   bool need_to_reset_for_midstream_resize = false;
   if (inputImage._frameType == webrtc::kVideoFrameKey) {
-    gfx::Size new_frame_size(inputImage._encodedWidth,
-                             inputImage._encodedHeight);
+    const gfx::Size new_frame_size(inputImage._encodedWidth,
+                                   inputImage._encodedHeight);
     DVLOG(2) << "Got key frame. size=" << new_frame_size.ToString();
 
     if (new_frame_size.width() > max_resolution_.width() ||
@@ -230,7 +211,7 @@
   // If a shared memory segment is available, there are no pending buffers, and
   // this isn't a mid-stream resolution change, then send the buffer for decode
   // immediately. Otherwise, save the buffer in the queue for later decode.
-  scoped_ptr<SHMBuffer> shm_buffer;
+  scoped_ptr<base::SharedMemory> shm_buffer;
   if (!need_to_reset_for_midstream_resize && pending_buffers_.empty())
     shm_buffer = GetSHM_Locked(inputImage._length);
   if (!shm_buffer) {
@@ -263,6 +244,7 @@
 int32_t RTCVideoDecoder::RegisterDecodeCompleteCallback(
     webrtc::DecodedImageCallback* callback) {
   DVLOG(2) << "RegisterDecodeCompleteCallback";
+  DCHECK(callback);
   base::AutoLock auto_lock(lock_);
   decode_complete_callback_ = callback;
   return WEBRTC_VIDEO_CODEC_OK;
@@ -396,7 +378,7 @@
   // Invoke decode callback. WebRTC expects no callback after Reset or Release.
   {
     base::AutoLock auto_lock(lock_);
-    DCHECK(decode_complete_callback_ != NULL);
+    DCHECK(decode_complete_callback_);
     if (IsBufferAfterReset(picture.bitstream_buffer_id(),
                            reset_bitstream_buffer_id_)) {
       decode_complete_callback_->Decoded(decoded_image);
@@ -436,7 +418,7 @@
   DVLOG(3) << "NotifyEndOfBitstreamBuffer. id=" << id;
   DCheckGpuVideoAcceleratorFactoriesTaskRunnerIsCurrent();
 
-  std::map<int32, SHMBuffer*>::iterator it =
+  std::map<int32, base::SharedMemory*>::iterator it =
       bitstream_buffers_in_decoder_.find(id);
   if (it == bitstream_buffers_in_decoder_.end()) {
     NotifyError(media::VideoDecodeAccelerator::PLATFORM_FAILURE);
@@ -446,7 +428,7 @@
 
   {
     base::AutoLock auto_lock(lock_);
-    PutSHM_Locked(scoped_ptr<SHMBuffer>(it->second));
+    PutSHM_Locked(scoped_ptr<base::SharedMemory>(it->second));
   }
   bitstream_buffers_in_decoder_.erase(it);
 
@@ -498,32 +480,33 @@
 
   while (CanMoreDecodeWorkBeDone()) {
     // Get a buffer and data from the queue.
-    SHMBuffer* shm_buffer = NULL;
+    scoped_ptr<base::SharedMemory> shm_buffer;
     BufferData buffer_data;
     {
       base::AutoLock auto_lock(lock_);
       // Do not request decode if VDA is resetting.
       if (decode_buffers_.empty() || state_ == RESETTING)
         return;
-      shm_buffer = decode_buffers_.front().first;
+      shm_buffer.reset(decode_buffers_.front().first);
       buffer_data = decode_buffers_.front().second;
       decode_buffers_.pop_front();
       // Drop the buffers before Reset or Release is called.
       if (!IsBufferAfterReset(buffer_data.bitstream_buffer_id,
                               reset_bitstream_buffer_id_)) {
-        PutSHM_Locked(scoped_ptr<SHMBuffer>(shm_buffer));
+        PutSHM_Locked(shm_buffer.Pass());
         continue;
       }
     }
 
     // Create a BitstreamBuffer and send to VDA to decode.
     media::BitstreamBuffer bitstream_buffer(
-        buffer_data.bitstream_buffer_id, shm_buffer->shm->handle(),
-        buffer_data.size,
+        buffer_data.bitstream_buffer_id, shm_buffer->handle(), buffer_data.size,
         base::TimeDelta::FromInternalValue(buffer_data.timestamp));
-    bool inserted = bitstream_buffers_in_decoder_
-        .insert(std::make_pair(bitstream_buffer.id(), shm_buffer)).second;
-    DCHECK(inserted);
+    const bool inserted =
+        bitstream_buffers_in_decoder_.insert(
+            std::make_pair(bitstream_buffer.id(), shm_buffer.release())).second;
+    DCHECK(inserted) << "bitstream_buffer_id " << bitstream_buffer.id()
+                     << " existed already in bitstream_buffers_in_decoder_";
     RecordBufferData(buffer_data);
     vda_->Decode(bitstream_buffer);
   }
@@ -550,10 +533,10 @@
 
 void RTCVideoDecoder::SaveToDecodeBuffers_Locked(
     const webrtc::EncodedImage& input_image,
-    scoped_ptr<SHMBuffer> shm_buffer,
+    scoped_ptr<base::SharedMemory> shm_buffer,
     const BufferData& buffer_data) {
-  memcpy(shm_buffer->shm->memory(), input_image._buffer, input_image._length);
-  std::pair<SHMBuffer*, BufferData> buffer_pair =
+  memcpy(shm_buffer->memory(), input_image._buffer, input_image._length);
+  std::pair<base::SharedMemory*, BufferData> buffer_pair =
       std::make_pair(shm_buffer.release(), buffer_data);
 
   // Store the buffer and the metadata to the queue.
@@ -603,7 +586,8 @@
       continue;
     }
     // Get shared memory and save it to decode buffers.
-    scoped_ptr<SHMBuffer> shm_buffer = GetSHM_Locked(input_image._length);
+    scoped_ptr<base::SharedMemory> shm_buffer =
+        GetSHM_Locked(input_image._length);
     if (!shm_buffer)
       return;
     SaveToDecodeBuffers_Locked(input_image, shm_buffer.Pass(), buffer_data);
@@ -696,19 +680,12 @@
 
   // Not destroying PictureBuffers in |picture_buffers_at_display_| yet, since
   // their textures may still be in use by the user of this RTCVideoDecoder.
-  for (PictureBufferTextureMap::iterator it =
-           picture_buffers_at_display_.begin();
-       it != picture_buffers_at_display_.end();
-       ++it) {
-    assigned_picture_buffers_.erase(it->first);
-  }
+  for (const auto& picture_buffer_at_display : picture_buffers_at_display_)
+    assigned_picture_buffers_.erase(picture_buffer_at_display.first);
 
-  for (std::map<int32, media::PictureBuffer>::iterator it =
-           assigned_picture_buffers_.begin();
-       it != assigned_picture_buffers_.end();
-       ++it) {
-    factories_->DeleteTexture(it->second.texture_id());
-  }
+  for (const auto& assigned_picture_buffer : assigned_picture_buffers_)
+    factories_->DeleteTexture(assigned_picture_buffer.second.texture_id());
+
   assigned_picture_buffers_.clear();
 }
 
@@ -722,12 +699,11 @@
   state_ = UNINITIALIZED;
 }
 
-scoped_ptr<RTCVideoDecoder::SHMBuffer> RTCVideoDecoder::GetSHM_Locked(
-    size_t min_size) {
+scoped_ptr<base::SharedMemory> RTCVideoDecoder::GetSHM_Locked(size_t min_size) {
   // Reuse a SHM if possible.
   if (!available_shm_segments_.empty() &&
-      available_shm_segments_.back()->size >= min_size) {
-    scoped_ptr<SHMBuffer> buffer(available_shm_segments_.back());
+      available_shm_segments_.back()->mapped_size() >= min_size) {
+    scoped_ptr<base::SharedMemory> buffer(available_shm_segments_.back());
     available_shm_segments_.pop_back();
     return buffer;
   }
@@ -756,7 +732,8 @@
   return NULL;
 }
 
-void RTCVideoDecoder::PutSHM_Locked(scoped_ptr<SHMBuffer> shm_buffer) {
+void RTCVideoDecoder::PutSHM_Locked(scoped_ptr<base::SharedMemory> shm_buffer) {
+  lock_.AssertAcquired();
   available_shm_segments_.push_back(shm_buffer.release());
 }
 
@@ -773,7 +750,7 @@
     }
 
     base::AutoLock auto_lock(lock_);
-    PutSHM_Locked(scoped_ptr<SHMBuffer>(new SHMBuffer(shm.Pass(), size)));
+    PutSHM_Locked(shm.Pass());
     ++num_shm_buffers_;
   }
 
@@ -796,13 +773,11 @@
 void RTCVideoDecoder::GetBufferData(int32 bitstream_buffer_id,
                                     uint32_t* timestamp,
                                     gfx::Rect* visible_rect) {
-  for (std::list<BufferData>::iterator it = input_buffer_data_.begin();
-       it != input_buffer_data_.end();
-       ++it) {
-    if (it->bitstream_buffer_id != bitstream_buffer_id)
+  for (const auto& buffer_data : input_buffer_data_) {
+    if (buffer_data.bitstream_buffer_id != bitstream_buffer_id)
       continue;
-    *timestamp = it->timestamp;
-    *visible_rect = it->visible_rect;
+    *timestamp = buffer_data.timestamp;
+    *visible_rect = buffer_data.visible_rect;
     return;
   }
   NOTREACHED() << "Missing bitstream buffer id: " << bitstream_buffer_id;
@@ -823,12 +798,8 @@
 
 void RTCVideoDecoder::ClearPendingBuffers() {
   // Delete WebRTC input buffers.
-  for (std::deque<std::pair<webrtc::EncodedImage, BufferData>>::iterator it =
-           pending_buffers_.begin();
-       it != pending_buffers_.end(); ++it) {
-    delete[] it->first._buffer;
-  }
-
+  for (const auto& pending_buffer : pending_buffers_)
+    delete[] pending_buffer.first._buffer;
   pending_buffers_.clear();
 }
 
diff --git a/content/renderer/media/rtc_video_decoder.h b/content/renderer/media/rtc_video_decoder.h
index 813aabe..56ee543c 100644
--- a/content/renderer/media/rtc_video_decoder.h
+++ b/content/renderer/media/rtc_video_decoder.h
@@ -89,7 +89,6 @@
   void NotifyError(media::VideoDecodeAccelerator::Error error) override;
 
  private:
-  class SHMBuffer;
   // Metadata of a bitstream buffer.
   struct BufferData {
     BufferData(int32 bitstream_buffer_id,
@@ -125,7 +124,7 @@
 
   // Saves a WebRTC buffer in |decode_buffers_| for decode.
   void SaveToDecodeBuffers_Locked(const webrtc::EncodedImage& input_image,
-                                  scoped_ptr<SHMBuffer> shm_buffer,
+                                  scoped_ptr<base::SharedMemory> shm_buffer,
                                   const BufferData& buffer_data);
 
   // Saves a WebRTC buffer in |pending_buffers_| waiting for SHM available.
@@ -163,10 +162,10 @@
   // Gets a shared-memory segment of at least |min_size| bytes from
   // |available_shm_segments_|. Returns NULL if there is no buffer or the
   // buffer is not big enough.
-  scoped_ptr<SHMBuffer> GetSHM_Locked(size_t min_size);
+  scoped_ptr<base::SharedMemory> GetSHM_Locked(size_t min_size);
 
   // Returns a shared-memory segment to the available pool.
-  void PutSHM_Locked(scoped_ptr<SHMBuffer> shm_buffer);
+  void PutSHM_Locked(scoped_ptr<base::SharedMemory> shm_buffer);
 
   // Allocates |count| shared memory buffers of |size| bytes.
   void CreateSHM(size_t count, size_t size);
@@ -212,7 +211,7 @@
   // The size of the incoming video frames.
   gfx::Size frame_size_;
 
-  media::GpuVideoAcceleratorFactories* factories_;
+  media::GpuVideoAcceleratorFactories* const factories_;
 
   // The texture target used for decoded pictures.
   uint32 decoder_texture_target_;
@@ -222,7 +221,7 @@
 
   // A map from bitstream buffer IDs to bitstream buffers that are being
   // processed by VDA. The map owns SHM buffers.
-  std::map<int32, SHMBuffer*> bitstream_buffers_in_decoder_;
+  std::map<int32, base::SharedMemory*> bitstream_buffers_in_decoder_;
 
   // A map from picture buffer IDs to texture-backed picture buffers.
   std::map<int32, media::PictureBuffer> assigned_picture_buffers_;
@@ -255,15 +254,15 @@
   // round-trip to the browser process, we keep allocation out of the
   // steady-state of the decoder. The vector owns SHM buffers. Guarded by
   // |lock_|.
-  std::vector<SHMBuffer*> available_shm_segments_;
+  std::vector<base::SharedMemory*> available_shm_segments_;
 
   // A queue storing WebRTC encoding images (and their metadata) that are
   // waiting for the shared memory. Guarded by |lock_|.
-  std::deque<std::pair<webrtc::EncodedImage, BufferData> > pending_buffers_;
+  std::deque<std::pair<webrtc::EncodedImage, BufferData>> pending_buffers_;
 
   // A queue storing buffers (and their metadata) that will be sent to VDA for
   // decode. The queue owns SHM buffers. Guarded by |lock_|.
-  std::deque<std::pair<SHMBuffer*, BufferData> > decode_buffers_;
+  std::deque<std::pair<base::SharedMemory*, BufferData>> decode_buffers_;
 
   // The id that will be given to the next bitstream buffer. Guarded by |lock_|.
   int32 next_bitstream_buffer_id_;
diff --git a/content/renderer/media/rtc_video_decoder_factory.cc b/content/renderer/media/rtc_video_decoder_factory.cc
index 02729314..4e99ab5 100644
--- a/content/renderer/media/rtc_video_decoder_factory.cc
+++ b/content/renderer/media/rtc_video_decoder_factory.cc
@@ -4,7 +4,6 @@
 
 #include "content/renderer/media/rtc_video_decoder_factory.h"
 
-#include "base/location.h"
 #include "base/memory/scoped_ptr.h"
 #include "content/renderer/media/rtc_video_decoder.h"
 #include "media/renderers/gpu_video_accelerator_factories.h"
@@ -14,24 +13,22 @@
 RTCVideoDecoderFactory::RTCVideoDecoderFactory(
     media::GpuVideoAcceleratorFactories* gpu_factories)
     : gpu_factories_(gpu_factories) {
-  DVLOG(2) << "RTCVideoDecoderFactory";
+  DVLOG(2) << __FUNCTION__;
 }
 
 RTCVideoDecoderFactory::~RTCVideoDecoderFactory() {
-  DVLOG(2) << "~RTCVideoDecoderFactory";
+  DVLOG(2) << __FUNCTION__;
 }
 
 webrtc::VideoDecoder* RTCVideoDecoderFactory::CreateVideoDecoder(
     webrtc::VideoCodecType type) {
-  DVLOG(2) << "CreateVideoDecoder";
-  scoped_ptr<RTCVideoDecoder> decoder =
-      RTCVideoDecoder::Create(type, gpu_factories_);
-  return decoder.release();
+  DVLOG(2) << __FUNCTION__;
+  return RTCVideoDecoder::Create(type, gpu_factories_).release();
 }
 
 void RTCVideoDecoderFactory::DestroyVideoDecoder(
     webrtc::VideoDecoder* decoder) {
-  DVLOG(2) << "DestroyVideoDecoder";
+  DVLOG(2) << __FUNCTION__;
   gpu_factories_->GetTaskRunner()->DeleteSoon(FROM_HERE, decoder);
 }
 
diff --git a/content/renderer/media/rtc_video_encoder.cc b/content/renderer/media/rtc_video_encoder.cc
index f544fb8..43ad247 100644
--- a/content/renderer/media/rtc_video_encoder.cc
+++ b/content/renderer/media/rtc_video_encoder.cc
@@ -9,6 +9,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_vector.h"
 #include "base/metrics/histogram.h"
+#include "base/numerics/safe_conversions.h"
 #include "base/rand_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/synchronization/waitable_event.h"
@@ -23,12 +24,6 @@
 #include "third_party/libyuv/include/libyuv.h"
 #include "third_party/webrtc/system_wrappers/include/tick_util.h"
 
-#define NOTIFY_ERROR(x)                             \
-  do {                                              \
-    DLOG(ERROR) << "calling NotifyError(): " << x;  \
-    NotifyError(x);                                 \
-  } while (0)
-
 namespace content {
 
 namespace {
@@ -36,7 +31,8 @@
 // Translate from webrtc::VideoCodecType and webrtc::VideoCodec to
 // media::VideoCodecProfile.
 media::VideoCodecProfile WebRTCVideoCodecToVideoCodecProfile(
-    webrtc::VideoCodecType type, const webrtc::VideoCodec* codec_settings) {
+    webrtc::VideoCodecType type,
+    const webrtc::VideoCodec* codec_settings) {
   DCHECK_EQ(type, codec_settings->codecType);
   switch (type) {
     case webrtc::kVideoCodecVP8:
@@ -158,6 +154,11 @@
 
   ~Impl() override;
 
+  // Logs the |error| and |str| sent from |location| and NotifyError()s forward.
+  void LogAndNotifyError(const tracked_objects::Location& location,
+                         const std::string& str,
+                         media::VideoEncodeAccelerator::Error error);
+
   // Perform encoding on an input frame from the input queue.
   void EncodeOneFrame();
 
@@ -169,6 +170,9 @@
   void RegisterAsyncWaiter(base::WaitableEvent* waiter, int32_t* retval);
   void SignalAsyncWaiter(int32_t retval);
 
+  // Checks if the bitrate would overflow when passing from kbps to bps.
+  bool IsBitrateTooHigh(uint32 bitrate);
+
   base::ThreadChecker thread_checker_;
 
   // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
@@ -247,20 +251,20 @@
   RegisterAsyncWaiter(async_waiter, async_retval);
 
   // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
-  if (bitrate > kuint32max / 1000) {
-    NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
+  if (IsBitrateTooHigh(bitrate))
     return;
-  }
 
   video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator().Pass();
   if (!video_encoder_) {
-    NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+    LogAndNotifyError(FROM_HERE, "Error creating VideoEncodeAccelerator",
+                      media::VideoEncodeAccelerator::kPlatformFailureError);
     return;
   }
   input_visible_size_ = input_visible_size;
   if (!video_encoder_->Initialize(media::PIXEL_FORMAT_I420, input_visible_size_,
                                   profile, bitrate * 1000, this)) {
-    NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
+    LogAndNotifyError(FROM_HERE, "Error initializing video_encoder",
+                      media::VideoEncodeAccelerator::kInvalidArgumentError);
     return;
   }
 }
@@ -325,10 +329,8 @@
   DCHECK(thread_checker_.CalledOnValidThread());
 
   // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
-  if (bitrate > kuint32max / 1000) {
-    NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError);
+  if (IsBitrateTooHigh(bitrate))
     return;
-  }
 
   if (video_encoder_)
     video_encoder_->RequestEncodingParametersChange(bitrate * 1000, framerate);
@@ -359,9 +361,8 @@
         gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize(
             media::PIXEL_FORMAT_I420, input_coded_size));
     if (!shm) {
-      DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
-                     "failed to create input buffer " << i;
-      NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+      LogAndNotifyError(FROM_HERE, "failed to create input buffer ",
+                        media::VideoEncodeAccelerator::kPlatformFailureError);
       return;
     }
     input_buffers_.push_back(shm.release());
@@ -372,9 +373,8 @@
     scoped_ptr<base::SharedMemory> shm =
         gpu_factories_->CreateSharedMemory(output_buffer_size);
     if (!shm) {
-      DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): "
-                     "failed to create output buffer " << i;
-      NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+      LogAndNotifyError(FROM_HERE, "failed to create output buffer",
+                        media::VideoEncodeAccelerator::kPlatformFailureError);
       return;
     }
     output_buffers_.push_back(shm.release());
@@ -400,16 +400,14 @@
 
   if (bitstream_buffer_id < 0 ||
       bitstream_buffer_id >= static_cast<int>(output_buffers_.size())) {
-    DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid bitstream_buffer_id="
-                << bitstream_buffer_id;
-    NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+    LogAndNotifyError(FROM_HERE, "invalid bitstream_buffer_id",
+                      media::VideoEncodeAccelerator::kPlatformFailureError);
     return;
   }
   base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
   if (payload_size > output_buffer->mapped_size()) {
-    DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid payload_size="
-                << payload_size;
-    NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+    LogAndNotifyError(FROM_HERE, "invalid payload_size",
+                      media::VideoEncodeAccelerator::kPlatformFailureError);
     return;
   }
   output_buffers_free_count_--;
@@ -445,7 +443,6 @@
 
 void RTCVideoEncoder::Impl::NotifyError(
     media::VideoEncodeAccelerator::Error error) {
-  DVLOG(3) << "Impl::NotifyError(): error=" << error;
   DCHECK(thread_checker_.CalledOnValidThread());
   int32_t retval;
   switch (error) {
@@ -469,6 +466,19 @@
 
 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); }
 
+void RTCVideoEncoder::Impl::LogAndNotifyError(
+    const tracked_objects::Location& location,
+    const std::string& str,
+    media::VideoEncodeAccelerator::Error error) {
+  static const char* kErrorNames[] = {
+      "kIllegalStateError", "kInvalidArgumentError", "kPlatformFailureError"};
+  static_assert(
+      arraysize(kErrorNames) == media::VideoEncodeAccelerator::kErrorMax + 1,
+      "Different number of errors and textual descriptions");
+  DLOG(ERROR) << location.ToString() << kErrorNames[error] << " - " << str;
+  NotifyError(error);
+}
+
 void RTCVideoEncoder::Impl::EncodeOneFrame() {
   DVLOG(3) << "Impl::EncodeOneFrame()";
   DCHECK(thread_checker_.CalledOnValidThread());
@@ -502,8 +512,8 @@
         input_buffer->mapped_size(), input_buffer->handle(), 0,
         base::TimeDelta());
     if (!frame.get()) {
-      DLOG(ERROR) << "Impl::EncodeOneFrame(): failed to create frame";
-      NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+      LogAndNotifyError(FROM_HERE, "failed to create frame",
+                        media::VideoEncodeAccelerator::kPlatformFailureError);
       return;
     }
     // Do a strided copy of the input frame to match the input requirements for
@@ -522,8 +532,8 @@
                          frame->data(media::VideoFrame::kVPlane),
                          frame->stride(media::VideoFrame::kVPlane),
                          next_frame->width(), next_frame->height())) {
-      DLOG(ERROR) << "Failed to copy buffer";
-      NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError);
+      LogAndNotifyError(FROM_HERE, "Failed to copy buffer",
+                        media::VideoEncodeAccelerator::kPlatformFailureError);
       return;
     }
   }
@@ -561,13 +571,13 @@
   async_waiter_ = NULL;
 }
 
-#undef NOTIFY_ERROR
-
-////////////////////////////////////////////////////////////////////////////////
-//
-// RTCVideoEncoder
-//
-////////////////////////////////////////////////////////////////////////////////
+bool RTCVideoEncoder::Impl::IsBitrateTooHigh(uint32 bitrate) {
+  if (base::IsValueInRangeForNumericType<uint32>(bitrate * UINT64_C(1000)))
+    return false;
+  LogAndNotifyError(FROM_HERE, "Overflow converting bitrate from kbps to bps",
+                    media::VideoEncodeAccelerator::kInvalidArgumentError);
+  return true;
+}
 
 RTCVideoEncoder::RTCVideoEncoder(
     webrtc::VideoCodecType type,
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index 3f2c5e8..ae19127 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -21,6 +21,7 @@
 #include "content/renderer/pepper/pepper_video_decoder_host.h"
 #include "content/renderer/render_thread_impl.h"
 #include "gpu/command_buffer/client/gles2_implementation.h"
+#include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/limits.h"
 #include "media/base/media_util.h"
@@ -700,7 +701,7 @@
   DCHECK_EQ(decoder_->GetMaxDecodeRequests(), 1);
 
   decoder_->Initialize(
-      config, true /* low_delay */,
+      config, true /* low_delay */, media::SetCdmReadyCB(),
       base::Bind(&VideoDecoderShim::DecoderImpl::OnInitDone,
                  weak_ptr_factory_.GetWeakPtr()),
       base::Bind(&VideoDecoderShim::DecoderImpl::OnOutputComplete,
diff --git a/content/renderer/presentation/presentation_dispatcher.cc b/content/renderer/presentation/presentation_dispatcher.cc
index 1a249e8..bcb33fa 100644
--- a/content/renderer/presentation/presentation_dispatcher.cc
+++ b/content/renderer/presentation/presentation_dispatcher.cc
@@ -205,7 +205,7 @@
   }
 }
 
-void PresentationDispatcher::closeSession(
+void PresentationDispatcher::terminateSession(
     const blink::WebString& presentationUrl,
     const blink::WebString& presentationId) {
   ConnectToPresentationServiceIfNeeded();
diff --git a/content/renderer/presentation/presentation_dispatcher.h b/content/renderer/presentation/presentation_dispatcher.h
index 56c88f3..c96789c 100644
--- a/content/renderer/presentation/presentation_dispatcher.h
+++ b/content/renderer/presentation/presentation_dispatcher.h
@@ -76,8 +76,8 @@
                     const blink::WebString& presentationId,
                     const uint8* data,
                     size_t length) override;
-  void closeSession(const blink::WebString& presentationUrl,
-                    const blink::WebString& presentationId) override;
+  void terminateSession(const blink::WebString& presentationUrl,
+                        const blink::WebString& presentationId) override;
   void getAvailability(
       const blink::WebString& availabilityUrl,
       blink::WebPresentationAvailabilityCallbacks* callbacks) override;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index d92ca9a..f8c5afa 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -2721,6 +2721,8 @@
   // Start time is only set after request time.
   document_state->set_start_load_time(Time::Now());
 
+  NavigationStateImpl* navigation_state = static_cast<NavigationStateImpl*>(
+      document_state->navigation_state());
   bool is_top_most = !frame->parent();
   if (is_top_most) {
     render_view_->set_navigation_gesture(
@@ -2730,16 +2732,19 @@
     // Subframe navigations that don't add session history items must be
     // marked with AUTO_SUBFRAME. See also didFailProvisionalLoad for how we
     // handle loading of error pages.
-    static_cast<NavigationStateImpl*>(document_state->navigation_state())
-        ->set_transition_type(ui::PAGE_TRANSITION_AUTO_SUBFRAME);
+    navigation_state->set_transition_type(ui::PAGE_TRANSITION_AUTO_SUBFRAME);
   }
 
+  base::TimeTicks navigation_start =
+      navigation_state->common_params().navigation_start;
+  DCHECK(!navigation_start.is_null());
+
   FOR_EACH_OBSERVER(RenderViewObserver, render_view_->observers(),
                     DidStartProvisionalLoad(frame));
   FOR_EACH_OBSERVER(RenderFrameObserver, observers_, DidStartProvisionalLoad());
 
-  Send(new FrameHostMsg_DidStartProvisionalLoadForFrame(
-       routing_id_, ds->request().url()));
+  Send(new FrameHostMsg_DidStartProvisionalLoad(
+      routing_id_, ds->request().url(), navigation_start));
 }
 
 void RenderFrameImpl::didReceiveServerRedirectForProvisionalLoad(
@@ -4350,8 +4355,8 @@
 
   // Inform the browser of the start of the provisional load. This is needed so
   // that the load is properly tracked by the WebNavigation API.
-  Send(new FrameHostMsg_DidStartProvisionalLoadForFrame(
-      routing_id_, common_params.url));
+  Send(new FrameHostMsg_DidStartProvisionalLoad(
+      routing_id_, common_params.url, common_params.navigation_start));
 
   // Send the provisional load failure.
   blink::WebURLError error =
@@ -4685,6 +4690,14 @@
   pending_navigation_params_->common_params.navigation_start =
       base::TimeTicks();
 
+  // Unless the load is a WebFrameLoadType::Standard, this should remain
+  // uninitialized. It will be updated when the load type is determined to be
+  // Standard, or after the previous document's unload handler has been
+  // triggered. This occurs in UpdateNavigationState.
+  // TODO(csharrison) See if we can always use the browser timestamp.
+  pending_navigation_params_->common_params.navigation_start =
+      base::TimeTicks();
+
   // Create parameters for a standard navigation.
   blink::WebFrameLoadType load_type = blink::WebFrameLoadType::Standard;
   bool should_load_request = false;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 407952e..28fde258 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -141,7 +141,6 @@
 #include "third_party/WebKit/public/platform/WebString.h"
 #include "third_party/WebKit/public/platform/WebThread.h"
 #include "third_party/WebKit/public/web/WebCache.h"
-#include "third_party/WebKit/public/web/WebColorName.h"
 #include "third_party/WebKit/public/web/WebDatabase.h"
 #include "third_party/WebKit/public/web/WebDocument.h"
 #include "third_party/WebKit/public/web/WebFrame.h"
diff --git a/content/renderer/render_view_browsertest.cc b/content/renderer/render_view_browsertest.cc
index 3783e905..bc3788c 100644
--- a/content/renderer/render_view_browsertest.cc
+++ b/content/renderer/render_view_browsertest.cc
@@ -137,6 +137,13 @@
   }
 };
 
+// Timestamps logged close to each other under low resolution timers
+// are more likely to record the same value. Allow for this by relaxing
+// constraints on systems with these timers.
+bool TimeTicksGT(const base::TimeTicks& x, const base::TimeTicks& y) {
+  return base::TimeTicks::IsHighResolution() ? x > y : x >= y;
+}
+
 }  // namespace
 
 class RenderViewImplTest : public RenderViewTest {
@@ -168,6 +175,37 @@
     return static_cast<TestRenderFrame*>(view()->GetMainRenderFrame());
   }
 
+  void GoToOffsetWithParams(int offset,
+                            const PageState& state,
+                            const CommonNavigationParams common_params,
+                            const StartNavigationParams start_params,
+                            RequestNavigationParams request_params) {
+    EXPECT_TRUE(common_params.transition & ui::PAGE_TRANSITION_FORWARD_BACK);
+    int pending_offset = offset + view()->history_list_offset_;
+
+    request_params.page_state = state;
+    request_params.page_id = view()->page_id_ + offset;
+    request_params.nav_entry_id = pending_offset + 1;
+    request_params.pending_history_list_offset = pending_offset;
+    request_params.current_history_list_offset = view()->history_list_offset_;
+    request_params.current_history_list_length = view()->history_list_length_;
+    frame()->Navigate(common_params, start_params, request_params);
+
+    // The load actually happens asynchronously, so we pump messages to process
+    // the pending continuation.
+    FrameLoadWaiter(frame()).Wait();
+  }
+
+  template<class T>
+  typename T::Param ProcessAndReadIPC() {
+    ProcessPendingMessages();
+    const IPC::Message* message =
+        render_thread_->sink().GetUniqueMessageMatching(T::ID);
+    typename T::Param param;
+    T::Read(message, &param);
+    return param;
+  }
+
   // Sends IPC messages that emulates a key-press event.
   int SendKeyEvent(MockKeyboard::Layout layout,
                    int key_code,
@@ -2284,6 +2322,91 @@
   EXPECT_LE(late_nav_reported_start, after_navigation);
 }
 
+TEST_F(RenderViewImplTest, RendererNavigationStartTransmittedToBrowser) {
+  base::TimeTicks lower_bound_navigation_start;
+  frame()->GetWebFrame()->loadHTMLString(
+      "hello world", blink::WebURL(GURL("data:text/html,")));
+  ProcessPendingMessages();
+  const IPC::Message* frame_navigate_msg =
+      render_thread_->sink().GetUniqueMessageMatching(
+          FrameHostMsg_DidStartProvisionalLoad::ID);
+  FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params;
+  FrameHostMsg_DidStartProvisionalLoad::Read(frame_navigate_msg,
+                                                     &host_nav_params);
+  base::TimeTicks transmitted_start = base::get<1>(host_nav_params);
+  EXPECT_FALSE(transmitted_start.is_null());
+  EXPECT_LT(lower_bound_navigation_start, transmitted_start);
+}
+
+TEST_F(RenderViewImplTest, BrowserNavigationStartNotUsedForReload) {
+  const char url_string[] = "data:text/html,<div>Page</div>";
+  // Navigate once, then reload.
+  LoadHTML(url_string);
+  ProcessPendingMessages();
+  render_thread_->sink().ClearMessages();
+
+  CommonNavigationParams common_params;
+  common_params.url = GURL(url_string);
+  common_params.navigation_type =
+      FrameMsg_Navigate_Type::RELOAD_ORIGINAL_REQUEST_URL;
+  common_params.transition = ui::PAGE_TRANSITION_RELOAD;
+
+  frame()->Navigate(common_params, StartNavigationParams(),
+                    RequestNavigationParams());
+
+  FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params =
+      ProcessAndReadIPC<FrameHostMsg_DidStartProvisionalLoad>();
+  // The true timestamp is later than the browser initiated one.
+  EXPECT_PRED2(TimeTicksGT, base::get<1>(host_nav_params),
+               common_params.navigation_start);
+}
+
+TEST_F(RenderViewImplTest, BrowserNavigationStartNotUsedForHistoryNavigation) {
+  LoadHTML("<div id=pagename>Page A</div>");
+  LoadHTML("<div id=pagename>Page B</div>");
+  PageState back_state =
+      HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
+  LoadHTML("<div id=pagename>Page C</div>");
+  PageState forward_state =
+      HistoryEntryToPageState(view()->history_controller()->GetCurrentEntry());
+  ProcessPendingMessages();
+  render_thread_->sink().ClearMessages();
+
+  CommonNavigationParams common_params;
+  common_params.transition = ui::PAGE_TRANSITION_FORWARD_BACK;
+  // Go back.
+  GoToOffsetWithParams(-1, back_state, common_params, StartNavigationParams(),
+                       RequestNavigationParams());
+  FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params =
+      ProcessAndReadIPC<FrameHostMsg_DidStartProvisionalLoad>();
+  EXPECT_PRED2(TimeTicksGT, base::get<1>(host_nav_params),
+               common_params.navigation_start);
+  render_thread_->sink().ClearMessages();
+
+  // Go forward.
+  GoToOffsetWithParams(1, forward_state, common_params,
+                             StartNavigationParams(),
+                             RequestNavigationParams());
+  FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params2 =
+      ProcessAndReadIPC<FrameHostMsg_DidStartProvisionalLoad>();
+  EXPECT_PRED2(TimeTicksGT, base::get<1>(host_nav_params2),
+               common_params.navigation_start);
+}
+
+TEST_F(RenderViewImplTest, BrowserNavigationStartSuccessfullyTransmitted) {
+  CommonNavigationParams common_params;
+  common_params.url = GURL("data:text/html,<div>Page</div>");
+  common_params.navigation_type = FrameMsg_Navigate_Type::NORMAL;
+  common_params.transition = ui::PAGE_TRANSITION_TYPED;
+
+  frame()->Navigate(common_params, StartNavigationParams(),
+                    RequestNavigationParams());
+
+  FrameHostMsg_DidStartProvisionalLoad::Param host_nav_params =
+      ProcessAndReadIPC<FrameHostMsg_DidStartProvisionalLoad>();
+  EXPECT_EQ(base::get<1>(host_nav_params), common_params.navigation_start);
+}
+
 TEST_F(RenderViewImplTest, PreferredSizeZoomed) {
   LoadHTML("<body style='margin:0;'><div style='display:inline-block; "
            "width:400px; height:400px;'/></body>");
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index b1d18cc2..216d6187 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -129,7 +129,6 @@
 #include "third_party/WebKit/public/platform/WebURLResponse.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
 #include "third_party/WebKit/public/web/WebAXObject.h"
-#include "third_party/WebKit/public/web/WebColorName.h"
 #include "third_party/WebKit/public/web/WebColorSuggestion.h"
 #include "third_party/WebKit/public/web/WebDOMEvent.h"
 #include "third_party/WebKit/public/web/WebDOMMessageEvent.h"
@@ -217,7 +216,6 @@
 using blink::WebApplicationCacheHostClient;
 using blink::WebCString;
 using blink::WebColor;
-using blink::WebColorName;
 using blink::WebConsoleMessage;
 using blink::WebData;
 using blink::WebDataSource;
@@ -2708,8 +2706,7 @@
 
 #if defined(USE_DEFAULT_RENDER_THEME)
   if (renderer_prefs.use_custom_colors) {
-    WebColorName name = blink::WebColorWebkitFocusRingColor;
-    blink::setNamedColors(&name, &renderer_prefs.focus_ring_color, 1);
+    blink::setFocusRingColor(renderer_prefs.focus_ring_color);
     blink::setCaretBlinkInterval(renderer_prefs.caret_blink_interval);
 
     if (webview()) {
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 4ca6980..38a917ff 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -46,8 +46,6 @@
     "app/shell_main_delegate_mac.mm",
     "browser/blink_test_controller.cc",
     "browser/blink_test_controller.h",
-    "browser/ipc_echo_message_filter.cc",
-    "browser/ipc_echo_message_filter.h",
     "browser/layout_test/layout_test_android.cc",
     "browser/layout_test/layout_test_android.h",
     "browser/layout_test/layout_test_bluetooth_adapter_provider.cc",
@@ -151,8 +149,6 @@
     "common/shell_switches.h",
     "common/shell_test_configuration.cc",
     "common/shell_test_configuration.h",
-    "renderer/ipc_echo.cc",
-    "renderer/ipc_echo.h",
     "renderer/layout_test/blink_test_helpers.cc",
     "renderer/layout_test/blink_test_helpers.h",
     "renderer/layout_test/blink_test_runner.cc",
diff --git a/content/shell/browser/ipc_echo_message_filter.cc b/content/shell/browser/ipc_echo_message_filter.cc
deleted file mode 100644
index d383789..0000000
--- a/content/shell/browser/ipc_echo_message_filter.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2014 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 "content/shell/browser/ipc_echo_message_filter.h"
-
-#include "content/shell/common/shell_messages.h"
-
-namespace content {
-
-IPCEchoMessageFilter::IPCEchoMessageFilter()
-    : BrowserMessageFilter(ShellMsgStart) {
-}
-
-IPCEchoMessageFilter::~IPCEchoMessageFilter() {
-}
-
-bool IPCEchoMessageFilter::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(IPCEchoMessageFilter, message)
-    IPC_MESSAGE_HANDLER(ShellViewHostMsg_EchoPing, OnEchoPing)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
-void IPCEchoMessageFilter::OnEchoPing(int routing_id, int id,
-                                    const std::string& body) {
-  Send(new ShellViewMsg_EchoPong(routing_id, id, body));
-}
-
-}  // namespace content
diff --git a/content/shell/browser/ipc_echo_message_filter.h b/content/shell/browser/ipc_echo_message_filter.h
deleted file mode 100644
index 2b5f25c..0000000
--- a/content/shell/browser/ipc_echo_message_filter.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef CONTENT_SHELL_BROWSER_IPC_ECHO_MESSAGE_FILTER_H_
-#define CONTENT_SHELL_BROWSER_IPC_ECHO_MESSAGE_FILTER_H_
-
-#include <string>
-
-#include "content/public/browser/browser_message_filter.h"
-
-namespace content {
-
-class IPCEchoMessageFilter : public BrowserMessageFilter {
- public:
-  IPCEchoMessageFilter();
-
- private:
-  ~IPCEchoMessageFilter() override;
-
-  // BrowserMessageFilter implementation.
-  bool OnMessageReceived(const IPC::Message& message) override;
-
-  void OnEchoPing(int routing_id, int id, const std::string& body);
-
-  DISALLOW_COPY_AND_ASSIGN(IPCEchoMessageFilter);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_BROWSER_IPC_ECHO_MESSAGE_FILTER_H_
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
index 6b5bcd7..b6635053 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -62,6 +62,7 @@
 const char kGenericAccessServiceUUID[] = "1800";
 const char kGlucoseServiceUUID[] = "1808";
 const char kHeartRateServiceUUID[] = "180d";
+const char kTxPowerServiceUUID[] = "1804";
 const char kHeartRateMeasurementUUID[] = "2a37";
 const char kBodySensorLocation[] = "2a38";
 const char kDeviceNameUUID[] = "2a00";
@@ -141,12 +142,10 @@
     return GetGlucoseHeartRateAdapter();
   else if (fake_adapter_name == "UnicodeDeviceAdapter")
     return GetUnicodeDeviceAdapter();
-  else if (fake_adapter_name == "MissingServiceGenericAccessAdapter")
-    return GetMissingServiceGenericAccessAdapter();
-  else if (fake_adapter_name == "MissingCharacteristicGenericAccessAdapter")
-    return GetMissingCharacteristicGenericAccessAdapter();
-  else if (fake_adapter_name == "GenericAccessAdapter")
-    return GetGenericAccessAdapter();
+  else if (fake_adapter_name == "MissingServiceHeartRateAdapter")
+    return GetMissingServiceHeartRateAdapter();
+  else if (fake_adapter_name == "MissingCharacteristicHeartRateAdapter")
+    return GetMissingCharacteristicHeartRateAdapter();
   else if (fake_adapter_name == "HeartRateAdapter")
     return GetHeartRateAdapter();
   else if (fake_adapter_name == "FailingConnectionsAdapter")
@@ -392,66 +391,30 @@
 
 // static
 scoped_refptr<NiceMockBluetoothAdapter>
-LayoutTestBluetoothAdapterProvider::GetMissingServiceGenericAccessAdapter() {
+LayoutTestBluetoothAdapterProvider::GetMissingServiceHeartRateAdapter() {
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
 
-  adapter->AddMockDevice(GetGenericAccessDevice(adapter.get()));
-
-  return adapter.Pass();
-}
-
-// static
-scoped_refptr<NiceMockBluetoothAdapter> LayoutTestBluetoothAdapterProvider::
-    GetMissingCharacteristicGenericAccessAdapter() {
-  scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
-
-  scoped_ptr<NiceMockBluetoothDevice> device(
-      GetGenericAccessDevice(adapter.get()));
-
-  scoped_ptr<NiceMockBluetoothGattService> generic_access(
-      GetBaseGATTService(device.get(), kGenericAccessServiceUUID));
-
-  // Intentionally NOT adding a characteristic to generic_access service.
-
-  device->AddMockService(generic_access.Pass());
-
-  adapter->AddMockDevice(device.Pass());
+  adapter->AddMockDevice(GetHeartRateDevice(adapter.get()));
 
   return adapter.Pass();
 }
 
 // static
 scoped_refptr<NiceMockBluetoothAdapter>
-LayoutTestBluetoothAdapterProvider::GetGenericAccessAdapter() {
+LayoutTestBluetoothAdapterProvider::GetMissingCharacteristicHeartRateAdapter() {
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
 
-  scoped_ptr<NiceMockBluetoothDevice> device(
-      GetGenericAccessDevice(adapter.get()));
+  scoped_ptr<NiceMockBluetoothDevice> device(GetHeartRateDevice(adapter.get()));
 
   scoped_ptr<NiceMockBluetoothGattService> generic_access(
       GetBaseGATTService(device.get(), kGenericAccessServiceUUID));
+  scoped_ptr<NiceMockBluetoothGattService> heart_rate(
+      GetBaseGATTService(device.get(), kHeartRateServiceUUID));
 
-  scoped_ptr<NiceMockBluetoothGattCharacteristic> device_name(
-      GetBaseGATTCharacteristic(
-          generic_access.get(),
-          kDeviceNameUUID,
-          BluetoothGattCharacteristic::PROPERTY_READ |
-          BluetoothGattCharacteristic::PROPERTY_WRITE));
+  // Intentionally NOT adding a characteristic to heart_rate service.
 
-  // Read response.
-  std::string device_name_str = device->GetDeviceName();
-  std::vector<uint8_t> device_name_value(device_name_str.begin(),
-                                         device_name_str.end());
-
-  ON_CALL(*device_name, ReadRemoteCharacteristic(_, _))
-      .WillByDefault(RunCallback<0>(device_name_value));
-
-  // Write response.
-  ON_CALL(*device_name, WriteRemoteCharacteristic(_, _, _))
-      .WillByDefault(RunCallback<1 /* sucess callback */>());
-
-  generic_access->AddMockCharacteristic(device_name.Pass());
   device->AddMockService(generic_access.Pass());
+  device->AddMockService(heart_rate.Pass());
   adapter->AddMockDevice(device.Pass());
 
   return adapter.Pass();
@@ -506,69 +469,16 @@
 scoped_refptr<NiceMockBluetoothAdapter>
 LayoutTestBluetoothAdapterProvider::GetHeartRateAdapter() {
   scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
-  // Used by lambdas that need the adapter.
-  NiceMockBluetoothAdapter* adapter_ptr = adapter.get();
-
   scoped_ptr<NiceMockBluetoothDevice> device(GetHeartRateDevice(adapter.get()));
-  scoped_ptr<NiceMockBluetoothGattService> heart_rate(
-      GetBaseGATTService(device.get(), kHeartRateServiceUUID));
 
   // TODO(ortuno): Implement the rest of the service's characteristics
   // See: http://crbug.com/529975
 
-  // Body Sensor Location Characteristic
-
-  scoped_ptr<NiceMockBluetoothGattCharacteristic> body_sensor_location(
-      GetBaseGATTCharacteristic(
-          heart_rate.get(),
-          kBodySensorLocation,
-          BluetoothGattCharacteristic::PROPERTY_READ));
-  BluetoothGattCharacteristic* location_ptr = body_sensor_location.get();
-
-  ON_CALL(*body_sensor_location, ReadRemoteCharacteristic(_, _))
-      .WillByDefault(RunCallbackWithResult<0 /* success_callback */>(
-          [adapter_ptr, location_ptr]() {
-            std::vector<uint8_t> location(1 /* size */);
-            location[0] = 1;  // Chest
-            // Read a characteristic has a side effect of
-            // GattCharacteristicValueChanged being called.
-            FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
-                              adapter_ptr->GetObservers(),
-                              GattCharacteristicValueChanged(
-                                  adapter_ptr, location_ptr, location));
-            return location;
-          }));
-
-  // Heart Rate Measurement Characteristic
-  scoped_ptr<NiceMockBluetoothGattCharacteristic> heart_rate_measurement(
-      GetBaseGATTCharacteristic(
-          heart_rate.get(),
-          kHeartRateMeasurementUUID,
-          BluetoothGattCharacteristic::PROPERTY_NOTIFY));
-  NiceMockBluetoothGattCharacteristic* measurement_ptr =
-      heart_rate_measurement.get();
-
-  ON_CALL(*heart_rate_measurement, StartNotifySession(_, _))
-      .WillByDefault(RunCallbackWithResult<0 /* success_callback */>(
-          [adapter_ptr, measurement_ptr]() {
-            scoped_ptr<NiceMockBluetoothGattNotifySession> notify_session(
-                GetBaseGATTNotifySession(measurement_ptr->GetIdentifier()));
-
-            std::vector<uint8_t> rate(1 /* size */);
-            rate[0] = 60;
-
-            notify_session->StartTestNotifications(adapter_ptr, measurement_ptr,
-                                                   rate);
-
-            return notify_session.Pass();
-          }));
-
-  heart_rate->AddMockCharacteristic(heart_rate_measurement.Pass());
-  heart_rate->AddMockCharacteristic(body_sensor_location.Pass());
-  device->AddMockService(heart_rate.Pass());
+  device->AddMockService(GetGenericAccessService(adapter.get(), device.get()));
+  device->AddMockService(GetHeartRateService(adapter.get(), device.get()));
   adapter->AddMockDevice(device.Pass());
 
-  return adapter.Pass();
+  return adapter;
 }
 
 // static
@@ -671,7 +581,6 @@
 LayoutTestBluetoothAdapterProvider::GetBatteryDevice(
     MockBluetoothAdapter* adapter) {
   BluetoothDevice::UUIDList uuids;
-  uuids.push_back(BluetoothUUID(kGenericAccessServiceUUID));
   uuids.push_back(BluetoothUUID(kBatteryServiceUUID));
 
   return GetBaseDevice(adapter, "Battery Device", uuids, makeMACAddress(0x1));
@@ -682,7 +591,7 @@
 LayoutTestBluetoothAdapterProvider::GetGlucoseDevice(
     MockBluetoothAdapter* adapter) {
   BluetoothDevice::UUIDList uuids;
-  uuids.push_back(BluetoothUUID(kGenericAccessServiceUUID));
+  uuids.push_back(BluetoothUUID(kTxPowerServiceUUID));
   uuids.push_back(BluetoothUUID(kGlucoseServiceUUID));
 
   return GetBaseDevice(adapter, "Glucose Device", uuids, makeMACAddress(0x2));
@@ -690,18 +599,6 @@
 
 // static
 scoped_ptr<NiceMockBluetoothDevice>
-LayoutTestBluetoothAdapterProvider::GetHeartRateDevice(
-    MockBluetoothAdapter* adapter) {
-  BluetoothDevice::UUIDList uuids;
-  uuids.push_back(BluetoothUUID(kGenericAccessServiceUUID));
-  uuids.push_back(BluetoothUUID(kHeartRateServiceUUID));
-
-  return GetConnectableDevice(adapter, "Heart Rate Device", uuids,
-                              makeMACAddress(0x3));
-}
-
-// static
-scoped_ptr<NiceMockBluetoothDevice>
 LayoutTestBluetoothAdapterProvider::GetConnectableDevice(
     device::MockBluetoothAdapter* adapter,
     const std::string& device_name,
@@ -745,13 +642,12 @@
 
 // static
 scoped_ptr<NiceMockBluetoothDevice>
-LayoutTestBluetoothAdapterProvider::GetGenericAccessDevice(
-    MockBluetoothAdapter* adapter,
-    const std::string& device_name) {
+LayoutTestBluetoothAdapterProvider::GetHeartRateDevice(
+    MockBluetoothAdapter* adapter) {
   BluetoothDevice::UUIDList uuids;
-  uuids.push_back(BluetoothUUID(kGenericAccessServiceUUID));
+  uuids.push_back(BluetoothUUID(kHeartRateServiceUUID));
 
-  return GetConnectableDevice(adapter, device_name, uuids);
+  return GetConnectableDevice(adapter, "Heart Rate Device", uuids);
 }
 
 // Services
@@ -777,6 +673,93 @@
   return service.Pass();
 }
 
+// static
+scoped_ptr<NiceMockBluetoothGattService>
+LayoutTestBluetoothAdapterProvider::GetGenericAccessService(
+    MockBluetoothAdapter* adapter,
+    MockBluetoothDevice* device) {
+  scoped_ptr<NiceMockBluetoothGattService> generic_access(
+      GetBaseGATTService(device, kGenericAccessServiceUUID));
+
+  scoped_ptr<NiceMockBluetoothGattCharacteristic> device_name(
+      GetBaseGATTCharacteristic(
+          generic_access.get(), kDeviceNameUUID,
+          BluetoothGattCharacteristic::PROPERTY_READ |
+              BluetoothGattCharacteristic::PROPERTY_WRITE));
+
+  // Read response.
+  std::string device_name_str = device->GetDeviceName();
+  std::vector<uint8_t> device_name_value(device_name_str.begin(),
+                                         device_name_str.end());
+
+  ON_CALL(*device_name, ReadRemoteCharacteristic(_, _))
+      .WillByDefault(RunCallback<0>(device_name_value));
+
+  // Write response.
+  ON_CALL(*device_name, WriteRemoteCharacteristic(_, _, _))
+      .WillByDefault(RunCallback<1 /* sucess callback */>());
+
+  generic_access->AddMockCharacteristic(device_name.Pass());
+
+  return generic_access;
+}
+
+// static
+scoped_ptr<NiceMockBluetoothGattService>
+LayoutTestBluetoothAdapterProvider::GetHeartRateService(
+    MockBluetoothAdapter* adapter,
+    MockBluetoothDevice* device) {
+  scoped_ptr<NiceMockBluetoothGattService> heart_rate(
+      GetBaseGATTService(device, kHeartRateServiceUUID));
+
+  // Heart Rate Measurement
+  scoped_ptr<NiceMockBluetoothGattCharacteristic> heart_rate_measurement(
+      GetBaseGATTCharacteristic(heart_rate.get(), kHeartRateMeasurementUUID,
+                                BluetoothGattCharacteristic::PROPERTY_NOTIFY));
+  NiceMockBluetoothGattCharacteristic* measurement_ptr =
+      heart_rate_measurement.get();
+
+  ON_CALL(*heart_rate_measurement, StartNotifySession(_, _))
+      .WillByDefault(RunCallbackWithResult<0 /* success_callback */>(
+          [adapter, measurement_ptr]() {
+            scoped_ptr<NiceMockBluetoothGattNotifySession> notify_session(
+                GetBaseGATTNotifySession(measurement_ptr->GetIdentifier()));
+
+            std::vector<uint8_t> rate(1 /* size */);
+            rate[0] = 60;
+
+            notify_session->StartTestNotifications(adapter, measurement_ptr,
+                                                   rate);
+
+            return notify_session.Pass();
+          }));
+
+  // Body Sensor Location Characteristic
+  scoped_ptr<NiceMockBluetoothGattCharacteristic> body_sensor_location(
+      GetBaseGATTCharacteristic(heart_rate.get(), kBodySensorLocation,
+                                BluetoothGattCharacteristic::PROPERTY_READ));
+  BluetoothGattCharacteristic* location_ptr = body_sensor_location.get();
+
+  ON_CALL(*body_sensor_location, ReadRemoteCharacteristic(_, _))
+      .WillByDefault(RunCallbackWithResult<0 /* success_callback */>(
+          [adapter, location_ptr]() {
+            std::vector<uint8_t> location(1 /* size */);
+            location[0] = 1;  // Chest
+            // Read a characteristic has a side effect of
+            // GattCharacteristicValueChanged being called.
+            FOR_EACH_OBSERVER(BluetoothAdapter::Observer,
+                              adapter->GetObservers(),
+                              GattCharacteristicValueChanged(
+                                  adapter, location_ptr, location));
+            return location;
+          }));
+
+  heart_rate->AddMockCharacteristic(heart_rate_measurement.Pass());
+  heart_rate->AddMockCharacteristic(body_sensor_location.Pass());
+
+  return heart_rate;
+}
+
 // Characteristics
 
 // static
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
index d6204f24..6ffaa632 100644
--- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
+++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.h
@@ -18,9 +18,10 @@
 // Implements fake adapters with named mock data set for use in tests as a
 // result of layout tests calling testRunner.setBluetoothMockDataSet.
 
-// We have a complete “GenericAccessAdapter”, meaning it has a device which has
-// a Generic Access service with a Device Name characteristic with a descriptor.
-// The other adapters are named based on their particular non-expected behavior.
+// An adapter named 'FooAdapter' in
+// https://webbluetoothcg.github.io/web-bluetooth/tests/ is provided by a
+// corresponding 'GetFooAdapter' function, and re-documented here to capture
+// differences between our implementations.
 
 class LayoutTestBluetoothAdapterProvider {
  public:
@@ -166,38 +167,41 @@
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
   GetSecondDiscoveryFindsHeartRateAdapter();
 
-  // |MissingServiceGenericAccessAdapter|
+  // |MissingServiceHeartRateAdapter|
   // Inherits from |EmptyAdapter|
   // Internal Structure:
-  //   - Generic Access Device
-  //       - Generic Access UUID (0x1800)
+  //   - Heart Rate Device
+  //      - Advertised UUIDs:
+  //         - Heart Rate UUID (0x180d)
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-  GetMissingServiceGenericAccessAdapter();
+  GetMissingServiceHeartRateAdapter();
 
-  // |MissingCharacteristicGenericAccessAdapter|
+  // |MissingCharacteristicHeartRateAdapter|
   // Inherits from |EmptyAdapter|
+  // The services in this adapter do not contain any characteristics.
   // Internal Structure:
-  //   - Generic Access Device
-  //       - Generic Access UUID (0x1800)
-  //       - Generic Access Service
+  //   - Heart Rate Device
+  //      - Advertised UUIDs:
+  //         - Heart Rate UUID (0x180d)
+  //      - Services:
+  //         - Generic Access Service
+  //         - Heart Rate Service
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-  GetMissingCharacteristicGenericAccessAdapter();
+  GetMissingCharacteristicHeartRateAdapter();
 
-  // |GenericAccessAdapter|
+  // |HeartRateAdapter|
   // Inherits from |EmptyAdapter|
   // Internal Structure:
-  //  - Generic Access Device
-  //     - Generic Access UUID (0x1800)
-  //     - Generic Access Service
-  //        - Device Name Characteristic:
-  //          - Mock Functions:
-  //            - Read: Calls success callback with device's name.
-  //            - Write: Calls success callback.
-  //            - GetProperties: Returns
-  //                BluetoothGattCharacteristic::PROPERTY_READ |
-  //                BluetoothGattCharacteristic::PROPERTY_WRITE
+  //   - Heart Rate Device
+  //      - Advertised UUIDs:
+  //         - Heart Rate UUID (0x180d)
+  //      - Services:
+  //         - Generic Access Service - Characteristics as described in
+  //           GetGenericAccessService.
+  //         - Heart Rate Service - Characteristics as described in
+  //           GetHeartRateService.
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-  GetGenericAccessAdapter();
+  GetHeartRateAdapter();
 
   // |DelayedServicesDiscoveryAdapter|
   // Inherits from |EmptyAdapter|
@@ -211,34 +215,6 @@
   static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
   GetDelayedServicesDiscoveryAdapter();
 
-  // |HeartRateAdapter|
-  // Inherits from |EmptyAdapter|
-  // Internal Structure:
-  //   - Heart Rate Device
-  //      - Generic Access UUID (0x1800)
-  //      - Heart Rate UUID (0x180D)
-  //      - Heart Rate Service
-  //         - Body Sensor Location
-  //           - Mock Functions:
-  //              - Read: Calls GattCharacteristicValueChanged and success
-  //                      callback with [1] which corresponds to chest.
-  //              - GetProperties: Returns
-  //                  BluetoothGattCharacteristic::PROPERTY_READ
-  //         - Heart Rate Measurement Characteristic:
-  //            - Mock Functions:
-  //               - GetProperties: Returns
-  //                  BluetoothGattCharacteristic::PROPERTY_NOTIFY
-  //               - StartNotifySession: Sets a timer to call
-  //                 GattCharacteristicValueChanged every 10ms and calls success
-  //                 callback with a
-  //                 BaseGATTNotifySession(characteristic_instance_id)
-  //                 TODO: Instead of a timer we should be able to tell
-  //                 the fake adapter to call GattCharacteristicValueChanged
-  //                 from js.
-  //                 https://crbug.com/543884
-  static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
-  GetHeartRateAdapter();
-
   // |FailingConnectionsAdapter|
   // Inherits from |EmptyAdapter|
   // FailingConnectionsAdapter holds a device for each type of connection error
@@ -369,17 +345,6 @@
   static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
   GetGlucoseDevice(device::MockBluetoothAdapter* adapter);
 
-  // |HeartRateDevice|
-  // Inherits from |ConnectableDevice|(adapter, "Heart Rate Device", uuids,
-  //                            "00:00:00:00:00:03")
-  // Adv UUIDs added:
-  //   - Generic Access (0x1800)
-  //   - Heart Rate UUID (0x180D)
-  // Services added:
-  // None.
-  static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
-  GetHeartRateDevice(device::MockBluetoothAdapter* adapter);
-
   // |ConnectableDevice|
   // Inherits from |BaseDevice|(adapter, device_name)
   // Adv UUIDs added:
@@ -411,17 +376,15 @@
       device::BluetoothDevice::ConnectErrorCode error_code,
       const std::string& device_name = "Unconnectable Device");
 
-  // |GenericAccessDevice|
-  // Inherits from |ConnectableDevice|(adapter, device_name)
+  // |HeartRateDevice|
+  // Inherits from |ConnectableDevice|(adapter, "Heart Rate Device", uuids)
   // Adv UUIDs added:
-  //   - Generic Access UUID (0x1800)
+  //   - Heart Rate UUID (0x180D)
   // Services added:
-  // None. Each user of the GenericAccessDevice is in charge of adding the
-  // relevant services, characteristics, and descriptors.
+  // None. Each user of the HeartRateDevice is in charge of adding the
+  // relevant services, characteristics and descriptors.
   static scoped_ptr<testing::NiceMock<device::MockBluetoothDevice>>
-  GetGenericAccessDevice(
-      device::MockBluetoothAdapter* adapter,
-      const std::string& device_name = "Generic Access Device");
+  GetHeartRateDevice(device::MockBluetoothAdapter* adapter);
 
   // Services
 
@@ -448,6 +411,44 @@
   GetBaseGATTService(device::MockBluetoothDevice* device,
                      const std::string& uuid);
 
+  // |GenericAccessService|
+  // Internal Structure:
+  //  - Characteristics:
+  //     - Device Name:
+  //        - Mock Functions:
+  //           - Read: Calls success callback with device's name.
+  //           - Write: Calls success callback.
+  //           - GetProperties: Returns
+  //               BluetoothGattCharacteristic::PROPERTY_READ |
+  //               BluetoothGattCharacteristic::PROPERTY_WRITE
+  static scoped_ptr<testing::NiceMock<device::MockBluetoothGattService>>
+  GetGenericAccessService(device::MockBluetoothAdapter* adapter,
+                          device::MockBluetoothDevice* device);
+
+  // |HeartRateService|
+  // Internal Structure:
+  //  - Characteristics:
+  //     - Heart Rate Measurement (0x2a37)
+  //        - Mock Functions:
+  //           - StartNotifySession: Sets a timer to call
+  //               GattCharacteristicValueChanged every 10ms and calls
+  //               success callback with a
+  //               BaseGATTNotifySession(characteristic_instance_id)
+  //               TODO: Instead of a timer we should be able to tell the fake
+  //               to call GattCharacteristicValueChanged from js.
+  //               https://crbug.com/543884
+  //           - GetProperties: Returns
+  //               BluetoothGattCharacteristic::PROPERTY_NOTIFY
+  //     - Body Sensor Location (0x2a38)
+  //        - Mock Functions:
+  //           - Read: Calls GattCharacteristicValueChanged and success
+  //               callback with [1] which corresponds to chest.
+  //           - GetProperties: Returns
+  //               BluetoothGattCharacteristic::PROPERTY_READ
+  static scoped_ptr<testing::NiceMock<device::MockBluetoothGattService>>
+  GetHeartRateService(device::MockBluetoothAdapter* adapter,
+                      device::MockBluetoothDevice* device);
+
   // Characteristics
 
   // |BaseCharacteristic|(service, uuid)
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 394738e..8b0ca65 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -20,7 +20,6 @@
 #include "content/public/common/web_preferences.h"
 #include "content/public/test/test_mojo_app.h"
 #include "content/shell/browser/blink_test_controller.h"
-#include "content/shell/browser/ipc_echo_message_filter.h"
 #include "content/shell/browser/layout_test/layout_test_browser_main_parts.h"
 #include "content/shell/browser/layout_test/layout_test_resource_dispatcher_host_delegate.h"
 #include "content/shell/browser/shell.h"
@@ -147,13 +146,6 @@
   return shell_browser_main_parts_;
 }
 
-void ShellContentBrowserClient::RenderProcessWillLaunch(
-    RenderProcessHost* host) {
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kExposeIpcEcho))
-    host->AddFilter(new IPCEchoMessageFilter());
-}
-
 net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
     BrowserContext* content_browser_context,
     ProtocolHandlerMap* protocol_handlers,
@@ -238,10 +230,6 @@
     command_line->AppendSwitch(switches::kExposeInternalsForTesting);
   }
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kExposeIpcEcho)) {
-    command_line->AppendSwitch(switches::kExposeIpcEcho);
-  }
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kStableReleaseMode)) {
     command_line->AppendSwitch(switches::kStableReleaseMode);
   }
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
index 5841d90..d10ca3a 100644
--- a/content/shell/browser/shell_content_browser_client.h
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -32,7 +32,6 @@
   // ContentBrowserClient overrides.
   BrowserMainParts* CreateBrowserMainParts(
       const MainFunctionParams& parameters) override;
-  void RenderProcessWillLaunch(RenderProcessHost* host) override;
   net::URLRequestContextGetter* CreateRequestContext(
       BrowserContext* browser_context,
       ProtocolHandlerMap* protocol_handlers,
diff --git a/content/shell/common/shell_messages.h b/content/shell/common/shell_messages.h
index 9baf871..536a8396 100644
--- a/content/shell/common/shell_messages.h
+++ b/content/shell/common/shell_messages.h
@@ -94,14 +94,6 @@
 IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CaptureSessionHistory)
 IPC_MESSAGE_ROUTED0(ShellViewHostMsg_CloseRemainingWindows)
 
-IPC_MESSAGE_CONTROL3(ShellViewHostMsg_EchoPing,
-                     int /* routing_id */,
-                     int /* id */,
-                     std::string /* body */)
-IPC_MESSAGE_ROUTED2(ShellViewMsg_EchoPong,
-                    int /* id */,
-                    std::string /* body */)
-
 IPC_STRUCT_TRAITS_BEGIN(content::LeakDetectionResult)
 IPC_STRUCT_TRAITS_MEMBER(leaked)
 IPC_STRUCT_TRAITS_MEMBER(detail)
diff --git a/content/shell/common/shell_switches.cc b/content/shell/common/shell_switches.cc
index df7d3fe..ab5ad9ab 100644
--- a/content/shell/common/shell_switches.cc
+++ b/content/shell/common/shell_switches.cc
@@ -32,9 +32,6 @@
 // each LayoutBlockFlow to be dumped as well.
 const char kDumpLineBoxTrees[] = "dump-line-box-trees";
 
-// Expose window.ipcTester object for testing
-const char kExposeIpcEcho[] = "expose-ipc-echo";
-
 // Enable accelerated 2D canvas.
 const char kEnableAccelerated2DCanvas[] = "enable-accelerated-2d-canvas";
 
diff --git a/content/shell/common/shell_switches.h b/content/shell/common/shell_switches.h
index 129924c..bc24fab 100644
--- a/content/shell/common/shell_switches.h
+++ b/content/shell/common/shell_switches.h
@@ -19,7 +19,6 @@
 extern const char kCrashDumpsDir[];
 extern const char kCrashOnFailure[];
 extern const char kDumpLineBoxTrees[];
-extern const char kExposeIpcEcho[];
 extern const char kEnableAccelerated2DCanvas[];
 extern const char kEnableFontAntialiasing[];
 extern const char kAlwaysUseComplexText[];
diff --git a/content/shell/renderer/ipc_echo.cc b/content/shell/renderer/ipc_echo.cc
deleted file mode 100644
index 12f049b3..0000000
--- a/content/shell/renderer/ipc_echo.cc
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2014 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 "content/shell/renderer/ipc_echo.h"
-
-#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "content/shell/common/shell_messages.h"
-#include "gin/handle.h"
-#include "gin/object_template_builder.h"
-#include "gin/wrappable.h"
-#include "ipc/ipc_sender.h"
-#include "third_party/WebKit/public/web/WebDOMCustomEvent.h"
-#include "third_party/WebKit/public/web/WebDOMEvent.h"
-#include "third_party/WebKit/public/web/WebFrame.h"
-#include "third_party/WebKit/public/web/WebKit.h"
-#include "third_party/WebKit/public/web/WebSerializedScriptValue.h"
-
-namespace content {
-
-class IPCEchoBindings : public gin::Wrappable<IPCEchoBindings> {
-public:
-  static gin::WrapperInfo kWrapperInfo;
-  static void Install(base::WeakPtr<IPCEcho> echo, blink::WebFrame* frame);
-
-  explicit IPCEchoBindings(base::WeakPtr<IPCEcho>);
-
-  void RequestEcho(int id, int size);
-  int GetLastEchoId() const;
-  int GetLastEchoSize() const;
-
-private:
- gin::ObjectTemplateBuilder GetObjectTemplateBuilder(v8::Isolate*) override;
-
-  base::WeakPtr<IPCEcho> native_;
-};
-
-IPCEchoBindings::IPCEchoBindings(base::WeakPtr<IPCEcho> native)
-    : native_(native) {
-}
-
-void IPCEchoBindings::RequestEcho(int id, int size) {
-  if (!native_)
-    return;
-  native_->RequestEcho(id, size);
-}
-
-int IPCEchoBindings::GetLastEchoId() const {
-  if (!native_)
-    return 0;
-  return native_->last_echo_id();
-}
-
-int IPCEchoBindings::GetLastEchoSize() const {
-  if (!native_)
-    return 0;
-  return native_->last_echo_size();
-}
-
-gin::WrapperInfo IPCEchoBindings::kWrapperInfo = {
-    gin::kEmbedderNativeGin };
-
-gin::ObjectTemplateBuilder IPCEchoBindings::GetObjectTemplateBuilder(
-    v8::Isolate* isolate) {
-  return gin::Wrappable<IPCEchoBindings>::GetObjectTemplateBuilder(isolate)
-      .SetMethod("requestEcho",
-                 &IPCEchoBindings::RequestEcho)
-      .SetProperty("lastEchoId",
-                   &IPCEchoBindings::GetLastEchoId)
-      .SetProperty("lastEchoSize",
-                   &IPCEchoBindings::GetLastEchoSize);
-}
-
-// static
-void IPCEchoBindings::Install(base::WeakPtr<IPCEcho> echo,
-                              blink::WebFrame* frame) {
-  v8::Isolate* isolate = blink::mainThreadIsolate();
-  v8::HandleScope handle_scope(isolate);
-  v8::Local<v8::Context> context = frame->mainWorldScriptContext();
-  if (context.IsEmpty())
-    return;
-
-  v8::Context::Scope context_scope(context);
-
-  IPCEchoBindings* wrapped = new IPCEchoBindings(echo);
-  gin::Handle<IPCEchoBindings> bindings = gin::CreateHandle(isolate, wrapped);
-  if (bindings.IsEmpty())
-    return;
-  v8::Local<v8::Object> global = context->Global();
-  v8::Local<v8::Value> v8_bindings = bindings.ToV8();
-  global->Set(gin::StringToV8(isolate, "ipcEcho"), v8_bindings);
-}
-
-IPCEcho::IPCEcho(blink::WebDocument document,
-                 IPC::Sender* sender,
-                 int routing_id)
-    : document_(document), sender_(sender), routing_id_(routing_id),
-      last_echo_id_(0),
-      weak_factory_(this) {
-}
-
-IPCEcho::~IPCEcho() {
-}
-
-void IPCEcho::RequestEcho(int id, int size) {
-  sender_->Send(new ShellViewHostMsg_EchoPing(
-      routing_id_, id, std::string(size, '*')));
-}
-
-void IPCEcho::DidRespondEcho(int id, int size) {
-  last_echo_id_ = id;
-  last_echo_size_ = size;
-  document_.dispatchEvent(blink::WebDOMCustomEvent("pong"));
-}
-
-void IPCEcho::Install(blink::WebFrame* frame) {
-  IPCEchoBindings::Install(weak_factory_.GetWeakPtr(), frame);
-}
-
-}  // namespace content
diff --git a/content/shell/renderer/ipc_echo.h b/content/shell/renderer/ipc_echo.h
deleted file mode 100644
index ab4c21e0..0000000
--- a/content/shell/renderer/ipc_echo.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2014 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.
-
-#ifndef CONTENT_SHELL_RENDERER_IPC_ECHO_H_
-#define CONTENT_SHELL_RENDERER_IPC_ECHO_H_
-
-#include <utility>
-#include <vector>
-#include "base/compiler_specific.h"
-#include "base/memory/weak_ptr.h"
-#include "third_party/WebKit/public/web/WebDocument.h"
-
-namespace blink {
-class WebFrame;
-}
-
-namespace IPC {
-class Sender;
-}
-
-namespace content {
-
-// This class is for writing micro benchmarks exercising underlying
-// IPC::Channel using HTML and JavaScript.
-//
-// TODO(morrita): The benchmark effort tries to makesure that
-// IPC::ChannelMojo is as performant as native IPC::Channel
-// implementations. Currently IPC::ChannelMojo is hidden behind
-// "--enable-renderer-mojo-channel". Once it is turned on by default.
-// we no longer need this class and should remove it.
-class IPCEcho : public base::SupportsWeakPtr<IPCEcho> {
- public:
-  IPCEcho(blink::WebDocument document, IPC::Sender* sender, int routing_id);
-  ~IPCEcho();
-
-  void RequestEcho(int id, int size);
-  void DidRespondEcho(int id, int size);
-  void Install(blink::WebFrame*);
-
-  int last_echo_id() const { return last_echo_id_; }
-  int last_echo_size() const { return last_echo_size_; }
-
-  blink::WebDocument document_;
-  IPC::Sender* sender_;
-  int routing_id_;
-  int last_echo_id_;
-  int last_echo_size_;
-
-  base::WeakPtrFactory<IPCEcho> weak_factory_;
-
-};
-
-}  // namespace content
-
-#endif  // CONTENT_SHELL_RENDERER_IPC_ECHO_H_
diff --git a/content/shell/renderer/shell_render_view_observer.cc b/content/shell/renderer/shell_render_view_observer.cc
index 9dd4309..c24c121 100644
--- a/content/shell/renderer/shell_render_view_observer.cc
+++ b/content/shell/renderer/shell_render_view_observer.cc
@@ -5,12 +5,9 @@
 #include "content/shell/renderer/shell_render_view_observer.h"
 
 #include "base/command_line.h"
-#include "content/public/renderer/render_thread.h"
 #include "content/public/renderer/render_view.h"
 #include "content/public/renderer/render_view_observer.h"
-#include "content/shell/common/shell_messages.h"
 #include "content/shell/common/shell_switches.h"
-#include "content/shell/renderer/ipc_echo.h"
 #include "third_party/WebKit/public/web/WebTestingSupport.h"
 #include "third_party/WebKit/public/web/WebView.h"
 
@@ -29,29 +26,6 @@
           switches::kExposeInternalsForTesting)) {
     blink::WebTestingSupport::injectInternalsObject(frame);
   }
-
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kExposeIpcEcho)) {
-    RenderView* view = render_view();
-    if (!ipc_echo_)
-      ipc_echo_.reset(new IPCEcho(view->GetWebView()->mainFrame()->document(),
-                                  RenderThread::Get(), view->GetRoutingID()));
-    ipc_echo_->Install(view->GetWebView()->mainFrame());
-  }
-}
-
-bool ShellRenderViewObserver::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(ShellRenderViewObserver, message)
-    IPC_MESSAGE_HANDLER(ShellViewMsg_EchoPong, OnEchoPong)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-
-  return handled;
-}
-
-void ShellRenderViewObserver::OnEchoPong(int id, const std::string& body) {
-  ipc_echo_->DidRespondEcho(id, body.size());
 }
 
 }  // namespace content
diff --git a/content/shell/renderer/shell_render_view_observer.h b/content/shell/renderer/shell_render_view_observer.h
index e10a982..2bf2330 100644
--- a/content/shell/renderer/shell_render_view_observer.h
+++ b/content/shell/renderer/shell_render_view_observer.h
@@ -5,17 +5,14 @@
 #ifndef CONTENT_SHELL_RENDERER_SHELL_RENDER_VIEW_OBSERVER_H_
 #define CONTENT_SHELL_RENDERER_SHELL_RENDER_VIEW_OBSERVER_H_
 
-#include <string>
-#include "base/memory/scoped_ptr.h"
 #include "content/public/renderer/render_view_observer.h"
 
 namespace blink {
-class WebFrame;
+class WebLocalFrame;
 }
 
 namespace content {
 
-class IPCEcho;
 class RenderView;
 
 
@@ -25,14 +22,9 @@
   ~ShellRenderViewObserver() override;
 
  private:
-  // Message handlers.
-  void OnEchoPong(int id, const std::string& body);
-
   // RenderViewObserver implementation.
-  bool OnMessageReceived(const IPC::Message& message) override;
   void DidClearWindowObject(blink::WebLocalFrame* frame) override;
 
-  scoped_ptr<IPCEcho> ipc_echo_;
   DISALLOW_COPY_AND_ASSIGN(ShellRenderViewObserver);
 };
 
diff --git a/content/test/test_render_frame_host.cc b/content/test/test_render_frame_host.cc
index 457a1fdb..687bae5 100644
--- a/content/test/test_render_frame_host.cc
+++ b/content/test/test_render_frame_host.cc
@@ -99,7 +99,7 @@
   }
 
   OnDidStartLoading(true);
-  OnDidStartProvisionalLoadForFrame(url);
+  OnDidStartProvisionalLoad(url, base::TimeTicks::Now());
 }
 
 void TestRenderFrameHost::SimulateRedirect(const GURL& new_url) {
@@ -179,7 +179,7 @@
 void TestRenderFrameHost::SimulateNavigationErrorPageCommit() {
   CHECK(navigation_handle());
   GURL error_url = GURL(kUnreachableWebDataURL);
-  OnDidStartProvisionalLoadForFrame(error_url);
+  OnDidStartProvisionalLoad(error_url, base::TimeTicks::Now());
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   params.page_id = ComputeNextPageID();
   params.nav_entry_id = 0;
@@ -268,7 +268,7 @@
   // so we keep a copy of it to use below.
   GURL url_copy(url);
   OnDidStartLoading(true);
-  OnDidStartProvisionalLoadForFrame(url_copy);
+  OnDidStartProvisionalLoad(url_copy, base::TimeTicks::Now());
 
   FrameHostMsg_DidCommitProvisionalLoad_Params params;
   params.page_id = page_id;
diff --git a/extensions/browser/PRESUBMIT.py b/extensions/browser/PRESUBMIT.py
index bc31dcf3..15f8d93 100644
--- a/extensions/browser/PRESUBMIT.py
+++ b/extensions/browser/PRESUBMIT.py
@@ -41,6 +41,3 @@
   results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
   return results
 
-
-def CheckChangeOnCommit(input_api, output_api):
-  return _RunHistogramValueCheckers(input_api, output_api)
diff --git a/extensions/browser/api/device_permissions_prompt.cc b/extensions/browser/api/device_permissions_prompt.cc
index a72ebd3..8a691ba 100644
--- a/extensions/browser/api/device_permissions_prompt.cc
+++ b/extensions/browser/api/device_permissions_prompt.cc
@@ -105,10 +105,10 @@
     DevicePermissionsManager* permissions_manager =
         DevicePermissionsManager::Get(browser_context());
     std::vector<scoped_refptr<UsbDevice>> devices;
-    for (const DeviceInfo* device : devices_) {
+    for (const auto& device : devices_) {
       if (device->granted()) {
         const UsbDeviceInfo* usb_device =
-            static_cast<const UsbDeviceInfo*>(device);
+            static_cast<const UsbDeviceInfo*>(device.get());
         devices.push_back(usb_device->device());
         if (permissions_manager) {
           permissions_manager->AllowUsbDevice(extension()->id(),
@@ -135,7 +135,8 @@
 
   void OnDeviceRemoved(scoped_refptr<UsbDevice> device) override {
     for (auto it = devices_.begin(); it != devices_.end(); ++it) {
-      const UsbDeviceInfo* entry = static_cast<const UsbDeviceInfo*>(*it);
+      const UsbDeviceInfo* entry =
+          static_cast<const UsbDeviceInfo*>((*it).get());
       if (entry->device() == device) {
         devices_.erase(it);
         if (observer()) {
@@ -219,10 +220,10 @@
     DevicePermissionsManager* permissions_manager =
         DevicePermissionsManager::Get(browser_context());
     std::vector<scoped_refptr<device::HidDeviceInfo>> devices;
-    for (const DeviceInfo* device : devices_) {
+    for (const auto& device : devices_) {
       if (device->granted()) {
         const HidDeviceInfo* hid_device =
-            static_cast<const HidDeviceInfo*>(device);
+            static_cast<const HidDeviceInfo*>(device.get());
         devices.push_back(hid_device->device());
         if (permissions_manager) {
           permissions_manager->AllowHidDevice(extension()->id(),
@@ -258,7 +259,8 @@
 
   void OnDeviceRemoved(scoped_refptr<device::HidDeviceInfo> device) override {
     for (auto it = devices_.begin(); it != devices_.end(); ++it) {
-      const HidDeviceInfo* entry = static_cast<const HidDeviceInfo*>(*it);
+      const HidDeviceInfo* entry =
+          static_cast<const HidDeviceInfo*>((*it).get());
       if (entry->device() == device) {
         devices_.erase(it);
         if (observer()) {
diff --git a/extensions/browser/api/device_permissions_prompt.h b/extensions/browser/api/device_permissions_prompt.h
index 38f5d48..2ff9a80 100644
--- a/extensions/browser/api/device_permissions_prompt.h
+++ b/extensions/browser/api/device_permissions_prompt.h
@@ -10,7 +10,7 @@
 #include "base/callback_forward.h"
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 
 namespace content {
@@ -106,7 +106,7 @@
 
     // Subclasses may fill this with a particular subclass of DeviceInfo and may
     // assume that only that instances of that type are stored here.
-    ScopedVector<DeviceInfo> devices_;
+    std::vector<scoped_ptr<DeviceInfo>> devices_;
 
    private:
     friend class base::RefCounted<Prompt>;
diff --git a/extensions/browser/api/guest_view/extension_view/extension_view_internal_api.cc b/extensions/browser/api/guest_view/extension_view/extension_view_internal_api.cc
index 2b4e207..425e01b 100644
--- a/extensions/browser/api/guest_view/extension_view/extension_view_internal_api.cc
+++ b/extensions/browser/api/guest_view/extension_view/extension_view_internal_api.cc
@@ -12,6 +12,7 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/stop_find_action.h"
+#include "extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.h"
 #include "extensions/common/api/extension_view_internal.h"
 #include "extensions/common/constants.h"
 
@@ -34,17 +35,14 @@
 // Returns true if |src| is valid.
 bool IsSrcValid(GURL src) {
   // Check if src is valid and matches the extension scheme.
-  if (!src.is_valid() || !src.SchemeIs(kExtensionScheme)) {
-    VLOG(0) << "src not valid or match extension scheme";
+  if (!src.is_valid() || !src.SchemeIs(kExtensionScheme))
     return false;
-  }
 
   // Get the extension id and check if it is valid.
   std::string extension_id = src.host();
-  if (!crx_file::id_util::IdIsValid(extension_id)) {
-    VLOG(0) << "extension id not valid: " << extension_id;
+  if (!crx_file::id_util::IdIsValid(extension_id) ||
+      !IsExtensionIdWhitelisted(extension_id))
     return false;
-  }
 
   return true;
 }
diff --git a/extensions/browser/api/hid/hid_device_manager.cc b/extensions/browser/api/hid/hid_device_manager.cc
index 560ce673..955b2a1 100644
--- a/extensions/browser/api/hid/hid_device_manager.cc
+++ b/extensions/browser/api/hid/hid_device_manager.cc
@@ -124,7 +124,7 @@
         FROM_HERE, base::Bind(callback, base::Passed(&devices)));
   } else {
     pending_enumerations_.push_back(
-        new GetApiDevicesParams(extension, filters, callback));
+        make_scoped_ptr(new GetApiDevicesParams(extension, filters, callback)));
   }
 }
 
@@ -312,7 +312,7 @@
   }
   enumeration_ready_ = true;
 
-  for (const GetApiDevicesParams* params : pending_enumerations_) {
+  for (const auto& params : pending_enumerations_) {
     scoped_ptr<base::ListValue> devices =
         CreateApiDeviceList(params->extension, params->filters);
     params->callback.Run(devices.Pass());
diff --git a/extensions/browser/api/hid/hid_device_manager.h b/extensions/browser/api/hid/hid_device_manager.h
index 8479901..f9ecf4c 100644
--- a/extensions/browser/api/hid/hid_device_manager.h
+++ b/extensions/browser/api/hid/hid_device_manager.h
@@ -6,11 +6,11 @@
 #define EXTENSIONS_BROWSER_API_HID_HID_DEVICE_MANAGER_H_
 
 #include <map>
+#include <vector>
 
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/scoped_observer.h"
 #include "base/threading/thread_checker.h"
 #include "device/hid/hid_service.h"
@@ -119,7 +119,7 @@
   ScopedObserver<device::HidService, device::HidService::Observer>
       hid_service_observer_;
   bool enumeration_ready_ = false;
-  ScopedVector<GetApiDevicesParams> pending_enumerations_;
+  std::vector<scoped_ptr<GetApiDevicesParams>> pending_enumerations_;
   int next_resource_id_ = 0;
   ResourceIdToDeviceIdMap device_ids_;
   DeviceIdToResourceIdMap resource_ids_;
diff --git a/extensions/browser/guest_view/extension_view/extension_view_guest.cc b/extensions/browser/guest_view/extension_view/extension_view_guest.cc
index e000d6e..0a341ff 100644
--- a/extensions/browser/guest_view/extension_view/extension_view_guest.cc
+++ b/extensions/browser/guest_view/extension_view/extension_view_guest.cc
@@ -11,6 +11,7 @@
 #include "extensions/browser/api/extensions_api_client.h"
 #include "extensions/browser/bad_message.h"
 #include "extensions/browser/guest_view/extension_view/extension_view_constants.h"
+#include "extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.h"
 #include "extensions/common/constants.h"
 #include "extensions/common/extension_messages.h"
 #include "extensions/strings/grit/extensions_strings.h"
@@ -71,7 +72,8 @@
   std::string extension_id;
   create_params.GetString(extensionview::kAttributeExtension, &extension_id);
 
-  if (!crx_file::id_util::IdIsValid(extension_id)) {
+  if (!crx_file::id_util::IdIsValid(extension_id) ||
+      !IsExtensionIdWhitelisted(extension_id)) {
     callback.Run(nullptr);
     return;
   }
diff --git a/extensions/browser/guest_view/extension_view/whitelist/OWNERS b/extensions/browser/guest_view/extension_view/whitelist/OWNERS
new file mode 100644
index 0000000..4b00898
--- /dev/null
+++ b/extensions/browser/guest_view/extension_view/whitelist/OWNERS
@@ -0,0 +1,11 @@
+# Whitelisting new extension ids for ExtensionView use requires approval from
+# chrome-eng-review@google.com.
+set noparent
+
+ben@chromium.org
+brettw@chromium.org
+cpu@chromium.org
+darin@chromium.org
+dglazkov@chromium.org
+jam@chromium.org
+jochen@chromium.org
\ No newline at end of file
diff --git a/extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.cc b/extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.cc
new file mode 100644
index 0000000..ed62427
--- /dev/null
+++ b/extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.cc
@@ -0,0 +1,42 @@
+// Copyright 2015 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 "extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+
+namespace extensions {
+
+namespace {
+
+// =============================================================================
+//
+// ADDING NEW EXTENSIONS REQUIRES APPROVAL from chrome-eng-review@google.com
+//
+// =============================================================================
+
+const char* const kWhitelist[] = {
+    "pemeknaakobkocgmimdeamlcklioagkh",  // Used in browser tests
+    "dppcjffonoklmpdmljnpdojmoaefcabf",  // Used in browser tests
+    "fjhoaacokmgbjemoflkofnenfaiekifl",  // http://crbug.com/552208
+    "ekpaaapppgpmolpcldedioblbkmijaca",  // http://crbug.com/552208
+    "lhkfccafpkdlaodkicmokbmfapjadkij",  // http://crbug.com/552208
+    "ibiljbkambkbohapfhoonkcpcikdglop",  // http://crbug.com/552208
+    "enhhojjnijigcajfphajepfemndkmdlo",  // http://crbug.com/552208
+};
+
+}  // namespace
+
+// static
+bool IsExtensionIdWhitelisted(const std::string& extension_id) {
+  for (size_t i = 0; i < arraysize(kWhitelist); ++i) {
+    if (extension_id == kWhitelist[i])
+      return true;
+  }
+
+  return false;
+}
+
+}  // namespace extensions
diff --git a/extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.h b/extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.h
new file mode 100644
index 0000000..512600b
--- /dev/null
+++ b/extensions/browser/guest_view/extension_view/whitelist/extension_view_whitelist.h
@@ -0,0 +1,17 @@
+// Copyright 2015 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.
+
+#ifndef EXTENSIONS_BROWSER_GUEST_VIEW_EXTENSION_VIEW_WHITELIST_EXTENSION_VIEW_WHITELIST_H_
+#define EXTENSIONS_BROWSER_GUEST_VIEW_EXTENSION_VIEW_WHITELIST_EXTENSION_VIEW_WHITELIST_H_
+
+#include <string>
+
+namespace extensions {
+
+// Checks whether |extension_id| is whitelisted to be used by ExtensionView.
+bool IsExtensionIdWhitelisted(const std::string& extension_id);
+
+}  // namespace extensions
+
+#endif  // EXTENSIONS_BROWSER_GUEST_VIEW_EXTENSION_VIEW_WHITELIST_EXTENSION_VIEW_WHITELIST_H_
diff --git a/extensions/browser/load_monitoring_extension_host_queue_unittest.cc b/extensions/browser/load_monitoring_extension_host_queue_unittest.cc
index cd080b79..f403aca 100644
--- a/extensions/browser/load_monitoring_extension_host_queue_unittest.cc
+++ b/extensions/browser/load_monitoring_extension_host_queue_unittest.cc
@@ -3,9 +3,9 @@
 // found in the LICENSE file.
 
 #include <limits>
+#include <vector>
 
 #include "base/bind.h"
-#include "base/memory/scoped_vector.h"
 #include "base/run_loop.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/browser/deferred_start_render_host.h"
@@ -66,9 +66,8 @@
   // Creates a new DeferredStartRenderHost. Ownership is held by this class,
   // not passed to caller.
   StubDeferredStartRenderHost* CreateHost() {
-    StubDeferredStartRenderHost* stub = new StubDeferredStartRenderHost();
-    stubs_.push_back(stub);
-    return stub;
+    stubs_.push_back(make_scoped_ptr(new StubDeferredStartRenderHost()));
+    return stubs_.back().get();
   }
 
   // Our single LoadMonitoringExtensionHostQueue instance.
@@ -100,7 +99,7 @@
 
   content::TestBrowserThreadBundle thread_bundle_;
   scoped_ptr<LoadMonitoringExtensionHostQueue> queue_;
-  ScopedVector<StubDeferredStartRenderHost> stubs_;
+  std::vector<scoped_ptr<StubDeferredStartRenderHost>> stubs_;
 
   // Set after the queue has finished monitoring.
   bool finished_;
diff --git a/extensions/browser/mojo/stash_backend.cc b/extensions/browser/mojo/stash_backend.cc
index 74f4bfc..381142d 100644
--- a/extensions/browser/mojo/stash_backend.cc
+++ b/extensions/browser/mojo/stash_backend.cc
@@ -4,6 +4,8 @@
 
 #include "extensions/browser/mojo/stash_backend.h"
 
+#include <vector>
+
 #include "base/bind.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "mojo/public/cpp/environment/async_waiter.h"
@@ -79,7 +81,7 @@
   void OnHandleReady(MojoResult result);
 
   // The waiters that are waiting for handles to be readable.
-  ScopedVector<mojo::AsyncWaiter> waiters_;
+  std::vector<scoped_ptr<mojo::AsyncWaiter>> waiters_;
 
   StashedObjectPtr stashed_object_;
 
@@ -99,11 +101,11 @@
 
 void StashBackend::AddToStash(mojo::Array<StashedObjectPtr> stashed_objects) {
   for (size_t i = 0; i < stashed_objects.size(); i++) {
-    stashed_objects_.push_back(
-        new StashEntry(stashed_objects[i].Pass(),
-                       has_notified_ ? base::Closure()
-                                     : base::Bind(&StashBackend::OnHandleReady,
-                                                  weak_factory_.GetWeakPtr())));
+    stashed_objects_.push_back(make_scoped_ptr(new StashEntry(
+        stashed_objects[i].Pass(),
+        has_notified_ ? base::Closure()
+                      : base::Bind(&StashBackend::OnHandleReady,
+                                   weak_factory_.GetWeakPtr()))));
   }
 }
 
@@ -139,10 +141,10 @@
     return;
 
   for (size_t i = 0; i < stashed_object_->stashed_handles.size(); i++) {
-    waiters_.push_back(new mojo::AsyncWaiter(
+    waiters_.push_back(make_scoped_ptr(new mojo::AsyncWaiter(
         stashed_object_->stashed_handles[i].get(), MOJO_HANDLE_SIGNAL_READABLE,
         base::Bind(&StashBackend::StashEntry::OnHandleReady,
-                   base::Unretained(this))));
+                   base::Unretained(this)))));
   }
 }
 
diff --git a/extensions/browser/mojo/stash_backend.h b/extensions/browser/mojo/stash_backend.h
index 27f17a6..e9fdf26 100644
--- a/extensions/browser/mojo/stash_backend.h
+++ b/extensions/browser/mojo/stash_backend.h
@@ -5,8 +5,9 @@
 #ifndef EXTENSIONS_BROWSER_MOJO_STASH_BACKEND_H_
 #define EXTENSIONS_BROWSER_MOJO_STASH_BACKEND_H_
 
+#include <vector>
+
 #include "base/callback.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "extensions/common/mojo/stash.mojom.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
@@ -37,7 +38,7 @@
   void OnHandleReady();
 
   // The objects that have been stashed.
-  ScopedVector<StashEntry> stashed_objects_;
+  std::vector<scoped_ptr<StashEntry>> stashed_objects_;
 
   // The callback to call when a handle is readable.
   const base::Closure on_handle_readable_;
diff --git a/extensions/browser/updater/update_service_unittest.cc b/extensions/browser/updater/update_service_unittest.cc
index f570303..fe2aefe 100644
--- a/extensions/browser/updater/update_service_unittest.cc
+++ b/extensions/browser/updater/update_service_unittest.cc
@@ -46,6 +46,7 @@
     return false;
   }
   bool IsUpdating(const std::string& id) const override { return false; }
+  void Stop() override {}
 
  protected:
   friend class base::RefCounted<FakeUpdateClient>;
diff --git a/extensions/browser/web_ui_user_script_loader.cc b/extensions/browser/web_ui_user_script_loader.cc
index c1519c8..a3194c5d 100644
--- a/extensions/browser/web_ui_user_script_loader.cc
+++ b/extensions/browser/web_ui_user_script_loader.cc
@@ -98,7 +98,7 @@
     OnWebUIURLFetchComplete();
     return;
   }
-  for (auto fetcher : fetchers_)
+  for (const auto& fetcher : fetchers_)
     fetcher->Start();
 }
 
diff --git a/extensions/browser/web_ui_user_script_loader.h b/extensions/browser/web_ui_user_script_loader.h
index f74ef00..1a042b6 100644
--- a/extensions/browser/web_ui_user_script_loader.h
+++ b/extensions/browser/web_ui_user_script_loader.h
@@ -5,9 +5,10 @@
 #ifndef EXTENSIONS_BROWSER_WEB_UI_USER_SCRIPT_LOADER_H_
 #define EXTENSIONS_BROWSER_WEB_UI_USER_SCRIPT_LOADER_H_
 
+#include <vector>
+
 #include "base/callback.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "extensions/browser/user_script_loader.h"
 
 class WebUIURLFetcher;
@@ -64,7 +65,7 @@
 
   LoadScriptsCallback scripts_loaded_callback_;
 
-  ScopedVector<WebUIURLFetcher> fetchers_;
+  std::vector<scoped_ptr<WebUIURLFetcher>> fetchers_;
 
   DISALLOW_COPY_AND_ASSIGN(WebUIUserScriptLoader);
 };
diff --git a/extensions/common/features/complex_feature.h b/extensions/common/features/complex_feature.h
index 27628052..663b1e77 100644
--- a/extensions/common/features/complex_feature.h
+++ b/extensions/common/features/complex_feature.h
@@ -7,8 +7,9 @@
 
 #include <set>
 #include <string>
+#include <vector>
 
-#include "base/memory/scoped_vector.h"
+#include "base/memory/scoped_ptr.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/features/feature.h"
 #include "extensions/common/manifest.h"
@@ -20,7 +21,7 @@
 // available, but not if only some combination of Features is available.
 class ComplexFeature : public Feature {
  public:
-  typedef ScopedVector<Feature> FeatureList;
+  using FeatureList = std::vector<scoped_ptr<Feature>>;
 
   explicit ComplexFeature(scoped_ptr<FeatureList> features);
   ~ComplexFeature() override;
diff --git a/extensions/common/features/simple_feature.h b/extensions/common/features/simple_feature.h
index 5ec95cf..f69e658 100644
--- a/extensions/common/features/simple_feature.h
+++ b/extensions/common/features/simple_feature.h
@@ -13,7 +13,6 @@
 #include "base/gtest_prod_util.h"
 #include "base/lazy_instance.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/values.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/features/feature.h"
@@ -203,7 +202,7 @@
   bool component_extensions_auto_granted_;
   std::string command_line_switch_;
 
-  ScopedVector<SimpleFeatureFilter> filters_;;
+  std::vector<scoped_ptr<SimpleFeatureFilter>> filters_;
 
   DISALLOW_COPY_AND_ASSIGN(SimpleFeature);
 };
diff --git a/extensions/common/manifest_handlers/webview_info.cc b/extensions/common/manifest_handlers/webview_info.cc
index 9adbcbe3..12bafcc 100644
--- a/extensions/common/manifest_handlers/webview_info.cc
+++ b/extensions/common/manifest_handlers/webview_info.cc
@@ -71,7 +71,7 @@
   if (!webview_info)
     return false;
 
-  for (const PartitionItem* item : webview_info->partition_items_) {
+  for (const auto& item : webview_info->partition_items_) {
     if (item->Matches(partition_id) &&
         extension->ResourceMatches(item->accessible_resources(),
                                    relative_path)) {
@@ -83,7 +83,7 @@
 }
 
 void WebviewInfo::AddPartitionItem(scoped_ptr<PartitionItem> item) {
-  partition_items_.push_back(item.release());
+  partition_items_.push_back(item.Pass());
 }
 
 WebviewHandler::WebviewHandler() {
diff --git a/extensions/common/manifest_handlers/webview_info.h b/extensions/common/manifest_handlers/webview_info.h
index ca186a8..887394d 100644
--- a/extensions/common/manifest_handlers/webview_info.h
+++ b/extensions/common/manifest_handlers/webview_info.h
@@ -6,8 +6,10 @@
 #define EXTENSIONS_COMMON_MANIFEST_HANDLERS_WEBVIEW_INFO_H_
 
 #include <string>
+#include <vector>
 
-#include "base/memory/scoped_vector.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 #include "extensions/common/extension.h"
 #include "extensions/common/manifest_handler.h"
 
@@ -34,7 +36,9 @@
 
  private:
   std::string extension_id_;
-  ScopedVector<PartitionItem> partition_items_;
+  std::vector<scoped_ptr<PartitionItem>> partition_items_;
+
+  DISALLOW_COPY_AND_ASSIGN(WebviewInfo);
 };
 
 // Parses the "webview" manifest key.
diff --git a/extensions/common/permissions/PRESUBMIT.py b/extensions/common/permissions/PRESUBMIT.py
index 421841c3..1a070500 100644
--- a/extensions/common/permissions/PRESUBMIT.py
+++ b/extensions/common/permissions/PRESUBMIT.py
@@ -30,6 +30,3 @@
 def CheckChangeOnUpload(input_api, output_api):
   return _CreateAPIPermissionIDChecker(input_api, output_api).Run()
 
-def CheckChangeOnCommit(input_api, output_api):
-  return _CreateAPIPermissionIDChecker(input_api, output_api).Run()
-
diff --git a/extensions/common/value_counter.cc b/extensions/common/value_counter.cc
index 0266b9ac..3a5e662 100644
--- a/extensions/common/value_counter.cc
+++ b/extensions/common/value_counter.cc
@@ -25,19 +25,18 @@
 }
 
 bool ValueCounter::Add(const base::Value& value) {
-  for (Entry* entry : entries_) {
+  for (const auto& entry : entries_) {
     if (entry->value->Equals(&value)) {
       ++entry->count;
       return false;
     }
   }
-  entries_.push_back(new Entry(value.CreateDeepCopy()));
+  entries_.push_back(make_scoped_ptr(new Entry(value.CreateDeepCopy())));
   return true;
 }
 
 bool ValueCounter::Remove(const base::Value& value) {
-  for (ScopedVector<Entry>::iterator it = entries_.begin();
-       it != entries_.end(); ++it) {
+  for (auto it = entries_.begin(); it != entries_.end(); ++it) {
     if ((*it)->value->Equals(&value)) {
       if (--(*it)->count == 0) {
         std::swap(*it, entries_.back());
diff --git a/extensions/common/value_counter.h b/extensions/common/value_counter.h
index 03f7907f8..b113701 100644
--- a/extensions/common/value_counter.h
+++ b/extensions/common/value_counter.h
@@ -5,7 +5,10 @@
 #ifndef EXTENSIONS_COMMON_VALUE_COUNTER_H_
 #define EXTENSIONS_COMMON_VALUE_COUNTER_H_
 
-#include "base/memory/scoped_vector.h"
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
 
 namespace base {
 class Value;
@@ -39,7 +42,7 @@
 
  private:
   struct Entry;
-  ScopedVector<Entry> entries_;
+  std::vector<scoped_ptr<Entry>> entries_;
 
   DISALLOW_COPY_AND_ASSIGN(ValueCounter);
 };
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi
index 2397230..d963eb3 100644
--- a/extensions/extensions.gypi
+++ b/extensions/extensions.gypi
@@ -642,6 +642,8 @@
       'browser/guest_view/extension_view/extension_view_constants.h',
       'browser/guest_view/extension_view/extension_view_guest.cc',
       'browser/guest_view/extension_view/extension_view_guest.h',
+      'browser/guest_view/extension_view/whitelist/extension_view_whitelist.cc',
+      'browser/guest_view/extension_view/whitelist/extension_view_whitelist.h',
       'browser/guest_view/extensions_guest_view_manager_delegate.cc',
       'browser/guest_view/extensions_guest_view_manager_delegate.h',
       'browser/guest_view/extensions_guest_view_message_filter.cc',
diff --git a/gpu/blink/webgraphicscontext3d_impl.cc b/gpu/blink/webgraphicscontext3d_impl.cc
index 040d7e1..139dace 100644
--- a/gpu/blink/webgraphicscontext3d_impl.cc
+++ b/gpu/blink/webgraphicscontext3d_impl.cc
@@ -12,7 +12,6 @@
 #include "gpu/command_buffer/client/gles2_lib.h"
 #include "gpu/command_buffer/common/gles2_cmd_utils.h"
 #include "gpu/command_buffer/common/sync_token.h"
-#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h"
 
 #include "third_party/khronos/GLES2/gl2.h"
 #ifndef GL_GLEXT_PROTOTYPES
@@ -1212,10 +1211,6 @@
   return gl_->GetGraphicsResetStatusKHR();
 }
 
-GrGLInterface* WebGraphicsContext3DImpl::createGrGLInterface() {
-  return skia_bindings::CreateCommandBufferSkiaGLBinding();
-}
-
 ::gpu::gles2::GLES2ImplementationErrorMessageCallback*
     WebGraphicsContext3DImpl::getErrorMessageCallback() {
   if (!client_error_message_callback_) {
diff --git a/gpu/blink/webgraphicscontext3d_impl.h b/gpu/blink/webgraphicscontext3d_impl.h
index a7cc2907..6a644c9 100644
--- a/gpu/blink/webgraphicscontext3d_impl.h
+++ b/gpu/blink/webgraphicscontext3d_impl.h
@@ -932,8 +932,6 @@
   bool isContextLost() override;
   blink::WGC3Denum getGraphicsResetStatusARB() override;
 
-  GrGLInterface* createGrGLInterface() override;
-
   ::gpu::gles2::GLES2Interface* GetGLInterface() {
     return gl_;
   }
diff --git a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
index dc4b236..9afc900 100644
--- a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
+++ b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc
@@ -15,8 +15,7 @@
 
 namespace skia_bindings {
 
-GrGLInterface* CreateCommandBufferSkiaGLBinding() {
-  GrGLInterface* interface = new GrGLInterface;
+void InitCommandBufferSkiaGLBinding(GrGLInterface* interface) {
   interface->fStandard = kGLES_GrGLStandard;
   interface->fExtensions.init(kGLES_GrGLStandard,
                               glGetString,
@@ -180,8 +179,6 @@
         glProgramPathFragmentInputGenCHROMIUM;
     functions->fBindFragmentInputLocation = glBindFragmentInputLocationCHROMIUM;
   }
-
-  return interface;
 }
 
 }  // namespace skia
diff --git a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h
index 6a32929..e9504d70 100644
--- a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h
+++ b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h
@@ -12,8 +12,8 @@
 namespace skia_bindings {
 
 // The GPU back-end for skia requires pointers to GL functions. This function
-// returns a binding for skia-gpu to the cmd buffers GL.
-GrGLInterface* CreateCommandBufferSkiaGLBinding();
+// initializes bindings for skia-gpu to the cmd buffers GL.
+void InitCommandBufferSkiaGLBinding(GrGLInterface*);
 
 }  // namespace skia
 
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.h b/ios/chrome/browser/translate/chrome_ios_translate_client.h
index 743210f1..7c8d279 100644
--- a/ios/chrome/browser/translate/chrome_ios_translate_client.h
+++ b/ios/chrome/browser/translate/chrome_ios_translate_client.h
@@ -50,8 +50,8 @@
   scoped_ptr<infobars::InfoBar> CreateInfoBar(
       scoped_ptr<translate::TranslateInfoBarDelegate> delegate) const override;
   void ShowTranslateUI(translate::TranslateStep step,
-                       const std::string source_language,
-                       const std::string target_language,
+                       const std::string& source_language,
+                       const std::string& target_language,
                        translate::TranslateErrors::Type error_type,
                        bool triggered_from_menu) override;
   bool IsTranslatableURL(const GURL& url) override;
diff --git a/ios/chrome/browser/translate/chrome_ios_translate_client.mm b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
index 9eefa03b..ec7cad8 100644
--- a/ios/chrome/browser/translate/chrome_ios_translate_client.mm
+++ b/ios/chrome/browser/translate/chrome_ios_translate_client.mm
@@ -91,8 +91,8 @@
 
 void ChromeIOSTranslateClient::ShowTranslateUI(
     translate::TranslateStep step,
-    const std::string source_language,
-    const std::string target_language,
+    const std::string& source_language,
+    const std::string& target_language,
     translate::TranslateErrors::Type error_type,
     bool triggered_from_menu) {
   DCHECK(web_state());
diff --git a/ios/chrome/ios_chrome_tests.gyp b/ios/chrome/ios_chrome_tests.gyp
index 9afb267..fba3a28 100644
--- a/ios/chrome/ios_chrome_tests.gyp
+++ b/ios/chrome/ios_chrome_tests.gyp
@@ -114,6 +114,8 @@
         'browser/sync/sync_setup_service_mock.h',
         'test/block_cleanup_test.h',
         'test/block_cleanup_test.mm',
+        'test/ios_chrome_scoped_testing_local_state.cc',
+        'test/ios_chrome_scoped_testing_local_state.h',
         'test/ios_chrome_unit_test_suite.cc',
         'test/ios_chrome_unit_test_suite.h',
         'test/run_all_unittests.cc',
diff --git a/ios/chrome/test/ios_chrome_scoped_testing_local_state.cc b/ios/chrome/test/ios_chrome_scoped_testing_local_state.cc
new file mode 100644
index 0000000..e4b68f6
--- /dev/null
+++ b/ios/chrome/test/ios_chrome_scoped_testing_local_state.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 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 "ios/chrome/test/ios_chrome_scoped_testing_local_state.h"
+
+#include "ios/chrome/browser/prefs/browser_prefs.h"
+#include "ios/chrome/test/testing_application_context.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+IOSChromeScopedTestingLocalState::IOSChromeScopedTestingLocalState() {
+  RegisterLocalStatePrefs(local_state_.registry());
+  EXPECT_FALSE(TestingApplicationContext::GetGlobal()->GetLocalState());
+  TestingApplicationContext::GetGlobal()->SetLocalState(&local_state_);
+}
+
+IOSChromeScopedTestingLocalState::~IOSChromeScopedTestingLocalState() {
+  EXPECT_EQ(&local_state_,
+            TestingApplicationContext::GetGlobal()->GetLocalState());
+  TestingApplicationContext::GetGlobal()->SetLocalState(nullptr);
+}
+
+TestingPrefServiceSimple* IOSChromeScopedTestingLocalState::Get() {
+  return &local_state_;
+}
diff --git a/ios/chrome/test/ios_chrome_scoped_testing_local_state.h b/ios/chrome/test/ios_chrome_scoped_testing_local_state.h
new file mode 100644
index 0000000..498cb92f
--- /dev/null
+++ b/ios/chrome/test/ios_chrome_scoped_testing_local_state.h
@@ -0,0 +1,26 @@
+// Copyright 2015 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.
+
+#ifndef IOS_CHROME_TEST_IOS_CHROME_SCOPED_TESTING_LOCAL_STATE_H_
+#define IOS_CHROME_TEST_IOS_CHROME_SCOPED_TESTING_LOCAL_STATE_H_
+
+#include "base/macros.h"
+#include "base/prefs/testing_pref_service.h"
+
+// Helper class to temporarily set up a |local_state| in the global
+// TestingApplicationContext.
+class IOSChromeScopedTestingLocalState {
+ public:
+  IOSChromeScopedTestingLocalState();
+  ~IOSChromeScopedTestingLocalState();
+
+  TestingPrefServiceSimple* Get();
+
+ private:
+  TestingPrefServiceSimple local_state_;
+
+  DISALLOW_COPY_AND_ASSIGN(IOSChromeScopedTestingLocalState);
+};
+
+#endif  // IOS_CHROME_TEST_IOS_CHROME_SCOPED_TESTING_LOCAL_STATE_H_
diff --git a/ios/testing/BUILD.gn b/ios/testing/BUILD.gn
index d63e0cf..782c2ae 100644
--- a/ios/testing/BUILD.gn
+++ b/ios/testing/BUILD.gn
@@ -9,6 +9,9 @@
 
   deps = [
     "//base",
+  ]
+
+  public_deps = [
     "//third_party/google_toolbox_for_mac",
     "//third_party/ocmock",
   ]
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 9eb1a11c..dc48fa08 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -2,13 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# GN build of //ios/web only supports building with the web implementation of
-# WebThread as opposed to GYP build that allow using a shim implementation based
-# on top of BrowserThread.
-#
-# See ios/web/ios_web.gyp for more information on how gyp supports this. The
-# gn targets will fold the target selection in the gyp "incomplete" targets.
-
 import("//testing/test.gni")
 import("//ios/web/js_compile.gni")
 
@@ -27,9 +20,6 @@
 
 source_set("web") {
   deps = [
-    ":core",
-    ":js_resources",
-    ":user_agent",
     "//base",
     "//components/url_formatter",
     "//ios/net",
@@ -40,6 +30,9 @@
     "//ui/gfx/geometry:geometry",
     "//ui/resources",
     "//url",
+    ":core",
+    ":js_resources",
+    ":user_agent",
   ]
 
   sources = [
@@ -84,6 +77,8 @@
     "navigation/time_smoother.h",
     "navigation/web_load_params.h",
     "navigation/web_load_params.mm",
+    "net/cert_host_pair.cc",
+    "net/cert_host_pair.h",
     "net/cert_policy.cc",
     "net/cert_store_impl.cc",
     "net/cert_store_impl.h",
@@ -107,8 +102,6 @@
     "net/clients/crw_redirect_network_client_factory.mm",
     "net/cookie_notification_bridge.h",
     "net/cookie_notification_bridge.mm",
-    "net/crw_cert_policy_cache.h",
-    "net/crw_cert_policy_cache.mm",
     "net/crw_cert_verification_controller.h",
     "net/crw_cert_verification_controller.mm",
     "net/crw_request_tracker_delegate.h",
@@ -383,14 +376,14 @@
   deps = [
     "//base",
     "//base/test:test_support",
+    "//ios/testing:ocmock_support",
     "//net:test_support",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/ocmock",
     "//ui/base:test_support",
-    "//ios/testing:ocmock_support",
-    ":web",
     ":test_support",
+    ":web",
   ]
 
   sources = [
@@ -406,12 +399,12 @@
     "navigation/navigation_item_impl_unittest.mm",
     "navigation/navigation_manager_impl_unittest.mm",
     "navigation/nscoder_util_unittest.mm",
+    "net/cert_host_pair_unittest.cc",
     "net/cert_policy_unittest.cc",
     "net/cert_verifier_block_adapter_unittest.cc",
     "net/clients/crw_csp_network_client_unittest.mm",
     "net/clients/crw_js_injection_network_client_unittest.mm",
     "net/clients/crw_passkit_network_client_unittest.mm",
-    "net/crw_cert_policy_cache_unittest.mm",
     "net/crw_cert_verification_controller_unittest.mm",
     "net/crw_url_verifying_protocol_handler_unittest.mm",
     "net/request_group_util_unittest.mm",
diff --git a/ios/web/active_state_manager_impl_unittest.mm b/ios/web/active_state_manager_impl_unittest.mm
index 3a98754..110fdb0 100644
--- a/ios/web/active_state_manager_impl_unittest.mm
+++ b/ios/web/active_state_manager_impl_unittest.mm
@@ -9,7 +9,7 @@
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/test/test_browser_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
diff --git a/ios/web/crw_browsing_data_store_unittest.mm b/ios/web/crw_browsing_data_store_unittest.mm
index 2d5f800e..8db9898 100644
--- a/ios/web/crw_browsing_data_store_unittest.mm
+++ b/ios/web/crw_browsing_data_store_unittest.mm
@@ -13,7 +13,7 @@
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/test/test_browser_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 
diff --git a/ios/web/net/crw_cert_verification_controller_unittest.mm b/ios/web/net/crw_cert_verification_controller_unittest.mm
index 34ed67f..04dca59 100644
--- a/ios/web/net/crw_cert_verification_controller_unittest.mm
+++ b/ios/web/net/crw_cert_verification_controller_unittest.mm
@@ -8,7 +8,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/test/ios/wait_util.h"
 #include "ios/web/public/web_thread.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #import "ios/web/web_state/wk_web_view_security_util.h"
 #include "net/base/test_data_directory.h"
 #include "net/cert/mock_cert_verifier.h"
diff --git a/ios/web/test/web_test.h b/ios/web/test/web_test.h
index 01aec2a7..b7e4e80 100644
--- a/ios/web/test/web_test.h
+++ b/ios/web/test/web_test.h
@@ -107,6 +107,16 @@
   base::scoped_nsobject<CRWWebController> webController_;
   // true if a task has been processed.
   bool processed_a_task_;
+
+ private:
+  // LoadURL() for data URLs sometimes lock up navigation, so if the loaded page
+  // is not the one expected, reset the web view. In some cases, document or
+  // document.body does not exist either; also reset in those cases.
+  // Returns true if a reset occurred. One may want to load the page again.
+  bool ResetPageIfNavigationStalled(NSString* load_check);
+  // Creates a unique HTML element to look for in
+  // ResetPageIfNavigationStalled().
+  NSString* CreateLoadCheck();
 };
 
 #pragma mark -
@@ -136,4 +146,4 @@
 
 }  // namespace web
 
-#endif // IOS_WEB_TEST_WEB_TEST_H_
+#endif  // IOS_WEB_TEST_WEB_TEST_H_
diff --git a/ios/web/test/web_test.mm b/ios/web/test/web_test.mm
index 9c518c561..cfb0859 100644
--- a/ios/web/test/web_test.mm
+++ b/ios/web/test/web_test.mm
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 
 #include "base/base64.h"
 #include "base/strings/stringprintf.h"
@@ -83,24 +83,14 @@
 }
 
 void WebTestWithWebController::LoadHtml(const std::string& html) {
-  NSString* load_check = [NSString stringWithFormat:
-      @"<p style=\"display: none;\">%d</p>", s_html_load_count++];
-
+  NSString* load_check = CreateLoadCheck();
   std::string marked_html = html + [load_check UTF8String];
   std::string encoded_html;
   base::Base64Encode(marked_html, &encoded_html);
-  GURL url("data:text/html;base64," + encoded_html);
+  GURL url("data:text/html;charset=utf8;base64," + encoded_html);
   LoadURL(url);
 
-  // Data URLs sometimes lock up navigation, so if the loaded page is not the
-  // one expected, reset the web view. In some cases, document or document.body
-  // does not exist either; also reset in those cases.
-  NSString* inner_html = RunJavaScript(
-      @"(document && document.body && document.body.innerHTML) || 'undefined'");
-  if ([inner_html rangeOfString:load_check].location == NSNotFound) {
-    [webController_ setWebUsageEnabled:NO];
-    [webController_ setWebUsageEnabled:YES];
-    [webController_ triggerPendingLoad];
+  if (ResetPageIfNavigationStalled(load_check)) {
     LoadHtml(html);
   }
 }
@@ -249,6 +239,24 @@
   processed_a_task_ = true;
 }
 
+bool WebTestWithWebController::ResetPageIfNavigationStalled(
+    NSString* load_check) {
+  NSString* inner_html = RunJavaScript(
+      @"(document && document.body && document.body.innerHTML) || 'undefined'");
+  if ([inner_html rangeOfString:load_check].location == NSNotFound) {
+    [webController_ setWebUsageEnabled:NO];
+    [webController_ setWebUsageEnabled:YES];
+    [webController_ triggerPendingLoad];
+    return true;
+  }
+  return false;
+}
+
+NSString* WebTestWithWebController::CreateLoadCheck() {
+  return [NSString stringWithFormat:@"<p style=\"display: none;\">%d</p>",
+                                    s_html_load_count++];
+}
+
 #pragma mark -
 
 CRWWebController* WebTestWithUIWebViewWebController::CreateWebController() {
diff --git a/ios/web/web_state/crw_web_view_scroll_view_proxy.mm b/ios/web/web_state/crw_web_view_scroll_view_proxy.mm
index ebbe3d9..83456e8 100644
--- a/ios/web/web_state/crw_web_view_scroll_view_proxy.mm
+++ b/ios/web/web_state/crw_web_view_scroll_view_proxy.mm
@@ -174,6 +174,10 @@
 - (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView {
   DCHECK_EQ(_scrollView, scrollView);
   [_observers webViewScrollViewWillBeginDragging:self];
+
+  // TODO(crbug.com/555723) Remove this once the fix to
+  // https://bugs.webkit.org/show_bug.cgi?id=148086 makes it's way in to iOS.
+  scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
 }
 
 - (void)scrollViewWillEndDragging:(UIScrollView*)scrollView
diff --git a/ios/web/web_state/js/common_js_unittest.mm b/ios/web/web_state/js/common_js_unittest.mm
index 2044cbf..1947b69 100644
--- a/ios/web/web_state/js/common_js_unittest.mm
+++ b/ios/web/web_state/js/common_js_unittest.mm
@@ -7,7 +7,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/sys_string_conversions.h"
 #include "ios/web/public/test/web_test_util.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 
diff --git a/ios/web/web_state/js/core_js_unittest.mm b/ios/web/web_state/js/core_js_unittest.mm
index 93b91b5..443158b 100644
--- a/ios/web/web_state/js/core_js_unittest.mm
+++ b/ios/web/web_state/js/core_js_unittest.mm
@@ -8,7 +8,7 @@
 
 #include "base/strings/stringprintf.h"
 #include "ios/web/public/test/web_test_util.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 
diff --git a/ios/web/web_state/js/crw_js_injection_manager_unittest.mm b/ios/web/web_state/js/crw_js_injection_manager_unittest.mm
index fb7f657..83297a8 100644
--- a/ios/web/web_state/js/crw_js_injection_manager_unittest.mm
+++ b/ios/web/web_state/js/crw_js_injection_manager_unittest.mm
@@ -7,7 +7,7 @@
 #include "ios/web/public/test/web_test_util.h"
 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #import "testing/gtest_mac.h"
 
 // Testing class of JsInjectioManager that has no dependencies.
diff --git a/ios/web/web_state/js/page_script_util_unittest.mm b/ios/web/web_state/js/page_script_util_unittest.mm
index 719de80..5eee4f2 100644
--- a/ios/web/web_state/js/page_script_util_unittest.mm
+++ b/ios/web/web_state/js/page_script_util_unittest.mm
@@ -15,7 +15,7 @@
 #import "ios/web/public/test/test_web_client.h"
 #include "ios/web/public/test/web_test_util.h"
 #import "ios/web/public/web_view_creation_util.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "testing/gtest_mac.h"
 
 namespace web {
diff --git a/ios/web/web_state/js/resources/core.js b/ios/web/web_state/js/resources/core.js
index 7c00525b..4e68df0b 100644
--- a/ios/web/web_state/js/resources/core.js
+++ b/ios/web/web_state/js/resources/core.js
@@ -431,6 +431,19 @@
     return anchor.href;
   };
 
+  // Tracks whether user is in the middle of scrolling/dragging. If user is
+  // scrolling, ignore window.scrollTo() until user stops scrolling.
+  var webViewScrollViewIsDragging_ = false;
+  __gCrWeb['setWebViewScrollViewIsDragging'] = function(state) {
+    webViewScrollViewIsDragging_ = state;
+  };
+  var originalWindowScrollTo = window.scrollTo;
+  window.scrollTo = function(x, y) {
+    if (webViewScrollViewIsDragging_)
+      return;
+    originalWindowScrollTo(x, y);
+  };
+
   // Intercept window.close calls.
   window.close = function() {
     invokeOnHost_({'command': 'window.close.self'});
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index c2ea6be..f599f35 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -166,15 +166,17 @@
 }  // namespace
 
 @interface CRWWebController () <CRWNativeContentDelegate,
+                                CRWWebControllerContainerViewDelegate,
                                 CRWWebViewScrollViewProxyObserver> {
   base::WeakNSProtocol<id<CRWWebDelegate>> _delegate;
   base::WeakNSProtocol<id<CRWWebUserInterfaceDelegate>> _UIDelegate;
   base::WeakNSProtocol<id<CRWNativeContentProvider>> _nativeProvider;
   base::WeakNSProtocol<id<CRWSwipeRecognizerProvider>> _swipeRecognizerProvider;
-  base::scoped_nsobject<CRWWebControllerContainerView> _containerView;
   // The CRWWebViewProxy is the wrapper to give components access to the
   // web view in a controlled and limited way.
   base::scoped_nsobject<CRWWebViewProxyImpl> _webViewProxy;
+  // The view used to display content.  Must outlive |_webViewProxy|.
+  base::scoped_nsobject<CRWWebControllerContainerView> _containerView;
   // If |_contentView| contains a native view rather than a web view, this
   // is its controller. If it's a web view, this is nil.
   base::scoped_nsprotocol<id<CRWNativeContent>> _nativeController;
@@ -1550,8 +1552,8 @@
     // native or web). Note, this needs to be created with a non-zero size
     // to allow for (native) subviews with autosize constraints to be correctly
     // processed.
-    _containerView.reset([[CRWWebControllerContainerView alloc]
-        initWithContentViewProxy:_webViewProxy]);
+    _containerView.reset(
+        [[CRWWebControllerContainerView alloc] initWithDelegate:self]);
     self.containerView.frame = [[UIScreen mainScreen] bounds];
     [self.containerView addGestureRecognizer:[self touchTrackingRecognizer]];
     [self.containerView setAccessibilityIdentifier:web::kContainerViewID];
@@ -1798,9 +1800,8 @@
   // the web view.
   web::NavigationItemImpl* currentItem =
       self.currentSessionEntry.navigationItemImpl;
-  NSString* state = currentItem->GetSerializedStateObject();
-  if (state.length)
-    [self setPushedOrReplacedURL:currentItem->GetURL() stateObject:state];
+  [self setPushedOrReplacedURL:currentItem->GetURL()
+                   stateObject:currentItem->GetSerializedStateObject()];
   // Only load the new URL if the current entry was not created by a JavaScript
   // window.history.pushState() call from |fromEntry|.
   if (![_webStateImpl->GetNavigationManagerImpl().GetSessionController()
@@ -1921,6 +1922,19 @@
 }
 
 #pragma mark -
+#pragma mark CRWWebControllerContainerViewDelegate
+
+- (CRWWebViewProxyImpl*)contentViewProxyForContainerView:
+        (CRWWebControllerContainerView*)containerView {
+  return _webViewProxy.get();
+}
+
+- (CGFloat)headerHeightForContainerView:
+        (CRWWebControllerContainerView*)containerView {
+  return [self headerHeight];
+}
+
+#pragma mark -
 #pragma mark CRWJSInjectionEvaluator Methods
 
 - (void)evaluateJavaScript:(NSString*)script
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.h b/ios/web/web_state/ui/crw_web_controller_container_view.h
index ac7ffad..c24af83 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view.h
+++ b/ios/web/web_state/ui/crw_web_controller_container_view.h
@@ -9,10 +9,24 @@
 
 #include "ios/web/public/web_state/ui/crw_content_view.h"
 
+@class CRWWebControllerContainerView;
 @class CRWWebViewContentView;
 @class CRWWebViewProxyImpl;
 @protocol CRWNativeContent;
 
+@protocol CRWWebControllerContainerViewDelegate<NSObject>
+
+// Returns the proxy object that's backed by the CRWContentView displayed by
+// |containerView|.
+- (CRWWebViewProxyImpl*)contentViewProxyForContainerView:
+        (CRWWebControllerContainerView*)containerView;
+
+// Returns the height for any toolbars that overlap the top |containerView|.
+- (CGFloat)headerHeightForContainerView:
+        (CRWWebControllerContainerView*)containerView;
+
+@end
+
 // Container view class that manages the display of content within
 // CRWWebController.
 @interface CRWWebControllerContainerView : UIView
@@ -28,7 +42,8 @@
 
 // Designated initializer.  |proxy|'s content view will be updated as different
 // content is added to the container.
-- (instancetype)initWithContentViewProxy:(CRWWebViewProxyImpl*)proxy
+- (instancetype)initWithDelegate:
+        (id<CRWWebControllerContainerViewDelegate>)delegate
     NS_DESIGNATED_INITIALIZER;
 
 // CRWWebControllerContainerView should be initialized via
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view.mm b/ios/web/web_state/ui/crw_web_controller_container_view.mm
index 4a119f9..f0ec9976 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view.mm
+++ b/ios/web/web_state/ui/crw_web_controller_container_view.mm
@@ -89,9 +89,8 @@
 #pragma mark - CRWWebControllerContainerView
 
 @interface CRWWebControllerContainerView () {
-  // The proxy for the content added to the container.  It is owned by the web
-  // controller.
-  base::WeakNSObject<CRWWebViewProxyImpl> _webViewProxy;
+  // The delegate passed on initialization.
+  base::WeakNSProtocol<id<CRWWebControllerContainerViewDelegate>> _delegate;
   // Backing objects for corresponding properties.
   base::scoped_nsobject<CRWWebViewContentView> _webViewContentView;
   base::scoped_nsprotocol<id<CRWNativeContent>> _nativeController;
@@ -110,15 +109,25 @@
 @property(nonatomic, retain, readonly)
     CRWToolbarContainerView* toolbarContainerView;
 
+// Convenience getter for the proxy object.
+@property(nonatomic, readonly) CRWWebViewProxyImpl* contentViewProxy;
+
+// Returns |self.bounds| after being inset at the top by the header height
+// returned by the delegate.  This is only used to lay out native controllers,
+// as the header height is already accounted for in the scroll view content
+// insets for other CRWContentViews.
+@property(nonatomic, readonly) CGRect visibleFrame;
+
 @end
 
 @implementation CRWWebControllerContainerView
 
-- (instancetype)initWithContentViewProxy:(CRWWebViewProxyImpl*)proxy {
+- (instancetype)initWithDelegate:
+        (id<CRWWebControllerContainerViewDelegate>)delegate {
   self = [super initWithFrame:CGRectZero];
   if (self) {
-    DCHECK(proxy);
-    _webViewProxy.reset(proxy);
+    DCHECK(delegate);
+    _delegate.reset(delegate);
     self.backgroundColor = [UIColor whiteColor];
     self.autoresizingMask =
         UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
@@ -137,7 +146,7 @@
 }
 
 - (void)dealloc {
-  [_webViewProxy setContentView:nil];
+  self.contentViewProxy.contentView = nil;
   [super dealloc];
 }
 
@@ -151,7 +160,6 @@
   if (![_webViewContentView isEqual:webViewContentView]) {
     [_webViewContentView removeFromSuperview];
     _webViewContentView.reset([webViewContentView retain]);
-    [self addSubview:_webViewContentView];
   }
 }
 
@@ -162,11 +170,11 @@
 - (void)setNativeController:(id<CRWNativeContent>)nativeController {
   if (![_nativeController isEqual:nativeController]) {
     base::WeakNSProtocol<id> oldController(_nativeController);
-    [[_nativeController view] removeFromSuperview];
+    [[oldController view] removeFromSuperview];
     _nativeController.reset([nativeController retain]);
-    [self addSubview:[_nativeController view]];
-    [[_nativeController view] setNeedsUpdateConstraints];
-    DCHECK(!oldController);
+    // TODO(crbug.com/503297): Re-enable this DCHECK once native controller
+    // leaks are fixed.
+    //    DCHECK(!oldController);
   }
 }
 
@@ -178,7 +186,6 @@
   if (![_transientContentView isEqual:transientContentView]) {
     [_transientContentView removeFromSuperview];
     _transientContentView.reset([transientContentView retain]);
-    [self addSubview:_transientContentView];
   }
 }
 
@@ -186,7 +193,6 @@
   if (![_toolbarContainerView isEqual:toolbarContainerView]) {
     [_toolbarContainerView removeFromSuperview];
     _toolbarContainerView.reset([toolbarContainerView retain]);
-    [self addSubview:_toolbarContainerView];
   }
 }
 
@@ -194,19 +200,51 @@
   return _toolbarContainerView.get();
 }
 
+- (CRWWebViewProxyImpl*)contentViewProxy {
+  return [_delegate contentViewProxyForContainerView:self];
+}
+
+- (CGRect)visibleFrame {
+  CGFloat headerHeight = [_delegate headerHeightForContainerView:self];
+  return UIEdgeInsetsInsetRect(self.bounds,
+                               UIEdgeInsetsMake(headerHeight, 0, 0, 0));
+}
+
 #pragma mark Layout
 
 - (void)layoutSubviews {
   [super layoutSubviews];
 
-  // Resize displayed content to the container's bounds.
-  self.webViewContentView.frame = self.bounds;
-  [self.nativeController view].frame = self.bounds;
-  self.transientContentView.frame = self.bounds;
+  // webViewcontentView layout.
+  if (self.webViewContentView) {
+    if (!self.webViewContentView.superview)
+      [self addSubview:self.webViewContentView];
+    self.webViewContentView.frame = self.bounds;
+  }
+
+  // nativeController layout.
+  if (self.nativeController) {
+    UIView* nativeView = [self.nativeController view];
+    if (!nativeView.superview) {
+      [self addSubview:nativeView];
+      [nativeView setNeedsUpdateConstraints];
+    }
+    nativeView.frame = self.visibleFrame;
+  }
+
+  // transientContentView layout.
+  if (self.transientContentView) {
+    if (!self.transientContentView.superview)
+      [self addSubview:self.transientContentView];
+    self.transientContentView.frame = self.bounds;
+  }
 
   // Bottom align the toolbars with the bottom of the container.
   if (self.toolbarContainerView) {
-    [self bringSubviewToFront:self.toolbarContainerView];
+    if (!self.toolbarContainerView.superview)
+      [self addSubview:self.toolbarContainerView];
+    else
+      [self bringSubviewToFront:self.toolbarContainerView];
     CGSize toolbarContainerSize =
         [self.toolbarContainerView sizeThatFits:self.bounds.size];
     self.toolbarContainerView.frame =
@@ -228,7 +266,7 @@
   self.nativeController = nil;
   self.transientContentView = nil;
   [self removeAllToolbars];
-  [_webViewProxy setContentView:nil];
+  self.contentViewProxy.contentView = nil;
 }
 
 - (void)displayWebViewContentView:(CRWWebViewContentView*)webViewContentView {
@@ -236,7 +274,7 @@
   self.webViewContentView = webViewContentView;
   self.nativeController = nil;
   self.transientContentView = nil;
-  [_webViewProxy setContentView:self.webViewContentView];
+  self.contentViewProxy.contentView = self.webViewContentView;
   [self setNeedsLayout];
 }
 
@@ -245,20 +283,20 @@
   self.webViewContentView = nil;
   self.nativeController = nativeController;
   self.transientContentView = nil;
-  [_webViewProxy setContentView:nil];
+  self.contentViewProxy.contentView = nil;
   [self setNeedsLayout];
 }
 
 - (void)displayTransientContent:(CRWContentView*)transientContentView {
   DCHECK(transientContentView);
   self.transientContentView = transientContentView;
-  [_webViewProxy setContentView:self.transientContentView];
+  self.contentViewProxy.contentView = self.transientContentView;
   [self setNeedsLayout];
 }
 
 - (void)clearTransientContentView {
   self.transientContentView = nil;
-  [_webViewProxy setContentView:self.webViewContentView];
+  self.contentViewProxy.contentView = self.webViewContentView;
 }
 
 #pragma mark Toolbars
diff --git a/ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm b/ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm
index 6afb6b16..197a3183 100644
--- a/ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_container_view_unittest.mm
@@ -28,21 +28,52 @@
 }
 @end
 
+// Test CRWWebControllerContainerViewDelegate implementation.
+@interface TestWebControllerContainerViewDelegate
+    : NSObject<CRWWebControllerContainerViewDelegate> {
+  base::scoped_nsobject<CRWWebViewProxyImpl> _proxy;
+}
+- (instancetype)initWithContentViewProxy:(CRWWebViewProxyImpl*)proxy;
+@end
+
+@implementation TestWebControllerContainerViewDelegate
+
+- (instancetype)initWithContentViewProxy:(CRWWebViewProxyImpl*)proxy {
+  if ((self = [super init]))
+    _proxy.reset([proxy retain]);
+  return self;
+}
+
+- (CRWWebViewProxyImpl*)contentViewProxyForContainerView:
+        (CRWWebControllerContainerView*)containerView {
+  return _proxy.get();
+}
+
+- (CGFloat)headerHeightForContainerView:
+        (CRWWebControllerContainerView*)containerView {
+  return 0;
+}
+
+@end
+
 #pragma mark - CRWWebControllerContainerViewTest
 
 class CRWWebControllerContainerViewTest : public PlatformTest {
  protected:
   void SetUp() override {
     PlatformTest::SetUp();
-    mock_web_view_proxy_.reset(
-        [[OCMockObject niceMockForClass:[CRWWebViewProxyImpl class]] retain]);
-    container_view_.reset([[CRWWebControllerContainerView alloc]
-        initWithContentViewProxy:mock_web_view_proxy_]);
+    CRWWebViewProxyImpl* proxy =
+        [OCMockObject niceMockForClass:[CRWWebViewProxyImpl class]];
+    delegate_.reset([[TestWebControllerContainerViewDelegate alloc]
+        initWithContentViewProxy:proxy]);
+    container_view_.reset(
+        [[CRWWebControllerContainerView alloc] initWithDelegate:delegate_]);
     [container_view_ setFrame:kContainerViewFrame];
   }
 
-  // The web view proxy object (required for designated initializer).
-  base::scoped_nsobject<id> mock_web_view_proxy_;
+  // The CRWWebControllerContainerViewDelegate (required for designated
+  // initializer).
+  base::scoped_nsobject<TestWebControllerContainerViewDelegate> delegate_;
   // The container view being tested.
   base::scoped_nsobject<CRWWebControllerContainerView> container_view_;
 };
diff --git a/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm b/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm
index 0f62688..0e16e15 100644
--- a/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_observer_unittest.mm
@@ -15,7 +15,7 @@
 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #import "ios/web/test/crw_fake_web_controller_observer.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "testing/gtest_mac.h"
 
 namespace {
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm
index bb06926..0f3e338 100644
--- a/ios/web/web_state/ui/crw_web_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -25,7 +25,7 @@
 #import "ios/web/public/web_state/ui/crw_content_view.h"
 #import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
 #include "ios/web/public/web_state/url_verification_constants.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #import "ios/web/test/wk_web_view_crash_utils.h"
 #include "ios/web/web_state/blocked_popup_info.h"
 #import "ios/web/web_state/js/crw_js_invoke_parameter_queue.h"
diff --git a/ios/web/web_state/ui/crw_wk_script_message_router_unittest.mm b/ios/web/web_state/ui/crw_wk_script_message_router_unittest.mm
index a638b8e..152a5b5 100644
--- a/ios/web/web_state/ui/crw_wk_script_message_router_unittest.mm
+++ b/ios/web/web_state/ui/crw_wk_script_message_router_unittest.mm
@@ -9,7 +9,7 @@
 #include "ios/web/public/test/test_browser_state.h"
 #import "ios/web/public/test/test_web_client.h"
 #include "ios/web/public/test/web_test_util.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "third_party/ocmock/OCMock/OCMock.h"
 #include "third_party/ocmock/gtest_support.h"
 
diff --git a/ios/web/web_state/ui/crw_wk_simple_web_view_controller_unittest.mm b/ios/web/web_state/ui/crw_wk_simple_web_view_controller_unittest.mm
index 72cb95fd..ea6ca996 100644
--- a/ios/web/web_state/ui/crw_wk_simple_web_view_controller_unittest.mm
+++ b/ios/web/web_state/ui/crw_wk_simple_web_view_controller_unittest.mm
@@ -13,7 +13,7 @@
 #import "ios/web/public/test/test_web_client.h"
 #include "ios/web/public/test/web_test_util.h"
 #import "ios/web/public/web_view_creation_util.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
 #import "third_party/ocmock/OCMock/OCMock.h"
diff --git a/ios/web/web_state/ui/crw_wk_web_view_crash_detector_unittest.mm b/ios/web/web_state/ui/crw_wk_web_view_crash_detector_unittest.mm
index 47d8626..6c87fa87 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_crash_detector_unittest.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_crash_detector_unittest.mm
@@ -7,7 +7,7 @@
 #include "base/mac/scoped_nsobject.h"
 #import "ios/web/public/test/test_web_client.h"
 #include "ios/web/public/test/web_test_util.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #import "ios/web/test/wk_web_view_crash_utils.h"
 
 namespace {
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
index 315fe701..a3eaff3 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -10,6 +10,7 @@
 #include "base/ios/ios_util.h"
 #include "base/ios/weak_nsobject.h"
 #include "base/json/json_reader.h"
+#include "base/mac/objc_property_releaser.h"
 #import "base/mac/scoped_nsobject.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
@@ -28,6 +29,7 @@
 #include "ios/web/public/ssl_status.h"
 #include "ios/web/public/url_util.h"
 #include "ios/web/public/web_client.h"
+#import "ios/web/public/web_state/crw_web_view_scroll_view_proxy.h"
 #import "ios/web/public/web_state/js/crw_js_injection_manager.h"
 #import "ios/web/public/web_state/ui/crw_native_content_provider.h"
 #import "ios/web/public/web_state/ui/crw_web_view_content_view.h"
@@ -107,6 +109,46 @@
 
 }  // namespace
 
+#pragma mark -
+
+// A container object for any navigation information that is only available
+// during pre-commit delegate callbacks, and thus must be held until the
+// navigation commits and the informatino can be used.
+@interface CRWWebControllerPendingNavigationInfo : NSObject {
+  base::mac::ObjCPropertyReleaser
+      _propertyReleaser_CRWWebControllerPendingNavigationInfo;
+}
+// The referrer for the page.
+@property(nonatomic, copy) NSString* referrer;
+// The MIME type for the page.
+@property(nonatomic, copy) NSString* MIMEType;
+// The navigation type for the load.
+@property(nonatomic, assign) WKNavigationType navigationType;
+// Whether the pending navigation has been directly cancelled in
+// |decidePolicyForNavigationAction| or |decidePolicyForNavigationResponse|.
+// Cancelled navigations should be simply discarded without handling any
+// specific error.
+@property(nonatomic, assign) BOOL cancelled;
+@end
+
+@implementation CRWWebControllerPendingNavigationInfo
+@synthesize referrer = _referrer;
+@synthesize MIMEType = _MIMEType;
+@synthesize navigationType = _navigationType;
+@synthesize cancelled = _cancelled;
+
+- (instancetype)init {
+  if ((self = [super init])) {
+    _propertyReleaser_CRWWebControllerPendingNavigationInfo.Init(
+        self, [CRWWebControllerPendingNavigationInfo class]);
+    _navigationType = WKNavigationTypeOther;
+  }
+  return self;
+}
+@end
+
+#pragma mark -
+
 @interface CRWWKWebViewWebController ()<WKNavigationDelegate, WKUIDelegate> {
   // The WKWebView managed by this instance.
   base::scoped_nsobject<WKWebView> _wkWebView;
@@ -130,21 +172,16 @@
   // idempotent.
   base::scoped_nsobject<NSMutableSet> _injectedScriptManagers;
 
-  // Referrer pending for the next navigated page. Lifetime of this value starts
-  // at |decidePolicyForNavigationAction| where the referrer is extracted from
-  // the request and ends at |didCommitNavigation| where the request is
-  // committed.
-  base::scoped_nsobject<NSString> _pendingReferrerString;
+  // Pending information for an in-progress page navigation. The lifetime of
+  // this object starts at |decidePolicyForNavigationAction| where the info is
+  // extracted from the request, and ends at either |didCommitNavigation| or
+  // |didFailProvisionalNavigation|.
+  base::scoped_nsobject<CRWWebControllerPendingNavigationInfo>
+      _pendingNavigationInfo;
 
   // Referrer for the current page.
   base::scoped_nsobject<NSString> _currentReferrerString;
 
-  // Navigation type of the pending navigation action of the main frame. This
-  // value is assigned at |decidePolicyForNavigationAction| where the navigation
-  // type is extracted from the request and associated with a committed
-  // navigation item at |didCommitNavigation|.
-  scoped_ptr<WKNavigationType> _pendingNavigationTypeForMainFrame;
-
   // Whether the web page is currently performing window.history.pushState or
   // window.history.replaceState
   // Set to YES on window.history.willChangeState message. To NO on
@@ -160,12 +197,6 @@
   base::scoped_nsobject<CRWCertVerificationController>
       _certVerificationController;
 
-  // Whether the pending navigation has been directly cancelled in
-  // |decidePolicyForNavigationAction| or |decidePolicyForNavigationResponse|.
-  // Cancelled navigations should be simply discarded without handling any
-  // specific error.
-  BOOL _pendingNavigationCancelled;
-
   // CertVerification errors which happened inside
   // |webView:didReceiveAuthenticationChallenge:completionHandler:|.
   // Key is leaf-cert/host pair. This storage is used to carry calculated
@@ -216,37 +247,27 @@
 // Sets _documentURL to newURL, and updates any relevant state information.
 - (void)setDocumentURL:(const GURL&)newURL;
 
-// Sets value of the pendingReferrerString property.
-- (void)setPendingReferrerString:(NSString*)referrer;
-
-// Extracts the referrer value from WKNavigationAction and sets it as a pending.
-// The referrer is known in |decidePolicyForNavigationAction| however it must
-// be in a pending state until |didCommitNavigation| where it becames current.
-- (void)updatePendingReferrerFromNavigationAction:(WKNavigationAction*)action;
-
-// Replaces the current referrer with the pending one. Referrer becames current
-// at |didCommitNavigation| callback.
-- (void)commitPendingReferrerString;
-
-// Discards the pending referrer.
-- (void)discardPendingReferrerString;
-
-// Extracts the current navigation type from WKNavigationAction and sets it as
-// the pending navigation type. The value should be considered pending until it
-// becomes associated with a navigation item at |didCommitNavigation|.
-- (void)updatePendingNavigationTypeForMainFrameFromNavigationAction:
+// Extracts navigation info from WKNavigationAction and sets it as a pending.
+// Some pieces of navigation information are only known in
+// |decidePolicyForNavigationAction|, but must be in a pending state until
+// |didCommitNavigation| where it becames current.
+- (void)updatePendingNavigationInfoFromNavigationAction:
     (WKNavigationAction*)action;
 
-// Discards the pending navigation type.
-- (void)discardPendingNavigationTypeForMainFrame;
+// Extracts navigation info from WKNavigationResponse and sets it as a pending.
+// Some pieces of navigation information are only known in
+// |decidePolicyForNavigationResponse|, but must be in a pending state until
+// |didCommitNavigation| where it becames current.
+- (void)updatePendingNavigationInfoFromNavigationResponse:
+    (WKNavigationResponse*)response;
+
+// Updates current state with any pending information. Should be called when a
+// navigation is committed.
+- (void)commitPendingNavigationInfo;
 
 // Returns the WKBackForwardListItemHolder for the current navigation item.
 - (web::WKBackForwardListItemHolder*)currentBackForwardListItemHolder;
 
-// Stores the current WKBackForwardListItem and the current navigation type
-// with the current navigation item.
-- (void)updateCurrentBackForwardListItemHolder;
-
 // Returns YES if the given WKBackForwardListItem is valid to use for
 // navigation.
 - (BOOL)isBackForwardListItemValid:(WKBackForwardListItem*)item;
@@ -483,11 +504,11 @@
 }
 
 - (BOOL)isCurrentNavigationItemPOST {
-  // |_pendingNavigationTypeForMainFrame| will be nil if
-  // |decidePolicyForNavigationAction| was not reached.
+  // |_pendingNavigationInfo| will be nil if the decidePolicy* delegate methods
+  // were not called.
   WKNavigationType type =
-      (_pendingNavigationTypeForMainFrame)
-          ? *_pendingNavigationTypeForMainFrame
+      _pendingNavigationInfo
+          ? [_pendingNavigationInfo navigationType]
           : [self currentBackForwardListItemHolder]->navigation_type();
   return type == WKNavigationTypeFormSubmitted ||
          type == WKNavigationTypeFormResubmitted;
@@ -789,32 +810,38 @@
   }
 }
 
-- (void)setPendingReferrerString:(NSString*)referrer {
-  _pendingReferrerString.reset([referrer copy]);
-}
-
-- (void)updatePendingReferrerFromNavigationAction:(WKNavigationAction*)action {
-  if (action.targetFrame.mainFrame)
-    [self setPendingReferrerString:GetRefererFromNavigationAction(action)];
-}
-
-- (void)commitPendingReferrerString {
-  _currentReferrerString.reset(_pendingReferrerString.release());
-}
-
-- (void)discardPendingReferrerString {
-  _pendingReferrerString.reset();
-}
-
-- (void)updatePendingNavigationTypeForMainFrameFromNavigationAction:
+- (void)updatePendingNavigationInfoFromNavigationAction:
     (WKNavigationAction*)action {
-  if (action.targetFrame.mainFrame)
-    _pendingNavigationTypeForMainFrame.reset(
-        new WKNavigationType(action.navigationType));
+  if (action.targetFrame.mainFrame) {
+    _pendingNavigationInfo.reset(
+        [[CRWWebControllerPendingNavigationInfo alloc] init]);
+    [_pendingNavigationInfo setReferrer:GetRefererFromNavigationAction(action)];
+    [_pendingNavigationInfo setNavigationType:action.navigationType];
+  }
 }
 
-- (void)discardPendingNavigationTypeForMainFrame {
-  _pendingNavigationTypeForMainFrame.reset();
+- (void)updatePendingNavigationInfoFromNavigationResponse:
+    (WKNavigationResponse*)response {
+  if (response.isForMainFrame) {
+    if (!_pendingNavigationInfo) {
+      _pendingNavigationInfo.reset(
+          [[CRWWebControllerPendingNavigationInfo alloc] init]);
+    }
+    [_pendingNavigationInfo setMIMEType:response.response.MIMEType];
+  }
+}
+
+- (void)commitPendingNavigationInfo {
+  if ([_pendingNavigationInfo referrer]) {
+    _currentReferrerString.reset([[_pendingNavigationInfo referrer] copy]);
+  }
+  if ([_pendingNavigationInfo MIMEType]) {
+    self.webStateImpl->SetContentsMimeType(
+        base::SysNSStringToUTF8([_pendingNavigationInfo MIMEType]));
+  }
+  [self updateCurrentBackForwardListItemHolder];
+
+  _pendingNavigationInfo.reset();
 }
 
 - (web::WKBackForwardListItemHolder*)currentBackForwardListItemHolder {
@@ -835,15 +862,12 @@
 
   web::WKBackForwardListItemHolder* holder =
       [self currentBackForwardListItemHolder];
-  // If |decidePolicyForNavigationAction| gets called for every load,
-  // it should not necessary to perform this if check - just
-  // overwrite the holder with the newest data. See crbug.com/520279.
-  if (_pendingNavigationTypeForMainFrame) {
+  WKNavigationType navigationType =
+      _pendingNavigationInfo ? [_pendingNavigationInfo navigationType]
+                             : WKNavigationTypeOther;
     holder->set_back_forward_list_item(
         [_wkWebView backForwardList].currentItem);
-    holder->set_navigation_type(*_pendingNavigationTypeForMainFrame);
-    _pendingNavigationTypeForMainFrame.reset();
-  }
+    holder->set_navigation_type(navigationType);
 }
 
 - (BOOL)isBackForwardListItemValid:(WKBackForwardListItem*)item {
@@ -1161,9 +1185,9 @@
 - (void)registerLoadRequest:(const GURL&)url {
   // Get the navigation type from the last main frame load request, and try to
   // map that to a PageTransition.
-  WKNavigationType navigationType = _pendingNavigationTypeForMainFrame
-                                        ? *_pendingNavigationTypeForMainFrame
-                                        : WKNavigationTypeOther;
+  WKNavigationType navigationType =
+      _pendingNavigationInfo ? [_pendingNavigationInfo navigationType]
+                             : WKNavigationTypeOther;
   ui::PageTransition transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
   switch (navigationType) {
     case WKNavigationTypeLinkActivated:
@@ -1338,6 +1362,27 @@
 }
 
 #pragma mark -
+#pragma mark CRWWebViewScrollViewProxyObserver
+
+// Under WKWebView, JavaScript can execute asynchronously. User can start
+// scrolling and calls to window.scrollTo executed during scrolling will be
+// treated as "during user interaction" and can cause app to go fullscreen.
+// This is a workaround to use this webViewScrollViewIsDragging flag to ignore
+// window.scrollTo while user is scrolling. See crbug.com/554257
+- (void)webViewScrollViewWillBeginDragging:
+    (CRWWebViewScrollViewProxy*)webViewScrollViewProxy {
+  [self evaluateJavaScript:@"__gCrWeb.setWebViewScrollViewIsDragging(true)"
+       stringResultHandler:nil];
+}
+
+- (void)webViewScrollViewDidEndDragging:
+            (CRWWebViewScrollViewProxy*)webViewScrollViewProxy
+                         willDecelerate:(BOOL)decelerate {
+  [self evaluateJavaScript:@"__gCrWeb.setWebViewScrollViewIsDragging(false)"
+       stringResultHandler:nil];
+}
+
+#pragma mark -
 #pragma mark JavaScript message handlers
 
 - (BOOL)handleWindowHistoryWillChangeStateMessage:
@@ -1502,11 +1547,8 @@
   GURL url = net::GURLWithNSURL(request.URL);
 
   // The page will not be changed until this navigation is commited, so the
-  // retrieved referrer will be pending until |didCommitNavigation| callback.
-  // Same for the last navigation type.
-  [self updatePendingReferrerFromNavigationAction:navigationAction];
-  [self updatePendingNavigationTypeForMainFrameFromNavigationAction:
-            navigationAction];
+  // retrieved state will be pending until |didCommitNavigation| callback.
+  [self updatePendingNavigationInfoFromNavigationAction:navigationAction];
 
   web::FrameInfo targetFrame(navigationAction.targetFrame.mainFrame);
   BOOL isLinkClick = [self isLinkNavigation:navigationAction.navigationType];
@@ -1516,7 +1558,9 @@
 
   if (allowLoad) {
     allowLoad = self.webStateImpl->ShouldAllowRequest(request);
-    _pendingNavigationCancelled = !allowLoad;
+    if (!allowLoad && navigationAction.targetFrame.mainFrame) {
+      [_pendingNavigationInfo setCancelled:YES];
+    }
   }
 
   decisionHandler(allowLoad ? WKNavigationActionPolicyAllow
@@ -1541,11 +1585,17 @@
         HTTPHeaders.get(), net::GURLWithNSURL(navigationResponse.response.URL));
   }
 
+  // The page will not be changed until this navigation is commited, so the
+  // retrieved state will be pending until |didCommitNavigation| callback.
+  [self updatePendingNavigationInfoFromNavigationResponse:navigationResponse];
+
   BOOL allowNavigation = navigationResponse.canShowMIMEType;
   if (allowNavigation) {
     allowNavigation =
         self.webStateImpl->ShouldAllowResponse(navigationResponse.response);
-    _pendingNavigationCancelled = !allowNavigation;
+    if (!allowNavigation && navigationResponse.isForMainFrame) {
+      [_pendingNavigationInfo setCancelled:YES];
+    }
   }
 
   handler(allowNavigation ? WKNavigationResponsePolicyAllow
@@ -1600,37 +1650,35 @@
 - (void)webView:(WKWebView *)webView
     didFailProvisionalNavigation:(WKNavigation *)navigation
                        withError:(NSError *)error {
-  [self discardPendingReferrerString];
-
-  if (_pendingNavigationCancelled) {
-    // Directly cancelled navigations are simply discarded without handling
-    // their potential errors.
-    _pendingNavigationCancelled = NO;
-    return;
-  }
-
-  error = WKWebViewErrorWithSource(error, PROVISIONAL_LOAD);
+  // Directly cancelled navigations are simply discarded without handling
+  // their potential errors.
+  if (![_pendingNavigationInfo cancelled]) {
+    error = WKWebViewErrorWithSource(error, PROVISIONAL_LOAD);
 
 #if defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
-  // For WKWebViews, the underlying errors for errors reported by the net stack
-  // are not copied over when transferring the errors from the IO thread.  For
-  // cancelled errors that trigger load abortions, translate the error early to
-  // trigger |-discardNonCommittedEntries| from |-handleLoadError:inMainFrame:|.
-  if (error.code == NSURLErrorCancelled &&
-      [self shouldAbortLoadForCancelledError:error] &&
-      !error.userInfo[NSUnderlyingErrorKey]) {
-    error = web::NetErrorFromError(error);
-  }
+    // For WKWebViews, the underlying errors for errors reported by the net
+    // stack are not copied over when transferring the errors from the IO
+    // thread.  For cancelled errors that trigger load abortions, translate the
+    // error early to trigger |-discardNonCommittedEntries| from
+    // |-handleLoadError:inMainFrame:|.
+    if (error.code == NSURLErrorCancelled &&
+        [self shouldAbortLoadForCancelledError:error] &&
+        !error.userInfo[NSUnderlyingErrorKey]) {
+      error = web::NetErrorFromError(error);
+    }
 #endif  // defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
 
 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
-  if (web::IsWKWebViewSSLCertError(error))
-    [self handleSSLCertError:error];
-  else
+    if (web::IsWKWebViewSSLCertError(error))
+      [self handleSSLCertError:error];
+    else
 #endif
-    [self handleLoadError:error inMainFrame:YES];
+      [self handleLoadError:error inMainFrame:YES];
+  }
 
-  [self discardPendingNavigationTypeForMainFrame];
+  // This must be reset at the end, since code above may need information about
+  // the pending load.
+  _pendingNavigationInfo.reset();
   _certVerificationErrors->Clear();
 }
 
@@ -1643,17 +1691,14 @@
   _injectedScriptManagers.reset([[NSMutableSet alloc] init]);
   [self injectWindowID];
 
-  // The page has changed; commit the pending referrer.
-  [self commitPendingReferrerString];
-
-  // This is the point where the document's URL has actually changed.
+  // This is the point where the document's URL has actually changed, and
+  // pending navigation information should be applied to state information.
   [self setDocumentURL:net::GURLWithNSURL([_wkWebView URL])];
   DCHECK(_documentURL == self.lastRegisteredRequestURL);
   self.webStateImpl->OnNavigationCommitted(_documentURL);
+  [self commitPendingNavigationInfo];
   [self webPageChanged];
 
-  [self updateCurrentBackForwardListItemHolder];
-
 #if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW)
   [self updateSSLStatusForCurrentNavigationItem];
 #endif
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index b5d346a..a8da094 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -173,6 +173,11 @@
   void OnHttpResponseHeadersReceived(net::HttpResponseHeaders* response_headers,
                                      const GURL& resource_url);
 
+  // Explicitly sets the MIME type, overwriting any MIME type that was set by
+  // headers. Note that this should be called after OnNavigationCommitted, as
+  // that is the point where MIME type is set from HTTP headers.
+  void SetContentsMimeType(const std::string& mime_type);
+
   // Executes a JavaScript string on the page asynchronously.
   // TODO(shreyasv): Rename this to ExecuteJavaScript for consistency with
   // upstream API.
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 7a8aaf8..0a921e9 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -394,6 +394,10 @@
   return NULL;
 }
 
+void WebStateImpl::SetContentsMimeType(const std::string& mime_type) {
+  mime_type_ = mime_type;
+}
+
 void WebStateImpl::ExecuteJavaScriptAsync(const base::string16& javascript) {
   DCHECK(Configured());
   [web_controller_ evaluateJavaScript:base::SysUTF16ToNSString(javascript)
diff --git a/ios/web/web_state/web_view_internal_creation_util_unittest.mm b/ios/web/web_state/web_view_internal_creation_util_unittest.mm
index 4b48c1d..4770d07 100644
--- a/ios/web/web_state/web_view_internal_creation_util_unittest.mm
+++ b/ios/web/web_state/web_view_internal_creation_util_unittest.mm
@@ -19,7 +19,7 @@
 #import "ios/web/web_state/ui/crw_simple_web_view_controller.h"
 #import "ios/web/web_state/ui/crw_static_file_web_view.h"
 #import "ios/web/web_state/ui/wk_web_view_configuration_provider.h"
-#include "ios/web/test/web_test.h"
+#import "ios/web/test/web_test.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest_mac.h"
 
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index 8acdd7c1..c151c547 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -131,6 +131,7 @@
   IPCTestMsgStart,
   ArcInstanceMsgStart,
   ArcInstanceHostMsgStart,
+  DistillerMsgStart,
   LastIPCMsgStart  // Must come last.
 };
 
diff --git a/mandoline/BUILD.gn b/mandoline/BUILD.gn
index e077bf08..9022e7d 100644
--- a/mandoline/BUILD.gn
+++ b/mandoline/BUILD.gn
@@ -9,6 +9,7 @@
   testonly = true
 
   deps = [
+    "//mojo",
     ":tests",
   ]
 
diff --git a/media/BUILD.gn b/media/BUILD.gn
index f191317..1e2589f5 100644
--- a/media/BUILD.gn
+++ b/media/BUILD.gn
@@ -658,7 +658,7 @@
     "test/data/",
   ]
 
-  # TODO(wolenetz): Fix size_t to int trunctaion in win64.
+  # TODO(wolenetz): Fix size_t to int truncation in win64.
   # See http://crbug.com/171009
   configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
 
@@ -695,6 +695,12 @@
     ]
   }
 
+  # If ExternalClearKey is built, we can test CdmAdapter.
+  if (enable_pepper_cdms) {
+    sources += [ "cdm/cdm_adapter_unittest.cc" ]
+    deps += [ "//media/cdm/ppapi:clearkeycdm" ]
+  }
+
   if (media_use_ffmpeg) {
     sources += [
       "ffmpeg/ffmpeg_common_unittest.cc",
diff --git a/media/base/audio_decoder.h b/media/base/audio_decoder.h
index 3da8547c..337d2a7 100644
--- a/media/base/audio_decoder.h
+++ b/media/base/audio_decoder.h
@@ -10,6 +10,7 @@
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "media/base/audio_decoder_config.h"
+#include "media/base/cdm_context.h"
 #include "media/base/channel_layout.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_export.h"
@@ -56,9 +57,15 @@
 
   // Initializes an AudioDecoder with the given DemuxerStream, executing the
   // callback upon completion.
+  //
+  // |set_cdm_ready_cb| can be used to set/cancel a CdmReadyCB with which the
+  // decoder can be notified when a CDM is ready. The decoder can use the CDM to
+  // handle encrypted video stream.
+  //
   //  |init_cb| is used to return initialization status.
   //  |output_cb| is called for decoded audio buffers (see Decode()).
   virtual void Initialize(const AudioDecoderConfig& config,
+                          const SetCdmReadyCB& set_cdm_ready_cb,
                           const InitCB& init_cb,
                           const OutputCB& output_cb) = 0;
 
diff --git a/media/base/mac/coremedia_glue.h b/media/base/mac/coremedia_glue.h
index b64a27f3..3a6ca07 100644
--- a/media/base/mac/coremedia_glue.h
+++ b/media/base/mac/coremedia_glue.h
@@ -95,6 +95,7 @@
       CMSampleBufferRef sbuf,
       Boolean createIfNecessary);
   static CFStringRef kCMSampleAttachmentKey_NotSync();
+  static CMTime CMSampleBufferGetPresentationTimeStamp(CMSampleBufferRef sbuf);
 
   // Originally from CMFormatDescription.h.
   static FourCharCode CMFormatDescriptionGetMediaSubType(
diff --git a/media/base/mac/coremedia_glue.mm b/media/base/mac/coremedia_glue.mm
index e161a6e58..a1c4f5c 100644
--- a/media/base/mac/coremedia_glue.mm
+++ b/media/base/mac/coremedia_glue.mm
@@ -51,6 +51,8 @@
   typedef CFArrayRef (*CMSampleBufferGetSampleAttachmentsArrayMethod)(
       CoreMediaGlue::CMSampleBufferRef,
       Boolean);
+  typedef CoreMediaGlue::CMTime (*CMSampleBufferGetPresentationTimeStampMethod)(
+      CoreMediaGlue::CMSampleBufferRef);
 
   typedef FourCharCode (*CMFormatDescriptionGetMediaSubTypeMethod)(
       CoreMediaGlue::CMFormatDescriptionRef desc);
@@ -112,6 +114,10 @@
         reinterpret_cast<CMSampleBufferGetSampleAttachmentsArrayMethod>(
             dlsym(library_handle, "CMSampleBufferGetSampleAttachmentsArray"));
     CHECK(cm_sample_buffer_get_sample_attachments_array_method_) << dlerror();
+    cm_sample_buffer_get_presentation_timestamp_method_ =
+        reinterpret_cast<CMSampleBufferGetPresentationTimeStampMethod>(
+            dlsym(library_handle, "CMSampleBufferGetPresentationTimeStamp"));
+    CHECK(cm_sample_buffer_get_presentation_timestamp_method_) << dlerror();
     k_cm_sample_attachment_key_not_sync_ = reinterpret_cast<CFStringRef*>(
         dlsym(library_handle, "kCMSampleAttachmentKey_NotSync"));
     CHECK(k_cm_sample_attachment_key_not_sync_) << dlerror();
@@ -168,6 +174,10 @@
   cm_sample_buffer_get_sample_attachments_array_method() const {
     return cm_sample_buffer_get_sample_attachments_array_method_;
   }
+  const CMSampleBufferGetPresentationTimeStampMethod&
+  cm_sample_buffer_get_presentation_timestamp_method() const {
+    return cm_sample_buffer_get_presentation_timestamp_method_;
+  }
   CFStringRef* const& k_cm_sample_attachment_key_not_sync() const {
     return k_cm_sample_attachment_key_not_sync_;
   }
@@ -208,6 +218,8 @@
       cm_video_format_description_get_dimensions_method_;
   CMVideoFormatDescriptionGetH264ParameterSetAtIndexMethod
       cm_video_format_description_get_h264_parameter_set_at_index_method_;
+  CMSampleBufferGetPresentationTimeStampMethod
+      cm_sample_buffer_get_presentation_timestamp_method_;
 
   DISALLOW_COPY_AND_ASSIGN(CoreMediaLibraryInternal);
 };
@@ -301,6 +313,13 @@
 }
 
 // static
+CoreMediaGlue::CMTime CoreMediaGlue::CMSampleBufferGetPresentationTimeStamp(
+    CMSampleBufferRef sbuf) {
+  return g_coremedia_handle.Get()
+      .cm_sample_buffer_get_presentation_timestamp_method()(sbuf);
+}
+
+// static
 CFStringRef CoreMediaGlue::kCMSampleAttachmentKey_NotSync() {
   return *g_coremedia_handle.Get().k_cm_sample_attachment_key_not_sync();
 }
diff --git a/media/base/media_file_checker.cc b/media/base/media_file_checker.cc
index 4a49ac7..0ecdbf45 100644
--- a/media/base/media_file_checker.cc
+++ b/media/base/media_file_checker.cc
@@ -66,14 +66,11 @@
     result = av_read_frame(glue.format_context(), &packet);
     if (result < 0)
       break;
-    result = av_dup_packet(&packet);
-    if (result < 0)
-      break;
 
     std::map<int, AVCodecContext*>::const_iterator it =
         stream_contexts.find(packet.stream_index);
     if (it == stream_contexts.end()) {
-      av_free_packet(&packet);
+      av_packet_unref(&packet);
       continue;
     }
     AVCodecContext* av_context = it->second;
@@ -81,7 +78,7 @@
     int frame_decoded = 0;
     if (av_context->codec_type == AVMEDIA_TYPE_AUDIO) {
       // A shallow copy of packet so we can slide packet.data as frames are
-      // decoded; otherwise av_free_packet() will corrupt memory.
+      // decoded; otherwise av_packet_unref() will corrupt memory.
       AVPacket temp_packet = packet;
       do {
         result = avcodec_decode_audio4(av_context, frame.get(), &frame_decoded,
@@ -99,7 +96,7 @@
       if (result >= 0 && frame_decoded)
         av_frame_unref(frame.get());
     }
-    av_free_packet(&packet);
+    av_packet_unref(&packet);
   } while (base::TimeTicks::Now() < deadline && read_ok && result >= 0);
 
   return read_ok && (result == AVERROR_EOF || result >= 0);
diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h
index 5fb2a3e..c558430 100644
--- a/media/base/mock_filters.h
+++ b/media/base/mock_filters.h
@@ -86,9 +86,10 @@
 
   // VideoDecoder implementation.
   virtual std::string GetDisplayName() const;
-  MOCK_METHOD4(Initialize,
+  MOCK_METHOD5(Initialize,
                void(const VideoDecoderConfig& config,
                     bool low_delay,
+                    const SetCdmReadyCB& set_cdm_ready_cb,
                     const InitCB& init_cb,
                     const OutputCB& output_cb));
   MOCK_METHOD2(Decode, void(const scoped_refptr<DecoderBuffer>& buffer,
@@ -107,8 +108,9 @@
 
   // AudioDecoder implementation.
   virtual std::string GetDisplayName() const;
-  MOCK_METHOD3(Initialize,
+  MOCK_METHOD4(Initialize,
                void(const AudioDecoderConfig& config,
+                    const SetCdmReadyCB& set_cdm_ready_cb,
                     const InitCB& init_cb,
                     const OutputCB& output_cb));
   MOCK_METHOD2(Decode,
diff --git a/media/base/video_decoder.h b/media/base/video_decoder.h
index f7bae3c..074718b 100644
--- a/media/base/video_decoder.h
+++ b/media/base/video_decoder.h
@@ -9,6 +9,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
+#include "media/base/cdm_context.h"
 #include "media/base/media_export.h"
 #include "media/base/pipeline_status.h"
 #include "ui/gfx/geometry/size.h"
@@ -63,6 +64,10 @@
   // Initialization should fail if |low_delay| is true and the decoder cannot
   // satisfy the requirements above.
   //
+  // |set_cdm_ready_cb| can be used to set/cancel a CdmReadyCB with which the
+  // decoder can be notified when a CDM is ready. The decoder can use the CDM to
+  // handle encrypted video stream.
+  //
   // Note:
   // 1) The VideoDecoder will be reinitialized if it was initialized before.
   //    Upon reinitialization, all internal buffered frames will be dropped.
@@ -70,6 +75,7 @@
   // 3) No VideoDecoder calls should be made before |init_cb| is executed.
   virtual void Initialize(const VideoDecoderConfig& config,
                           bool low_delay,
+                          const SetCdmReadyCB& set_cdm_ready_cb,
                           const InitCB& init_cb,
                           const OutputCB& output_cb) = 0;
 
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn
index 06937b7e..54d5429 100644
--- a/media/blink/BUILD.gn
+++ b/media/blink/BUILD.gn
@@ -41,9 +41,13 @@
     "cdm_result_promise_helper.h",
     "cdm_session_adapter.cc",
     "cdm_session_adapter.h",
+    "interval_map.h",
     "key_system_config_selector.cc",
     "key_system_config_selector.h",
+    "lru.h",
     "media_blink_export.h",
+    "multibuffer.cc",
+    "multibuffer.h",
     "new_session_cdm_result_promise.cc",
     "new_session_cdm_result_promise.h",
     "texttrack_impl.cc",
diff --git a/media/blink/media_blink.gyp b/media/blink/media_blink.gyp
index a99d84a..17a577d 100644
--- a/media/blink/media_blink.gyp
+++ b/media/blink/media_blink.gyp
@@ -46,9 +46,13 @@
         'cdm_session_adapter.h',
         'encrypted_media_player_support.cc',
         'encrypted_media_player_support.h',
+        'interval_map.h',
         'key_system_config_selector.cc',
         'key_system_config_selector.h',
+        'lru.h',
         'media_blink_export.h',
+        'multibuffer.cc',
+        'multibuffer.h',
         'new_session_cdm_result_promise.cc',
         'new_session_cdm_result_promise.h',
         'texttrack_impl.cc',
diff --git a/media/blink/multibuffer.cc b/media/blink/multibuffer.cc
new file mode 100644
index 0000000..41c3582
--- /dev/null
+++ b/media/blink/multibuffer.cc
@@ -0,0 +1,480 @@
+// Copyright 2015 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 "media/blink/multibuffer.h"
+
+#include "base/bind.h"
+
+namespace media {
+
+// Returns the block ID closest to (but less or equal than) |pos| from |index|.
+template <class T>
+static MultiBuffer::BlockId ClosestPreviousEntry(
+    const std::map<MultiBuffer::BlockId, T>& index,
+    MultiBuffer::BlockId pos) {
+  auto i = index.upper_bound(pos);
+  DCHECK(i == index.end() || i->first > pos);
+  if (i == index.begin()) {
+    return std::numeric_limits<MultiBufferBlockId>::min();
+  }
+  --i;
+  DCHECK_LE(i->first, pos);
+  return i->first;
+}
+
+// Returns the block ID closest to (but greter than or equal to) |pos|
+// from |index|.
+template <class T>
+static MultiBuffer::BlockId ClosestNextEntry(
+    const std::map<MultiBuffer::BlockId, T>& index,
+    MultiBuffer::BlockId pos) {
+  auto i = index.lower_bound(pos);
+  if (i == index.end()) {
+    return std::numeric_limits<MultiBufferBlockId>::max();
+  }
+  DCHECK_GE(i->first, pos);
+  return i->first;
+}
+
+//
+// MultiBuffer::GlobalLRU
+//
+MultiBuffer::GlobalLRU::GlobalLRU() : max_size_(0), data_size_(0) {}
+
+MultiBuffer::GlobalLRU::~GlobalLRU() {
+  // By the time we're freed, all blocks should have been removed,
+  // and our sums should be zero.
+  DCHECK(lru_.Empty());
+  DCHECK_EQ(max_size_, 0);
+  DCHECK_EQ(data_size_, 0);
+}
+
+void MultiBuffer::GlobalLRU::Use(MultiBuffer* multibuffer,
+                                 MultiBufferBlockId block_id) {
+  GlobalBlockId id(multibuffer, block_id);
+  lru_.Use(id);
+}
+
+void MultiBuffer::GlobalLRU::Insert(MultiBuffer* multibuffer,
+                                    MultiBufferBlockId block_id) {
+  GlobalBlockId id(multibuffer, block_id);
+  lru_.Insert(id);
+}
+
+void MultiBuffer::GlobalLRU::Remove(MultiBuffer* multibuffer,
+                                    MultiBufferBlockId block_id) {
+  GlobalBlockId id(multibuffer, block_id);
+  lru_.Remove(id);
+}
+
+bool MultiBuffer::GlobalLRU::Contains(MultiBuffer* multibuffer,
+                                      MultiBufferBlockId block_id) {
+  GlobalBlockId id(multibuffer, block_id);
+  return lru_.Contains(id);
+}
+
+void MultiBuffer::GlobalLRU::IncrementDataSize(int64_t blocks) {
+  data_size_ += blocks;
+  DCHECK_GE(data_size_, 0);
+}
+
+void MultiBuffer::GlobalLRU::IncrementMaxSize(int64_t blocks) {
+  max_size_ += blocks;
+  DCHECK_GE(max_size_, 0);
+}
+
+void MultiBuffer::GlobalLRU::Prune(int64_t max_to_free) {
+  // We group the blocks by multibuffer so that we can free as many blocks as
+  // possible in one call. This reduces the number of callbacks to clients
+  // when their available ranges change.
+  std::map<MultiBuffer*, std::vector<MultiBufferBlockId>> to_free;
+  int64_t freed = 0;
+  while (data_size_ - freed > max_size_ && !lru_.Empty() &&
+         freed < max_to_free) {
+    GlobalBlockId block_id = lru_.Pop();
+    to_free[block_id.first].push_back(block_id.second);
+    freed++;
+  }
+  for (const auto& to_free_pair : to_free) {
+    to_free_pair.first->ReleaseBlocks(to_free_pair.second);
+  }
+}
+
+int64_t MultiBuffer::GlobalLRU::Size() const {
+  return lru_.Size();
+}
+
+//
+// MultiBuffer
+//
+MultiBuffer::MultiBuffer(int32_t block_size_shift,
+                         const scoped_refptr<GlobalLRU>& global_lru)
+    : max_size_(0), block_size_shift_(block_size_shift), lru_(global_lru) {}
+
+MultiBuffer::~MultiBuffer() {
+  // Delete all writers.
+  for (const auto& i : writer_index_) {
+    delete i.second;
+  }
+  // Remove all blocks from the LRU.
+  for (const auto& i : data_) {
+    lru_->Remove(this, i.first);
+  }
+  lru_->IncrementDataSize(-static_cast<int64_t>(data_.size()));
+  lru_->IncrementMaxSize(-max_size_);
+}
+
+void MultiBuffer::AddReader(const BlockId& pos, Reader* reader) {
+  std::set<Reader*>* set_of_readers = &readers_[pos];
+  bool already_waited_for = !set_of_readers->empty();
+  set_of_readers->insert(reader);
+
+  if (already_waited_for || Contains(pos)) {
+    return;
+  }
+
+  // We may need to create a new data provider to service this request.
+  // Look for an existing data provider first.
+  DataProvider* provider = nullptr;
+  BlockId closest_writer = ClosestPreviousEntry(writer_index_, pos);
+
+  if (closest_writer > pos - kMaxWaitForWriterOffset) {
+    auto i = present_.find(pos);
+    BlockId closest_block;
+    if (i.value()) {
+      // Shouldn't happen, we already tested that Contains(pos) is true.
+      NOTREACHED();
+      closest_block = pos;
+    } else if (i == present_.begin()) {
+      closest_block = -1;
+    } else {
+      closest_block = i.interval_begin() - 1;
+    }
+
+    // Make sure that there are no present blocks between the writer and
+    // the requested position, as that will cause the writer to quit.
+    if (closest_writer > closest_block) {
+      provider = writer_index_[closest_writer];
+      DCHECK(provider);
+    }
+  }
+  if (!provider) {
+    DCHECK(writer_index_.find(pos) == writer_index_.end());
+    provider = writer_index_[pos] = CreateWriter(pos);
+    provider->SetAvailableCallback(base::Bind(
+        &MultiBuffer::DataProviderEvent, base::Unretained(this), provider));
+  }
+  provider->SetDeferred(false);
+}
+
+void MultiBuffer::RemoveReader(const BlockId& pos, Reader* reader) {
+  auto i = readers_.find(pos);
+  if (i == readers_.end())
+    return;
+  i->second.erase(reader);
+  if (i->second.empty()) {
+    readers_.erase(i);
+  }
+}
+
+void MultiBuffer::CleanupWriters(const BlockId& pos) {
+  BlockId p2 = pos + kMaxWaitForReaderOffset;
+  BlockId closest_writer = ClosestPreviousEntry(writer_index_, p2);
+  while (closest_writer > pos - kMaxWaitForWriterOffset) {
+    DCHECK(writer_index_[closest_writer]);
+    DataProviderEvent(writer_index_[closest_writer]);
+    closest_writer = ClosestPreviousEntry(writer_index_, closest_writer - 1);
+  }
+}
+
+bool MultiBuffer::Contains(const BlockId& pos) const {
+  DCHECK(present_[pos] == 0 || present_[pos] == 1)
+      << " pos = " << pos << " present_[pos] " << present_[pos];
+  DCHECK_EQ(present_[pos], data_.find(pos) != data_.end() ? 1 : 0);
+  return !!present_[pos];
+}
+
+MultiBufferBlockId MultiBuffer::FindNextUnavailable(const BlockId& pos) const {
+  auto i = present_.find(pos);
+  if (i.value())
+    return i.interval_end();
+  return pos;
+}
+
+void MultiBuffer::NotifyAvailableRange(
+    const Interval<MultiBufferBlockId>& observer_range,
+    const Interval<MultiBufferBlockId>& new_range) {
+  std::set<Reader*> tmp;
+  for (auto i = readers_.lower_bound(observer_range.begin);
+       i != readers_.end() && i->first < observer_range.end; ++i) {
+    tmp.insert(i->second.begin(), i->second.end());
+  }
+  for (Reader* reader : tmp) {
+    reader->NotifyAvailableRange(new_range);
+  }
+}
+
+void MultiBuffer::ReleaseBlocks(const std::vector<MultiBufferBlockId>& blocks) {
+  IntervalMap<BlockId, int32_t> freed;
+  for (MultiBufferBlockId to_free : blocks) {
+    DCHECK(data_[to_free]);
+    DCHECK_EQ(pinned_[to_free], 0);
+    DCHECK_EQ(present_[to_free], 1);
+    data_.erase(to_free);
+    freed.IncrementInterval(to_free, to_free + 1, 1);
+    present_.IncrementInterval(to_free, to_free + 1, -1);
+  }
+  lru_->IncrementDataSize(-static_cast<int64_t>(blocks.size()));
+
+  for (const auto& freed_range : freed) {
+    if (freed_range.second) {
+      // Technically, there shouldn't be any observers in this range
+      // as all observers really should be pinning the range where it's
+      // actually observing.
+      NotifyAvailableRange(
+          freed_range.first,
+          // Empty range.
+          Interval<BlockId>(freed_range.first.begin, freed_range.first.begin));
+
+      auto i = present_.find(freed_range.first.begin);
+      DCHECK_EQ(i.value(), 0);
+      DCHECK_LE(i.interval_begin(), freed_range.first.begin);
+      DCHECK_LE(freed_range.first.end, i.interval_end());
+
+      if (i.interval_begin() == freed_range.first.begin) {
+        // Notify the previous range that it contains fewer blocks.
+        auto j = i;
+        --j;
+        DCHECK_EQ(j.value(), 1);
+        NotifyAvailableRange(j.interval(), j.interval());
+      }
+      if (i.interval_end() == freed_range.first.end) {
+        // Notify the following range that it contains fewer blocks.
+        auto j = i;
+        ++j;
+        DCHECK_EQ(j.value(), 1);
+        NotifyAvailableRange(j.interval(), j.interval());
+      }
+    }
+  }
+}
+
+void MultiBuffer::AddProvider(scoped_ptr<DataProvider> provider) {
+  // If there is already a provider in the same location, we delete it.
+  DCHECK(!provider->Available());
+  BlockId pos = provider->Tell();
+  DataProvider** place = &writer_index_[pos];
+  DCHECK_NE(*place, provider.get());
+  if (*place)
+    delete *place;
+  *place = provider.release();
+}
+
+scoped_ptr<MultiBuffer::DataProvider> MultiBuffer::RemoveProvider(
+    DataProvider* provider) {
+  BlockId pos = provider->Tell();
+  DCHECK_EQ(writer_index_[pos], provider);
+  writer_index_.erase(pos);
+  return scoped_ptr<DataProvider>(provider);
+}
+
+MultiBuffer::ProviderState MultiBuffer::SuggestProviderState(
+    const BlockId& pos) const {
+  MultiBufferBlockId next_reader_pos = ClosestNextEntry(readers_, pos);
+  if (next_reader_pos != std::numeric_limits<MultiBufferBlockId>::max() &&
+      (next_reader_pos - pos <= kMaxWaitForWriterOffset || !RangeSupported())) {
+    // Check if there is another writer between us and the next reader.
+    MultiBufferBlockId next_writer_pos =
+        ClosestNextEntry(writer_index_, pos + 1);
+    if (next_writer_pos > next_reader_pos) {
+      return ProviderStateLoad;
+    }
+  }
+
+  MultiBufferBlockId previous_reader_pos =
+      ClosestPreviousEntry(readers_, pos - 1);
+  if (previous_reader_pos != std::numeric_limits<MultiBufferBlockId>::min() &&
+      (pos - previous_reader_pos <= kMaxWaitForReaderOffset ||
+       !RangeSupported())) {
+    MultiBufferBlockId previous_writer_pos =
+        ClosestPreviousEntry(writer_index_, pos - 1);
+    if (previous_writer_pos < previous_reader_pos) {
+      return ProviderStateDefer;
+    }
+  }
+
+  return ProviderStateDead;
+}
+
+bool MultiBuffer::ProviderCollision(const BlockId& id) const {
+  // If there is a writer at the same location, it is always a collision.
+  if (writer_index_.find(id) != writer_index_.end())
+    return true;
+
+  // Data already exists at providers current position,
+  // if the URL supports ranges, we can kill the data provider.
+  if (RangeSupported() && Contains(id))
+    return true;
+
+  return false;
+}
+
+void MultiBuffer::Prune(size_t max_to_free) {
+  lru_->Prune(max_to_free);
+}
+
+void MultiBuffer::DataProviderEvent(DataProvider* provider_tmp) {
+  scoped_ptr<DataProvider> provider(RemoveProvider(provider_tmp));
+  BlockId start_pos = provider->Tell();
+  BlockId pos = start_pos;
+  bool eof = false;
+  int64_t blocks_before = data_.size();
+
+  while (!ProviderCollision(pos) && !eof) {
+    if (!provider->Available()) {
+      AddProvider(provider.Pass());
+      break;
+    }
+    DCHECK_GE(pos, 0);
+    scoped_refptr<DataBuffer> data = provider->Read();
+    data_[pos] = data;
+    eof = data->end_of_stream();
+    if (!pinned_[pos])
+      lru_->Use(this, pos);
+    ++pos;
+  }
+  int64_t blocks_after = data_.size();
+  int64_t blocks_added = blocks_after - blocks_before;
+
+  if (pos > start_pos) {
+    present_.SetInterval(start_pos, pos, 1);
+    Interval<BlockId> expanded_range = present_.find(start_pos).interval();
+    NotifyAvailableRange(expanded_range, expanded_range);
+
+    lru_->IncrementDataSize(blocks_added);
+    Prune(blocks_added * kMaxFreesPerAdd + 1);
+  }
+
+  // Check that it's still there before we try to delete it.
+  // In case of EOF or a collision, we might not have called AddProvider above.
+  // Even if we did call AddProvider, calling NotifyAvailableRange can cause
+  // readers to seek or self-destruct and clean up any associated writers.
+  auto i = writer_index_.find(pos);
+  if (i != writer_index_.end() && i->second == provider_tmp) {
+    switch (SuggestProviderState(pos)) {
+      case ProviderStateLoad:
+        // Not sure we actually need to do this
+        provider_tmp->SetDeferred(false);
+        break;
+      case ProviderStateDefer:
+        provider_tmp->SetDeferred(true);
+        break;
+      case ProviderStateDead:
+        RemoveProvider(provider_tmp);
+        break;
+    }
+  }
+}
+
+void MultiBuffer::MergeFrom(MultiBuffer* other) {
+  // Import data and update LRU.
+  for (const auto& data : other->data_) {
+    if (data_.insert(std::make_pair(data.first, data.second)).second) {
+      if (!pinned_[data.first]) {
+        lru_->Insert(this, data.first);
+      }
+    }
+  }
+  // Update present_
+  for (const auto& r : other->present_) {
+    if (r.second) {
+      present_.SetInterval(r.first.begin, r.first.end, 1);
+    }
+  }
+  // Notify existing readers.
+  auto last = present_.begin();
+  for (const auto& r : other->present_) {
+    if (r.second) {
+      auto i = present_.find(r.first.begin);
+      if (i != last) {
+        NotifyAvailableRange(i.interval(), i.interval());
+        last = i;
+      }
+    }
+  }
+}
+
+void MultiBuffer::PinRange(const BlockId& from,
+                           const BlockId& to,
+                           int32_t how_much) {
+  DCHECK_NE(how_much, 0);
+  DVLOG(3) << "PINRANGE [" << from << " - " << to << ") += " << how_much;
+  pinned_.IncrementInterval(from, to, how_much);
+  Interval<BlockId> modified_range(from, to);
+
+  // Iterate over all the modified ranges and check if any of them have
+  // transitioned in or out of the unlocked state. If so, we iterate over
+  // all buffers in that range and add/remove them from the LRU as approperiate.
+  // We iterate *backwards* through the ranges, with the idea that data in a
+  // continous range should be freed from the end first.
+
+  if (data_.empty())
+    return;
+
+  auto range = pinned_.find(to - 1);
+  while (1) {
+    if (range.value() == 0 || range.value() == how_much) {
+      bool pin = range.value() == how_much;
+      Interval<BlockId> transition_range =
+          modified_range.Intersect(range.interval());
+      if (transition_range.Empty())
+        break;
+
+      // For each range that has transitioned to/from a pinned state,
+      // we iterate over the corresponding ranges in |present_| to find
+      // the blocks that are actually in the multibuffer.
+      for (auto present_block_range = present_.find(transition_range.end - 1);
+           present_block_range != present_.begin(); --present_block_range) {
+        if (!present_block_range.value())
+          continue;
+        Interval<BlockId> present_transitioned_range =
+            transition_range.Intersect(present_block_range.interval());
+        if (present_transitioned_range.Empty())
+          break;
+        for (BlockId block = present_transitioned_range.end - 1;
+             block >= present_transitioned_range.begin; --block) {
+          DCHECK_GE(block, 0);
+          DCHECK(data_.find(block) != data_.end());
+          if (pin) {
+            DCHECK(pinned_[block]);
+            lru_->Remove(this, block);
+          } else {
+            DCHECK(!pinned_[block]);
+            lru_->Insert(this, block);
+          }
+        }
+      }
+    }
+    if (range == pinned_.begin())
+      break;
+    --range;
+  }
+}
+
+void MultiBuffer::PinRanges(const IntervalMap<BlockId, int32_t>& ranges) {
+  for (const auto& r : ranges) {
+    if (r.second != 0) {
+      PinRange(r.first.begin, r.first.end, r.second);
+    }
+  }
+}
+
+void MultiBuffer::IncrementMaxSize(int32_t size) {
+  max_size_ += size;
+  lru_->IncrementMaxSize(size);
+  DCHECK_GE(max_size_, 0);
+  // Pruning only happens when blocks are added.
+}
+
+}  // namespace media
diff --git a/media/blink/multibuffer.h b/media/blink/multibuffer.h
new file mode 100644
index 0000000..d469d43f
--- /dev/null
+++ b/media/blink/multibuffer.h
@@ -0,0 +1,317 @@
+// Copyright 2015 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.
+
+#ifndef MEDIA_BLINK_MULTIBUFFER_H_
+#define MEDIA_BLINK_MULTIBUFFER_H_
+
+#include <stdint.h>
+
+#include <limits>
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "media/base/data_buffer.h"
+#include "media/blink/interval_map.h"
+#include "media/blink/lru.h"
+#include "media/blink/media_blink_export.h"
+
+namespace media {
+
+typedef int32_t MultiBufferBlockId;
+class MultiBuffer;
+typedef std::pair<MultiBuffer*, MultiBufferBlockId> MultiBufferGlobalBlockId;
+
+}  // namespace media
+
+namespace BASE_HASH_NAMESPACE {
+
+template <>
+struct hash<media::MultiBufferGlobalBlockId> {
+  std::size_t operator()(const media::MultiBufferGlobalBlockId& key) const {
+// It would be nice if we could use intptr_t instead of int64_t here, but
+// on some platforms, int64_t is declared as "long" which doesn't match
+// any of the HashPair() functions. This leads to a compile error since
+// the compiler can't decide which HashPair() function to call.
+#if defined(ARCH_CPU_64_BITS)
+    return base::HashPair(reinterpret_cast<int64_t>(key.first), key.second);
+#else
+    return base::HashPair(reinterpret_cast<int32_t>(key.first), key.second);
+#endif
+  }
+};
+
+}  // namespace BASE_HASH_NAMESPACE
+
+namespace media {
+
+// Freeing a lot of blocks can be expensive, to keep thing
+// flowing smoothly we only free a maximum of |kMaxFreesPerAdd|
+// blocks when a new block is added to the cache.
+const int kMaxFreesPerAdd = 10;
+
+// There is a simple logic for creating, destroying and deferring
+// data providers. Every data provider has a look-ahead region and
+// a look-behind region. If there are readers in the look-ahead
+// region, we keep reading. If not, but there are readers in the
+// look-behind region, we defer. If there are no readers in either
+// region, we destroy the data provider.
+
+// When new readers are added, new data providers are created if
+// the new reader doesn't fall into the look-ahead region of
+// an existing data provider.
+
+// This is the size of the look-ahead region.
+const int kMaxWaitForWriterOffset = 5;
+
+// This is the size of the look-behind region.
+const int kMaxWaitForReaderOffset = 50;
+
+class MultiBuffer;
+
+// MultiBuffers are multi-reader multi-writer cache/buffers with
+// prefetching and pinning. Data is stored internally in ref-counted
+// blocks of identical size. |block_size_shift| is log2 of the block
+// size.
+//
+// Users should inherit this class and implement CreateWriter().
+// TODO(hubbe): Make the multibuffer respond to memory pressure.
+class MEDIA_BLINK_EXPORT MultiBuffer {
+ public:
+  // Interface for clients wishing to read data out of this cache.
+  // Note: It might look tempting to replace this with a callback,
+  // but we keep and compare pointers to Readers internally.
+  class Reader {
+   public:
+    Reader() {}
+    virtual ~Reader() {}
+    // Notifies the reader that the range of available blocks has changed.
+    // The reader must call MultiBuffer::Observe() to activate this callback.
+    virtual void NotifyAvailableRange(
+        const Interval<MultiBufferBlockId>& range) = 0;
+
+   private:
+    DISALLOW_COPY_AND_ASSIGN(Reader);
+  };
+
+  // DataProvider is the interface that MultiBuffer
+  // uses to get data into the cache.
+  class DataProvider {
+   public:
+    virtual ~DataProvider() {}
+
+    // Returns the block number that is to be returned
+    // by the next Read() call.
+    virtual MultiBufferBlockId Tell() const = 0;
+
+    // Returns true if one (or more) blocks are
+    // availble to read.
+    virtual bool Available() const = 0;
+
+    // Returns the next block. Only valid if Available()
+    // returns true. Last block might be of a smaller size
+    // and after the last block we will get an end-of-stream
+    // DataBuffer.
+    virtual scoped_refptr<DataBuffer> Read() = 0;
+
+    // |cb| is called every time Available() becomes true.
+    virtual void SetAvailableCallback(const base::Closure& cb) = 0;
+
+    // Ask the data provider to stop giving us data.
+    // It's ok if the effect is not immediate.
+    virtual void SetDeferred(bool deferred) = 0;
+  };
+
+  // Multibuffers use a global shared LRU to free memory.
+  // This effectively means that recently used multibuffers can
+  // borrow memory from less recently used ones.
+  class MEDIA_BLINK_EXPORT GlobalLRU : public base::RefCounted<GlobalLRU> {
+   public:
+    typedef MultiBufferGlobalBlockId GlobalBlockId;
+    GlobalLRU();
+
+    // Free elements from cache if needed and possible.
+    // Don't free more than |max_to_free| blocks.
+    // Virtual for testing purposes.
+    void Prune(int64_t max_to_free);
+
+    void IncrementDataSize(int64_t blocks);
+    void IncrementMaxSize(int64_t blocks);
+
+    // LRU operations.
+    void Use(MultiBuffer* multibuffer, MultiBufferBlockId id);
+    void Remove(MultiBuffer* multibuffer, MultiBufferBlockId id);
+    void Insert(MultiBuffer* multibuffer, MultiBufferBlockId id);
+    bool Contains(MultiBuffer* multibuffer, MultiBufferBlockId id);
+    int64_t Size() const;
+
+   private:
+    friend class base::RefCounted<GlobalLRU>;
+    ~GlobalLRU();
+
+    // Max number of blocks.
+    int64_t max_size_;
+
+    // Sum of all multibuffer::data_.size().
+    int64_t data_size_;
+
+    // The LRU should contain all blocks which are not pinned from
+    // all multibuffers.
+    LRU<GlobalBlockId> lru_;
+  };
+
+  MultiBuffer(int32_t block_size_shift,
+              const scoped_refptr<GlobalLRU>& global_lru);
+  virtual ~MultiBuffer();
+
+  // Identifies a block in the cache.
+  // Block numbers can be calculated from byte positions as:
+  // block_num = byte_pos >> block_size_shift
+  typedef MultiBufferBlockId BlockId;
+  typedef base::hash_map<BlockId, scoped_refptr<DataBuffer>> DataMap;
+
+  // Registers a reader at the given position.
+  // If the cache does not already contain |pos|, it will activate
+  // or create data providers to make sure that the block becomes
+  // available soon. If |pos| is already in the cache, no action is
+  // taken, it simply lets the cache know that this reader is likely
+  // to read pos+1, pos+2.. soon.
+  //
+  // Registered readers will be notified when the available range
+  // at their position changes. The available range at |pos| is a range
+  // from A to B where: A <= |pos|, B >= |pos| and all blocks in [A..B)
+  // are present in the cache.  When this changes, we will call
+  // NotifyAvailableRange() on the reader.
+  void AddReader(const BlockId& pos, Reader* reader);
+
+  // Unregister a reader at block |pos|.
+  // Often followed by a call to AddReader(pos + 1, ...);
+  // Idempotent.
+  void RemoveReader(const BlockId& pos, Reader* reader);
+
+  // Immediately remove writers at or before |pos| if nobody needs them.
+  // Note that we can't really do this in StopWaitFor(), because it's very
+  // likely that StopWaitFor() is immediately followed by a call to WaitFor().
+  // It is also a bad idea to wait for the writers to clean themselves up when
+  // they try to provide unwanted data to the cache. Besides the obvoius
+  // inefficiency, it will also cause the http_cache to bypass the disk/memory
+  // cache if we have multiple simultaneous requests going against the same
+  // url.
+  void CleanupWriters(const BlockId& pos);
+
+  // Returns true if block |pos| is available in the cache.
+  bool Contains(const BlockId& pos) const;
+
+  // Returns the next unavailable block at or after |pos|.
+  BlockId FindNextUnavailable(const BlockId& pos) const;
+
+  // Change the pin count for a range of data blocks.
+  // Note that blocks do not have to be present in the
+  // cache to be pinned.
+  // Examples:
+  // Pin block 3, 4 & 5: PinRange(3, 6, 1);
+  // Unpin block 4 & 5: PinRange(4, 6, -1);
+  void PinRange(const BlockId& from, const BlockId& to, int32_t how_much);
+
+  // Calls PinRange for each range in |ranges|, convenience
+  // function for applying multiple changes to the pinned ranges.
+  void PinRanges(const IntervalMap<BlockId, int32_t>& ranges);
+
+  // Increment max cache size by |size| (counted in blocks).
+  void IncrementMaxSize(int32_t size);
+
+  // Caller takes ownership of 'provider', cache will
+  // not call it anymore.
+  scoped_ptr<DataProvider> RemoveProvider(DataProvider* provider);
+
+  // Add a writer to this cache. Cache takes ownership and
+  // may choose to destroy it.
+  void AddProvider(scoped_ptr<DataProvider> provider);
+
+  // Transfer all data from |other| to this.
+  void MergeFrom(MultiBuffer* other);
+
+  // Accessors.
+  const DataMap& map() const { return data_; }
+  int32_t block_size_shift() const { return block_size_shift_; }
+
+ protected:
+  // Create a new writer at |pos| and return it.
+  // Users needs to implemement this method.
+  virtual DataProvider* CreateWriter(const BlockId& pos) = 0;
+
+  virtual bool RangeSupported() const = 0;
+
+ private:
+  // For testing.
+  friend class TestMultiBuffer;
+
+  enum ProviderState {
+    ProviderStateDead,
+    ProviderStateDefer,
+    ProviderStateLoad
+  };
+
+  // Can be overriden for testing.
+  virtual void Prune(size_t max_to_free);
+
+  // Remove the given blocks from the multibuffer, called from
+  // GlobalLRU::Prune().
+  void ReleaseBlocks(const std::vector<MultiBufferBlockId>& blocks);
+
+  // Figure out what state a writer at |pos| should be in.
+  ProviderState SuggestProviderState(const BlockId& pos) const;
+
+  // Returns true if a writer at |pos| is colliding with
+  // output of another writer.
+  bool ProviderCollision(const BlockId& pos) const;
+
+  // Call NotifyAvailableRange(new_range) on all readers waiting
+  // for a block in |observer_range|
+  void NotifyAvailableRange(const Interval<MultiBufferBlockId>& observer_range,
+                            const Interval<MultiBufferBlockId>& new_range);
+
+  // Callback which notifies us that a data provider has
+  // some data for us. Also called when it might be apprperiate
+  // for a provider in a deferred state to wake up.
+  void DataProviderEvent(DataProvider* provider);
+
+  // Max number of blocks.
+  int64_t max_size_;
+
+  // log2 of block size.
+  int32_t block_size_shift_;
+
+  // Stores the actual data.
+  DataMap data_;
+
+  // Keeps track of readers waiting for data.
+  std::map<MultiBufferBlockId, std::set<Reader*>> readers_;
+
+  // Keeps track of writers by their position.
+  // The writers are owned by this class.
+  // TODO(hubbe): Use ScopedPtrMap here. (must add upper/lower_bound first)
+  std::map<BlockId, DataProvider*> writer_index_;
+
+  // Gloabally shared LRU, decides which block to free next.
+  scoped_refptr<GlobalLRU> lru_;
+
+  // Keeps track of what blocks are pinned. If block p is pinned,
+  // then pinned_[p] > 0. Pinned blocks cannot be freed and should not
+  // be present in |lru_|.
+  IntervalMap<BlockId, int32_t> pinned_;
+
+  // present_[block] should be 1 for all blocks that are present
+  // and 0 for all blocks that are not. Used to quickly figure out
+  // ranges of available/unavailable blocks without iterating.
+  IntervalMap<BlockId, int32_t> present_;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_BLINK_MULTIBUFFER_H_
diff --git a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
index 5f1893ae..45cd482 100644
--- a/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
+++ b/media/capture/video/mac/video_capture_device_avfoundation_mac.mm
@@ -4,11 +4,13 @@
 
 #import "media/capture/video/mac/video_capture_device_avfoundation_mac.h"
 
+#import <CoreMedia/CoreMedia.h>
 #import <CoreVideo/CoreVideo.h>
 
 #include "base/location.h"
 #include "base/logging.h"
 #include "base/mac/foundation_util.h"
+#include "media/base/timestamp_constants.h"
 #include "media/base/video_capture_types.h"
 #include "media/capture/video/mac/video_capture_device_mac.h"
 #include "ui/gfx/geometry/size.h"
@@ -329,9 +331,18 @@
 
   {
     base::AutoLock lock(lock_);
+    const CoreMediaGlue::CMTime cm_timestamp =
+        CoreMediaGlue::CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
+    const base::TimeDelta timestamp =
+        CMTIME_IS_VALID(cm_timestamp)
+            ? base::TimeDelta::FromMicroseconds(
+                  cm_timestamp.value * base::TimeTicks::kMicrosecondsPerSecond /
+                  cm_timestamp.timescale)
+            : media::kNoTimestamp();
+
     if (frameReceiver_ && baseAddress) {
       frameReceiver_->ReceiveFrame(reinterpret_cast<uint8_t*>(baseAddress),
-                                   frameSize, captureFormat, 0, 0);
+                                   frameSize, captureFormat, 0, 0, timestamp);
     }
   }
 
diff --git a/media/capture/video/mac/video_capture_device_mac.h b/media/capture/video/mac/video_capture_device_mac.h
index 1b91c87..c6ac509 100644
--- a/media/capture/video/mac/video_capture_device_mac.h
+++ b/media/capture/video/mac/video_capture_device_mac.h
@@ -74,7 +74,8 @@
                     int video_frame_length,
                     const VideoCaptureFormat& frame_format,
                     int aspect_numerator,
-                    int aspect_denominator);
+                    int aspect_denominator,
+                    base::TimeDelta timestamp);
 
   // Forwarder to VideoCaptureDevice::Client::OnError().
   void ReceiveError(const tracked_objects::Location& from_here,
@@ -108,6 +109,9 @@
 
   id<PlatformVideoCapturingMac> capture_device_;
 
+  base::TimeDelta first_timestamp_;
+  base::TimeTicks first_aligned_timestamp_;
+
   // Used with Bind and PostTask to ensure that methods aren't called after the
   // VideoCaptureDeviceMac is destroyed.
   // NOTE: Weak pointers must be invalidated before all other member variables.
diff --git a/media/capture/video/mac/video_capture_device_mac.mm b/media/capture/video/mac/video_capture_device_mac.mm
index cc8608e..34c38f73 100644
--- a/media/capture/video/mac/video_capture_device_mac.mm
+++ b/media/capture/video/mac/video_capture_device_mac.mm
@@ -18,6 +18,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "base/time/time.h"
 #import "media/base/mac/avfoundation_glue.h"
+#include "media/base/timestamp_constants.h"
 #import "media/capture/video/mac/platform_video_capturing_mac.h"
 #import "media/capture/video/mac/video_capture_device_avfoundation_mac.h"
 #import "media/capture/video/mac/video_capture_device_qtkit_mac.h"
@@ -344,6 +345,7 @@
       task_runner_(base::ThreadTaskRunnerHandle::Get()),
       state_(kNotInitialized),
       capture_device_(nil),
+      first_timestamp_(media::kNoTimestamp()),
       weak_factory_(this) {
   // Avoid reconfiguring AVFoundation or blacklisted devices.
   final_resolution_selected_ = AVFoundationGlue::IsAVFoundationSupported() ||
@@ -464,7 +466,8 @@
                                          int video_frame_length,
                                          const VideoCaptureFormat& frame_format,
                                          int aspect_numerator,
-                                         int aspect_denominator) {
+                                         int aspect_denominator,
+                                         base::TimeDelta timestamp) {
   // This method is safe to call from a device capture thread, i.e. any thread
   // controlled by QTKit/AVFoundation.
   if (!final_resolution_selected_) {
@@ -536,8 +539,18 @@
     return;
   }
 
+  base::TimeTicks aligned_timestamp;
+  if (timestamp == media::kNoTimestamp()) {
+    aligned_timestamp = base::TimeTicks::Now();
+  } else {
+    if (first_timestamp_ == media::kNoTimestamp()) {
+      first_timestamp_ = timestamp;
+      first_aligned_timestamp_ = base::TimeTicks::Now();
+    }
+    aligned_timestamp = first_aligned_timestamp_ + timestamp - first_timestamp_;
+  }
   client_->OnIncomingCapturedData(video_frame, video_frame_length, frame_format,
-                                  0, base::TimeTicks::Now());
+                                  0, aligned_timestamp);
 }
 
 void VideoCaptureDeviceMac::ReceiveError(
diff --git a/media/capture/video/mac/video_capture_device_qtkit_mac.mm b/media/capture/video/mac/video_capture_device_qtkit_mac.mm
index 9218a11..ac11f20 100644
--- a/media/capture/video/mac/video_capture_device_qtkit_mac.mm
+++ b/media/capture/video/mac/video_capture_device_qtkit_mac.mm
@@ -9,6 +9,7 @@
 #include "base/debug/crash_logging.h"
 #include "base/location.h"
 #include "base/logging.h"
+#include "media/base/timestamp_constants.h"
 #include "media/base/video_capture_types.h"
 #include "media/capture/video/mac/video_capture_device_mac.h"
 #include "media/capture/video/video_capture_device.h"
@@ -326,8 +327,17 @@
     }
 
     // Deliver the captured video frame.
+    const QTTime qt_timestamp = [sampleBuffer presentationTime];
+    base::TimeDelta timestamp;
+    if (!(qt_timestamp.flags & kQTTimeIsIndefinite) && qt_timestamp.timeScale) {
+      timestamp = base::TimeDelta::FromMicroseconds(
+          qt_timestamp.timeValue * base::TimeTicks::kMicrosecondsPerSecond /
+          qt_timestamp.timeScale);
+    } else {
+      timestamp = media::kNoTimestamp();
+    }
     frameReceiver_->ReceiveFrame(addressToPass, frameSize, captureFormat,
-                                 aspectNumerator, aspectDenominator);
+                                 aspectNumerator, aspectDenominator, timestamp);
 
     CVPixelBufferUnlockBaseAddress(videoFrame, kLockFlags);
   }
diff --git a/media/cast/sender/h264_vt_encoder_unittest.cc b/media/cast/sender/h264_vt_encoder_unittest.cc
index e44d9f8..419cbb87 100644
--- a/media/cast/sender/h264_vt_encoder_unittest.cc
+++ b/media/cast/sender/h264_vt_encoder_unittest.cc
@@ -12,6 +12,7 @@
 #include "base/test/power_monitor_test_base.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "base/test/test_suite.h"
+#include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media.h"
 #include "media/base/media_switches.h"
@@ -135,7 +136,8 @@
         count_frames_checked_(0) {
     bool decoder_init_result;
     decoder_.Initialize(
-        config, false, base::Bind(&SaveDecoderInitResult, &decoder_init_result),
+        config, false, media::SetCdmReadyCB(),
+        base::Bind(&SaveDecoderInitResult, &decoder_init_result),
         base::Bind(&EndToEndFrameChecker::CompareFrameWithExpected,
                    base::Unretained(this)));
     base::MessageLoop::current()->RunUntilIdle();
diff --git a/media/cast/test/fake_media_source.cc b/media/cast/test/fake_media_source.cc
index 7288728..b8820b7 100644
--- a/media/cast/test/fake_media_source.cc
+++ b/media/cast/test/fake_media_source.cc
@@ -441,7 +441,7 @@
   AVFrame* avframe = av_frame_alloc();
 
   // Make a shallow copy of packet so we can slide packet.data as frames are
-  // decoded from the packet; otherwise av_free_packet() will corrupt memory.
+  // decoded from the packet; otherwise av_packet_unref() will corrupt memory.
   AVPacket packet_temp = *packet.get();
 
   do {
diff --git a/media/cdm/aes_decryptor.cc b/media/cdm/aes_decryptor.cc
index 8eaa058..1c3f367 100644
--- a/media/cdm/aes_decryptor.cc
+++ b/media/cdm/aes_decryptor.cc
@@ -309,8 +309,8 @@
   promise->resolve(session_id);
 
   // No URL needed for license requests.
-  session_message_cb_.Run(session_id, LICENSE_REQUEST, message,
-                          GURL::EmptyGURL());
+  GURL empty_gurl;
+  session_message_cb_.Run(session_id, LICENSE_REQUEST, message, empty_gurl);
 }
 
 void AesDecryptor::LoadSession(SessionType session_type,
diff --git a/media/cdm/cdm_adapter_unittest.cc b/media/cdm/cdm_adapter_unittest.cc
new file mode 100644
index 0000000..1b3f12b
--- /dev/null
+++ b/media/cdm/cdm_adapter_unittest.cc
@@ -0,0 +1,374 @@
+// Copyright 2015 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/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/scoped_native_library.h"
+#include "media/base/cdm_callback_promise.h"
+#include "media/base/cdm_key_information.h"
+#include "media/base/media_keys.h"
+#include "media/cdm/api/content_decryption_module.h"
+#include "media/cdm/cdm_adapter.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::_;
+using ::testing::SaveArg;
+MATCHER(IsNotEmpty, "") {
+  return !arg.empty();
+}
+
+// TODO(jrummell): These tests are a subset of those in aes_decryptor_unittest.
+// Refactor aes_decryptor_unittest.cc to handle AesDecryptor directly and
+// via CdmAdapter once CdmAdapter supports decrypting functionality. There
+// will also be tests that only CdmAdapter supports, like file IO, which
+// will need to be handled separately.
+
+namespace media {
+
+// INITIALIZE_CDM_MODULE is a macro in api/content_decryption_module.h.
+// However, we need to pass it as a string to GetFunctionPointer() once it
+// is expanded.
+#define STRINGIFY(X) #X
+#define MAKE_STRING(X) STRINGIFY(X)
+
+const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
+
+// File name of the External ClearKey CDM on different platforms.
+const base::FilePath::CharType kExternalClearKeyCdmFileName[] =
+#if defined(OS_MACOSX)
+    FILE_PATH_LITERAL("libclearkeycdm.dylib");
+#elif defined(OS_WIN)
+    FILE_PATH_LITERAL("clearkeycdm.dll");
+#else  // OS_LINUX, etc.
+    FILE_PATH_LITERAL("libclearkeycdm.so");
+#endif
+
+// Random key ID used to create a session.
+const uint8 kKeyId[] = {
+    // base64 equivalent is AQIDBAUGBwgJCgsMDQ4PEA
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+};
+
+const char kKeyIdAsJWK[] = "{\"kids\": [\"AQIDBAUGBwgJCgsMDQ4PEA\"]}";
+
+const uint8 kKeyIdAsPssh[] = {
+    0x00, 0x00, 0x00, 0x00, 'p',  's',  's',  'h',   // size = 0
+    0x01,                                            // version = 1
+    0x00, 0x00, 0x00,                                // flags
+    0x10, 0x77, 0xEF, 0xEC, 0xC0, 0xB2, 0x4D, 0x02,  // Common SystemID
+    0xAC, 0xE3, 0x3C, 0x1E, 0x52, 0xE2, 0xFB, 0x4B,
+    0x00, 0x00, 0x00, 0x01,                          // key count
+    0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,  // key
+    0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+    0x00, 0x00, 0x00, 0x00,  // datasize
+};
+
+// Key is 0x0405060708090a0b0c0d0e0f10111213,
+// base64 equivalent is BAUGBwgJCgsMDQ4PEBESEw.
+const char kKeyAsJWK[] =
+    "{"
+    "  \"keys\": ["
+    "    {"
+    "      \"kty\": \"oct\","
+    "      \"alg\": \"A128KW\","
+    "      \"kid\": \"AQIDBAUGBwgJCgsMDQ4PEA\","
+    "      \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
+    "    }"
+    "  ],"
+    "  \"type\": \"temporary\""
+    "}";
+
+class CdmAdapterTest : public testing::Test {
+ public:
+  enum ExpectedResult { SUCCESS, FAILURE };
+
+  CdmAdapterTest() {}
+  ~CdmAdapterTest() override {}
+
+ protected:
+  // Initializes the adapter. |expected_result| tests that the call succeeds
+  // or generates an error.
+  void InitializeAndExpect(base::FilePath library_path,
+                           ExpectedResult expected_result) {
+    CdmConfig cdm_config;  // default settings of false are sufficient.
+
+    CdmAdapter::Create(
+        kExternalClearKeyKeySystem, library_path, cdm_config,
+        base::Bind(&CdmAdapterTest::OnSessionMessage, base::Unretained(this)),
+        base::Bind(&CdmAdapterTest::OnSessionClosed, base::Unretained(this)),
+        base::Bind(&CdmAdapterTest::OnLegacySessionError,
+                   base::Unretained(this)),
+        base::Bind(&CdmAdapterTest::OnSessionKeysChange,
+                   base::Unretained(this)),
+        base::Bind(&CdmAdapterTest::OnSessionExpirationUpdate,
+                   base::Unretained(this)),
+        base::Bind(&CdmAdapterTest::OnCdmCreated, base::Unretained(this),
+                   expected_result));
+    RunUntilIdle();
+  }
+
+  // Creates a new session using |key_id|. |session_id_| will be set
+  // when the promise is resolved. |expected_result| tests that
+  // CreateSessionAndGenerateRequest() succeeds or generates an error.
+  void CreateSessionAndExpect(EmeInitDataType data_type,
+                              const std::vector<uint8>& key_id,
+                              ExpectedResult expected_result) {
+    DCHECK(!key_id.empty());
+
+    if (expected_result == SUCCESS) {
+      EXPECT_CALL(*this,
+                  OnSessionMessage(IsNotEmpty(), _, _, GURL::EmptyGURL()));
+    }
+
+    adapter_->CreateSessionAndGenerateRequest(
+        MediaKeys::TEMPORARY_SESSION, data_type, key_id,
+        CreateSessionPromise(expected_result));
+    RunUntilIdle();
+  }
+
+  // Loads the session specified by |session_id|. |expected_result| tests
+  // that LoadSession() succeeds or generates an error.
+  void LoadSessionAndExpect(const std::string& session_id,
+                            ExpectedResult expected_result) {
+    DCHECK(!session_id.empty());
+    ASSERT_EQ(expected_result, FAILURE) << "LoadSession not supported.";
+
+    adapter_->LoadSession(MediaKeys::TEMPORARY_SESSION, session_id,
+                          CreateSessionPromise(expected_result));
+    RunUntilIdle();
+  }
+
+  // Updates the session specified by |session_id| with |key|. |expected_result|
+  // tests that the update succeeds or generates an error. |new_key_expected|
+  // is the expected parameter when the SessionKeysChange event happens.
+  void UpdateSessionAndExpect(std::string session_id,
+                              const std::string& key,
+                              ExpectedResult expected_result,
+                              bool new_key_expected) {
+    DCHECK(!key.empty());
+
+    if (expected_result == SUCCESS) {
+      EXPECT_CALL(*this,
+                  OnSessionKeysChangeCalled(session_id, new_key_expected));
+    } else {
+      EXPECT_CALL(*this, OnSessionKeysChangeCalled(_, _)).Times(0);
+    }
+
+    adapter_->UpdateSession(session_id,
+                            std::vector<uint8>(key.begin(), key.end()),
+                            CreatePromise(expected_result));
+    RunUntilIdle();
+  }
+
+  base::FilePath ExternalClearKeyLibrary() { return library_path_; }
+
+  std::string SessionId() { return session_id_; }
+
+ private:
+  void SetUp() override {
+    // Determine the location of the CDM. It is expected to be in the same
+    // directory as the current module.
+    base::FilePath current_module_dir;
+    ASSERT_TRUE(PathService::Get(base::DIR_MODULE, &current_module_dir));
+    library_path_ =
+        current_module_dir.Append(base::FilePath(kExternalClearKeyCdmFileName));
+    ASSERT_TRUE(base::PathExists(library_path_)) << library_path_.value();
+
+    // Now load the CDM library.
+    base::NativeLibraryLoadError error;
+    library_.Reset(base::LoadNativeLibrary(library_path_, &error));
+    ASSERT_TRUE(library_.is_valid()) << error.ToString();
+
+    // Call INITIALIZE_CDM_MODULE()
+    typedef void (*InitializeCdmFunc)();
+    InitializeCdmFunc initialize_cdm_func = reinterpret_cast<InitializeCdmFunc>(
+        library_.GetFunctionPointer(MAKE_STRING(INITIALIZE_CDM_MODULE)));
+    ASSERT_TRUE(initialize_cdm_func) << "No INITIALIZE_CDM_MODULE in library";
+    initialize_cdm_func();
+  }
+
+  void TearDown() override {
+    // Call DeinitializeCdmModule()
+    typedef void (*DeinitializeCdmFunc)();
+    DeinitializeCdmFunc deinitialize_cdm_func =
+        reinterpret_cast<DeinitializeCdmFunc>(
+            library_.GetFunctionPointer("DeinitializeCdmModule"));
+    ASSERT_TRUE(deinitialize_cdm_func)
+        << "No DeinitializeCdmModule() in library";
+    deinitialize_cdm_func();
+  }
+
+  void OnCdmCreated(ExpectedResult expected_result,
+                    const scoped_refptr<MediaKeys>& cdm,
+                    const std::string& error_message) {
+    if (cdm) {
+      EXPECT_EQ(expected_result, SUCCESS) << "CDM should not have loaded.";
+      adapter_ = cdm;
+    } else {
+      EXPECT_EQ(expected_result, FAILURE) << error_message;
+    }
+  }
+
+  // Create a promise. |expected_result| is used to indicate how the promise
+  // should be fulfilled.
+  scoped_ptr<SimpleCdmPromise> CreatePromise(ExpectedResult expected_result) {
+    if (expected_result == SUCCESS) {
+      EXPECT_CALL(*this, OnResolve());
+    } else {
+      EXPECT_CALL(*this, OnReject(_, _, IsNotEmpty()));
+    }
+
+    scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>(
+        base::Bind(&CdmAdapterTest::OnResolve, base::Unretained(this)),
+        base::Bind(&CdmAdapterTest::OnReject, base::Unretained(this))));
+    return promise.Pass();
+  }
+
+  // Create a promise to be used when a new session is created.
+  // |expected_result| is used to indicate how the promise should be fulfilled.
+  scoped_ptr<NewSessionCdmPromise> CreateSessionPromise(
+      ExpectedResult expected_result) {
+    if (expected_result == SUCCESS) {
+      EXPECT_CALL(*this, OnResolveWithSession(_))
+          .WillOnce(SaveArg<0>(&session_id_));
+    } else {
+      EXPECT_CALL(*this, OnReject(_, _, IsNotEmpty()));
+    }
+
+    scoped_ptr<NewSessionCdmPromise> promise(
+        new CdmCallbackPromise<std::string>(
+            base::Bind(&CdmAdapterTest::OnResolveWithSession,
+                       base::Unretained(this)),
+            base::Bind(&CdmAdapterTest::OnReject, base::Unretained(this))));
+    return promise.Pass();
+  }
+
+  void RunUntilIdle() { message_loop_.RunUntilIdle(); }
+
+  // Methods used for promise resolved/rejected.
+  MOCK_METHOD0(OnResolve, void());
+  MOCK_METHOD1(OnResolveWithSession, void(const std::string& session_id));
+  MOCK_METHOD3(OnReject,
+               void(MediaKeys::Exception exception_code,
+                    uint32 system_code,
+                    const std::string& error_message));
+
+  // Methods used for the events possibly generated by CdmAdapater.
+  MOCK_METHOD4(OnSessionMessage,
+               void(const std::string& session_id,
+                    MediaKeys::MessageType message_type,
+                    const std::vector<uint8_t>& message,
+                    const GURL& legacy_destination_url));
+  MOCK_METHOD1(OnSessionClosed, void(const std::string& session_id));
+  MOCK_METHOD4(OnLegacySessionError,
+               void(const std::string& session_id,
+                    MediaKeys::Exception exception,
+                    uint32_t system_code,
+                    const std::string& error_message));
+  MOCK_METHOD2(OnSessionKeysChangeCalled,
+               void(const std::string& session_id,
+                    bool has_additional_usable_key));
+  void OnSessionKeysChange(const std::string& session_id,
+                           bool has_additional_usable_key,
+                           CdmKeysInfo keys_info) {
+    // MOCK methods don't like CdmKeysInfo.
+    OnSessionKeysChangeCalled(session_id, has_additional_usable_key);
+  }
+  MOCK_METHOD2(OnSessionExpirationUpdate,
+               void(const std::string& session_id,
+                    const base::Time& new_expiry_time));
+
+  // Keep a reference to the CDM.
+  base::FilePath library_path_;
+  base::ScopedNativeLibrary library_;
+
+  scoped_refptr<MediaKeys> adapter_;
+
+  // |session_id_| is the latest result of calling CreateSession().
+  std::string session_id_;
+
+  base::MessageLoop message_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(CdmAdapterTest);
+};
+
+TEST_F(CdmAdapterTest, Initialize) {
+  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
+}
+
+TEST_F(CdmAdapterTest, BadLibraryPath) {
+  InitializeAndExpect(base::FilePath(FILE_PATH_LITERAL("no_library_here")),
+                      FAILURE);
+}
+
+TEST_F(CdmAdapterTest, CreateWebmSession) {
+  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
+
+  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
+  CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
+}
+
+TEST_F(CdmAdapterTest, CreateKeyIdsSession) {
+  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
+
+  // Don't include the trailing /0 from the string in the data passed in.
+  std::vector<uint8> key_id(kKeyIdAsJWK,
+                            kKeyIdAsJWK + arraysize(kKeyIdAsJWK) - 1);
+  CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, SUCCESS);
+}
+
+TEST_F(CdmAdapterTest, CreateCencSession) {
+  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
+
+  std::vector<uint8> key_id(kKeyIdAsPssh,
+                            kKeyIdAsPssh + arraysize(kKeyIdAsPssh));
+#if defined(USE_PROPRIETARY_CODECS)
+  CreateSessionAndExpect(EmeInitDataType::CENC, key_id, SUCCESS);
+#else
+  CreateSessionAndExpect(EmeInitDataType::CENC, key_id, FAILURE);
+#endif
+}
+
+TEST_F(CdmAdapterTest, CreateSessionWithBadData) {
+  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
+
+  // Use |kKeyId| but specify KEYIDS format.
+  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
+  CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, FAILURE);
+}
+
+TEST_F(CdmAdapterTest, LoadSession) {
+  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
+
+  // LoadSession() is not supported by AesDecryptor.
+  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
+  CreateSessionAndExpect(EmeInitDataType::KEYIDS, key_id, FAILURE);
+}
+
+TEST_F(CdmAdapterTest, UpdateSession) {
+  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
+
+  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
+  CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
+
+  UpdateSessionAndExpect(SessionId(), kKeyAsJWK, SUCCESS, true);
+}
+
+TEST_F(CdmAdapterTest, UpdateSessionWithBadData) {
+  InitializeAndExpect(ExternalClearKeyLibrary(), SUCCESS);
+
+  std::vector<uint8> key_id(kKeyId, kKeyId + arraysize(kKeyId));
+  CreateSessionAndExpect(EmeInitDataType::WEBM, key_id, SUCCESS);
+
+  UpdateSessionAndExpect(SessionId(), "random data", FAILURE, true);
+}
+
+}  // namespace media
diff --git a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
index f6c7781..61f0820 100644
--- a/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
+++ b/media/cdm/ppapi/external_clear_key/clear_key_cdm.cc
@@ -212,23 +212,15 @@
   }
 }
 
-template<typename Type>
-class ScopedResetter {
- public:
-  explicit ScopedResetter(Type* object) : object_(object) {}
-  ~ScopedResetter() { object_->Reset(); }
-
- private:
-  Type* const object_;
-};
-
 void INITIALIZE_CDM_MODULE() {
+  DVLOG(1) << __FUNCTION__;
 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
   av_register_all();
 #endif  // CLEAR_KEY_CDM_USE_FFMPEG_DECODER
 }
 
 void DeinitializeCdmModule() {
+  DVLOG(1) << __FUNCTION__;
 }
 
 void* CreateCdmInstance(int cdm_interface_version,
@@ -255,7 +247,8 @@
     return NULL;
 
   // TODO(jrummell): Obtain the proper origin for this instance.
-  return new media::ClearKeyCdm(host, key_system_string, GURL::EmptyGURL());
+  GURL empty_gurl;
+  return new media::ClearKeyCdm(host, key_system_string, empty_gurl);
 }
 
 const char* GetCdmVersion() {
diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h
index 299946b..7938a325 100644
--- a/media/ffmpeg/ffmpeg_common.h
+++ b/media/ffmpeg/ffmpeg_common.h
@@ -20,9 +20,16 @@
 // Include FFmpeg header files.
 extern "C" {
 // Disable deprecated features which result in spammy compile warnings.  This
-// list of defines must mirror those in the 'defines' section of the ffmpeg.gyp
-// file or the headers below will generate different structures.
-// None currently.
+// list of defines must mirror those in the 'defines' section of BUILD.gn file &
+// ffmpeg.gyp file or the headers below will generate different structures!
+#define FF_API_CONVERGENCE_DURATION 0
+// Upstream libavcodec/utils.c still uses the deprecated
+// av_dup_packet(), causing deprecation warnings.
+// The normal fix for such things is to disable the feature as below,
+// but the upstream code does not yet compile with it disabled.
+// (In this case, the fix is replacing the call with a new function.)
+// In the meantime, we directly disable those warnings in the C file.
+//#define FF_API_AVPACKET_OLD_API 0
 
 // Temporarily disable possible loss of data warning.
 // TODO(scherkus): fix and upstream the compiler warnings.
@@ -54,7 +61,7 @@
 
 inline void ScopedPtrAVFreePacket::operator()(void* x) const {
   AVPacket* packet = static_cast<AVPacket*>(x);
-  av_free_packet(packet);
+  av_packet_unref(packet);
   delete packet;
 }
 
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index b2b8a8a..2f5adaa 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -208,8 +208,8 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
 
   SelectDecoder();
@@ -220,7 +220,7 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -231,10 +231,10 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, IsNull()));
 
   SelectDecoder();
@@ -245,9 +245,9 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -258,8 +258,8 @@
   UseClearStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
 
   SelectDecoder();
@@ -269,7 +269,7 @@
   UseClearStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -280,8 +280,8 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _))
-      .WillOnce(RunCallback<1>(false));
+  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(false));
   EXPECT_CALL(*this, OnDecoderSelected(IsNull(), IsNull()));
 
   SelectDecoder();
@@ -292,7 +292,7 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -303,10 +303,10 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _))
-      .WillOnce(RunCallback<1>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(EncryptedConfig(), _, _))
-      .WillOnce(RunCallback<1>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(EncryptedConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, IsNull()));
 
   SelectDecoder();
@@ -317,9 +317,9 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _))
-      .WillOnce(RunCallback<1>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(EncryptedConfig(), _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(EncryptedConfig(), _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -349,8 +349,8 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, NotNull()));
 
   SelectDecoder();
@@ -361,7 +361,7 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -374,10 +374,10 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, NotNull()));
 
   SelectDecoder();
@@ -388,9 +388,9 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -408,8 +408,8 @@
 #else
   // A DecryptingDemuxerStream will be created. The clear decoder will be
   // initialized and returned.
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _))
-      .WillOnce(RunCallback<1>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
+      .WillOnce(RunCallback<2>(true));
   EXPECT_CALL(*this, OnDecoderSelected(NotNull(), NotNull()));
 #endif
 
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index cfe6a1c1..0f07b4a7 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -147,7 +147,7 @@
     EXPECT_EQ(GetParam().first_packet_pts, packet.pts);
     start_timestamp_ = ConvertFromTimeBase(
         reader_->GetAVStreamForTesting()->time_base, packet.pts);
-    av_free_packet(&packet);
+    av_packet_unref(&packet);
 
     // Seek back to the beginning.
     ASSERT_TRUE(reader_->SeekForTesting(start_timestamp_));
@@ -170,7 +170,7 @@
   void InitializeDecoderWithResult(const AudioDecoderConfig& config,
                                    bool success) {
     decoder_->Initialize(
-        config, NewExpectedBoolCB(success),
+        config, SetCdmReadyCB(), NewExpectedBoolCB(success),
         base::Bind(&AudioDecoderTest::OnDecoderOutput, base::Unretained(this)));
     base::RunLoop().RunUntilIdle();
   }
@@ -197,7 +197,7 @@
       SetDiscardPadding(&packet, buffer, GetParam().samples_per_second);
 
     // DecodeBuffer() shouldn't need the original packet since it uses the copy.
-    av_free_packet(&packet);
+    av_packet_unref(&packet);
     DecodeBuffer(buffer);
   }
 
diff --git a/media/filters/audio_file_reader.cc b/media/filters/audio_file_reader.cc
index 70b60d75..2cc4059 100644
--- a/media/filters/audio_file_reader.cc
+++ b/media/filters/audio_file_reader.cc
@@ -136,7 +136,7 @@
   while (current_frame < audio_bus->frames() && continue_decoding &&
          ReadPacket(&packet)) {
     // Make a shallow copy of packet so we can slide packet.data as frames are
-    // decoded from the packet; otherwise av_free_packet() will corrupt memory.
+    // decoded from the packet; otherwise av_packet_unref() will corrupt memory.
     AVPacket packet_temp = packet;
     do {
       // Reset frame to default values.
@@ -221,7 +221,7 @@
 
       current_frame += frames_read;
     } while (packet_temp.size > 0);
-    av_free_packet(&packet);
+    av_packet_unref(&packet);
   }
 
   // Zero any remaining frames.
@@ -257,11 +257,10 @@
 }
 
 bool AudioFileReader::ReadPacket(AVPacket* output_packet) {
-  while (av_read_frame(glue_->format_context(), output_packet) >= 0 &&
-         av_dup_packet(output_packet) >= 0) {
+  while (av_read_frame(glue_->format_context(), output_packet) >= 0) {
     // Skip packets from other streams.
     if (output_packet->stream_index != stream_index_) {
-      av_free_packet(output_packet);
+      av_packet_unref(output_packet);
       continue;
     }
     return true;
diff --git a/media/filters/audio_file_reader_unittest.cc b/media/filters/audio_file_reader_unittest.cc
index 1ca99327..1c2f2cd 100644
--- a/media/filters/audio_file_reader_unittest.cc
+++ b/media/filters/audio_file_reader_unittest.cc
@@ -73,7 +73,7 @@
           EXPECT_EQ(packet_md5_hashes_[j], md5_hash) << "j = " << j;
         }
 
-        av_free_packet(&packet);
+        av_packet_unref(&packet);
       }
       ASSERT_TRUE(reader_->SeekForTesting(start_timestamp));
     }
diff --git a/media/filters/decoder_selector.cc b/media/filters/decoder_selector.cc
index 0f99e79..4d06d9c 100644
--- a/media/filters/decoder_selector.cc
+++ b/media/filters/decoder_selector.cc
@@ -125,11 +125,10 @@
 template <DemuxerStream::Type StreamType>
 void DecoderSelector<StreamType>::InitializeDecryptingDecoder() {
   decoder_.reset(new typename StreamTraits::DecryptingDecoderType(
-      task_runner_, media_log_, set_cdm_ready_cb_,
-      waiting_for_decryption_key_cb_));
+      task_runner_, media_log_, waiting_for_decryption_key_cb_));
 
   DecoderStreamTraits<StreamType>::InitializeDecoder(
-      decoder_.get(), input_stream_,
+      decoder_.get(), input_stream_, set_cdm_ready_cb_,
       base::Bind(&DecoderSelector<StreamType>::DecryptingDecoderInitDone,
                  weak_ptr_factory_.GetWeakPtr()),
       output_cb_);
@@ -156,12 +155,11 @@
 
 template <DemuxerStream::Type StreamType>
 void DecoderSelector<StreamType>::InitializeDecryptingDemuxerStream() {
-  decrypted_stream_.reset(
-      new DecryptingDemuxerStream(task_runner_, media_log_, set_cdm_ready_cb_,
-                                  waiting_for_decryption_key_cb_));
+  decrypted_stream_.reset(new DecryptingDemuxerStream(
+      task_runner_, media_log_, waiting_for_decryption_key_cb_));
 
   decrypted_stream_->Initialize(
-      input_stream_,
+      input_stream_, set_cdm_ready_cb_,
       base::Bind(&DecoderSelector<StreamType>::DecryptingDemuxerStreamInitDone,
                  weak_ptr_factory_.GetWeakPtr()));
 }
@@ -203,7 +201,7 @@
   decoders_.weak_erase(decoders_.begin());
 
   DecoderStreamTraits<StreamType>::InitializeDecoder(
-      decoder_.get(), input_stream_,
+      decoder_.get(), input_stream_, set_cdm_ready_cb_,
       base::Bind(&DecoderSelector<StreamType>::DecoderInitDone,
                  weak_ptr_factory_.GetWeakPtr()),
       output_cb_);
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc
index 91a5b1e1..772f1266 100644
--- a/media/filters/decoder_stream.cc
+++ b/media/filters/decoder_stream.cc
@@ -516,8 +516,9 @@
   DCHECK_EQ(pending_decode_requests_, 0);
 
   state_ = STATE_REINITIALIZING_DECODER;
+  // Decoders should not need CDMs during reinitialization.
   DecoderStreamTraits<StreamType>::InitializeDecoder(
-      decoder_.get(), stream_,
+      decoder_.get(), stream_, SetCdmReadyCB(),
       base::Bind(&DecoderStream<StreamType>::OnDecoderReinitialized,
                  weak_factory_.GetWeakPtr()),
       base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady,
@@ -540,8 +541,8 @@
     // Reinitialization failed. Try to fall back to one of the remaining
     // decoders. This will consume at least one decoder so doing it more than
     // once is safe.
-    // For simplicity, don't attempt to fall back to a decryptor. Calling this
-    // with a null callback ensures that one won't be selected.
+    // For simplicity, don't attempt to fall back to a decrypting decoder.
+    // Calling this with a null callback ensures that one won't be selected.
     SelectDecoder(SetCdmReadyCB());
   } else {
     CompleteDecoderReinitialization(true);
diff --git a/media/filters/decoder_stream_traits.cc b/media/filters/decoder_stream_traits.cc
index 7583b172b..c40d69fa 100644
--- a/media/filters/decoder_stream_traits.cc
+++ b/media/filters/decoder_stream_traits.cc
@@ -21,10 +21,12 @@
 void DecoderStreamTraits<DemuxerStream::AUDIO>::InitializeDecoder(
     DecoderType* decoder,
     DemuxerStream* stream,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const InitCB& init_cb,
     const OutputCB& output_cb) {
   DCHECK(stream->audio_decoder_config().IsValidConfig());
-  decoder->Initialize(stream->audio_decoder_config(), init_cb, output_cb);
+  decoder->Initialize(stream->audio_decoder_config(), set_cdm_ready_cb, init_cb,
+                      output_cb);
 }
 
 void DecoderStreamTraits<DemuxerStream::AUDIO>::ReportStatistics(
@@ -47,12 +49,13 @@
 void DecoderStreamTraits<DemuxerStream::VIDEO>::InitializeDecoder(
     DecoderType* decoder,
     DemuxerStream* stream,
+    const SetCdmReadyCB& set_cdm_ready_cb,
     const InitCB& init_cb,
     const OutputCB& output_cb) {
   DCHECK(stream->video_decoder_config().IsValidConfig());
   decoder->Initialize(stream->video_decoder_config(),
                       stream->liveness() == DemuxerStream::LIVENESS_LIVE,
-                      init_cb, output_cb);
+                      set_cdm_ready_cb, init_cb, output_cb);
 }
 
 bool DecoderStreamTraits<DemuxerStream::VIDEO>::NeedsBitstreamConversion(
diff --git a/media/filters/decoder_stream_traits.h b/media/filters/decoder_stream_traits.h
index 8caf2df1..920aefc 100644
--- a/media/filters/decoder_stream_traits.h
+++ b/media/filters/decoder_stream_traits.h
@@ -5,6 +5,7 @@
 #ifndef MEDIA_FILTERS_DECODER_STREAM_TRAITS_H_
 #define MEDIA_FILTERS_DECODER_STREAM_TRAITS_H_
 
+#include "media/base/cdm_context.h"
 #include "media/base/demuxer_stream.h"
 #include "media/base/pipeline_status.h"
 
@@ -32,6 +33,7 @@
   static std::string ToString();
   static void InitializeDecoder(DecoderType* decoder,
                                 DemuxerStream* stream,
+                                const SetCdmReadyCB& set_cdm_ready_cb,
                                 const InitCB& init_cb,
                                 const OutputCB& output_cb);
   static bool NeedsBitstreamConversion(DecoderType* decoder) { return false; }
@@ -51,6 +53,7 @@
   static std::string ToString();
   static void InitializeDecoder(DecoderType* decoder,
                                 DemuxerStream* stream,
+                                const SetCdmReadyCB& set_cdm_ready_cb,
                                 const InitCB& init_cb,
                                 const OutputCB& output_cb);
   static bool NeedsBitstreamConversion(DecoderType* decoder);
diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc
index 1c620a7..42f1939 100644
--- a/media/filters/decrypting_audio_decoder.cc
+++ b/media/filters/decrypting_audio_decoder.cc
@@ -34,13 +34,11 @@
 DecryptingAudioDecoder::DecryptingAudioDecoder(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<MediaLog>& media_log,
-    const SetCdmReadyCB& set_cdm_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
-      set_cdm_ready_cb_(set_cdm_ready_cb),
       decryptor_(NULL),
       key_added_while_decode_pending_(false),
       weak_factory_(this) {}
@@ -50,6 +48,7 @@
 }
 
 void DecryptingAudioDecoder::Initialize(const AudioDecoderConfig& config,
+                                        const SetCdmReadyCB& set_cdm_ready_cb,
                                         const InitCB& init_cb,
                                         const OutputCB& output_cb) {
   DVLOG(2) << "Initialize()";
@@ -76,7 +75,9 @@
   config_ = config;
 
   if (state_ == kUninitialized) {
+    DCHECK(!set_cdm_ready_cb.is_null());
     state_ = kDecryptorRequested;
+    set_cdm_ready_cb_ = set_cdm_ready_cb;
     set_cdm_ready_cb_.Run(BindToCurrentLoop(
         base::Bind(&DecryptingAudioDecoder::SetCdm, weak_this_)));
     return;
diff --git a/media/filters/decrypting_audio_decoder.h b/media/filters/decrypting_audio_decoder.h
index b566fdd..43db799 100644
--- a/media/filters/decrypting_audio_decoder.h
+++ b/media/filters/decrypting_audio_decoder.h
@@ -35,13 +35,13 @@
   DecryptingAudioDecoder(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<MediaLog>& media_log,
-      const SetCdmReadyCB& set_cdm_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
   ~DecryptingAudioDecoder() override;
 
   // AudioDecoder implementation.
   std::string GetDisplayName() const override;
   void Initialize(const AudioDecoderConfig& config,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index 016e09a4c..733a6e6 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -64,8 +64,6 @@
       : decoder_(new DecryptingAudioDecoder(
             message_loop_.task_runner(),
             new MediaLog(),
-            base::Bind(&DecryptingAudioDecoderTest::RequestCdmNotification,
-                       base::Unretained(this)),
             base::Bind(&DecryptingAudioDecoderTest::OnWaitingForDecryptionKey,
                        base::Unretained(this)))),
         cdm_context_(new StrictMock<MockCdmContext>()),
@@ -96,9 +94,12 @@
                                                     kNoTimestamp());
     decoded_frame_list_.push_back(decoded_frame_);
 
-    decoder_->Initialize(config, NewExpectedBoolCB(success),
-                         base::Bind(&DecryptingAudioDecoderTest::FrameReady,
-                                    base::Unretained(this)));
+    decoder_->Initialize(
+        config, base::Bind(&DecryptingAudioDecoderTest::RequestCdmNotification,
+                           base::Unretained(this)),
+        NewExpectedBoolCB(success),
+        base::Bind(&DecryptingAudioDecoderTest::FrameReady,
+                   base::Unretained(this)));
     message_loop_.RunUntilIdle();
   }
 
@@ -145,7 +146,7 @@
         .WillOnce(RunCallback<1>(true));
     EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
               .WillOnce(SaveArg<1>(&key_added_cb_));
-    decoder_->Initialize(new_config, NewExpectedBoolCB(true),
+    decoder_->Initialize(new_config, SetCdmReadyCB(), NewExpectedBoolCB(true),
                          base::Bind(&DecryptingAudioDecoderTest::FrameReady,
                                     base::Unretained(this)));
   }
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index 2189545..883d4c1 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -28,14 +28,12 @@
 DecryptingDemuxerStream::DecryptingDemuxerStream(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<MediaLog>& media_log,
-    const SetCdmReadyCB& set_cdm_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
       demuxer_stream_(NULL),
-      set_cdm_ready_cb_(set_cdm_ready_cb),
       decryptor_(NULL),
       key_added_while_decrypt_pending_(false),
       weak_factory_(this) {}
@@ -45,6 +43,7 @@
 }
 
 void DecryptingDemuxerStream::Initialize(DemuxerStream* stream,
+                                         const SetCdmReadyCB& set_cdm_ready_cb,
                                          const PipelineStatusCB& status_cb) {
   DVLOG(2) << __FUNCTION__;
   DCHECK(task_runner_->BelongsToCurrentThread());
@@ -53,6 +52,7 @@
   DCHECK(!demuxer_stream_);
   weak_this_ = weak_factory_.GetWeakPtr();
   demuxer_stream_ = stream;
+  set_cdm_ready_cb_ = set_cdm_ready_cb;
   init_cb_ = BindToCurrentLoop(status_cb);
 
   InitializeDecoderConfig();
diff --git a/media/filters/decrypting_demuxer_stream.h b/media/filters/decrypting_demuxer_stream.h
index 88f86a2..c128cf7 100644
--- a/media/filters/decrypting_demuxer_stream.h
+++ b/media/filters/decrypting_demuxer_stream.h
@@ -33,13 +33,14 @@
   DecryptingDemuxerStream(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<MediaLog>& media_log,
-      const SetCdmReadyCB& set_cdm_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
 
   // Cancels all pending operations immediately and fires all pending callbacks.
   ~DecryptingDemuxerStream() override;
 
-  void Initialize(DemuxerStream* stream, const PipelineStatusCB& status_cb);
+  void Initialize(DemuxerStream* stream,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
+                  const PipelineStatusCB& status_cb);
 
   // Cancels all pending operations and fires all pending callbacks. If in
   // kPendingDemuxerRead or kPendingDecrypt state, waits for the pending
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc
index 7275029..87c5d5e 100644
--- a/media/filters/decrypting_demuxer_stream_unittest.cc
+++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -63,8 +63,6 @@
       : demuxer_stream_(new DecryptingDemuxerStream(
             message_loop_.task_runner(),
             new MediaLog(),
-            base::Bind(&DecryptingDemuxerStreamTest::RequestCdmNotification,
-                       base::Unretained(this)),
             base::Bind(&DecryptingDemuxerStreamTest::OnWaitingForDecryptionKey,
                        base::Unretained(this)))),
         cdm_context_(new StrictMock<MockCdmContext>()),
@@ -88,16 +86,22 @@
   void InitializeAudioAndExpectStatus(const AudioDecoderConfig& config,
                                       PipelineStatus status) {
     input_audio_stream_->set_audio_decoder_config(config);
-    demuxer_stream_->Initialize(input_audio_stream_.get(),
-                                NewExpectedStatusCB(status));
+    demuxer_stream_->Initialize(
+        input_audio_stream_.get(),
+        base::Bind(&DecryptingDemuxerStreamTest::RequestCdmNotification,
+                   base::Unretained(this)),
+        NewExpectedStatusCB(status));
     message_loop_.RunUntilIdle();
   }
 
   void InitializeVideoAndExpectStatus(const VideoDecoderConfig& config,
                                       PipelineStatus status) {
     input_video_stream_->set_video_decoder_config(config);
-    demuxer_stream_->Initialize(input_video_stream_.get(),
-                                NewExpectedStatusCB(status));
+    demuxer_stream_->Initialize(
+        input_video_stream_.get(),
+        base::Bind(&DecryptingDemuxerStreamTest::RequestCdmNotification,
+                   base::Unretained(this)),
+        NewExpectedStatusCB(status));
     message_loop_.RunUntilIdle();
   }
 
diff --git a/media/filters/decrypting_video_decoder.cc b/media/filters/decrypting_video_decoder.cc
index ac6a244..9ec48c9 100644
--- a/media/filters/decrypting_video_decoder.cc
+++ b/media/filters/decrypting_video_decoder.cc
@@ -23,13 +23,11 @@
 DecryptingVideoDecoder::DecryptingVideoDecoder(
     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
     const scoped_refptr<MediaLog>& media_log,
-    const SetCdmReadyCB& set_cdm_ready_cb,
     const base::Closure& waiting_for_decryption_key_cb)
     : task_runner_(task_runner),
       media_log_(media_log),
       state_(kUninitialized),
       waiting_for_decryption_key_cb_(waiting_for_decryption_key_cb),
-      set_cdm_ready_cb_(set_cdm_ready_cb),
       decryptor_(NULL),
       key_added_while_decode_pending_(false),
       trace_id_(0),
@@ -41,6 +39,7 @@
 
 void DecryptingVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                         bool /* low_delay */,
+                                        const SetCdmReadyCB& set_cdm_ready_cb,
                                         const InitCB& init_cb,
                                         const OutputCB& output_cb) {
   DVLOG(2) << "Initialize()";
@@ -59,7 +58,9 @@
   config_ = config;
 
   if (state_ == kUninitialized) {
+    DCHECK(!set_cdm_ready_cb.is_null());
     state_ = kDecryptorRequested;
+    set_cdm_ready_cb_ = set_cdm_ready_cb;
     set_cdm_ready_cb_.Run(BindToCurrentLoop(
         base::Bind(&DecryptingVideoDecoder::SetCdm, weak_this_)));
     return;
diff --git a/media/filters/decrypting_video_decoder.h b/media/filters/decrypting_video_decoder.h
index 1ac97b81..0651edb 100644
--- a/media/filters/decrypting_video_decoder.h
+++ b/media/filters/decrypting_video_decoder.h
@@ -31,7 +31,6 @@
   DecryptingVideoDecoder(
       const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
       const scoped_refptr<MediaLog>& media_log,
-      const SetCdmReadyCB& set_cdm_ready_cb,
       const base::Closure& waiting_for_decryption_key_cb);
   ~DecryptingVideoDecoder() override;
 
@@ -39,6 +38,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/decrypting_video_decoder_unittest.cc b/media/filters/decrypting_video_decoder_unittest.cc
index dba3e2e8..5fcb74e1 100644
--- a/media/filters/decrypting_video_decoder_unittest.cc
+++ b/media/filters/decrypting_video_decoder_unittest.cc
@@ -57,8 +57,6 @@
       : decoder_(new DecryptingVideoDecoder(
             message_loop_.task_runner(),
             new MediaLog(),
-            base::Bind(&DecryptingVideoDecoderTest::RequestCdmNotification,
-                       base::Unretained(this)),
             base::Bind(&DecryptingVideoDecoderTest::OnWaitingForDecryptionKey,
                        base::Unretained(this)))),
         cdm_context_(new StrictMock<MockCdmContext>()),
@@ -97,9 +95,13 @@
   // can succeed or fail.
   void InitializeAndExpectResult(const VideoDecoderConfig& config,
                                  bool success) {
-    decoder_->Initialize(config, false, NewExpectedBoolCB(success),
-                         base::Bind(&DecryptingVideoDecoderTest::FrameReady,
-                                    base::Unretained(this)));
+    decoder_->Initialize(
+        config, false,
+        base::Bind(&DecryptingVideoDecoderTest::RequestCdmNotification,
+                   base::Unretained(this)),
+        NewExpectedBoolCB(success),
+        base::Bind(&DecryptingVideoDecoderTest::FrameReady,
+                   base::Unretained(this)));
     message_loop_.RunUntilIdle();
   }
 
@@ -428,10 +430,13 @@
   CdmReadyCB cdm_ready_cb;
   EXPECT_CALL(*this, RequestCdmNotification(_))
       .WillOnce(SaveArg<0>(&cdm_ready_cb));
-  decoder_->Initialize(TestVideoConfig::NormalEncrypted(), false,
-                       NewExpectedBoolCB(false),
-                       base::Bind(&DecryptingVideoDecoderTest::FrameReady,
-                                  base::Unretained(this)));
+  decoder_->Initialize(
+      TestVideoConfig::NormalEncrypted(), false,
+      base::Bind(&DecryptingVideoDecoderTest::RequestCdmNotification,
+                 base::Unretained(this)),
+      NewExpectedBoolCB(false),
+      base::Bind(&DecryptingVideoDecoderTest::FrameReady,
+                 base::Unretained(this)));
   message_loop_.RunUntilIdle();
   // |cdm_ready_cb| is saved but not called here.
   EXPECT_FALSE(cdm_ready_cb.is_null());
diff --git a/media/filters/fake_video_decoder.cc b/media/filters/fake_video_decoder.cc
index 00264ea..bbd68b4 100644
--- a/media/filters/fake_video_decoder.cc
+++ b/media/filters/fake_video_decoder.cc
@@ -46,6 +46,7 @@
 
 void FakeVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                   bool low_delay,
+                                  const SetCdmReadyCB& set_cdm_ready_cb,
                                   const InitCB& init_cb,
                                   const OutputCB& output_cb) {
   DCHECK(thread_checker_.CalledOnValidThread());
diff --git a/media/filters/fake_video_decoder.h b/media/filters/fake_video_decoder.h
index e784387..14d19569 100644
--- a/media/filters/fake_video_decoder.h
+++ b/media/filters/fake_video_decoder.h
@@ -44,6 +44,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/fake_video_decoder_unittest.cc b/media/filters/fake_video_decoder_unittest.cc
index 610987d20..533022c 100644
--- a/media/filters/fake_video_decoder_unittest.cc
+++ b/media/filters/fake_video_decoder_unittest.cc
@@ -50,7 +50,7 @@
   void InitializeWithConfigAndExpectResult(const VideoDecoderConfig& config,
                                            bool success) {
     decoder_->Initialize(
-        config, false, NewExpectedBoolCB(success),
+        config, false, SetCdmReadyCB(), NewExpectedBoolCB(success),
         base::Bind(&FakeVideoDecoderTest::FrameReady, base::Unretained(this)));
     message_loop_.RunUntilIdle();
     current_config_ = config;
diff --git a/media/filters/ffmpeg_aac_bitstream_converter.cc b/media/filters/ffmpeg_aac_bitstream_converter.cc
index 616cd1f..a0f175f 100644
--- a/media/filters/ffmpeg_aac_bitstream_converter.cc
+++ b/media/filters/ffmpeg_aac_bitstream_converter.cc
@@ -230,7 +230,7 @@
   av_packet_copy_props(&dest_packet, packet);
 
   // Release the old packet.
-  av_free_packet(packet);
+  av_packet_unref(packet);
   *packet = dest_packet;  // Finally, replace the values in the input packet.
 
   return true;
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc
index a498c17..206f971 100644
--- a/media/filters/ffmpeg_audio_decoder.cc
+++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -146,6 +146,7 @@
 }
 
 void FFmpegAudioDecoder::Initialize(const AudioDecoderConfig& config,
+                                    const SetCdmReadyCB& /* set_cdm_ready_cb */,
                                     const InitCB& init_cb,
                                     const OutputCB& output_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/filters/ffmpeg_audio_decoder.h b/media/filters/ffmpeg_audio_decoder.h
index a394e7d..c3bf60ca 100644
--- a/media/filters/ffmpeg_audio_decoder.h
+++ b/media/filters/ffmpeg_audio_decoder.h
@@ -38,6 +38,7 @@
   // AudioDecoder implementation.
   std::string GetDisplayName() const override;
   void Initialize(const AudioDecoderConfig& config,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 81bd2e9..08cf092 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -862,7 +862,7 @@
   // this does not increase the amount of data downloaded.  The default value
   // is 5 AV_TIME_BASE units (1 second each), which prevents some oddly muxed
   // streams from being detected properly; this value was chosen arbitrarily.
-  format_context->max_analyze_duration2 = 60 * AV_TIME_BASE;
+  format_context->max_analyze_duration = 60 * AV_TIME_BASE;
 
   // Open the AVFormatContext using our glue layer.
   CHECK(blocking_thread_.Start());
diff --git a/media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc b/media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc
index b836db9..dd1b3d7 100644
--- a/media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc
+++ b/media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.cc
@@ -71,7 +71,7 @@
     configuration_processed_ = true;
 
   // At the end we must destroy the old packet.
-  av_free_packet(packet);
+  av_packet_unref(packet);
   *packet = dest_packet;  // Finally, replace the values in the input packet.
 
   return true;
diff --git a/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc b/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
index a643f53..06327a4 100644
--- a/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
+++ b/media/filters/ffmpeg_h265_to_annex_b_bitstream_converter.cc
@@ -84,7 +84,7 @@
   memcpy(dest_packet.data, &input_frame[0], input_frame.size());
 
   // At the end we must destroy the old packet.
-  av_free_packet(packet);
+  av_packet_unref(packet);
   *packet = dest_packet;  // Finally, replace the values in the input packet.
 
   return true;
diff --git a/media/filters/ffmpeg_video_decoder.cc b/media/filters/ffmpeg_video_decoder.cc
index 93e9425..5c419f5f 100644
--- a/media/filters/ffmpeg_video_decoder.cc
+++ b/media/filters/ffmpeg_video_decoder.cc
@@ -165,6 +165,7 @@
 
 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                     bool low_delay,
+                                    const SetCdmReadyCB& /* set_cdm_ready_cb */,
                                     const InitCB& init_cb,
                                     const OutputCB& output_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/filters/ffmpeg_video_decoder.h b/media/filters/ffmpeg_video_decoder.h
index 53999aa..8477ad5 100644
--- a/media/filters/ffmpeg_video_decoder.h
+++ b/media/filters/ffmpeg_video_decoder.h
@@ -41,6 +41,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index 44f6852d..307c0f673 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -71,7 +71,8 @@
 
   void InitializeWithConfigWithResult(const VideoDecoderConfig& config,
                                       bool success) {
-    decoder_->Initialize(config, false, NewExpectedBoolCB(success),
+    decoder_->Initialize(config, false, SetCdmReadyCB(),
+                         NewExpectedBoolCB(success),
                          base::Bind(&FFmpegVideoDecoderTest::FrameReady,
                                     base::Unretained(this)));
     message_loop_.RunUntilIdle();
diff --git a/media/filters/gpu_video_decoder.cc b/media/filters/gpu_video_decoder.cc
index 90decc76..b791be7 100644
--- a/media/filters/gpu_video_decoder.cc
+++ b/media/filters/gpu_video_decoder.cc
@@ -121,8 +121,10 @@
   return kDecoderName;
 }
 
+// TODO(xhwang): Support CDM setting using |set_cdm_ready_cb|.
 void GpuVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                  bool /* low_delay */,
+                                 const SetCdmReadyCB& /* set_cdm_ready_cb */,
                                  const InitCB& init_cb,
                                  const OutputCB& output_cb) {
   DVLOG(3) << "Initialize()";
diff --git a/media/filters/gpu_video_decoder.h b/media/filters/gpu_video_decoder.h
index ac4d0e0c..271d2fb 100644
--- a/media/filters/gpu_video_decoder.h
+++ b/media/filters/gpu_video_decoder.h
@@ -47,6 +47,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/opus_audio_decoder.cc b/media/filters/opus_audio_decoder.cc
index 454dc29..d1e759bf 100644
--- a/media/filters/opus_audio_decoder.cc
+++ b/media/filters/opus_audio_decoder.cc
@@ -132,6 +132,7 @@
 }
 
 void OpusAudioDecoder::Initialize(const AudioDecoderConfig& config,
+                                  const SetCdmReadyCB& /* set_cdm_ready_cb */,
                                   const InitCB& init_cb,
                                   const OutputCB& output_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/filters/opus_audio_decoder.h b/media/filters/opus_audio_decoder.h
index 116fcb0be..40956568 100644
--- a/media/filters/opus_audio_decoder.h
+++ b/media/filters/opus_audio_decoder.h
@@ -33,6 +33,7 @@
   // AudioDecoder implementation.
   std::string GetDisplayName() const override;
   void Initialize(const AudioDecoderConfig& config,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/filters/video_decoder_selector_unittest.cc b/media/filters/video_decoder_selector_unittest.cc
index 087661df..27968456 100644
--- a/media/filters/video_decoder_selector_unittest.cc
+++ b/media/filters/video_decoder_selector_unittest.cc
@@ -205,8 +205,8 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
 
   SelectDecoder();
@@ -217,7 +217,7 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -228,10 +228,10 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, IsNull()));
 
   SelectDecoder();
@@ -242,9 +242,9 @@
   UseClearStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -255,8 +255,8 @@
   UseClearStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, IsNull()));
 
   SelectDecoder();
@@ -266,7 +266,7 @@
   UseClearStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -277,8 +277,8 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(false));
+  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(false));
   EXPECT_CALL(*this, OnDecoderSelected(IsNull(), IsNull()));
 
   SelectDecoder();
@@ -289,7 +289,7 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kNoDecryptor, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -300,10 +300,10 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(EncryptedConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(EncryptedConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, IsNull()));
 
   SelectDecoder();
@@ -314,9 +314,9 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kNoDecryptor, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(EncryptedConfig(), _, _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(EncryptedConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(EncryptedConfig(), _, _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -348,8 +348,8 @@
 
   // Since we use DecryptingDemuxerStream, the decoder will be initialized with
   // a clear config.
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_1_, NotNull()));
 
   SelectDecoder();
@@ -360,7 +360,7 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 1);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -373,10 +373,10 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(true));
   EXPECT_CALL(*this, OnDecoderSelected(decoder_2_, NotNull()));
 
   SelectDecoder();
@@ -387,9 +387,9 @@
   UseEncryptedStream();
   InitializeDecoderSelector(kDecryptOnly, 2);
 
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(false));
-  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(false));
+  EXPECT_CALL(*decoder_2_, Initialize(ClearConfig(), _, _, _, _));
 
   SelectDecoderAndDestroy();
 }
@@ -407,8 +407,8 @@
 #else
   // A DecryptingDemuxerStream will be created. The clear decoder will be
   // initialized and returned.
-  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _))
-      .WillOnce(RunCallback<2>(true));
+  EXPECT_CALL(*decoder_1_, Initialize(ClearConfig(), _, _, _, _))
+      .WillOnce(RunCallback<3>(true));
   EXPECT_CALL(*this, OnDecoderSelected(NotNull(), NotNull()));
 #endif
 
diff --git a/media/filters/vpx_video_decoder.cc b/media/filters/vpx_video_decoder.cc
index fc839141..0a14d3e 100644
--- a/media/filters/vpx_video_decoder.cc
+++ b/media/filters/vpx_video_decoder.cc
@@ -278,6 +278,7 @@
 
 void VpxVideoDecoder::Initialize(const VideoDecoderConfig& config,
                                  bool low_delay,
+                                 const SetCdmReadyCB& /* set_cdm_ready_cb */,
                                  const InitCB& init_cb,
                                  const OutputCB& output_cb) {
   DCHECK(task_runner_->BelongsToCurrentThread());
diff --git a/media/filters/vpx_video_decoder.h b/media/filters/vpx_video_decoder.h
index bbf9895..5bbc086d 100644
--- a/media/filters/vpx_video_decoder.h
+++ b/media/filters/vpx_video_decoder.h
@@ -35,6 +35,7 @@
   std::string GetDisplayName() const override;
   void Initialize(const VideoDecoderConfig& config,
                   bool low_delay,
+                  const SetCdmReadyCB& set_cdm_ready_cb,
                   const InitCB& init_cb,
                   const OutputCB& output_cb) override;
   void Decode(const scoped_refptr<DecoderBuffer>& buffer,
diff --git a/media/media.gyp b/media/media.gyp
index 26760c5d..b56a23b 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -1389,6 +1389,15 @@
             'filters/decrypting_video_decoder_unittest.cc',
           ],
         }],
+        # If ExternalClearKey is built, we can test CdmAdapter.
+        ['enable_pepper_cdms == 1', {
+          'dependencies': [
+            'clearkeycdm',
+          ],
+          'sources': [
+            'cdm/cdm_adapter_unittest.cc',
+          ],
+        }],
         ['target_arch != "arm" and chromeos == 1 and use_x11 == 1', {
           'sources': [
             'filters/h264_bitstream_buffer_unittest.cc',
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index 0dd3969..d434548a 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -54,7 +54,7 @@
 static int kOutputSamplesPerSecond = 10000;
 
 ACTION_P(EnterPendingDecoderInitStateAction, test) {
-  test->EnterPendingDecoderInitState(arg1);
+  test->EnterPendingDecoderInitState(arg2);
 }
 
 class AudioRendererImplTest : public ::testing::Test {
@@ -109,8 +109,8 @@
   }
 
   void ExpectUnsupportedAudioDecoder() {
-    EXPECT_CALL(*decoder_, Initialize(_, _, _))
-        .WillOnce(DoAll(SaveArg<2>(&output_cb_), RunCallback<1>(false)));
+    EXPECT_CALL(*decoder_, Initialize(_, _, _, _))
+        .WillOnce(DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(false)));
   }
 
   void OnStatistics(const PipelineStatistics& stats) {
@@ -136,8 +136,8 @@
   }
 
   void Initialize() {
-    EXPECT_CALL(*decoder_, Initialize(_, _, _))
-        .WillOnce(DoAll(SaveArg<2>(&output_cb_), RunCallback<1>(true)));
+    EXPECT_CALL(*decoder_, Initialize(_, _, _, _))
+        .WillOnce(DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(true)));
     InitializeWithStatus(PIPELINE_OK);
 
     next_timestamp_.reset(new AudioTimestampHelper(kInputSamplesPerSecond));
@@ -155,7 +155,8 @@
   }
 
   void InitializeAndDestroy() {
-    EXPECT_CALL(*decoder_, Initialize(_, _, _)).WillOnce(RunCallback<1>(true));
+    EXPECT_CALL(*decoder_, Initialize(_, _, _, _))
+        .WillOnce(RunCallback<2>(true));
 
     WaitableMessageLoopEvent event;
     InitializeRenderer(event.GetPipelineStatusCB());
@@ -168,7 +169,7 @@
   }
 
   void InitializeAndDestroyDuringDecoderInit() {
-    EXPECT_CALL(*decoder_, Initialize(_, _, _))
+    EXPECT_CALL(*decoder_, Initialize(_, _, _, _))
         .WillOnce(EnterPendingDecoderInitStateAction(this));
 
     WaitableMessageLoopEvent event;
diff --git a/media/renderers/video_renderer_impl_unittest.cc b/media/renderers/video_renderer_impl_unittest.cc
index 74d9a1e6..a40a4d7 100644
--- a/media/renderers/video_renderer_impl_unittest.cc
+++ b/media/renderers/video_renderer_impl_unittest.cc
@@ -114,9 +114,9 @@
                       bool expect_to_success) {
     if (low_delay)
       demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE);
-    EXPECT_CALL(*decoder_, Initialize(_, _, _, _))
+    EXPECT_CALL(*decoder_, Initialize(_, _, _, _, _))
         .WillOnce(
-            DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(expect_to_success)));
+            DoAll(SaveArg<4>(&output_cb_), RunCallback<3>(expect_to_success)));
     EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
     renderer_->Initialize(
         &demuxer_stream_, status_cb, SetCdmReadyCB(),
diff --git a/media/video/video_decode_accelerator.cc b/media/video/video_decode_accelerator.cc
index 6ffbda5..0c6b2b9 100644
--- a/media/video/video_decode_accelerator.cc
+++ b/media/video/video_decode_accelerator.cc
@@ -9,8 +9,16 @@
 
 namespace media {
 
+void VideoDecodeAccelerator::Client::NotifyCdmAttached(bool success) {
+  NOTREACHED() << "By default CDM is not supported.";
+}
+
 VideoDecodeAccelerator::~VideoDecodeAccelerator() {}
 
+void VideoDecodeAccelerator::SetCdm(int cdm_id) {
+  NOTREACHED() << "By default CDM is not supported.";
+}
+
 bool VideoDecodeAccelerator::CanDecodeOnIOThread() {
   // GPU process subclasses must override this.
   LOG(FATAL) << "This should only get called in the GPU process";
diff --git a/media/video/video_decode_accelerator.h b/media/video/video_decode_accelerator.h
index 2b71d65a..a53e352b 100644
--- a/media/video/video_decode_accelerator.h
+++ b/media/video/video_decode_accelerator.h
@@ -60,6 +60,11 @@
   // implements.
   class MEDIA_EXPORT Client {
    public:
+    // SetCdm completion callback to indicate whether the CDM is successfully
+    // attached to the decoder. The default implementation is a no-op since most
+    // VDAs don't support encrypted video.
+    virtual void NotifyCdmAttached(bool success);
+
     // Callback to tell client how many and what size of buffers to provide.
     // Note that the actual count provided through AssignPictureBuffers() can be
     // larger than the value requested.
@@ -97,12 +102,25 @@
   // Initializes the video decoder with specific configuration.  Called once per
   // decoder construction.  This call is synchronous and returns true iff
   // initialization is successful.
+  //
+  // For encrpyted video, the decoder needs a CDM to be able to decode encrypted
+  // buffers. SetCdm() should be called after Initialize() to set such a CDM.
+  // Client::NotifyCdmAttached() will then be called to indicate whether the CDM
+  // is successfully attached to the decoder. Only when a CDM is successfully
+  // attached can we start to decode.
+  //
   // Parameters:
   //  |profile| is the video stream's format profile.
-  //  |client| is the client of this video decoder.  The provided pointer must
-  //  be valid until Destroy() is called.
+  //  |client| is the client of this video decoder. Does not take ownership of
+  //  |client| which must be valid until Destroy() is called.
   virtual bool Initialize(VideoCodecProfile profile, Client* client) = 0;
 
+  // Sets a CDM to be used by the decoder to decode encrypted buffers.
+  // Client::NotifyCdmAttached() will then be called to indicate whether the CDM
+  // is successfully attached to the decoder. The default implementation is a
+  // no-op since most VDAs don't support encrypted video.
+  virtual void SetCdm(int cdm_id);
+
   // Decodes given bitstream buffer that contains at most one frame.  Once
   // decoder is done with processing |bitstream_buffer| it will call
   // NotifyEndOfBitstreamBuffer() with the bitstream buffer id.
diff --git a/mojo/edk/embedder/BUILD.gn b/mojo/edk/embedder/BUILD.gn
index feb1b63..4b29824 100644
--- a/mojo/edk/embedder/BUILD.gn
+++ b/mojo/edk/embedder/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../mojo_edk.gni")
-
-mojo_edk_source_set("embedder") {
+source_set("embedder") {
   # This isn't really a standalone target; it must be linked into the
   # mojo_system_impl component.
   visibility = [
@@ -32,7 +30,7 @@
     "MOJO_SYSTEM_IMPLEMENTATION",
   ]
 
-  configs = [ "//mojo/edk/system:system_config" ]
+  configs += [ "//mojo/edk/system:system_config" ]
 
   public_deps = [
     ":delegates",
@@ -45,7 +43,7 @@
   ]
 }
 
-mojo_edk_source_set("platform") {
+source_set("platform") {
   # This isn't really a standalone target; it must be linked into the
   # mojo_system_impl component.
   visibility = [
@@ -80,7 +78,7 @@
 
   defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
 
-  configs = [ "//mojo/edk/system:system_config" ]
+  configs += [ "//mojo/edk/system:system_config" ]
 
   public_deps = [
     "//mojo/public/cpp/system",
@@ -95,7 +93,7 @@
   }
 }
 
-mojo_edk_source_set("delegates") {
+source_set("delegates") {
   # This isn't really a standalone target; it must be linked into the
   # mojo_system_impl component.
   visibility = [
@@ -109,7 +107,7 @@
 
   defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
 
-  configs = [ "//mojo/edk/system:system_config" ]
+  configs += [ "//mojo/edk/system:system_config" ]
 
   public_deps = [
     "//mojo/public/cpp/system",
@@ -117,7 +115,7 @@
 }
 
 # TODO(use_chrome_edk): remove "2"
-mojo_edk_source_set("embedder_unittests2") {
+source_set("embedder_unittests2") {
   testonly = true
 
   # TODO(use_chrome_edk): remove "2". Also enable this visibility check when we
diff --git a/mojo/edk/embedder/embedder_unittest.cc b/mojo/edk/embedder/embedder_unittest.cc
index f53e440..60a2b801 100644
--- a/mojo/edk/embedder/embedder_unittest.cc
+++ b/mojo/edk/embedder/embedder_unittest.cc
@@ -465,6 +465,7 @@
 }
 
 MOJO_MULTIPROCESS_TEST_CHILD_TEST(MultiprocessChannelsClient) {
+  base::MessageLoop message_loop;
   ScopedPlatformHandle client_platform_handle =
       test::MultiprocessTestHelper::client_platform_handle.Pass();
   EXPECT_TRUE(client_platform_handle.is_valid());
diff --git a/mojo/edk/embedder/platform_channel_pair_win.cc b/mojo/edk/embedder/platform_channel_pair_win.cc
index 8ba325a..f7788ad 100644
--- a/mojo/edk/embedder/platform_channel_pair_win.cc
+++ b/mojo/edk/embedder/platform_channel_pair_win.cc
@@ -89,9 +89,8 @@
   DCHECK(handle_passing_info);
   DCHECK(client_handle_.is_valid());
 
-  CHECK_GE(base::win::GetVersion(), base::win::VERSION_VISTA);
-
-  handle_passing_info->push_back(client_handle_.get().handle);
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA)
+    handle_passing_info->push_back(client_handle_.get().handle);
 
   // Log a warning if the command line already has the switch, but "clobber" it
   // anyway, since it's reasonably likely that all the switches were just copied
diff --git a/mojo/edk/embedder/simple_platform_shared_buffer_unittest.cc b/mojo/edk/embedder/simple_platform_shared_buffer_unittest.cc
index a0e915e..27c3bf5b 100644
--- a/mojo/edk/embedder/simple_platform_shared_buffer_unittest.cc
+++ b/mojo/edk/embedder/simple_platform_shared_buffer_unittest.cc
@@ -8,9 +8,14 @@
 
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/sys_info.h"
 #include "mojo/public/cpp/system/macros.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 namespace mojo {
 namespace edk {
 namespace {
@@ -128,13 +133,15 @@
 TEST(SimplePlatformSharedBufferTest, TooBig) {
   // If |size_t| is 32-bit, it's quite possible/likely that |Create()| succeeds
   // (since it only involves creating a 4 GB file).
-  const size_t kMaxSizeT = std::numeric_limits<size_t>::max();
+  size_t max_size = std::numeric_limits<size_t>::max();
+  if (max_size > static_cast<size_t>(base::SysInfo::AmountOfVirtualMemory()))
+    max_size = static_cast<size_t>(base::SysInfo::AmountOfVirtualMemory());
   scoped_refptr<SimplePlatformSharedBuffer> buffer(
-      SimplePlatformSharedBuffer::Create(kMaxSizeT));
+      SimplePlatformSharedBuffer::Create(max_size));
   // But, assuming |sizeof(size_t) == sizeof(void*)|, mapping all of it should
   // always fail.
   if (buffer)
-    EXPECT_FALSE(buffer->Map(0, kMaxSizeT));
+    EXPECT_FALSE(buffer->Map(0, max_size));
 }
 
 // Tests that separate mappings get distinct addresses.
diff --git a/mojo/edk/js/BUILD.gn b/mojo/edk/js/BUILD.gn
index 0c3f6ad..9acb481 100644
--- a/mojo/edk/js/BUILD.gn
+++ b/mojo/edk/js/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../mojo_edk.gni")
-
 # TODO(hansmuller): The organization of tests in this directory is weird:
 #   * Really, js_unittests tests public stuff, so that should live in public
 #     and be reworked as some sort of apptest.
@@ -19,7 +17,7 @@
   ]
 }
 
-mojo_edk_source_set("js") {
+source_set("js") {
   sources = [
     "core.cc",
     "core.h",
@@ -50,7 +48,7 @@
   ]
 }
 
-mojo_edk_source_set("js_unittests") {
+source_set("js_unittests") {
   testonly = true
   sources = [
     "handle_unittest.cc",
diff --git a/mojo/edk/js/tests/BUILD.gn b/mojo/edk/js/tests/BUILD.gn
index 8d4a959..f58f3c3 100644
--- a/mojo/edk/js/tests/BUILD.gn
+++ b/mojo/edk/js/tests/BUILD.gn
@@ -2,10 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_edk.gni")
 import("../../../../mojo/public/tools/bindings/mojom.gni")
 
-mojo_edk_source_set("js_to_cpp_tests") {
+source_set("js_to_cpp_tests") {
   testonly = true
 
   deps = [
diff --git a/mojo/edk/mojo_edk.gni b/mojo/edk/mojo_edk.gni
deleted file mode 100644
index 60d6e9f..0000000
--- a/mojo/edk/mojo_edk.gni
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright 2014 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.
-
-import("../../mojo/public/mojo_sdk.gni")
-
-# A mojo_edk_source_set is a mojo_sdk_source_set that does not restrict
-# external dependencies and understands the following additional variables, all
-# of which admit a list of the relevant elements specified relative to the
-# location of the Mojo EDK:
-template("mojo_edk_source_set") {
-  mojo_sdk_source_set(target_name) {
-    if (defined(invoker.public_deps) || defined(invoker.deps)) {
-      restrict_external_deps = false
-    }
-
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    }
-    if (defined(invoker.testonly)) {
-      testonly = invoker.testonly
-    }
-    if (defined(invoker.sources)) {
-      sources = invoker.sources
-    }
-    if (defined(invoker.defines)) {
-      defines = invoker.defines
-    }
-    if (defined(invoker.public_configs)) {
-      public_configs = invoker.public_configs
-    }
-
-    configs = []
-    if (defined(invoker.configs)) {
-      configs = invoker.configs
-    }
-
-    allow_circular_includes_from = []
-    if (defined(invoker.allow_circular_includes_from)) {
-      allow_circular_includes_from += invoker.allow_circular_includes_from
-    }
-
-    if (defined(invoker.public_deps)) {
-      public_deps = invoker.public_deps
-    }
-    mojo_sdk_public_deps = []
-    if (defined(invoker.mojo_sdk_public_deps)) {
-      mojo_sdk_public_deps += invoker.mojo_sdk_public_deps
-    }
-
-    if (defined(invoker.deps)) {
-      deps = invoker.deps
-    }
-    mojo_sdk_deps = []
-    if (defined(invoker.mojo_sdk_deps)) {
-      mojo_sdk_deps += invoker.mojo_sdk_deps
-    }
-  }
-}
diff --git a/mojo/edk/system/BUILD.gn b/mojo/edk/system/BUILD.gn
index 358a9fa..11a3a8f 100644
--- a/mojo/edk/system/BUILD.gn
+++ b/mojo/edk/system/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../mojo_edk.gni")
 import("//testing/test.gni")
 import("../../../mojo/public/tools/bindings/mojom.gni")
 
@@ -122,7 +121,7 @@
   ]
 }
 
-mojo_edk_source_set("test_utils") {
+source_set("test_utils") {
   testonly = true
 
   sources = [
diff --git a/mojo/edk/system/core_unittest.cc b/mojo/edk/system/core_unittest.cc
index 28a038c1..cbbd905 100644
--- a/mojo/edk/system/core_unittest.cc
+++ b/mojo/edk/system/core_unittest.cc
@@ -15,6 +15,10 @@
 #include "mojo/edk/system/test_utils.h"
 #include "mojo/public/cpp/system/macros.h"
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 namespace mojo {
 namespace edk {
 namespace {
@@ -714,10 +718,16 @@
             core()->WriteMessage(h_passing[0], kHello, kHelloSize,
                                  &h_passing[0], 1,
                                  MOJO_WRITE_MESSAGE_FLAG_NONE));
+#if defined(OS_WIN)
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
+#endif
   ASSERT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
             core()->WriteMessage(h_passing[0], kHello, kHelloSize,
                                  &h_passing[1], 1,
                                  MOJO_WRITE_MESSAGE_FLAG_NONE));
+#if defined(OS_WIN)
+  }
+#endif
 
   MojoHandle h_passed[2];
   ASSERT_EQ(MOJO_RESULT_OK,
diff --git a/mojo/edk/system/raw_channel_win.cc b/mojo/edk/system/raw_channel_win.cc
index 3063ebe..0ceb521 100644
--- a/mojo/edk/system/raw_channel_win.cc
+++ b/mojo/edk/system/raw_channel_win.cc
@@ -14,6 +14,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/process/process.h"
 #include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/windows_version.h"
 #include "mojo/edk/embedder/embedder_internal.h"
@@ -82,6 +83,11 @@
 base::LazyInstance<VistaOrHigherFunctions> g_vista_or_higher_functions =
     LAZY_INSTANCE_INITIALIZER;
 
+void CancelOnIO(HANDLE handle, base::WaitableEvent* event) {
+  CancelIo(handle);
+  event->Signal();
+}
+
 class RawChannelWin final : public RawChannel {
  public:
   RawChannelWin(ScopedPlatformHandle handle)
@@ -230,10 +236,22 @@
         std::vector<char>* serialized_write_buffer,
         bool* write_error) {
       // Cancel pending IO calls.
+      bool is_xp = false;
       if (g_vista_or_higher_functions.Get().is_vista_or_higher()) {
         g_vista_or_higher_functions.Get().CancelIoEx(handle(), nullptr);
       } else {
-        CHECK(false) << "TODO(jam): handle XP";
+        is_xp = true;
+        if (pending_read_) {
+          if (internal::g_io_thread_task_runner->RunsTasksOnCurrentThread()) {
+            CancelIo(handle());
+          } else {
+            base::WaitableEvent event(false, false);
+            internal::g_io_thread_task_runner->PostTask(
+                FROM_HERE,
+                base::Bind(&CancelOnIO, handle(), &event));
+            event.Wait();
+          }
+        }
       }
 
       size_t additional_bytes_read = 0;
@@ -270,7 +288,11 @@
       size_t additional_platform_handles_written = 0;
       *write_error = owner_->pending_write_error();
       if (pending_write_) {
-        bool wait = false;
+        // If we had a pending write, then on XP we just wait till it completes.
+        // We use limited size buffers, so Windows should always find paged pool
+        // memory to finish the writes.
+        // TODO(jam): use background thread to verify that we don't hang here?
+        bool wait = is_xp;
         UnregisterWaitEx(write_wait_object_, INVALID_HANDLE_VALUE);
         write_wait_object_ = NULL;
         if (!write_event_signalled_)
@@ -777,8 +799,9 @@
     std::wstring filepath2(fileinfo2->FileName, fileinfo2->FileNameLength / 2);
     return filepath1 == filepath2;
   } else {
-    // TODO: XP: see http://stackoverflow.com/questions/65170/how-to-get-name-associated-with-open-handle/5286888#5286888
-    CHECK(false) << "TODO(jam): handle XP";
+    // This is to catch developer errors. Let them be caught on Vista and above,
+    // i.e. no point in implementing this on XP since support for it will be
+    // removed in early 2016.
     return false;
   }
 }
diff --git a/mojo/edk/test/BUILD.gn b/mojo/edk/test/BUILD.gn
index 5f8ec77..9a52c99 100644
--- a/mojo/edk/test/BUILD.gn
+++ b/mojo/edk/test/BUILD.gn
@@ -2,10 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//mojo/edk/mojo_edk.gni")
 import("//testing/test.gni")
 
-mojo_edk_source_set("test_support") {
+source_set("test_support") {
   testonly = true
   sources = [
     "multiprocess_test_helper.cc",
@@ -29,7 +28,7 @@
   ]
 }
 
-mojo_edk_source_set("run_all_unittests") {
+source_set("run_all_unittests") {
   testonly = true
   sources = [
     "run_all_unittests.cc",
@@ -49,7 +48,7 @@
   ]
 }
 
-mojo_edk_source_set("run_all_perftests") {
+source_set("run_all_perftests") {
   testonly = true
   deps = [
     ":test_support_impl",
@@ -67,7 +66,7 @@
   ]
 }
 
-mojo_edk_source_set("test_support_impl") {
+source_set("test_support_impl") {
   testonly = true
   deps = [
     "//base",
diff --git a/mojo/edk/test/multiprocess_test_helper.cc b/mojo/edk/test/multiprocess_test_helper.cc
index 10645f9..b07866ef 100644
--- a/mojo/edk/test/multiprocess_test_helper.cc
+++ b/mojo/edk/test/multiprocess_test_helper.cc
@@ -11,6 +11,10 @@
 #include "build/build_config.h"
 #include "mojo/edk/embedder/platform_channel_pair.h"
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 namespace mojo {
 namespace edk {
 namespace test {
@@ -59,7 +63,10 @@
   options.fds_to_remap = &handle_passing_info;
 #elif defined(OS_WIN)
   options.start_hidden = true;
-  options.handles_to_inherit = &handle_passing_info;
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA)
+    options.handles_to_inherit = &handle_passing_info;
+  else
+    options.inherit_handles = true;
 #else
 #error "Not supported yet."
 #endif
diff --git a/mojo/edk/test/scoped_ipc_support.cc b/mojo/edk/test/scoped_ipc_support.cc
index c416875..6e9c11c 100644
--- a/mojo/edk/test/scoped_ipc_support.cc
+++ b/mojo/edk/test/scoped_ipc_support.cc
@@ -13,8 +13,7 @@
 
 namespace internal {
 
-ScopedIPCSupportHelper::ScopedIPCSupportHelper()
-    : event_(true, false) {  // Manual reset.
+ScopedIPCSupportHelper::ScopedIPCSupportHelper() {
 }
 
 ScopedIPCSupportHelper::~ScopedIPCSupportHelper() {
@@ -23,7 +22,7 @@
     ShutdownIPCSupportOnIOThread();
   } else {
     ShutdownIPCSupportAndWaitForNoChannels();
-    event_.Wait();
+    run_loop_.Run();
   }
 }
 
@@ -31,12 +30,11 @@
     ProcessDelegate* process_delegate,
     scoped_refptr<base::TaskRunner> io_thread_task_runner) {
   io_thread_task_runner_ = io_thread_task_runner;
-  // Note: Run delegate methods on the I/O thread.
   InitIPCSupport(process_delegate, io_thread_task_runner_);
 }
 
 void ScopedIPCSupportHelper::OnShutdownCompleteImpl() {
-  event_.Signal();
+  run_loop_.Quit();
 }
 
 }  // namespace internal
diff --git a/mojo/edk/test/scoped_ipc_support.h b/mojo/edk/test/scoped_ipc_support.h
index cff0da76..132ed44 100644
--- a/mojo/edk/test/scoped_ipc_support.h
+++ b/mojo/edk/test/scoped_ipc_support.h
@@ -7,7 +7,7 @@
 
 #include "base/callback.h"
 #include "base/memory/ref_counted.h"
-#include "base/synchronization/waitable_event.h"
+#include "base/run_loop.h"
 #include "base/task_runner.h"
 #include "mojo/edk/embedder/process_delegate.h"
 #include "mojo/edk/embedder/scoped_platform_handle.h"
@@ -32,8 +32,7 @@
  private:
   scoped_refptr<base::TaskRunner> io_thread_task_runner_;
 
-  // Set after shut down.
-  base::WaitableEvent event_;
+  base::RunLoop run_loop_;
 
   MOJO_DISALLOW_COPY_AND_ASSIGN(ScopedIPCSupportHelper);
 };
diff --git a/mojo/mojo_edk.gyp b/mojo/mojo_edk.gyp
index 79bd3c4..531def5 100644
--- a/mojo/mojo_edk.gyp
+++ b/mojo/mojo_edk.gyp
@@ -36,7 +36,6 @@
       ],
       'sources': [
         'edk/embedder/configuration.h',
-        'edk/embedder/channel_info_forward.h',
         'edk/embedder/embedder.cc',
         'edk/embedder/embedder.h',
         'edk/embedder/embedder_internal.h',
diff --git a/mojo/public/c/environment/BUILD.gn b/mojo/public/c/environment/BUILD.gn
index 3fd1689..26e8256 100644
--- a/mojo/public/c/environment/BUILD.gn
+++ b/mojo/public/c/environment/BUILD.gn
@@ -2,13 +2,13 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
-mojo_sdk_source_set("environment") {
+source_set("environment") {
   sources = [
     "async_waiter.h",
     "logger.h",
   ]
 
-  mojo_sdk_deps = [ "mojo/public/c/system" ]
+  deps = [
+    "//mojo/public/c/system",
+  ]
 }
diff --git a/mojo/public/c/gles2/BUILD.gn b/mojo/public/c/gles2/BUILD.gn
index eb7a6f2..a009d00 100644
--- a/mojo/public/c/gles2/BUILD.gn
+++ b/mojo/public/c/gles2/BUILD.gn
@@ -2,13 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
 config("gles2_config") {
   defines = [ "GLES2_USE_MOJO" ]
 }
 
-mojo_sdk_source_set("gles2") {
+source_set("gles2") {
   sources = [
     "chromium_extension.h",
     "gles2.h",
@@ -20,8 +18,8 @@
 
   public_configs = [ ":gles2_config" ]
 
-  mojo_sdk_public_deps = [
-    "mojo/public/c/environment",
-    "mojo/public/c/system",
+  public_deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/c/system",
   ]
 }
diff --git a/mojo/public/c/gpu/BUILD.gn b/mojo/public/c/gpu/BUILD.gn
index c12b92a..07e00d1 100644
--- a/mojo/public/c/gpu/BUILD.gn
+++ b/mojo/public/c/gpu/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
 config("gpu_configs") {
   include_dirs = [ "." ]
   defines = [ "GLES2_USE_MOJO" ]
@@ -30,16 +28,18 @@
   ]
 }
 
-mojo_sdk_source_set("MGL") {
+source_set("MGL") {
   sources = [
     "MGL/mgl.h",
     "MGL/mgl_types.h",
   ]
 
-  mojo_sdk_public_deps = [ "mojo/public/c/system" ]
+  public_deps = [
+    "//mojo/public/c/system",
+  ]
 }
 
-mojo_sdk_source_set("MGL_onscreen") {
+source_set("MGL_onscreen") {
   sources = [
     "MGL/mgl_onscreen.h",
   ]
diff --git a/mojo/public/c/system/BUILD.gn b/mojo/public/c/system/BUILD.gn
index 51fc58d..f31964a9 100644
--- a/mojo/public/c/system/BUILD.gn
+++ b/mojo/public/c/system/BUILD.gn
@@ -2,13 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
 # Depend on this target to use the types etc defined in the system without
 # linking against a specific implementation of the system. To link against a
 # particular implementation, use the :for_component or
 # :for_shared_library targets, depending on the type of target you are.
-mojo_sdk_source_set("system") {
+source_set("system") {
   sources = [
     "buffer.h",
     "core.h",
diff --git a/mojo/public/c/system/tests/BUILD.gn b/mojo/public/c/system/tests/BUILD.gn
index bb3cc5e..9f55259 100644
--- a/mojo/public/c/system/tests/BUILD.gn
+++ b/mojo/public/c/system/tests/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../../mojo_sdk.gni")
-
-mojo_sdk_source_set("tests") {
+source_set("tests") {
   testonly = true
 
   visibility = [
@@ -19,16 +17,13 @@
   ]
 
   deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/c/system",
     "//testing/gtest",
   ]
-
-  mojo_sdk_deps = [
-    "mojo/public/c/environment",
-    "mojo/public/c/system",
-  ]
 }
 
-mojo_sdk_source_set("perftests") {
+source_set("perftests") {
   testonly = true
 
   sources = [
@@ -36,14 +31,11 @@
   ]
 
   deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
     "//testing/gtest",
   ]
-
-  mojo_sdk_deps = [
-    "mojo/public/c/environment",
-    "mojo/public/cpp/environment:standalone",
-    "mojo/public/cpp/system",
-    "mojo/public/cpp/test_support:test_utils",
-    "mojo/public/cpp/utility",
-  ]
 }
diff --git a/mojo/public/cpp/bindings/BUILD.gn b/mojo/public/cpp/bindings/BUILD.gn
index 89679f2e..6438960 100644
--- a/mojo/public/cpp/bindings/BUILD.gn
+++ b/mojo/public/cpp/bindings/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
-mojo_sdk_source_set("bindings") {
+source_set("bindings") {
   sources = [
     "array.h",
     "associated_interface_ptr_info.h",
@@ -67,19 +65,16 @@
 
   public_deps = [
     ":callback",
+    "//mojo/public/cpp/system",
   ]
 
-  mojo_sdk_public_deps = [
-    "mojo/public/cpp/system",
-  ]
-
-  mojo_sdk_deps = [
-    "mojo/public/cpp/environment",
-    "mojo/public/interfaces/bindings:bindings_cpp_sources",
+  deps = [
+    "//mojo/public/cpp/environment",
+    "//mojo/public/interfaces/bindings:bindings_cpp_sources",
   ]
 }
 
-mojo_sdk_source_set("callback") {
+source_set("callback") {
   sources = [
     "callback.h",
     "lib/callback_internal.h",
@@ -91,5 +86,7 @@
     "lib/thread_checker_posix.h",
   ]
 
-  mojo_sdk_deps = [ "mojo/public/cpp/system" ]
+  deps = [
+    "//mojo/public/cpp/system",
+  ]
 }
diff --git a/mojo/public/cpp/bindings/tests/BUILD.gn b/mojo/public/cpp/bindings/tests/BUILD.gn
index 1bc018c..30b631ba 100644
--- a/mojo/public/cpp/bindings/tests/BUILD.gn
+++ b/mojo/public/cpp/bindings/tests/BUILD.gn
@@ -3,9 +3,8 @@
 # found in the LICENSE file.
 
 import("../../../mojo_application.gni")
-import("../../../mojo_sdk.gni")
 
-mojo_sdk_source_set("tests") {
+source_set("tests") {
   testonly = true
 
   sources = [
@@ -39,22 +38,19 @@
     ":mojo_public_bindings_test_utils",
     "//mojo/environment:chromium",
     "//mojo/message_pump",
+    "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/bindings:callback",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
+    "//mojo/public/interfaces/bindings/tests:test_associated_interfaces",
+    "//mojo/public/interfaces/bindings/tests:test_interfaces",
+    "//mojo/public/interfaces/bindings/tests:test_interfaces_experimental",
     "//testing/gtest",
   ]
-
-  mojo_sdk_deps = [
-    "mojo/public/cpp/bindings",
-    "mojo/public/cpp/bindings:callback",
-    "mojo/public/cpp/system",
-    "mojo/public/cpp/test_support:test_utils",
-    "mojo/public/cpp/utility",
-    "mojo/public/interfaces/bindings/tests:test_associated_interfaces",
-    "mojo/public/interfaces/bindings/tests:test_interfaces",
-    "mojo/public/interfaces/bindings/tests:test_interfaces_experimental",
-  ]
 }
 
-mojo_sdk_source_set("perftests") {
+source_set("perftests") {
   testonly = true
 
   sources = [
@@ -62,25 +58,24 @@
   ]
 
   deps = [
+    "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/bindings:callback",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
+    "//mojo/public/interfaces/bindings/tests:test_interfaces",
     "//testing/gtest",
   ]
-
-  mojo_sdk_deps = [
-    "mojo/public/cpp/bindings",
-    "mojo/public/cpp/bindings:callback",
-    "mojo/public/cpp/environment:standalone",
-    "mojo/public/cpp/system",
-    "mojo/public/cpp/test_support:test_utils",
-    "mojo/public/cpp/utility",
-    "mojo/public/interfaces/bindings/tests:test_interfaces",
-  ]
 }
 
-mojo_sdk_source_set("mojo_public_bindings_test_utils") {
+source_set("mojo_public_bindings_test_utils") {
   sources = [
     "validation_test_input_parser.cc",
     "validation_test_input_parser.h",
   ]
 
-  mojo_sdk_deps = [ "mojo/public/c/system" ]
+  deps = [
+    "//mojo/public/c/system",
+  ]
 }
diff --git a/mojo/public/cpp/environment/BUILD.gn b/mojo/public/cpp/environment/BUILD.gn
index fe3a011..e2dfc91 100644
--- a/mojo/public/cpp/environment/BUILD.gn
+++ b/mojo/public/cpp/environment/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
-mojo_sdk_source_set("environment") {
+source_set("environment") {
   sources = [
     "async_waiter.h",
     "environment.h",
@@ -12,15 +10,17 @@
     "task_tracker.h",
   ]
 
-  mojo_sdk_public_deps = [ "mojo/public/c/environment" ]
+  public_deps = [
+    "//mojo/public/c/environment",
+  ]
 
-  mojo_sdk_deps = [
-    "mojo/public/cpp/bindings:callback",
-    "mojo/public/cpp/system",
+  deps = [
+    "//mojo/public/cpp/bindings:callback",
+    "//mojo/public/cpp/system",
   ]
 }
 
-mojo_sdk_source_set("standalone") {
+source_set("standalone") {
   sources = [
     "lib/async_waiter.cc",
     "lib/default_async_waiter.cc",
@@ -39,9 +39,9 @@
     ":environment",
   ]
 
-  mojo_sdk_deps = [
-    "mojo/public/c/environment",
-    "mojo/public/cpp/system",
-    "mojo/public/cpp/utility",
+  deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/utility",
   ]
 }
diff --git a/mojo/public/cpp/environment/tests/BUILD.gn b/mojo/public/cpp/environment/tests/BUILD.gn
index 10fd056..717c657 100644
--- a/mojo/public/cpp/environment/tests/BUILD.gn
+++ b/mojo/public/cpp/environment/tests/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../../mojo_sdk.gni")
-
-mojo_sdk_source_set("tests") {
+source_set("tests") {
   testonly = true
 
   sources = [
@@ -15,15 +13,12 @@
   ]
 
   deps = [
+    "//mojo/public/c/environment",
+    "//mojo/public/cpp/bindings:callback",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
     "//testing/gtest",
   ]
-
-  mojo_sdk_deps = [
-    "mojo/public/c/environment",
-    "mojo/public/cpp/bindings:callback",
-    "mojo/public/cpp/environment:standalone",
-    "mojo/public/cpp/system",
-    "mojo/public/cpp/test_support:test_utils",
-    "mojo/public/cpp/utility",
-  ]
 }
diff --git a/mojo/public/cpp/system/BUILD.gn b/mojo/public/cpp/system/BUILD.gn
index e120462..91b8b28 100644
--- a/mojo/public/cpp/system/BUILD.gn
+++ b/mojo/public/cpp/system/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
-mojo_sdk_source_set("system") {
+source_set("system") {
   sources = [
     "buffer.h",
     "core.h",
@@ -15,5 +13,7 @@
     "message_pipe.h",
   ]
 
-  mojo_sdk_public_deps = [ "mojo/public/c/system" ]
+  public_deps = [
+    "//mojo/public/c/system",
+  ]
 }
diff --git a/mojo/public/cpp/system/tests/BUILD.gn b/mojo/public/cpp/system/tests/BUILD.gn
index 3b6058c..068f009 100644
--- a/mojo/public/cpp/system/tests/BUILD.gn
+++ b/mojo/public/cpp/system/tests/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../../mojo_sdk.gni")
-
-mojo_sdk_source_set("tests") {
+source_set("tests") {
   testonly = true
 
   sources = [
@@ -13,13 +11,10 @@
   ]
 
   deps = [
+    "//mojo/public/c/system/tests",
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
     "//testing/gtest",
   ]
-
-  mojo_sdk_deps = [
-    "mojo/public/c/system/tests",
-    "mojo/public/cpp/environment:standalone",
-    "mojo/public/cpp/system",
-    "mojo/public/cpp/test_support:test_utils",
-  ]
 }
diff --git a/mojo/public/cpp/test_support/BUILD.gn b/mojo/public/cpp/test_support/BUILD.gn
index a1f7d31..308b8036 100644
--- a/mojo/public/cpp/test_support/BUILD.gn
+++ b/mojo/public/cpp/test_support/BUILD.gn
@@ -2,10 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
 # GYP version: mojo/public/mojo_public.gyp:mojo_public_test_utils
-mojo_sdk_source_set("test_utils") {
+source_set("test_utils") {
   testonly = true
 
   sources = [
@@ -15,11 +13,8 @@
   ]
 
   deps = [
+    "//mojo/public/c/test_support",
+    "//mojo/public/cpp/system",
     "//testing/gtest",
   ]
-
-  mojo_sdk_deps = [
-    "mojo/public/c/test_support",
-    "mojo/public/cpp/system",
-  ]
 }
diff --git a/mojo/public/cpp/utility/BUILD.gn b/mojo/public/cpp/utility/BUILD.gn
index 96c1d11..c95efac 100644
--- a/mojo/public/cpp/utility/BUILD.gn
+++ b/mojo/public/cpp/utility/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
-mojo_sdk_source_set("utility") {
+source_set("utility") {
   sources = [
     "lib/mutex.cc",
     "lib/run_loop.cc",
@@ -18,9 +16,9 @@
     "thread.h",
   ]
 
-  mojo_sdk_deps = [
-    "mojo/public/cpp/bindings:callback",
-    "mojo/public/cpp/system",
+  deps = [
+    "//mojo/public/cpp/bindings:callback",
+    "//mojo/public/cpp/system",
   ]
 
   if (is_win) {
diff --git a/mojo/public/cpp/utility/tests/BUILD.gn b/mojo/public/cpp/utility/tests/BUILD.gn
index acbbc9f..d324a57 100644
--- a/mojo/public/cpp/utility/tests/BUILD.gn
+++ b/mojo/public/cpp/utility/tests/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../../mojo_sdk.gni")
-
-mojo_sdk_source_set("tests") {
+source_set("tests") {
   testonly = true
 
   sources = [
@@ -12,16 +10,13 @@
   ]
 
   deps = [
+    "//mojo/public/cpp/environment:standalone",
+    "//mojo/public/cpp/system",
+    "//mojo/public/cpp/test_support:test_utils",
+    "//mojo/public/cpp/utility",
     "//testing/gtest",
   ]
 
-  mojo_sdk_deps = [
-    "mojo/public/cpp/environment:standalone",
-    "mojo/public/cpp/system",
-    "mojo/public/cpp/test_support:test_utils",
-    "mojo/public/cpp/utility",
-  ]
-
   # crbug.com/342893
   if (!is_win) {
     sources += [
diff --git a/mojo/public/js/BUILD.gn b/mojo/public/js/BUILD.gn
index 1cb1a60..4b86e6eb 100644
--- a/mojo/public/js/BUILD.gn
+++ b/mojo/public/js/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../mojo_sdk.gni")
-
-mojo_sdk_source_set("js") {
+source_set("js") {
   sources = [
     "constants.cc",
     "constants.h",
diff --git a/mojo/public/mojo_sdk.gni b/mojo/public/mojo_sdk.gni
deleted file mode 100644
index 1c5d9d3..0000000
--- a/mojo/public/mojo_sdk.gni
+++ /dev/null
@@ -1,153 +0,0 @@
-# Copyright 2014 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.
-
-# Takes as input a "source_set" that includes dependencies that are relative to
-# the parent directory of the Mojo public SDK (given in |mojo_sdk_deps|).
-# Generates a source_set that has the mojo_sdk_deps added as ordinary deps
-# rebased to the current directory.
-# By default, restricts the entries that are given in invoker.deps and
-# invoker.public_deps to be only within the same file and on a small set of
-# whitelisted external dependencies. This check can be elided by setting
-# restrict_external_deps to false in the invoker. DO NOT DO THIS in
-# //mojo/public.
-#
-# Example of a mojo_sdk_source_set:
-#
-# mojo_sdk_source_set("foo") {
-#   sources = [
-#     "foo.h",
-#     "foo.cc",
-#   ]
-#
-#   # Same-file deps are specified in the ordinary way. Any external
-#   dependencies are specified the same way (although in general there should
-#   be very few of these).
-#   deps = [
-#     ":bar",
-#   ]
-#
-#   # Mojo SDK deps are specified relative to the containing directory of the
-#   SDK via mojo_sdk_deps.
-#   mojo_sdk_deps = [
-#     "mojo/public/cpp/bindings",
-#     "mojo/public/cpp/environment",
-#     "mojo/public/cpp/system",
-#   ]
-# }
-#
-template("mojo_sdk_source_set") {
-  source_set(target_name) {
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    } else {
-      visibility = [ "*" ]
-    }
-    if (defined(invoker.mojo_edk_visibility)) {
-      foreach(edk_target, invoker.mojo_edk_visibility) {
-        # Check that the EDK target was not mistakenly given as an absolute
-        # path.
-        assert(get_path_info(edk_target, "abspath") != edk_target)
-        visibility += [ rebase_path(edk_target, ".", "//third_party/mojo/src") ]
-      }
-    }
-
-    if (defined(invoker.testonly)) {
-      testonly = invoker.testonly
-    }
-
-    if (defined(invoker.sources)) {
-      sources = invoker.sources
-    }
-
-    if (defined(invoker.defines)) {
-      defines = invoker.defines
-    }
-
-    if (defined(invoker.libs)) {
-      libs = invoker.libs
-    }
-
-    public_configs = []
-    if (defined(invoker.public_configs)) {
-      public_configs += invoker.public_configs
-    }
-
-    if (defined(invoker.configs)) {
-      configs += invoker.configs
-    }
-
-    if (defined(invoker.allow_circular_includes_from)) {
-      allow_circular_includes_from = invoker.allow_circular_includes_from
-    }
-
-    if (defined(invoker.public_deps) || defined(invoker.deps)) {
-      restrict_external_deps = true
-      if (defined(invoker.restrict_external_deps)) {
-        restrict_external_deps = invoker.restrict_external_deps
-      }
-    }
-
-    public_deps = []
-    if (defined(invoker.public_deps)) {
-      foreach(dep, invoker.public_deps) {
-        if (restrict_external_deps) {
-          # The only deps that are not specified relative to the location of
-          # the Mojo SDK should be on targets within the same file or on a
-          # whitelisted set of external dependencies.
-          assert(get_path_info(dep, "dir") == ".")
-        }
-        public_deps += [ dep ]
-      }
-    }
-    if (defined(invoker.mojo_edk_public_deps)) {
-      foreach(edk_dep, invoker.mojo_edk_public_deps) {
-        # Check that the EDK dep was not mistakenly given as an absolute path.
-        assert(get_path_info(edk_dep, "abspath") != edk_dep)
-        public_deps += [ rebase_path(edk_dep, ".", "//third_party/mojo/src") ]
-      }
-    }
-    if (defined(invoker.mojo_sdk_public_deps)) {
-      foreach(sdk_dep, invoker.mojo_sdk_public_deps) {
-        # Check that the SDK dep was not mistakenly given as an absolute path.
-        assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
-        public_deps += [ rebase_path(sdk_dep, ".", "//") ]
-      }
-    }
-
-    deps = []
-    if (defined(invoker.deps)) {
-      foreach(dep, invoker.deps) {
-        if (restrict_external_deps) {
-          # The only deps that are not specified relative to the location of
-          # the Mojo SDK should be on targets within the same file or on a
-          # whitelisted set of external dependencies.
-          dep_dir = get_path_info(dep, "dir")
-          assert(dep_dir == "." || dep == "//testing/gtest" ||
-                 dep == "//mojo/environment:chromium" ||
-                 dep == "//mojo/message_pump")
-        }
-        deps += [ dep ]
-      }
-    }
-    if (defined(invoker.mojo_edk_deps)) {
-      foreach(edk_dep, invoker.mojo_edk_deps) {
-        # Check that the EDK dep was not mistakenly given as an absolute path.
-        assert(get_path_info(edk_dep, "abspath") != edk_dep)
-        deps += [ rebase_path(edk_dep, ".", "//third_party/mojo/src") ]
-      }
-    }
-    if (defined(invoker.mojo_sdk_deps)) {
-      foreach(sdk_dep, invoker.mojo_sdk_deps) {
-        # Check that the SDK dep was not mistakenly given as an absolute path.
-        assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
-        deps += [ rebase_path(sdk_dep, ".", "//") ]
-      }
-    }
-
-    data_deps = []
-    if (defined(invoker.data_deps)) {
-      data_deps = invoker.data_deps
-    }
-  }
-}
diff --git a/mojo/public/platform/nacl/BUILD.gn b/mojo/public/platform/nacl/BUILD.gn
index 17edf327..ba29a79 100644
--- a/mojo/public/platform/nacl/BUILD.gn
+++ b/mojo/public/platform/nacl/BUILD.gn
@@ -4,28 +4,28 @@
 
 assert(is_nacl)
 
-import("../../mojo_sdk.gni")
-
 # Untrusted code
 if (is_nacl) {
   # Thunk mapping the Mojo public API onto NaCl syscalls.
-  mojo_sdk_source_set("mojo") {
+  source_set("mojo") {
     sources = [
       "libmojo.cc",
       "mojo_irt.h",
     ]
-    mojo_sdk_deps = [ "mojo/public/c/system" ]
+    deps = [
+      "//mojo/public/c/system",
+    ]
   }
 
-  mojo_sdk_source_set("system") {
+  source_set("system") {
     sources = [
       "mojo_initial_handle.h",
       "mojo_main_thunk.cc",
     ]
 
-    mojo_sdk_deps = [
-      "mojo/public/c/system",
-      "mojo/public/platform/nacl:mojo",
+    deps = [
+      "//mojo/public/c/system",
+      "//mojo/public/platform/nacl:mojo",
     ]
   }
 }
diff --git a/mojo/public/platform/native/BUILD.gn b/mojo/public/platform/native/BUILD.gn
index aded499..f7d31f5 100644
--- a/mojo/public/platform/native/BUILD.gn
+++ b/mojo/public/platform/native/BUILD.gn
@@ -4,15 +4,15 @@
 
 assert(!defined(is_nacl) || !is_nacl)
 
-import("../../mojo_sdk.gni")
-
-mojo_sdk_source_set("system") {
+source_set("system") {
   sources = [
     "system_thunks.cc",
     "system_thunks.h",
   ]
   defines = [ "MOJO_SYSTEM_IMPLEMENTATION" ]
-  mojo_sdk_deps = [ "mojo/public/c/system" ]
+  deps = [
+    "//mojo/public/c/system",
+  ]
 
   # The GYP target analogous to this one builds this code into a
   # static library.  When building for Android, both the GYP and GN
@@ -24,7 +24,7 @@
   # source_set here, this flag change is not needed.
 }
 
-mojo_sdk_source_set("gles2") {
+source_set("gles2") {
   sources = [
     "gles2_impl_chromium_extension_thunks.cc",
     "gles2_impl_chromium_extension_thunks.h",
@@ -36,12 +36,12 @@
 
   defines = [ "MOJO_GLES2_IMPLEMENTATION" ]
 
-  configs = [ "//third_party/khronos:khronos_headers" ]
+  configs += [ "//third_party/khronos:khronos_headers" ]
 
-  mojo_sdk_deps = [
-    "mojo/public/c/gles2",
-    "mojo/public/c/environment",
-    "mojo/public/c/system",
+  deps = [
+    "//mojo/public/c/gles2",
+    "//mojo/public/c/environment",
+    "//mojo/public/c/system",
   ]
 
   if (is_mac) {
@@ -50,24 +50,28 @@
   }
 }
 
-mojo_sdk_source_set("gpu_thunks") {
+source_set("gpu_thunks") {
   sources = []
 }
 
-mojo_sdk_source_set("mgl_thunks") {
+source_set("mgl_thunks") {
   sources = [
     "mgl_thunks.c",
     "mgl_thunks.h",
   ]
 
-  mojo_sdk_deps = [ "mojo/public/c/gpu:MGL" ]
+  deps = [
+    "//mojo/public/c/gpu:MGL",
+  ]
 }
 
-mojo_sdk_source_set("mgl_onscreen_thunks") {
+source_set("mgl_onscreen_thunks") {
   sources = [
     "mgl_onscreen_thunks.c",
     "mgl_onscreen_thunks.h",
   ]
 
-  mojo_sdk_deps = [ "mojo/public/c/gpu:MGL_onscreen" ]
+  deps = [
+    "//mojo/public/c/gpu:MGL_onscreen",
+  ]
 }
diff --git a/mojo/public/tools/bindings/mojom.gni b/mojo/public/tools/bindings/mojom.gni
index 7143ef8..cd0b390 100644
--- a/mojo/public/tools/bindings/mojom.gni
+++ b/mojo/public/tools/bindings/mojom.gni
@@ -2,18 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_sdk.gni")
-
 # Generate C++/JavaScript/Java source files from mojom files. The output files
 # will go under the generated file directory tree with the same path as each
 # input file.
 #
-# If a mojom target is intended for use in a client repo where the location of
-# the Mojo SDK will be different than its location in the Mojo repo,
-# dependencies on the SDK should be specified relative to the parent directory
-# of the Mojo public SDK in |mojo_sdk_deps| rather than via absolute paths in
-# |deps|.
-#
 # Parameters:
 #
 #   sources (optional if one of the deps sets listed below is present)
@@ -22,19 +14,9 @@
 #   deps (optional)
 #       Note: this can contain only other mojom targets.
 #
-#   mojo_sdk_deps (optional)
-#       List of deps specified relative to the parent directory of the Mojo
-#       public SDK. These deps will be added as ordinary deps rebased to the
-#       current directory.
-#
 #   public_deps (optional)
 #       Note: this can contain only other mojom targets.
 #
-#   mojo_sdk_public_deps (optional)
-#       List of public deps specified relative to the parent directory of the
-#       Mojo public SDK. These deps will be added as ordinary public deps
-#       rebased to the current directory.
-#
 #   import_dirs (optional)
 #       List of import directories that will get added when processing sources.
 #
@@ -49,8 +31,7 @@
 template("mojom") {
   assert(
       defined(invoker.sources) || defined(invoker.deps) ||
-          defined(invoker.public_deps) || defined(invoker.mojo_sdk_deps) ||
-          defined(invoker.mojo_sdk_public_deps),
+          defined(invoker.public_deps),
       "\"sources\" or \"deps\" must be defined for the $target_name template.")
 
   cpp_sources_suffix = "cpp_sources"
@@ -132,24 +113,6 @@
         [ "{{source_gen_dir}}/{{source_name_part}}.mojom.srcjar" ]
   }
 
-  rebased_mojo_sdk_public_deps = []
-  if (defined(invoker.mojo_sdk_public_deps)) {
-    foreach(sdk_dep, invoker.mojo_sdk_public_deps) {
-      # Check that the SDK dep was not mistakenly given as an absolute path.
-      assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
-      rebased_mojo_sdk_public_deps += [ rebase_path(sdk_dep, ".", "//") ]
-    }
-  }
-
-  rebased_mojo_sdk_deps = []
-  if (defined(invoker.mojo_sdk_deps)) {
-    foreach(sdk_dep, invoker.mojo_sdk_deps) {
-      # Check that the SDK dep was not mistakenly given as an absolute path.
-      assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
-      rebased_mojo_sdk_deps += [ rebase_path(sdk_dep, ".", "//") ]
-    }
-  }
-
   if (defined(invoker.sources)) {
     generator_target_name = target_name + "__generator"
     action_foreach(generator_target_name) {
@@ -197,7 +160,6 @@
     if (defined(invoker.sources)) {
       public_deps += [ ":${cpp_sources_target_name}" ]
     }
-    public_deps += rebased_mojo_sdk_public_deps
     if (defined(invoker.public_deps)) {
       public_deps += invoker.public_deps
     }
@@ -206,20 +168,12 @@
     if (defined(invoker.sources)) {
       public_deps += [ ":$generator_target_name" ]
     }
-    deps += rebased_mojo_sdk_deps
     if (defined(invoker.deps)) {
       deps += invoker.deps
     }
-    if (defined(invoker.mojo_sdk_deps)) {
-      foreach(sdk_dep, invoker.mojo_sdk_deps) {
-        # Check that the SDK dep was not mistakenly given as an absolute path.
-        assert(get_path_info(sdk_dep, "abspath") != sdk_dep)
-        deps += [ rebase_path(sdk_dep, ".", "//") ]
-      }
-    }
   }
 
-  all_deps = rebased_mojo_sdk_deps + rebased_mojo_sdk_public_deps
+  all_deps = []
   if (defined(invoker.deps)) {
     all_deps += invoker.deps
   }
diff --git a/mojo/runner/BUILD.gn b/mojo/runner/BUILD.gn
index 159af7d..49efb46 100644
--- a/mojo/runner/BUILD.gn
+++ b/mojo/runner/BUILD.gn
@@ -104,6 +104,7 @@
   deps = [
     "//mojo/runner/host:switches",
     "//base",
+    "//base:base_static",
     "//base:i18n",
   ]
 }
diff --git a/mojo/runner/child/BUILD.gn b/mojo/runner/child/BUILD.gn
index edf5f97b..028c1d72 100644
--- a/mojo/runner/child/BUILD.gn
+++ b/mojo/runner/child/BUILD.gn
@@ -42,6 +42,26 @@
   import_dirs = [ "//mojo/services" ]
 }
 
+source_set("test_native_main") {
+  sources = [
+    "test_native_main.cc",
+    "test_native_main.h",
+  ]
+
+  public_deps = [
+    "//mojo/runner:init",
+  ]
+
+  deps = [
+    "//base",
+    "//mojo/application/public/cpp",
+    "//mojo/gles2",
+    "//mojo/message_pump",
+    "//mojo/runner/child:lib",
+    "//third_party/mojo/src/mojo/edk/system",
+  ]
+}
+
 mojom("apptest_interfaces") {
   sources = [
     "test_native_service.mojom",
@@ -89,14 +109,9 @@
   deps = [
     ":apptest_interfaces",
     ":lib",
+    ":test_native_main",
     "//base",
-    "//base:base_static",
     "//mojo/application/public/cpp",
-    "//mojo/application/public/interfaces",
     "//mojo/common:common_base",
-    "//mojo/gles2",
-    "//mojo/message_pump",
-    "//mojo/runner:init",
-    "//third_party/mojo/src/mojo/edk/system",
   ]
 }
diff --git a/mojo/runner/child/native_apptest_target.cc b/mojo/runner/child/native_apptest_target.cc
index 36da1b3..f184400 100644
--- a/mojo/runner/child/native_apptest_target.cc
+++ b/mojo/runner/child/native_apptest_target.cc
@@ -4,28 +4,14 @@
 
 #include "base/at_exit.h"
 #include "base/command_line.h"
-#include "base/debug/stack_trace.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/process/launch.h"
-#include "base/threading/thread.h"
-#include "build/build_config.h"
 #include "mojo/application/public/cpp/application_connection.h"
 #include "mojo/application/public/cpp/application_delegate.h"
 #include "mojo/application/public/cpp/application_impl.h"
 #include "mojo/application/public/cpp/interface_factory.h"
-#include "mojo/application/public/interfaces/application.mojom.h"
 #include "mojo/common/weak_binding_set.h"
-#include "mojo/message_pump/message_pump_mojo.h"
-#include "mojo/runner/child/runner_connection.h"
+#include "mojo/runner/child/test_native_main.h"
 #include "mojo/runner/child/test_native_service.mojom.h"
 #include "mojo/runner/init.h"
-#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
-#include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
-
-#if defined(OS_WIN)
-#include <windows.h>
-#endif
 
 namespace {
 
@@ -63,17 +49,6 @@
   DISALLOW_COPY_AND_ASSIGN(TargetApplicationDelegate);
 };
 
-class ProcessDelegate : public mojo::embedder::ProcessDelegate {
- public:
-  ProcessDelegate() {}
-  ~ProcessDelegate() override {}
-
- private:
-  void OnShutdownComplete() override {}
-
-  DISALLOW_COPY_AND_ASSIGN(ProcessDelegate);
-};
-
 }  // namespace
 
 int main(int argc, char** argv) {
@@ -81,42 +56,7 @@
   base::CommandLine::Init(argc, argv);
 
   mojo::runner::InitializeLogging();
-  mojo::runner::WaitForDebuggerIfNecessary();
 
-#if !defined(OFFICIAL_BUILD)
-  base::debug::EnableInProcessStackDumping();
-#if defined(OS_WIN)
-  base::RouteStdioToConsole(false);
-#endif
-#endif
-
-  {
-    mojo::embedder::Init();
-
-    ProcessDelegate process_delegate;
-    base::Thread io_thread("io_thread");
-    base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
-    CHECK(io_thread.StartWithOptions(io_thread_options));
-
-    mojo::embedder::InitIPCSupport(
-        mojo::embedder::ProcessType::NONE, &process_delegate,
-        io_thread.task_runner().get(), mojo::embedder::ScopedPlatformHandle());
-
-    mojo::InterfaceRequest<mojo::Application> application_request;
-    scoped_ptr<mojo::runner::RunnerConnection> connection(
-        mojo::runner::RunnerConnection::ConnectToRunner(&application_request));
-
-    TargetApplicationDelegate delegate;
-    {
-      base::MessageLoop loop(mojo::common::MessagePumpMojo::Create());
-      mojo::ApplicationImpl impl(&delegate, application_request.Pass());
-      loop.Run();
-    }
-
-    connection.reset();
-
-    mojo::embedder::ShutdownIPCSupport();
-  }
-
-  return 0;
+  TargetApplicationDelegate delegate;
+  return mojo::runner::TestNativeMain(&delegate);
 }
diff --git a/mojo/runner/child/test_native_main.cc b/mojo/runner/child/test_native_main.cc
new file mode 100644
index 0000000..c9bf2539
--- /dev/null
+++ b/mojo/runner/child/test_native_main.cc
@@ -0,0 +1,79 @@
+// Copyright 2015 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 "mojo/runner/child/test_native_main.h"
+
+#include "base/debug/stack_trace.h"
+#include "base/message_loop/message_loop.h"
+#include "base/process/launch.h"
+#include "base/threading/thread.h"
+#include "build/build_config.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/message_pump/message_pump_mojo.h"
+#include "mojo/runner/child/runner_connection.h"
+#include "mojo/runner/init.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
+
+namespace mojo {
+namespace runner {
+namespace {
+
+class ProcessDelegate : public mojo::embedder::ProcessDelegate {
+ public:
+  ProcessDelegate() {}
+  ~ProcessDelegate() override {}
+
+ private:
+  void OnShutdownComplete() override {}
+
+  DISALLOW_COPY_AND_ASSIGN(ProcessDelegate);
+};
+
+}  // namespace
+
+int TestNativeMain(mojo::ApplicationDelegate* application_delegate) {
+  mojo::runner::WaitForDebuggerIfNecessary();
+
+#if !defined(OFFICIAL_BUILD)
+  base::debug::EnableInProcessStackDumping();
+#if defined(OS_WIN)
+  base::RouteStdioToConsole(false);
+#endif
+#endif
+
+  {
+    mojo::embedder::Init();
+
+    ProcessDelegate process_delegate;
+    base::Thread io_thread("io_thread");
+    base::Thread::Options io_thread_options(base::MessageLoop::TYPE_IO, 0);
+    CHECK(io_thread.StartWithOptions(io_thread_options));
+
+    mojo::embedder::InitIPCSupport(
+        mojo::embedder::ProcessType::NONE, &process_delegate,
+        io_thread.task_runner().get(), mojo::embedder::ScopedPlatformHandle());
+
+    mojo::InterfaceRequest<mojo::Application> application_request;
+    scoped_ptr<mojo::runner::RunnerConnection> connection(
+        mojo::runner::RunnerConnection::ConnectToRunner(&application_request));
+
+    base::MessageLoop loop(mojo::common::MessagePumpMojo::Create());
+    {
+      mojo::ApplicationImpl impl(application_delegate,
+                                 application_request.Pass());
+      loop.Run();
+    }
+
+    connection.reset();
+
+    mojo::embedder::ShutdownIPCSupport();
+  }
+
+  return 0;
+}
+
+}  // namespace runner
+}  // namespace mojo
diff --git a/mojo/runner/child/test_native_main.h b/mojo/runner/child/test_native_main.h
new file mode 100644
index 0000000..b1931af1
--- /dev/null
+++ b/mojo/runner/child/test_native_main.h
@@ -0,0 +1,17 @@
+// Copyright 2015 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.
+
+#ifndef MOJO_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
+#define MOJO_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
+
+namespace mojo {
+class ApplicationDelegate;
+namespace runner {
+
+int TestNativeMain(mojo::ApplicationDelegate* application_delegate);
+
+}  // namespace runner
+}  // namespace mojo
+
+#endif  // MOJO_RUNNER_CHILD_TEST_NATIVE_MAIN_H_
diff --git a/mojo/runner/host/child_process_host.cc b/mojo/runner/host/child_process_host.cc
index 6074b5b..10a2439 100644
--- a/mojo/runner/host/child_process_host.cc
+++ b/mojo/runner/host/child_process_host.cc
@@ -23,6 +23,10 @@
 #include "sandbox/linux/services/namespace_sandbox.h"
 #endif
 
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
 namespace mojo {
 namespace runner {
 
@@ -39,8 +43,20 @@
   CHECK(platform_channel_.is_valid());
 }
 
+ChildProcessHost::ChildProcessHost(ScopedHandle channel)
+    : launch_process_runner_(nullptr),
+      start_sandboxed_(false),
+      channel_info_(nullptr),
+      start_child_process_event_(false, false),
+      weak_factory_(this) {
+  CHECK(channel.is_valid());
+  ScopedMessagePipeHandle handle(MessagePipeHandle(channel.release().value()));
+  controller_.Bind(InterfacePtrInfo<ChildController>(handle.Pass(), 0u));
+}
+
 ChildProcessHost::~ChildProcessHost() {
-  CHECK(!controller_) << "Destroying ChildProcessHost before calling Join";
+  if (!app_path_.empty())
+    CHECK(!controller_) << "Destroying ChildProcessHost before calling Join";
 }
 
 void ChildProcessHost::Start() {
@@ -123,7 +139,14 @@
 
   base::LaunchOptions options;
 #if defined(OS_WIN)
-  options.handles_to_inherit = &handle_passing_info;
+  if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
+    options.handles_to_inherit = &handle_passing_info;
+  } else {
+#if defined(OFFICIAL_BUILD)
+    CHECK(false) << "Launching mojo process with inherit_handles is insecure!";
+#endif
+    options.inherit_handles = true;
+  }
   options.stdin_handle = INVALID_HANDLE_VALUE;
   options.stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
   options.stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
diff --git a/mojo/runner/host/child_process_host.h b/mojo/runner/host/child_process_host.h
index 68ea6c2..a4d15103 100644
--- a/mojo/runner/host/child_process_host.h
+++ b/mojo/runner/host/child_process_host.h
@@ -41,6 +41,9 @@
   ChildProcessHost(base::TaskRunner* launch_process_runner,
                    bool start_sandboxed,
                    const base::FilePath& app_path);
+  // Allows a ChildProcessHost to be instantiated for an existing channel
+  // created by someone else (e.g. an app that launched its own process).
+  explicit ChildProcessHost(ScopedHandle channel);
   virtual ~ChildProcessHost();
 
   // |Start()|s the child process; calls |DidStart()| (on the thread on which
diff --git a/mojo/runner/host/in_process_native_runner.cc b/mojo/runner/host/in_process_native_runner.cc
index ee5e9e3..1182fb6d 100644
--- a/mojo/runner/host/in_process_native_runner.cc
+++ b/mojo/runner/host/in_process_native_runner.cc
@@ -50,6 +50,12 @@
   thread_->Start();
 }
 
+void InProcessNativeRunner::InitHost(
+    ScopedHandle channel,
+    InterfaceRequest<Application> application_request) {
+  NOTREACHED();  // Can't host another process in this runner.
+}
+
 void InProcessNativeRunner::Run() {
   DVLOG(2) << "Loading/running Mojo app in process from library: "
            << app_path_.value()
diff --git a/mojo/runner/host/in_process_native_runner.h b/mojo/runner/host/in_process_native_runner.h
index ddd8395..4aa08404 100644
--- a/mojo/runner/host/in_process_native_runner.h
+++ b/mojo/runner/host/in_process_native_runner.h
@@ -29,11 +29,13 @@
   InProcessNativeRunner();
   ~InProcessNativeRunner() override;
 
-  // |NativeRunner| method:
+  // NativeRunner:
   void Start(const base::FilePath& app_path,
              bool start_sandboxed,
              InterfaceRequest<Application> application_request,
              const base::Closure& app_completed_callback) override;
+  void InitHost(ScopedHandle channel,
+                InterfaceRequest<Application> application_request) override;
 
  private:
   // |base::DelegateSimpleThread::Delegate| method:
diff --git a/mojo/runner/host/out_of_process_native_runner.cc b/mojo/runner/host/out_of_process_native_runner.cc
index 0388c953..2bc561e4 100644
--- a/mojo/runner/host/out_of_process_native_runner.cc
+++ b/mojo/runner/host/out_of_process_native_runner.cc
@@ -20,7 +20,7 @@
     : launch_process_runner_(launch_process_runner) {}
 
 OutOfProcessNativeRunner::~OutOfProcessNativeRunner() {
-  if (child_process_host_)
+  if (child_process_host_ && !app_path_.empty())
     child_process_host_->Join();
 }
 
@@ -44,6 +44,16 @@
                  base::Unretained(this)));
 }
 
+void OutOfProcessNativeRunner::InitHost(
+    ScopedHandle channel,
+    InterfaceRequest<Application> application_request) {
+  child_process_host_.reset(new ChildProcessHost(channel.Pass()));
+  child_process_host_->StartApp(
+      application_request.Pass(),
+      base::Bind(&OutOfProcessNativeRunner::AppCompleted,
+                 base::Unretained(this)));
+}
+
 void OutOfProcessNativeRunner::AppCompleted(int32_t result) {
   DVLOG(2) << "OutOfProcessNativeRunner::AppCompleted(" << result << ")";
 
diff --git a/mojo/runner/host/out_of_process_native_runner.h b/mojo/runner/host/out_of_process_native_runner.h
index 6cec241..0c913ed 100644
--- a/mojo/runner/host/out_of_process_native_runner.h
+++ b/mojo/runner/host/out_of_process_native_runner.h
@@ -27,11 +27,13 @@
   explicit OutOfProcessNativeRunner(base::TaskRunner* launch_process_runner);
   ~OutOfProcessNativeRunner() override;
 
-  // |NativeRunner| method:
+  // NativeRunner:
   void Start(const base::FilePath& app_path,
              bool start_sandboxed,
              InterfaceRequest<Application> application_request,
              const base::Closure& app_completed_callback) override;
+  void InitHost(ScopedHandle channel,
+                InterfaceRequest<Application> application_request) override;
 
  private:
   // |ChildController::StartApp()| callback:
diff --git a/mojo/services/network/public/cpp/BUILD.gn b/mojo/services/network/public/cpp/BUILD.gn
index cca613d..80262fc 100644
--- a/mojo/services/network/public/cpp/BUILD.gn
+++ b/mojo/services/network/public/cpp/BUILD.gn
@@ -2,10 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//mojo/public/mojo_sdk.gni")
-
-mojo_sdk_source_set("cpp") {
-  restrict_external_deps = false
+source_set("cpp") {
   public_configs = [ "../../../public/build/config:mojo_services" ]
   sources = [
     "udp_socket_wrapper.cc",
diff --git a/mojo/shell/BUILD.gn b/mojo/shell/BUILD.gn
index b54c7b50..8478000 100644
--- a/mojo/shell/BUILD.gn
+++ b/mojo/shell/BUILD.gn
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import("//mojo/public/mojo_application.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 import("//testing/test.gni")
 
@@ -108,6 +109,7 @@
 
 mojom("test_bindings") {
   sources = [
+    "application_manager_apptests.mojom",
     "capability_filter_unittest.mojom",
     "test.mojom",
   ]
@@ -118,3 +120,65 @@
     "application_manager.mojom",
   ]
 }
+
+mojo_native_application("apptests") {
+  output_name = "mojo_shell_apptests"
+  testonly = true
+
+  sources = [
+    "application_manager_apptest.cc",
+  ]
+
+  deps = [
+    ":test_bindings",
+    "//base",
+    "//base/test:test_config",
+    "//mojo/application/public/cpp:sources",
+    "//mojo/application/public/cpp:test_support",
+    "//mojo/common:common_base",
+    "//mojo/converters/network",
+  ]
+
+  data_deps = [
+    ":application_manager_apptest_driver",
+    ":application_manager_apptest_target",
+  ]
+}
+
+executable("application_manager_apptest_driver") {
+  testonly = true
+
+  sources = [
+    "application_manager_apptest_driver.cc",
+  ]
+
+  deps = [
+    ":test_bindings",
+    "//base",
+    "//base:base_static",
+    "//mojo/application/public/cpp",
+    "//mojo/common:common_base",
+    "//mojo/converters/network",
+    "//mojo/runner:init",
+    "//mojo/runner/child:test_native_main",
+    "//mojo/shell:interfaces",
+    "//third_party/mojo/src/mojo/edk/system",
+  ]
+}
+
+executable("application_manager_apptest_target") {
+  testonly = true
+
+  sources = [
+    "application_manager_apptest_target.cc",
+  ]
+
+  deps = [
+    ":test_bindings",
+    "//base",
+    "//mojo/application/public/cpp",
+    "//mojo/common:common_base",
+    "//mojo/converters/network",
+    "//mojo/runner/child:test_native_main",
+  ]
+}
diff --git a/mojo/shell/DEPS b/mojo/shell/DEPS
index f660650..5a272f0 100644
--- a/mojo/shell/DEPS
+++ b/mojo/shell/DEPS
@@ -1,3 +1,14 @@
 include_rules = [
   "-mojo/runner",
 ]
+
+specific_include_rules = {
+  "application_manager_apptest_driver.cc": [
+    "+mojo/runner/child",
+    "+mojo/runner/init.h",
+  ],
+  "application_manager_apptest_target.cc": [
+    "+mojo/runner/child",
+    "+mojo/runner/init.h",
+  ],
+}
diff --git a/mojo/shell/application_manager.cc b/mojo/shell/application_manager.cc
index 16c483d..d011049 100644
--- a/mojo/shell/application_manager.cc
+++ b/mojo/shell/application_manager.cc
@@ -89,7 +89,7 @@
   ApplicationLoader* loader = GetLoaderForURL(params->target().url());
   if (loader) {
     GURL url = params->target().url();
-    loader->Load(url, CreateInstance(params.Pass(), nullptr));
+    loader->Load(url, CreateAndConnectToInstance(params.Pass(), nullptr));
     return;
   }
 
@@ -110,29 +110,55 @@
   return true;
 }
 
-InterfaceRequest<Application> ApplicationManager::CreateInstance(
+ApplicationInstance* ApplicationManager::GetApplicationInstance(
+    const Identity& identity) const {
+  const auto& it = identity_to_instance_.find(identity);
+  return it != identity_to_instance_.end() ? it->second : nullptr;
+}
+
+void ApplicationManager::CreateInstanceForHandle(ScopedHandle channel,
+                                                 const GURL& url,
+                                                 const std::string& qualifier) {
+  // Instances created by others are considered unique, and thus have no
+  // identity. As such they cannot be connected to by anyone else, and so we
+  // never call ConnectToClient().
+  Identity target_id(url, qualifier, GetPermissiveCapabilityFilter());
+  InterfaceRequest<Application> application_request =
+      CreateInstance(target_id, base::Closure(), nullptr);
+  NativeRunner* runner =
+      native_runner_factory_->Create(base::FilePath()).release();
+  native_runners_.push_back(runner);
+  runner->InitHost(channel.Pass(), application_request.Pass());
+}
+
+InterfaceRequest<Application> ApplicationManager::CreateAndConnectToInstance(
     scoped_ptr<ConnectToApplicationParams> params,
     ApplicationInstance** resulting_instance) {
-  Identity target_id = params->target();
-  ApplicationPtr application;
-  InterfaceRequest<Application> application_request = GetProxy(&application);
-  ApplicationInstance* instance = new ApplicationInstance(
-      application.Pass(), this, target_id, Shell::kInvalidContentHandlerID,
-      params->on_application_end());
-  DCHECK(identity_to_instance_.find(target_id) ==
-         identity_to_instance_.end());
-  identity_to_instance_[target_id] = instance;
-  instance->InitializeApplication();
+  ApplicationInstance* instance = nullptr;
+  InterfaceRequest<Application> application_request =
+      CreateInstance(params->target(), params->on_application_end(), &instance);
   instance->ConnectToClient(params.Pass());
   if (resulting_instance)
     *resulting_instance = instance;
   return application_request.Pass();
 }
 
-ApplicationInstance* ApplicationManager::GetApplicationInstance(
-    const Identity& identity) const {
-  const auto& it = identity_to_instance_.find(identity);
-  return it != identity_to_instance_.end() ? it->second : nullptr;
+InterfaceRequest<Application> ApplicationManager::CreateInstance(
+    const Identity& target_id,
+    const base::Closure& on_application_end,
+    ApplicationInstance** resulting_instance) {
+  ApplicationPtr application;
+  InterfaceRequest<Application> application_request = GetProxy(&application);
+  ApplicationInstance* instance = new ApplicationInstance(
+      application.Pass(), this, target_id, Shell::kInvalidContentHandlerID,
+      on_application_end);
+  DCHECK(identity_to_instance_.find(target_id) ==
+         identity_to_instance_.end());
+  identity_to_instance_[target_id] = instance;
+  instance->InitializeApplication();
+  if (resulting_instance)
+    *resulting_instance = instance;
+  return application_request.Pass();
 }
 
 void ApplicationManager::HandleFetchCallback(
@@ -171,7 +197,8 @@
       params->connect_callback();
   params->set_connect_callback(EmptyConnectCallback());
   ApplicationInstance* app = nullptr;
-  InterfaceRequest<Application> request(CreateInstance(params.Pass(), &app));
+  InterfaceRequest<Application> request(
+      CreateAndConnectToInstance(params.Pass(), &app));
 
   uint32_t content_handler_id = package_manager_->HandleWithContentHandler(
       fetcher.get(), source, target.url(), target.filter(), &request);
diff --git a/mojo/shell/application_manager.h b/mojo/shell/application_manager.h
index 16afd44..bab42481 100644
--- a/mojo/shell/application_manager.h
+++ b/mojo/shell/application_manager.h
@@ -92,6 +92,10 @@
 
   ApplicationInstance* GetApplicationInstance(const Identity& identity) const;
 
+  void CreateInstanceForHandle(ScopedHandle channel,
+                               const GURL& url,
+                               const std::string& qualifier);
+
  private:
   using IdentityToInstanceMap = std::map<Identity, ApplicationInstance*>;
   using URLToLoaderMap = std::map<GURL, ApplicationLoader*>;
@@ -100,9 +104,13 @@
   bool ConnectToRunningApplication(
       scoped_ptr<ConnectToApplicationParams>* params);
 
-  InterfaceRequest<Application> CreateInstance(
+  InterfaceRequest<Application> CreateAndConnectToInstance(
       scoped_ptr<ConnectToApplicationParams> params,
       ApplicationInstance** instance);
+  InterfaceRequest<Application> CreateInstance(
+      const Identity& target_id,
+      const base::Closure& on_application_end,
+      ApplicationInstance** resulting_instance);
 
   // Called once |fetcher| has found app. |params->app_url()| is the url of
   // the requested application before any mappings/resolution have been applied.
diff --git a/mojo/shell/application_manager.mojom b/mojo/shell/application_manager.mojom
index c9135bb6..3132da6c 100644
--- a/mojo/shell/application_manager.mojom
+++ b/mojo/shell/application_manager.mojom
@@ -10,5 +10,6 @@
   // initialization. This assumes the target process will bind the other end of
   // channel to an implementation of ChildController and bind an Application
   // request there.
-  CreateInstanceForHandle(handle channel);
+  // TODO(beng): we should probably have an Identity mojom struct.
+  CreateInstanceForHandle(handle channel, string url, string qualifier);
 };
diff --git a/mojo/shell/application_manager_apptest.cc b/mojo/shell/application_manager_apptest.cc
new file mode 100644
index 0000000..c6b14a2
--- /dev/null
+++ b/mojo/shell/application_manager_apptest.cc
@@ -0,0 +1,111 @@
+// Copyright 2015 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/bind.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/application/public/cpp/application_test_base.h"
+#include "mojo/application/public/cpp/interface_factory.h"
+#include "mojo/converters/network/network_type_converters.h"
+#include "mojo/shell/application_manager_apptests.mojom.h"
+
+using mojo::shell::test::mojom::CreateInstanceForHandleTest;
+
+namespace mojo {
+namespace shell {
+namespace {
+
+class ApplicationManagerAppTestDelegate
+    : public ApplicationDelegate,
+      public InterfaceFactory<CreateInstanceForHandleTest>,
+      public CreateInstanceForHandleTest {
+ public:
+  ApplicationManagerAppTestDelegate() : binding_(this) {}
+  ~ApplicationManagerAppTestDelegate() override {}
+
+  const std::string& data() const { return data_; }
+
+ private:
+  // ApplicationDelegate:
+  void Initialize(ApplicationImpl* app) override {}
+  bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
+    connection->AddService<CreateInstanceForHandleTest>(this);
+    return true;
+  }
+
+  // InterfaceFactory<CreateInstanceForHandleTest>:
+  void Create(
+      ApplicationConnection* connection,
+      InterfaceRequest<CreateInstanceForHandleTest> request) override {
+    binding_.Bind(request.Pass());
+  }
+
+  // CreateInstanceForHandleTest:
+  void Ping(const String& data) override {
+    data_ = data;
+    base::MessageLoop::current()->QuitWhenIdle();
+  }
+
+  std::string data_;
+
+  Binding<CreateInstanceForHandleTest> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ApplicationManagerAppTestDelegate);
+};
+
+}  // namespace
+
+class ApplicationManagerAppTest : public mojo::test::ApplicationTestBase {
+ public:
+  ApplicationManagerAppTest() : delegate_(nullptr) {}
+  ~ApplicationManagerAppTest() override {}
+
+  void OnDriverQuit() {
+    base::MessageLoop::current()->QuitNow();
+  }
+
+ protected:
+  const std::string& data() const {
+    DCHECK(delegate_);
+    return delegate_->data();
+  }
+
+  ApplicationManagerAppTestDelegate* delegate() { return delegate_; }
+
+ private:
+  // test::ApplicationTestBase:
+  ApplicationDelegate* GetApplicationDelegate() override {
+    delegate_ = new ApplicationManagerAppTestDelegate;
+    return delegate_;
+  }
+
+  ApplicationManagerAppTestDelegate* delegate_;
+
+  DISALLOW_COPY_AND_ASSIGN(ApplicationManagerAppTest);
+};
+
+TEST_F(ApplicationManagerAppTest, CreateInstanceForHandle) {
+  // 1. Launch a process. (Actually, have the runner launch a process that
+  //    launches a process. #becauselinkerrors).
+  mojo::shell::test::mojom::DriverPtr driver;
+  application_impl()->ConnectToService(
+      URLRequest::From(std::string("exe:application_manager_apptest_driver")),
+      &driver);
+
+  // 2. Wait for it to connect to us. (via mojo:application_manager_apptests)
+  base::MessageLoop::current()->Run();
+
+  // 3. Profit!
+  EXPECT_EQ(data(), "From Target");
+
+  driver.set_connection_error_handler(
+      base::Bind(&ApplicationManagerAppTest::OnDriverQuit,
+                 base::Unretained(this)));
+  driver->QuitDriver();
+  base::MessageLoop::current()->Run();
+}
+
+}  // namespace shell
+}  // namespace mojo
diff --git a/mojo/shell/application_manager_apptest_driver.cc b/mojo/shell/application_manager_apptest_driver.cc
new file mode 100644
index 0000000..06f2fad
--- /dev/null
+++ b/mojo/shell/application_manager_apptest_driver.cc
@@ -0,0 +1,137 @@
+// Copyright 2015 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/at_exit.h"
+#include "base/base_paths.h"
+#include "base/base_switches.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/process/process.h"
+#include "base/thread_task_runner_handle.h"
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/application/public/cpp/interface_factory.h"
+#include "mojo/common/weak_binding_set.h"
+#include "mojo/converters/network/network_type_converters.h"
+#include "mojo/runner/child/test_native_main.h"
+#include "mojo/runner/init.h"
+#include "mojo/shell/application_manager.mojom.h"
+#include "mojo/shell/application_manager_apptests.mojom.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
+#include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
+#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
+
+using mojo::shell::test::mojom::Driver;
+
+namespace {
+
+class TargetApplicationDelegate : public mojo::ApplicationDelegate,
+                                  public mojo::InterfaceFactory<Driver>,
+                                  public Driver {
+ public:
+  TargetApplicationDelegate() : app_(nullptr), weak_factory_(this) {}
+  ~TargetApplicationDelegate() override {}
+
+ private:
+  // mojo::ApplicationDelegate:
+  void Initialize(mojo::ApplicationImpl* app) override {
+    app_ = app;
+    mojo::shell::mojom::ApplicationManagerPtr application_manager;
+    app_->ConnectToService(mojo::URLRequest::From(std::string("mojo:shell")),
+                           &application_manager);
+
+    base::FilePath target_path;
+    CHECK(base::PathService::Get(base::DIR_EXE, &target_path));
+  #if defined(OS_WIN)
+    target_path = target_path.Append(
+        FILE_PATH_LITERAL("application_manager_apptest_target.exe"));
+  #else
+    target_path = target_path.Append(
+        FILE_PATH_LITERAL("application_manager_apptest_target"));
+  #endif
+
+    base::CommandLine child_command_line(target_path);
+    // Forward the wait-for-debugger flag but nothing else - we don't want to
+    // stamp on the platform-channel flag.
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kWaitForDebugger)) {
+      child_command_line.AppendSwitch(switches::kWaitForDebugger);
+    }
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch("use-new-edk"))
+      child_command_line.AppendSwitch("use-new-edk");
+
+    mojo::embedder::HandlePassingInformation handle_passing_info;
+
+    // Create the channel to be shared with the target process.
+    mojo::embedder::PlatformChannelPair platform_channel_pair;
+    // Give one end to the shell so that it can create an instance.
+    mojo::embedder::ScopedPlatformHandle platform_channel =
+        platform_channel_pair.PassServerHandle();
+
+    mojo::ScopedMessagePipeHandle handle(mojo::embedder::CreateChannel(
+        platform_channel.Pass(),
+        base::Bind(&TargetApplicationDelegate::DidCreateChannel,
+                   weak_factory_.GetWeakPtr()),
+        base::ThreadTaskRunnerHandle::Get()));
+
+    application_manager->CreateInstanceForHandle(
+        mojo::ScopedHandle(mojo::Handle(handle.release().value())),
+        "exe:application_manager_apptest_target",
+        "0");
+    // Put the other end on the command line used to launch the target.
+    platform_channel_pair.PrepareToPassClientHandleToChildProcess(
+        &child_command_line, &handle_passing_info);
+
+    base::LaunchOptions options;
+  #if defined(OS_WIN)
+    options.handles_to_inherit = &handle_passing_info;
+  #elif defined(OS_POSIX)
+    options.fds_to_remap = &handle_passing_info;
+  #endif
+    target_ = base::LaunchProcess(child_command_line, options);
+  }
+  bool ConfigureIncomingConnection(mojo::ApplicationConnection* connection) {
+    connection->AddService<Driver>(this);
+    return true;
+  }
+
+  // mojo::InterfaceFactory<Driver>:
+  void Create(mojo::ApplicationConnection* connection,
+              mojo::InterfaceRequest<Driver> request) override {
+    bindings_.AddBinding(this, request.Pass());
+  }
+
+  // Driver:
+  void QuitDriver() override {
+    target_.Terminate(0, false);
+    app_->Quit();
+  }
+
+  void DidCreateChannel(mojo::embedder::ChannelInfo* channel_info) {}
+
+  mojo::ApplicationImpl* app_;
+  base::WeakPtrFactory<TargetApplicationDelegate> weak_factory_;
+  base::Process target_;
+  mojo::WeakBindingSet<Driver> bindings_;
+
+  DISALLOW_COPY_AND_ASSIGN(TargetApplicationDelegate);
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit;
+  base::CommandLine::Init(argc, argv);
+
+  mojo::runner::InitializeLogging();
+
+  TargetApplicationDelegate delegate;
+  return mojo::runner::TestNativeMain(&delegate);
+}
diff --git a/mojo/shell/application_manager_apptest_target.cc b/mojo/shell/application_manager_apptest_target.cc
new file mode 100644
index 0000000..aa7bc784
--- /dev/null
+++ b/mojo/shell/application_manager_apptest_target.cc
@@ -0,0 +1,51 @@
+// Copyright 2015 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/at_exit.h"
+#include "base/command_line.h"
+#include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/converters/network/network_type_converters.h"
+#include "mojo/runner/child/test_native_main.h"
+#include "mojo/runner/init.h"
+#include "mojo/shell/application_manager_apptests.mojom.h"
+
+using mojo::shell::test::mojom::CreateInstanceForHandleTestPtr;
+
+namespace {
+
+class TargetApplicationDelegate : public mojo::ApplicationDelegate {
+ public:
+  TargetApplicationDelegate() {}
+  ~TargetApplicationDelegate() override {}
+
+ private:
+  // mojo::ApplicationDelegate:
+  void Initialize(mojo::ApplicationImpl* app) override {
+    CreateInstanceForHandleTestPtr service;
+    app->ConnectToService(
+        mojo::URLRequest::From(std::string("mojo:mojo_shell_apptests")),
+        &service);
+    service->Ping("From Target");
+  }
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override {
+    return true;
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(TargetApplicationDelegate);
+};
+
+}  // namespace
+
+int main(int argc, char** argv) {
+  base::AtExitManager at_exit;
+  base::CommandLine::Init(argc, argv);
+
+  mojo::runner::InitializeLogging();
+
+  TargetApplicationDelegate delegate;
+  return mojo::runner::TestNativeMain(&delegate);
+}
diff --git a/mojo/shell/application_manager_apptests.mojom b/mojo/shell/application_manager_apptests.mojom
new file mode 100644
index 0000000..7ca390a
--- /dev/null
+++ b/mojo/shell/application_manager_apptests.mojom
@@ -0,0 +1,13 @@
+// Copyright 2015 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.
+
+module mojo.shell.test.mojom;
+
+interface CreateInstanceForHandleTest {
+  Ping(string data);
+};
+
+interface Driver {
+  QuitDriver();
+};
diff --git a/mojo/shell/native_runner.h b/mojo/shell/native_runner.h
index 77e73c8..ebde8405 100644
--- a/mojo/shell/native_runner.h
+++ b/mojo/shell/native_runner.h
@@ -38,6 +38,11 @@
                      bool start_sandboxed,
                      InterfaceRequest<Application> application_request,
                      const base::Closure& app_completed_callback) = 0;
+
+  // Like Start(), but used to initialize the host for a child process started
+  // by someone else. Provides |application_request| via |channel|.
+  virtual void InitHost(ScopedHandle channel,
+                        InterfaceRequest<Application> application_request) = 0;
 };
 
 class NativeRunnerFactory {
diff --git a/mojo/shell/shell_application_delegate.cc b/mojo/shell/shell_application_delegate.cc
index 00c4485..25153fc 100644
--- a/mojo/shell/shell_application_delegate.cc
+++ b/mojo/shell/shell_application_delegate.cc
@@ -5,6 +5,7 @@
 #include "mojo/shell/shell_application_delegate.h"
 
 #include "mojo/application/public/cpp/application_connection.h"
+#include "mojo/shell/application_manager.h"
 
 namespace mojo {
 namespace shell {
@@ -27,8 +28,11 @@
   bindings_.AddBinding(this, request.Pass());
 }
 
-void ShellApplicationDelegate::CreateInstanceForHandle(ScopedHandle channel) {
-  // TODO(beng): create the instance.
+void ShellApplicationDelegate::CreateInstanceForHandle(
+    ScopedHandle channel,
+    const String& url,
+    const String& qualifier) {
+  manager_->CreateInstanceForHandle(channel.Pass(), GURL(url), qualifier);
 }
 
 }  // namespace shell
diff --git a/mojo/shell/shell_application_delegate.h b/mojo/shell/shell_application_delegate.h
index e0dcce3..cb03dd18 100644
--- a/mojo/shell/shell_application_delegate.h
+++ b/mojo/shell/shell_application_delegate.h
@@ -35,7 +35,9 @@
       InterfaceRequest<mojom::ApplicationManager> request) override;
 
   // Overridden from mojom::ApplicationManager:
-  void CreateInstanceForHandle(ScopedHandle channel) override;
+  void CreateInstanceForHandle(ScopedHandle channel,
+                               const String& url,
+                               const String& qualifier) override;
 
   mojo::shell::ApplicationManager* manager_;
 
diff --git a/net/base/lookup_string_in_fixed_set.cc b/net/base/lookup_string_in_fixed_set.cc
new file mode 100644
index 0000000..46497f3c
--- /dev/null
+++ b/net/base/lookup_string_in_fixed_set.cc
@@ -0,0 +1,152 @@
+// Copyright 2015 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 "net/base/lookup_string_in_fixed_set.h"
+
+#include "base/logging.h"
+
+namespace net {
+
+namespace {
+
+// Read next offset from pos.
+// Returns true if an offset could be read, false otherwise.
+bool GetNextOffset(const unsigned char** pos,
+                   const unsigned char* end,
+                   const unsigned char** offset) {
+  if (*pos == end)
+    return false;
+
+  // When reading an offset the byte array must always contain at least
+  // three more bytes to consume. First the offset to read, then a node
+  // to skip over and finally a destination node. No object can be smaller
+  // than one byte.
+  CHECK_LT(*pos + 2, end);
+  size_t bytes_consumed;
+  switch (**pos & 0x60) {
+    case 0x60:  // Read three byte offset
+      *offset += (((*pos)[0] & 0x1F) << 16) | ((*pos)[1] << 8) | (*pos)[2];
+      bytes_consumed = 3;
+      break;
+    case 0x40:  // Read two byte offset
+      *offset += (((*pos)[0] & 0x1F) << 8) | (*pos)[1];
+      bytes_consumed = 2;
+      break;
+    default:
+      *offset += (*pos)[0] & 0x3F;
+      bytes_consumed = 1;
+  }
+  if ((**pos & 0x80) != 0) {
+    *pos = end;
+  } else {
+    *pos += bytes_consumed;
+  }
+  return true;
+}
+
+// Check if byte at offset is last in label.
+bool IsEOL(const unsigned char* offset, const unsigned char* end) {
+  CHECK_LT(offset, end);
+  return (*offset & 0x80) != 0;
+}
+
+// Check if byte at offset matches first character in key.
+// This version matches characters not last in label.
+bool IsMatch(const unsigned char* offset,
+             const unsigned char* end,
+             const char* key) {
+  CHECK_LT(offset, end);
+  return *offset == *key;
+}
+
+// Check if byte at offset matches first character in key.
+// This version matches characters last in label.
+bool IsEndCharMatch(const unsigned char* offset,
+                    const unsigned char* end,
+                    const char* key) {
+  CHECK_LT(offset, end);
+  return *offset == (*key | 0x80);
+}
+
+// Read return value at offset.
+// Returns true if a return value could be read, false otherwise.
+bool GetReturnValue(const unsigned char* offset,
+                    const unsigned char* end,
+                    int* return_value) {
+  CHECK_LT(offset, end);
+  if ((*offset & 0xE0) == 0x80) {
+    *return_value = *offset & 0x0F;
+    return true;
+  }
+  return false;
+}
+
+}  // namespace
+
+// Lookup a domain key in a byte array generated by make_dafsa.py.
+// The rule type is returned if key is found, otherwise kDafsaNotFound is
+// returned.
+int LookupStringInFixedSet(const unsigned char* graph,
+                           size_t length,
+                           const char* key,
+                           size_t key_length) {
+  const unsigned char* pos = graph;
+  const unsigned char* end = graph + length;
+  const unsigned char* offset = pos;
+  const char* key_end = key + key_length;
+  while (GetNextOffset(&pos, end, &offset)) {
+    //   char <char>+ end_char offsets
+    //   char <char>+ return value
+    //   char end_char offsets
+    //   char return value
+    //   end_char offsets
+    //   return_value
+    bool did_consume = false;
+    if (key != key_end && !IsEOL(offset, end)) {
+      // Leading <char> is not a match. Don't dive into this child
+      if (!IsMatch(offset, end, key))
+        continue;
+      did_consume = true;
+      ++offset;
+      ++key;
+      // Possible matches at this point:
+      // <char>+ end_char offsets
+      // <char>+ return value
+      // end_char offsets
+      // return value
+      // Remove all remaining <char> nodes possible
+      while (!IsEOL(offset, end) && key != key_end) {
+        if (!IsMatch(offset, end, key))
+          return kDafsaNotFound;
+        ++key;
+        ++offset;
+      }
+    }
+    // Possible matches at this point:
+    // end_char offsets
+    // return_value
+    // If one or more <char> elements were consumed, a failure
+    // to match is terminal. Otherwise, try the next node.
+    if (key == key_end) {
+      int return_value;
+      if (GetReturnValue(offset, end, &return_value))
+        return return_value;
+      // The DAFSA guarantees that if the first char is a match, all
+      // remaining char elements MUST match if the key is truly present.
+      if (did_consume)
+        return kDafsaNotFound;
+      continue;
+    }
+    if (!IsEndCharMatch(offset, end, key)) {
+      if (did_consume)
+        return kDafsaNotFound;  // Unexpected
+      continue;
+    }
+    ++key;
+    pos = ++offset;  // Dive into child
+  }
+  return kDafsaNotFound;  // No match
+}
+
+}  // namespace net
diff --git a/net/base/lookup_string_in_fixed_set.h b/net/base/lookup_string_in_fixed_set.h
new file mode 100644
index 0000000..793a782e
--- /dev/null
+++ b/net/base/lookup_string_in_fixed_set.h
@@ -0,0 +1,40 @@
+// Copyright 2015 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.
+
+#ifndef NET_BASE_LOOKUP_STRING_IN_FIXED_SET_H_
+#define NET_BASE_LOOKUP_STRING_IN_FIXED_SET_H_
+
+#include <stddef.h>
+
+#include "net/base/net_export.h"
+
+namespace net {
+
+enum {
+  kDafsaNotFound = -1,  // key is not in set
+  kDafsaFound = 0,      // key is in set
+  // The following return values are used by the implementation of
+  // GetDomainAndRegistry() and are probably not generally useful.
+  kDafsaExceptionRule = 1,  // key excluded from set via exception
+  kDafsaWildcardRule = 2,   // key matched a wildcard rule
+  kDafsaPrivateRule = 4,    // key matched a private rule
+};
+
+// Looks up the string |key| with length |key_length| in a fixed set of
+// strings. The set of strings must be known at compile time. It is converted to
+// a graph structure named a DAFSA (Deterministic Acyclic Finite State
+// Automaton) by the script make_dafsa.py during compilation. This permits
+// efficient (in time and space) lookup. The graph generated by make_dafsa.py
+// takes the form of a constant byte array which should be supplied via the
+// |graph| and |length| parameters.  The return value is kDafsaNotFound,
+// kDafsaFound, or a bitmap consisting of one or more of kDafsaExceptionRule,
+// kDafsaWildcardRule and kDafsaPrivateRule ORed together.
+NET_EXPORT int LookupStringInFixedSet(const unsigned char* graph,
+                                      size_t length,
+                                      const char* key,
+                                      size_t key_length);
+
+}  // namespace net
+
+#endif  // NET_BASE_LOOKUP_STRING_IN_FIXED_SET_H_
diff --git a/net/base/lookup_string_in_fixed_set_unittest.cc b/net/base/lookup_string_in_fixed_set_unittest.cc
new file mode 100644
index 0000000..82e6c22
--- /dev/null
+++ b/net/base/lookup_string_in_fixed_set_unittest.cc
@@ -0,0 +1,162 @@
+// Copyright 2015 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 "net/base/lookup_string_in_fixed_set.h"
+
+#include <string.h>
+#include <ostream>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace {
+namespace test1 {
+#include "net/base/registry_controlled_domains/effective_tld_names_unittest1-inc.cc"
+}
+namespace test3 {
+#include "net/base/registry_controlled_domains/effective_tld_names_unittest3-inc.cc"
+}
+namespace test4 {
+#include "net/base/registry_controlled_domains/effective_tld_names_unittest4-inc.cc"
+}
+namespace test5 {
+#include "net/base/registry_controlled_domains/effective_tld_names_unittest5-inc.cc"
+}
+namespace test6 {
+#include "net/base/registry_controlled_domains/effective_tld_names_unittest6-inc.cc"
+}
+
+struct Expectation {
+  const char* const key;
+  int value;
+};
+
+void PrintTo(const Expectation& expectation, std::ostream* os) {
+  *os << "{\"" << expectation.key << "\", " << expectation.value << "}";
+}
+
+class LookupStringInFixedSetTest : public testing::TestWithParam<Expectation> {
+ protected:
+  template <size_t N>
+  int LookupInGraph(const unsigned char(&graph)[N], const char* key) {
+    return LookupStringInFixedSet(graph, N, key, strlen(key));
+  }
+};
+
+class Dafsa1Test : public LookupStringInFixedSetTest {};
+
+TEST_P(Dafsa1Test, BasicTest) {
+  const Expectation& param = GetParam();
+  EXPECT_EQ(param.value, LookupInGraph(test1::kDafsa, param.key));
+}
+
+const Expectation kBasicTestCases[] = {
+    {"", -1},      {"j", -1},          {"jp", 0}, {"jjp", -1}, {"jpp", -1},
+    {"bar.jp", 2}, {"pref.bar.jp", 1}, {"c", 2},  {"b.c", 1},  {"priv.no", 4},
+};
+
+INSTANTIATE_TEST_CASE_P(LookupStringInFixedSetTest,
+                        Dafsa1Test,
+                        ::testing::ValuesIn(kBasicTestCases));
+
+class Dafsa3Test : public LookupStringInFixedSetTest {};
+
+// This DAFSA is constructed so that labels begin and end with unique
+// characters, which makes it impossible to merge labels. Each inner node
+// is about 100 bytes and a one byte offset can at most add 64 bytes to
+// previous offset. Thus the paths must go over two byte offsets.
+TEST_P(Dafsa3Test, TestDafsaTwoByteOffsets) {
+  const Expectation& param = GetParam();
+  EXPECT_EQ(param.value, LookupInGraph(test3::kDafsa, param.key));
+}
+
+const Expectation kTwoByteOffsetTestCases[] = {
+    {"0________________________________________________________________________"
+     "____________________________0",
+     0},
+    {"7________________________________________________________________________"
+     "____________________________7",
+     4},
+    {"a________________________________________________________________________"
+     "____________________________8",
+     -1},
+};
+
+INSTANTIATE_TEST_CASE_P(LookupStringInFixedSetTest,
+                        Dafsa3Test,
+                        ::testing::ValuesIn(kTwoByteOffsetTestCases));
+
+class Dafsa4Test : public LookupStringInFixedSetTest {};
+
+// This DAFSA is constructed so that labels begin and end with unique
+// characters, which makes it impossible to merge labels. The byte array
+// has a size of ~54k. A two byte offset can add at most add 8k to the
+// previous offset. Since we can skip only forward in memory, the nodes
+// representing the return values must be located near the end of the byte
+// array. The probability that we can reach from an arbitrary inner node to
+// a return value without using a three byte offset is small (but not zero).
+// The test is repeated with some different keys and with a reasonable
+// probability at least one of the tested paths has go over a three byte
+// offset.
+TEST_P(Dafsa4Test, TestDafsaThreeByteOffsets) {
+  const Expectation& param = GetParam();
+  EXPECT_EQ(param.value, LookupInGraph(test4::kDafsa, param.key));
+}
+
+const Expectation kThreeByteOffsetTestCases[] = {
+    {"Z6_______________________________________________________________________"
+     "_____________________________Z6",
+     0},
+    {"Z7_______________________________________________________________________"
+     "_____________________________Z7",
+     4},
+    {"Za_______________________________________________________________________"
+     "_____________________________Z8",
+     -1},
+};
+
+INSTANTIATE_TEST_CASE_P(LookupStringInFixedSetTest,
+                        Dafsa4Test,
+                        ::testing::ValuesIn(kThreeByteOffsetTestCases));
+
+class Dafsa5Test : public LookupStringInFixedSetTest {};
+
+// This DAFSA is constructed from words with similar prefixes but distinct
+// suffixes. The DAFSA will then form a trie with the implicit source node
+// as root.
+TEST_P(Dafsa5Test, TestDafsaJoinedPrefixes) {
+  const Expectation& param = GetParam();
+  EXPECT_EQ(param.value, LookupInGraph(test5::kDafsa, param.key));
+}
+
+const Expectation kJoinedPrefixesTestCases[] = {
+    {"ai", 0},   {"bj", 4},   {"aak", 0},   {"bbl", 4},
+    {"aaa", -1}, {"bbb", -1}, {"aaaam", 0}, {"bbbbn", 0},
+};
+
+INSTANTIATE_TEST_CASE_P(LookupStringInFixedSetTest,
+                        Dafsa5Test,
+                        ::testing::ValuesIn(kJoinedPrefixesTestCases));
+
+class Dafsa6Test : public LookupStringInFixedSetTest {};
+
+// This DAFSA is constructed from words with similar suffixes but distinct
+// prefixes. The DAFSA will then form a trie with the implicit sink node as
+// root.
+TEST_P(Dafsa6Test, TestDafsaJoinedSuffixes) {
+  const Expectation& param = GetParam();
+  EXPECT_EQ(param.value, LookupInGraph(test6::kDafsa, param.key));
+}
+
+const Expectation kJoinedSuffixesTestCases[] = {
+    {"ia", 0},   {"jb", 4},   {"kaa", 0},   {"lbb", 4},
+    {"aaa", -1}, {"bbb", -1}, {"maaaa", 0}, {"nbbbb", 0},
+};
+
+INSTANTIATE_TEST_CASE_P(LookupStringInFixedSetTest,
+                        Dafsa6Test,
+                        ::testing::ValuesIn(kJoinedSuffixesTestCases));
+
+}  // namespace
+}  // namespace net
diff --git a/net/base/registry_controlled_domains/BUILD.gn b/net/base/registry_controlled_domains/BUILD.gn
index d231ac1..d8aa971c 100644
--- a/net/base/registry_controlled_domains/BUILD.gn
+++ b/net/base/registry_controlled_domains/BUILD.gn
@@ -3,7 +3,7 @@
 # found in the LICENSE file.
 
 action_foreach("registry_controlled_domains") {
-  script = "//net/tools/tld_cleanup/make_dafsa.py"
+  script = "//net/tools/dafsa/make_dafsa.py"
   sources = [
     "effective_tld_names.gperf",
     "effective_tld_names_unittest1.gperf",
diff --git a/net/base/registry_controlled_domains/effective_tld_names.dat b/net/base/registry_controlled_domains/effective_tld_names.dat
index 165cc09..ce9ad58c 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.dat
+++ b/net/base/registry_controlled_domains/effective_tld_names.dat
@@ -1134,8 +1134,16 @@
 ie
 gov.ie
 
-// il : http://en.wikipedia.org/wiki/.il
-*.il
+// il : http://www.isoc.org.il/domains/
+il
+ac.il
+co.il
+gov.il
+idf.il
+k12.il
+muni.il
+net.il
+org.il
 
 // im : https://www.nic.im/
 // Submitted by registry <info@nic.im> 2013-11-15
@@ -6922,7 +6930,7 @@
 *.zw
 
 
-// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-09-25T01:37:01Z
+// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2015-11-12T22:43:48Z
 
 // aaa : 2015-02-26 American Automobile Association, Inc.
 aaa
@@ -7191,6 +7199,9 @@
 // bargains : 2013-11-14 Half Hallow, LLC
 bargains
 
+// baseball : 2015-10-29 MLB Advanced Media DH, LLC
+baseball
+
 // basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA)
 basketball
 
@@ -7449,6 +7460,9 @@
 // catering : 2013-12-05 New Falls. LLC
 catering
 
+// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+catholic
+
 // cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
 cba
 
@@ -7548,6 +7562,9 @@
 // clinic : 2014-03-20 Goose Park, LLC
 clinic
 
+// clinique : 2015-10-01 The Estée Lauder Companies Inc.
+clinique
+
 // clothing : 2013-08-27 Steel Lake, LLC
 clothing
 
@@ -7587,6 +7604,9 @@
 // company : 2013-11-07 Silver Avenue, LLC
 company
 
+// compare : 2015-10-08 iSelect Ltd
+compare
+
 // computer : 2013-10-24 Pine Mill, LLC
 computer
 
@@ -7761,6 +7781,9 @@
 // dish : 2015-07-30 Dish DBS Corporation
 dish
 
+// diy : 2015-11-05 Lifestyle Domain Holdings, Inc.
+diy
+
 // dnp : 2013-12-13 Dai Nippon Printing Co., Ltd.
 dnp
 
@@ -8583,6 +8606,9 @@
 // lamborghini : 2015-06-04 Automobili Lamborghini S.p.A.
 lamborghini
 
+// lamer : 2015-10-01 The Estée Lauder Companies Inc.
+lamer
+
 // lancaster : 2015-02-12 LANCASTER
 lancaster
 
@@ -9024,6 +9050,9 @@
 // nissan : 2014-03-27 NISSAN MOTOR CO., LTD.
 nissan
 
+// nissay : 2015-10-29 Nippon Life Insurance Company
+nissay
+
 // nokia : 2015-01-08 Nokia Corporation
 nokia
 
@@ -9117,6 +9146,9 @@
 // orientexpress : 2015-02-05 Belmond Ltd.
 orientexpress
 
+// origins : 2015-10-01 The Estée Lauder Companies Inc.
+origins
+
 // osaka : 2014-09-04 Interlink Co., Ltd.
 osaka
 
@@ -9297,6 +9329,9 @@
 // pub : 2013-12-12 United TLD Holdco Ltd.
 pub
 
+// pwc : 2015-10-29 PricewaterhouseCoopers LLP
+pwc
+
 // qpon : 2013-11-14 dotCOOL, Inc.
 qpon
 
@@ -9543,6 +9578,9 @@
 // seek : 2014-12-04 Seek Limited
 seek
 
+// select : 2015-10-08 iSelect Ltd
+select
+
 // sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A.
 sener
 
@@ -9693,7 +9731,7 @@
 // star : 2015-01-08 Star India Private Limited
 star
 
-// starhub : 2015-02-05 StarHub Limited
+// starhub : 2015-02-05 StarHub Ltd
 starhub
 
 // statebank : 2015-03-12 STATE BANK OF INDIA
@@ -9957,6 +9995,9 @@
 // uconnect : 2015-07-30 FCA US LLC.
 uconnect
 
+// unicom : 2015-10-15 China United Network Communications Corporation Limited
+unicom
+
 // university : 2014-03-06 Little Station, LLC
 university
 
@@ -10152,6 +10193,9 @@
 // world : 2014-06-12 Bitter Fields, LLC
 world
 
+// wow : 2015-10-08 Amazon EU S.à r.l.
+wow
+
 // wtc : 2013-12-19 World Trade Centers Association, Inc.
 wtc
 
@@ -10230,6 +10274,9 @@
 // xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
 москва
 
+// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+католик
+
 // xn--80asehdb : 2013-07-14 CORE Association
 онлайн
 
@@ -10314,6 +10361,9 @@
 // xn--gckr3f0f : 2015-02-26 Amazon EU S.à r.l.
 クラウド
 
+// xn--gk3at1e : 2015-10-08 Amazon EU S.à r.l.
+通販
+
 // xn--hxt814e : 2014-05-15 Zodiac Libra Limited
 网店
 
@@ -10362,6 +10412,9 @@
 // xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre
 ابوظبي
 
+// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+كاثوليك
+
 // xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
 همراه
 
@@ -10416,6 +10469,9 @@
 // xn--tckwe : 2015-01-15 VeriSign Sarl
 コム
 
+// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+天主教
+
 // xn--unup4y : 2013-07-14 Spring Fields, LLC
 游戏
 
@@ -11133,6 +11189,10 @@
 // Submitted by Trung Tran <Trung.Tran@neustar.biz> 2015-04-23
 4u.com
 
+// ngrok : https://ngrok.com/
+// Submitted by Alan Shreve <alan@ngrok.com> 2015-11-10
+ngrok.io
+
 // NFSN, Inc. : https://www.NearlyFreeSpeech.NET/
 // Submitted by Jeff Wheelhouse <support@nearlyfreespeech.net> 2014-02-02
 nfshost.com
diff --git a/net/base/registry_controlled_domains/effective_tld_names.gperf b/net/base/registry_controlled_domains/effective_tld_names.gperf
index 21b685b..94ba5c0 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.gperf
+++ b/net/base/registry_controlled_domains/effective_tld_names.gperf
@@ -59,6 +59,7 @@
 ac.cy, 0
 ac.gn, 0
 ac.id, 0
+ac.il, 0
 ac.im, 0
 ac.in, 0
 ac.ir, 0
@@ -511,6 +512,7 @@
 barrell-of-knowledge.info, 4
 barum.no, 0
 bas.it, 0
+baseball, 0
 baseball.museum, 0
 basel.museum, 0
 bashkiria.ru, 0
@@ -887,6 +889,7 @@
 catanzaro.it, 0
 catering, 0
 catering.aero, 0
+catholic, 0
 cb.it, 0
 cba, 0
 cbg.ru, 0
@@ -1078,6 +1081,7 @@
 cleaning, 0
 click, 0
 clinic, 0
+clinique, 0
 clinton.museum, 0
 clock.museum, 0
 clothing, 0
@@ -1120,6 +1124,7 @@
 co.gy, 0
 co.hu, 0
 co.id, 0
+co.il, 0
 co.im, 0
 co.in, 0
 co.ir, 0
@@ -1313,6 +1318,7 @@
 community.museum, 0
 como.it, 0
 company, 0
+compare, 0
 compute-1.amazonaws.com, 4
 compute.amazonaws.cn, 4
 compute.amazonaws.com, 4
@@ -1481,6 +1487,7 @@
 dish, 0
 divtasvuodna.no, 0
 divttasvuotna.no, 0
+diy, 0
 dj, 0
 dk, 0
 dk.eu.org, 4
@@ -2348,6 +2355,7 @@
 gov.gr, 0
 gov.hk, 0
 gov.ie, 0
+gov.il, 0
 gov.in, 0
 gov.iq, 0
 gov.ir, 0
@@ -2827,6 +2835,7 @@
 id.ly, 0
 id.us, 0
 ide.kyoto.jp, 0
+idf.il, 0
 idrett.no, 0
 idv.hk, 0
 idv.tw, 0
@@ -2859,7 +2868,7 @@
 iki.nagasaki.jp, 0
 ikoma.nara.jp, 0
 ikusaka.nagano.jp, 0
-il, 2
+il, 0
 il.eu.org, 4
 il.us, 0
 ilawa.pl, 0
@@ -3239,6 +3248,7 @@
 k12.gu.us, 0
 k12.ia.us, 0
 k12.id.us, 0
+k12.il, 0
 k12.il.us, 0
 k12.in.us, 0
 k12.ks.us, 0
@@ -3721,6 +3731,7 @@
 lajolla.museum, 0
 lakas.hu, 0
 lamborghini, 0
+lamer, 0
 lanbib.se, 0
 lancashire.museum, 0
 lancaster, 0
@@ -4409,6 +4420,7 @@
 multichoice, 0
 munakata.fukuoka.jp, 0
 muncie.museum, 0
+muni.il, 0
 muosat.no, 0
 mup.gov.pl, 0
 murakami.niigata.jp, 0
@@ -4658,6 +4670,7 @@
 net.hn, 0
 net.ht, 0
 net.id, 0
+net.il, 0
 net.im, 0
 net.in, 0
 net.iq, 0
@@ -4765,6 +4778,7 @@
 ngo.lk, 0
 ngo.ph, 0
 ngo.za, 0
+ngrok.io, 4
 nh.us, 0
 nhk, 0
 nhs.uk, 0
@@ -4816,6 +4830,7 @@
 nishitosa.kochi.jp, 0
 nishiwaki.hyogo.jp, 0
 nissan, 0
+nissay, 0
 nissedal.no, 0
 nisshin.aichi.jp, 0
 nittedal.no, 0
@@ -5144,6 +5159,7 @@
 org.hn, 0
 org.ht, 0
 org.hu, 0
+org.il, 0
 org.im, 0
 org.in, 0
 org.iq, 0
@@ -5235,6 +5251,7 @@
 org.za, 0
 organic, 0
 orientexpress, 0
+origins, 0
 oristano.it, 0
 orkanger.no, 0
 orkdal.no, 0
@@ -5556,6 +5573,7 @@
 pvt.ge, 0
 pvt.k12.ma.us, 0
 pw, 0
+pwc, 0
 py, 0
 pyatigorsk.ru, 0
 pz.it, 0
@@ -5959,6 +5977,7 @@
 sekikawa.niigata.jp, 0
 sel.no, 0
 selbu.no, 0
+select, 0
 selfip.biz, 4
 selfip.com, 4
 selfip.info, 4
@@ -6874,6 +6893,7 @@
 unazuki.toyama.jp, 0
 unbi.ba, 0
 undersea.museum, 0
+unicom, 0
 union.aero, 0
 univ.sn, 0
 university, 0
@@ -7194,6 +7214,7 @@
 workshop.museum, 0
 world, 0
 worse-than.tv, 4
+wow, 0
 writesthisblog.com, 4
 wroc.pl, 4
 wroclaw.pl, 0
@@ -7257,6 +7278,7 @@
 xn--7t0a264c.jp, 0
 xn--80adxhks, 0
 xn--80ao21a, 0
+xn--80aqecdr1a, 0
 xn--80asehdb, 0
 xn--80aswg, 0
 xn--80au.xn--90a3ac, 0
@@ -7352,6 +7374,7 @@
 xn--gildeskl-g0a.no, 0
 xn--givuotna-8ya.no, 0
 xn--gjvik-wua.no, 0
+xn--gk3at1e, 0
 xn--gls-elac.no, 0
 xn--gmq050i.hk, 0
 xn--gmqw5a.hk, 0
@@ -7449,6 +7472,7 @@
 xn--mgbca7dzdo, 0
 xn--mgberp4a5d4a87g, 0
 xn--mgberp4a5d4ar, 0
+xn--mgbi4ecexp, 0
 xn--mgbpl2fh, 0
 xn--mgbqly7c0a67fbc, 0
 xn--mgbqly7cvafr, 0
@@ -7565,6 +7589,7 @@
 xn--stre-toten-zcb.no, 0
 xn--t60b56a, 0
 xn--tckwe, 0
+xn--tiq49xqyj, 0
 xn--tjme-hra.no, 0
 xn--tn0ag.hk, 0
 xn--tnsberg-q1a.no, 0
diff --git a/net/base/registry_controlled_domains/registry_controlled_domain.cc b/net/base/registry_controlled_domains/registry_controlled_domain.cc
index 778e858a..7e62316 100644
--- a/net/base/registry_controlled_domains/registry_controlled_domain.cc
+++ b/net/base/registry_controlled_domains/registry_controlled_domain.cc
@@ -48,6 +48,7 @@
 #include "base/logging.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "net/base/lookup_string_in_fixed_set.h"
 #include "net/base/net_module.h"
 #include "net/base/net_util.h"
 #include "url/gurl.h"
@@ -64,141 +65,6 @@
 const unsigned char* g_graph = kDafsa;
 size_t g_graph_length = sizeof(kDafsa);
 
-const int kNotFound = -1;
-const int kExceptionRule = 1;
-const int kWildcardRule = 2;
-const int kPrivateRule = 4;
-
-// Read next offset from pos.
-// Returns true if an offset could be read, false otherwise.
-bool GetNextOffset(const unsigned char** pos, const unsigned char* end,
-                   const unsigned char** offset) {
-  if (*pos == end)
-    return false;
-
-  // When reading an offset the byte array must always contain at least
-  // three more bytes to consume. First the offset to read, then a node
-  // to skip over and finally a destination node. No object can be smaller
-  // than one byte.
-  CHECK_LT(*pos + 2, end);
-  size_t bytes_consumed;
-  switch (**pos & 0x60) {
-    case 0x60:  // Read three byte offset
-      *offset += (((*pos)[0] & 0x1F) << 16) | ((*pos)[1] << 8) | (*pos)[2];
-      bytes_consumed = 3;
-      break;
-    case 0x40:  // Read two byte offset
-      *offset += (((*pos)[0] & 0x1F) << 8) | (*pos)[1];
-      bytes_consumed = 2;
-      break;
-    default:
-      *offset += (*pos)[0] & 0x3F;
-      bytes_consumed = 1;
-  }
-  if ((**pos & 0x80) != 0) {
-    *pos = end;
-  } else {
-    *pos += bytes_consumed;
-  }
-  return true;
-}
-
-// Check if byte at offset is last in label.
-bool IsEOL(const unsigned char* offset, const unsigned char* end) {
-  CHECK_LT(offset, end);
-  return (*offset & 0x80) != 0;
-}
-
-// Check if byte at offset matches first character in key.
-// This version matches characters not last in label.
-bool IsMatch(const unsigned char* offset, const unsigned char* end,
-             const char* key) {
-  CHECK_LT(offset, end);
-  return *offset == *key;
-}
-
-// Check if byte at offset matches first character in key.
-// This version matches characters last in label.
-bool IsEndCharMatch(const unsigned char* offset, const unsigned char* end,
-                    const char* key) {
-  CHECK_LT(offset, end);
-  return *offset == (*key | 0x80);
-}
-
-// Read return value at offset.
-// Returns true if a return value could be read, false otherwise.
-bool GetReturnValue(const unsigned char* offset, const unsigned char* end,
-                    int* return_value) {
-  CHECK_LT(offset, end);
-  if ((*offset & 0xE0) == 0x80) {
-    *return_value = *offset & 0x0F;
-    return true;
-  }
-  return false;
-}
-
-// Lookup a domain key in a byte array generated by make_dafsa.py.
-// The rule type is returned if key is found, otherwise kNotFound is returned.
-int LookupString(const unsigned char* graph, size_t length, const char* key,
-                 size_t key_length) {
-  const unsigned char* pos = graph;
-  const unsigned char* end = graph + length;
-  const unsigned char* offset = pos;
-  const char* key_end = key + key_length;
-  while (GetNextOffset(&pos, end, &offset)) {
-    //   char <char>+ end_char offsets
-    //   char <char>+ return value
-    //   char end_char offsets
-    //   char return value
-    //   end_char offsets
-    //   return_value
-    bool did_consume = false;
-    if (key != key_end && !IsEOL(offset, end)) {
-      // Leading <char> is not a match. Don't dive into this child
-      if (!IsMatch(offset, end, key))
-        continue;
-      did_consume = true;
-      ++offset;
-      ++key;
-      // Possible matches at this point:
-      // <char>+ end_char offsets
-      // <char>+ return value
-      // end_char offsets
-      // return value
-      // Remove all remaining <char> nodes possible
-      while (!IsEOL(offset, end) && key != key_end) {
-        if (!IsMatch(offset, end, key))
-          return kNotFound;
-        ++key;
-        ++offset;
-      }
-    }
-    // Possible matches at this point:
-    // end_char offsets
-    // return_value
-    // If one or more <char> elements were consumed, a failure
-    // to match is terminal. Otherwise, try the next node.
-    if (key == key_end) {
-      int return_value;
-      if (GetReturnValue(offset, end, &return_value))
-        return return_value;
-      // The DAFSA guarantees that if the first char is a match, all
-      // remaining char elements MUST match if the key is truly present.
-      if (did_consume)
-        return kNotFound;
-      continue;
-    }
-    if (!IsEndCharMatch(offset, end, key)) {
-      if (did_consume)
-        return kNotFound;  // Unexpected
-      continue;
-    }
-    ++key;
-    pos = ++offset;  // Dive into child
-  }
-  return kNotFound;  // No match
-}
-
 size_t GetRegistryLengthImpl(
     const std::string& host,
     UnknownRegistryFilter unknown_filter,
@@ -231,24 +97,25 @@
   while (1) {
     const char* domain_str = host.data() + curr_start;
     size_t domain_length = host_check_len - curr_start;
-    int type = LookupString(g_graph, g_graph_length, domain_str, domain_length);
-    bool do_check =
-        type != kNotFound && (!(type & kPrivateRule) ||
-                              private_filter == INCLUDE_PRIVATE_REGISTRIES);
+    int type = LookupStringInFixedSet(g_graph, g_graph_length, domain_str,
+                                      domain_length);
+    bool do_check = type != kDafsaNotFound &&
+                    (!(type & kDafsaPrivateRule) ||
+                     private_filter == INCLUDE_PRIVATE_REGISTRIES);
 
     // If the apparent match is a private registry and we're not including
     // those, it can't be an actual match.
     if (do_check) {
       // Exception rules override wildcard rules when the domain is an exact
       // match, but wildcards take precedence when there's a subdomain.
-      if (type & kWildcardRule && (prev_start != std::string::npos)) {
+      if (type & kDafsaWildcardRule && (prev_start != std::string::npos)) {
         // If prev_start == host_check_begin, then the host is the registry
         // itself, so return 0.
         return (prev_start == host_check_begin) ? 0
                                                 : (host.length() - prev_start);
       }
 
-      if (type & kExceptionRule) {
+      if (type & kDafsaExceptionRule) {
         if (next_dot == std::string::npos) {
           // If we get here, we had an exception rule with no dots (e.g.
           // "!foo").  This would only be valid if we had a corresponding
diff --git a/net/cert/cert_verify_proc.cc b/net/cert/cert_verify_proc.cc
index bb379ff..0df2033a 100644
--- a/net/cert/cert_verify_proc.cc
+++ b/net/cert/cert_verify_proc.cc
@@ -165,6 +165,18 @@
   return weak_key;
 }
 
+// Beginning with Ballot 118, ratified in the Baseline Requirements v1.2.1,
+// CAs MUST NOT issue SHA-1 certificates beginning on 1 January 2016.
+bool IsPastSHA1DeprecationDate(const X509Certificate& cert) {
+  const base::Time& start = cert.valid_start();
+  if (start.is_max() || start.is_null())
+    return true;
+  // 2016-01-01 00:00:00 UTC.
+  const base::Time kSHA1DeprecationDate =
+      base::Time::FromInternalValue(INT64_C(13096080000000000));
+  return start >= kSHA1DeprecationDate;
+}
+
 }  // namespace
 
 // static
@@ -262,8 +274,19 @@
     rv = MapCertStatusToNetError(verify_result->cert_status);
   }
 
+  if (verify_result->has_sha1)
+    verify_result->cert_status |= CERT_STATUS_SHA1_SIGNATURE_PRESENT;
+
   // Flag certificates using weak signature algorithms.
-  if (verify_result->has_md5) {
+  // The CA/Browser Forum Baseline Requirements (beginning with v1.2.1)
+  // prohibits SHA-1 certificates from being issued beginning on
+  // 1 January 2016. Ideally, all of SHA-1 in new certificates would be
+  // disabled on this date, but enterprises need more time to transition.
+  // As the risk is greatest for publicly trusted certificates, prevent
+  // those certificates from being trusted from that date forward.
+  if (verify_result->has_md5 ||
+      (verify_result->has_sha1_leaf && verify_result->is_issued_by_known_root &&
+       IsPastSHA1DeprecationDate(*cert))) {
     verify_result->cert_status |= CERT_STATUS_WEAK_SIGNATURE_ALGORITHM;
     // Avoid replacing a more serious error, such as an OS/library failure,
     // by ensuring that if verification failed, it failed with a certificate
@@ -272,9 +295,6 @@
       rv = MapCertStatusToNetError(verify_result->cert_status);
   }
 
-  if (verify_result->has_sha1)
-    verify_result->cert_status |= CERT_STATUS_SHA1_SIGNATURE_PRESENT;
-
   // Flag certificates from publicly-trusted CAs that are issued to intranet
   // hosts. While the CA/Browser Forum Baseline Requirements (v1.1) permit
   // these to be issued until 1 November 2015, they represent a real risk for
diff --git a/net/cert/cert_verify_proc_android.cc b/net/cert/cert_verify_proc_android.cc
index d35f108..3825b20 100644
--- a/net/cert/cert_verify_proc_android.cc
+++ b/net/cert/cert_verify_proc_android.cc
@@ -101,6 +101,8 @@
                sig_alg == NID_dsaWithSHA1_2 || sig_alg == NID_sha1WithRSA ||
                sig_alg == NID_ecdsa_with_SHA1) {
       verify_result->has_sha1 = true;
+      if (i == 0)
+        verify_result->has_sha1_leaf = true;
     }
   }
 
diff --git a/net/cert/cert_verify_proc_mac.cc b/net/cert/cert_verify_proc_mac.cc
index 834b5cb..c4e0c41 100644
--- a/net/cert/cert_verify_proc_mac.cc
+++ b/net/cert/cert_verify_proc_mac.cc
@@ -192,6 +192,7 @@
   verify_result->has_md4 = false;
   verify_result->has_md5 = false;
   verify_result->has_sha1 = false;
+  verify_result->has_sha1_leaf = false;
 
   SecCertificateRef verified_cert = NULL;
   std::vector<SecCertificateRef> verified_chain;
@@ -252,8 +253,10 @@
                CSSMOIDEqual(alg_oid, &CSSMOID_SHA1WithDSA_JDK) ||
                CSSMOIDEqual(alg_oid, &CSSMOID_ECDSA_WithSHA1)) {
       verify_result->has_sha1 = true;
-      if (i == 0)
+      if (i == 0) {
+        verify_result->has_sha1_leaf = true;
         *leaf_is_weak = true;
+      }
     }
   }
   if (!verified_cert) {
diff --git a/net/cert/cert_verify_proc_nss.cc b/net/cert/cert_verify_proc_nss.cc
index 9ee65ee..b4443d5 100644
--- a/net/cert/cert_verify_proc_nss.cc
+++ b/net/cert/cert_verify_proc_nss.cc
@@ -165,7 +165,7 @@
 
   CERTCertificate* verified_cert = NULL;
   std::vector<CERTCertificate*> verified_chain;
-  int i = 0;
+  size_t i = 0;
   for (CERTCertListNode* node = CERT_LIST_HEAD(cert_list);
        !CERT_LIST_END(node, cert_list);
        node = CERT_LIST_NEXT(node), ++i) {
@@ -215,6 +215,8 @@
       case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST:
       case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE:
         verify_result->has_sha1 = true;
+        if (i == 0)
+          verify_result->has_sha1_leaf = true;
         break;
       default:
         break;
diff --git a/net/cert/cert_verify_proc_openssl.cc b/net/cert/cert_verify_proc_openssl.cc
index 286b21b..824a95c 100644
--- a/net/cert/cert_verify_proc_openssl.cc
+++ b/net/cert/cert_verify_proc_openssl.cc
@@ -125,6 +125,8 @@
                  sig_alg == NID_dsaWithSHA1_2 || sig_alg == NID_sha1WithRSA ||
                  sig_alg == NID_ecdsa_with_SHA1) {
         verify_result->has_sha1 = true;
+        if (i == 0)
+          verify_result->has_sha1_leaf = true;
       }
     }
   }
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index 502cfb5..a3c1fd8 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -46,21 +46,18 @@
   0x1f, 0xe8, 0x1b, 0xd6, 0xab, 0x7b, 0xe8, 0xd7
 };
 
-// Mock CertVerifyProc that will set |verify_result->is_issued_by_known_root|
-// for all certificates that are Verified.
-class WellKnownCaCertVerifyProc : public CertVerifyProc {
+// Mock CertVerifyProc that sets the CertVerifyResult to a given value for
+// all certificates that are Verify()'d
+class MockCertVerifyProc : public CertVerifyProc {
  public:
-  // Initialize a CertVerifyProc that will set
-  // |verify_result->is_issued_by_known_root| to |is_well_known|.
-  explicit WellKnownCaCertVerifyProc(bool is_well_known)
-      : is_well_known_(is_well_known) {}
-
+  explicit MockCertVerifyProc(const CertVerifyResult& result)
+      : result_(result) {}
   // CertVerifyProc implementation:
   bool SupportsAdditionalTrustAnchors() const override { return false; }
   bool SupportsOCSPStapling() const override { return false; }
 
  protected:
-  ~WellKnownCaCertVerifyProc() override {}
+  ~MockCertVerifyProc() override {}
 
  private:
   int VerifyInternal(X509Certificate* cert,
@@ -71,12 +68,12 @@
                      const CertificateList& additional_trust_anchors,
                      CertVerifyResult* verify_result) override;
 
-  const bool is_well_known_;
+  const CertVerifyResult result_;
 
-  DISALLOW_COPY_AND_ASSIGN(WellKnownCaCertVerifyProc);
+  DISALLOW_COPY_AND_ASSIGN(MockCertVerifyProc);
 };
 
-int WellKnownCaCertVerifyProc::VerifyInternal(
+int MockCertVerifyProc::VerifyInternal(
     X509Certificate* cert,
     const std::string& hostname,
     const std::string& ocsp_response,
@@ -84,7 +81,8 @@
     CRLSet* crl_set,
     const CertificateList& additional_trust_anchors,
     CertVerifyResult* verify_result) {
-  verify_result->is_issued_by_known_root = is_well_known_;
+  *verify_result = result_;
+  verify_result->verified_cert = cert;
   return OK;
 }
 
@@ -841,20 +839,102 @@
   int error = 0;
 
   // Intranet names for public CAs should be flagged:
-  verify_proc_ = new WellKnownCaCertVerifyProc(true);
+  CertVerifyResult dummy_result;
+  dummy_result.is_issued_by_known_root = true;
+  verify_proc_ = new MockCertVerifyProc(dummy_result);
   error =
       Verify(cert.get(), "intranet", 0, NULL, empty_cert_list_, &verify_result);
   EXPECT_EQ(OK, error);
   EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_NON_UNIQUE_NAME);
 
   // However, if the CA is not well known, these should not be flagged:
-  verify_proc_ = new WellKnownCaCertVerifyProc(false);
+  dummy_result.Reset();
+  dummy_result.is_issued_by_known_root = false;
+  verify_proc_ = new MockCertVerifyProc(dummy_result);
   error =
       Verify(cert.get(), "intranet", 0, NULL, empty_cert_list_, &verify_result);
   EXPECT_EQ(OK, error);
   EXPECT_FALSE(verify_result.cert_status & CERT_STATUS_NON_UNIQUE_NAME);
 }
 
+// Test that a SHA-1 certificate from a publicly trusted CA issued after
+// 1 January 2016 is rejected, but those issued before that date, or with
+// SHA-1 in the intermediate, is not rejected.
+TEST_F(CertVerifyProcTest, VerifyRejectsSHA1AfterDeprecation) {
+  CertVerifyResult dummy_result;
+  CertVerifyResult verify_result;
+  int error = 0;
+  scoped_refptr<X509Certificate> cert;
+
+  // Publicly trusted SHA-1 leaf certificates issued before 1 January 2016
+  // are accepted.
+  verify_result.Reset();
+  dummy_result.Reset();
+  dummy_result.is_issued_by_known_root = true;
+  dummy_result.has_sha1 = true;
+  dummy_result.has_sha1_leaf = true;
+  verify_proc_ = new MockCertVerifyProc(dummy_result);
+  cert = CreateCertificateChainFromFile(GetTestCertsDirectory(),
+                                        "sha1_dec_2015.pem",
+                                        X509Certificate::FORMAT_AUTO);
+  ASSERT_TRUE(cert);
+  error = Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_,
+                 &verify_result);
+  EXPECT_EQ(OK, error);
+  EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_SHA1_SIGNATURE_PRESENT);
+
+  // Publicly trusted SHA-1 leaf certificates issued on/after 1 January 2016
+  // are rejected.
+  verify_result.Reset();
+  dummy_result.Reset();
+  dummy_result.is_issued_by_known_root = true;
+  dummy_result.has_sha1 = true;
+  dummy_result.has_sha1_leaf = true;
+  verify_proc_ = new MockCertVerifyProc(dummy_result);
+  cert = CreateCertificateChainFromFile(GetTestCertsDirectory(),
+                                        "sha1_jan_2016.pem",
+                                        X509Certificate::FORMAT_AUTO);
+  ASSERT_TRUE(cert);
+  error = Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_,
+                 &verify_result);
+  EXPECT_EQ(ERR_CERT_WEAK_SIGNATURE_ALGORITHM, error);
+  EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_WEAK_SIGNATURE_ALGORITHM);
+
+  // Enterprise issued SHA-1 leaf certificates issued on/after 1 January 2016
+  // remain accepted until SHA-1 is disabled.
+  verify_result.Reset();
+  dummy_result.Reset();
+  dummy_result.is_issued_by_known_root = false;
+  dummy_result.has_sha1 = true;
+  dummy_result.has_sha1_leaf = true;
+  verify_proc_ = new MockCertVerifyProc(dummy_result);
+  cert = CreateCertificateChainFromFile(GetTestCertsDirectory(),
+                                        "sha1_jan_2016.pem",
+                                        X509Certificate::FORMAT_AUTO);
+  ASSERT_TRUE(cert);
+  error = Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_,
+                 &verify_result);
+  EXPECT_EQ(OK, error);
+  EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_SHA1_SIGNATURE_PRESENT);
+
+  // Publicly trusted SHA-1 intermediates issued on/after 1 January 2016 are,
+  // unfortunately, accepted. This can arise due to OS path building quirks.
+  verify_result.Reset();
+  dummy_result.Reset();
+  dummy_result.is_issued_by_known_root = true;
+  dummy_result.has_sha1 = true;
+  dummy_result.has_sha1_leaf = false;
+  verify_proc_ = new MockCertVerifyProc(dummy_result);
+  cert = CreateCertificateChainFromFile(GetTestCertsDirectory(),
+                                        "sha1_jan_2016.pem",
+                                        X509Certificate::FORMAT_AUTO);
+  ASSERT_TRUE(cert);
+  error = Verify(cert.get(), "127.0.0.1", 0, NULL, empty_cert_list_,
+                 &verify_result);
+  EXPECT_EQ(OK, error);
+  EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_SHA1_SIGNATURE_PRESENT);
+}
+
 // Test that the certificate returned in CertVerifyResult is able to reorder
 // certificates that are not ordered from end-entity to root. While this is
 // a protocol violation if sent during a TLS handshake, if multiple sources
@@ -1280,7 +1360,8 @@
   EXPECT_MD2 = 1 << 0,
   EXPECT_MD4 = 1 << 1,
   EXPECT_MD5 = 1 << 2,
-  EXPECT_SHA1 = 1 << 3
+  EXPECT_SHA1 = 1 << 3,
+  EXPECT_SHA1_LEAF = 1 << 4,
 };
 
 struct WeakDigestTestData {
@@ -1348,6 +1429,8 @@
   EXPECT_EQ(!!(data.expected_algorithms & EXPECT_MD4), verify_result.has_md4);
   EXPECT_EQ(!!(data.expected_algorithms & EXPECT_MD5), verify_result.has_md5);
   EXPECT_EQ(!!(data.expected_algorithms & EXPECT_SHA1), verify_result.has_sha1);
+  EXPECT_EQ(!!(data.expected_algorithms & EXPECT_SHA1_LEAF),
+            verify_result.has_sha1_leaf);
 
   EXPECT_FALSE(verify_result.is_issued_by_additional_trust_anchor);
 
@@ -1393,15 +1476,15 @@
 
 // The signature algorithm of the root CA should not matter.
 const WeakDigestTestData kVerifyRootCATestData[] = {
-  { "weak_digest_md5_root.pem", "weak_digest_sha1_intermediate.pem",
-    "weak_digest_sha1_ee.pem", EXPECT_SHA1 },
+    {"weak_digest_md5_root.pem", "weak_digest_sha1_intermediate.pem",
+     "weak_digest_sha1_ee.pem", EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN)
-  // MD4 is not supported by OS X / NSS
-  { "weak_digest_md4_root.pem", "weak_digest_sha1_intermediate.pem",
-    "weak_digest_sha1_ee.pem", EXPECT_SHA1 },
+    // MD4 is not supported by OS X / NSS
+    {"weak_digest_md4_root.pem", "weak_digest_sha1_intermediate.pem",
+     "weak_digest_sha1_ee.pem", EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 #endif
-  { "weak_digest_md2_root.pem", "weak_digest_sha1_intermediate.pem",
-    "weak_digest_sha1_ee.pem", EXPECT_SHA1 },
+    {"weak_digest_md2_root.pem", "weak_digest_sha1_intermediate.pem",
+     "weak_digest_sha1_ee.pem", EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 };
 #if defined(OS_ANDROID)
 #define MAYBE_VerifyRoot DISABLED_VerifyRoot
@@ -1414,15 +1497,15 @@
 
 // The signature algorithm of intermediates should be properly detected.
 const WeakDigestTestData kVerifyIntermediateCATestData[] = {
-  { "weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem",
-    "weak_digest_sha1_ee.pem", EXPECT_MD5 | EXPECT_SHA1 },
+    {"weak_digest_sha1_root.pem", "weak_digest_md5_intermediate.pem",
+     "weak_digest_sha1_ee.pem", EXPECT_MD5 | EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN)
-  // MD4 is not supported by OS X / NSS
-  { "weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem",
-    "weak_digest_sha1_ee.pem", EXPECT_MD4 | EXPECT_SHA1 },
+    // MD4 is not supported by OS X / NSS
+    {"weak_digest_sha1_root.pem", "weak_digest_md4_intermediate.pem",
+     "weak_digest_sha1_ee.pem", EXPECT_MD4 | EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 #endif
-  { "weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem",
-    "weak_digest_sha1_ee.pem", EXPECT_MD2 | EXPECT_SHA1 },
+    {"weak_digest_sha1_root.pem", "weak_digest_md2_intermediate.pem",
+     "weak_digest_sha1_ee.pem", EXPECT_MD2 | EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 };
 // Disabled on NSS - MD4 is not supported, and MD2 and MD5 are disabled.
 #if defined(USE_NSS_CERTS) || defined(OS_IOS) || defined(OS_ANDROID)
@@ -1461,15 +1544,15 @@
 
 // Incomplete chains should still report the status of the intermediate.
 const WeakDigestTestData kVerifyIncompleteIntermediateTestData[] = {
-  { NULL, "weak_digest_md5_intermediate.pem", "weak_digest_sha1_ee.pem",
-    EXPECT_MD5 | EXPECT_SHA1 },
+    {NULL, "weak_digest_md5_intermediate.pem", "weak_digest_sha1_ee.pem",
+     EXPECT_MD5 | EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 #if defined(USE_OPENSSL_CERTS) || defined(OS_WIN)
-  // MD4 is not supported by OS X / NSS
-  { NULL, "weak_digest_md4_intermediate.pem", "weak_digest_sha1_ee.pem",
-    EXPECT_MD4 | EXPECT_SHA1 },
+    // MD4 is not supported by OS X / NSS
+    {NULL, "weak_digest_md4_intermediate.pem", "weak_digest_sha1_ee.pem",
+     EXPECT_MD4 | EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 #endif
-  { NULL, "weak_digest_md2_intermediate.pem", "weak_digest_sha1_ee.pem",
-    EXPECT_MD2 | EXPECT_SHA1 },
+    {NULL, "weak_digest_md2_intermediate.pem", "weak_digest_sha1_ee.pem",
+     EXPECT_MD2 | EXPECT_SHA1 | EXPECT_SHA1_LEAF},
 };
 // Disabled on NSS - libpkix does not return constructed chains on error,
 // preventing us from detecting/inspecting the verified chain.
diff --git a/net/cert/cert_verify_proc_win.cc b/net/cert/cert_verify_proc_win.cc
index 4eada6f4..f67f823 100644
--- a/net/cert/cert_verify_proc_win.cc
+++ b/net/cert/cert_verify_proc_win.cc
@@ -295,7 +295,7 @@
     return;
 
   PCERT_SIMPLE_CHAIN first_chain = chain_context->rgpChain[0];
-  int num_elements = first_chain->cElement;
+  DWORD num_elements = first_chain->cElement;
   PCERT_CHAIN_ELEMENT* element = first_chain->rgpElement;
 
   PCCERT_CONTEXT verified_cert = NULL;
@@ -316,7 +316,7 @@
     num_elements -= 1;
   }
 
-  for (int i = 0; i < num_elements; ++i) {
+  for (DWORD i = 0; i < num_elements; ++i) {
     PCCERT_CONTEXT cert = element[i]->pCertContext;
     if (i == 0) {
       verified_cert = cert;
@@ -341,6 +341,8 @@
       // id-dsa-with-sha1: 1.2.840.10040.4.3
       // ecdsa-with-SHA1: 1.2.840.10045.4.1
       verify_result->has_sha1 = true;
+      if (i == 0)
+        verify_result->has_sha1_leaf = true;
     }
   }
 
diff --git a/net/cert/cert_verify_result.cc b/net/cert/cert_verify_result.cc
index b2413e67..2a41893 100644
--- a/net/cert/cert_verify_result.cc
+++ b/net/cert/cert_verify_result.cc
@@ -22,6 +22,7 @@
   has_md4 = false;
   has_md5 = false;
   has_sha1 = false;
+  has_sha1_leaf = false;
   is_issued_by_known_root = false;
   is_issued_by_additional_trust_anchor = false;
   common_name_fallback_used = false;
diff --git a/net/cert/cert_verify_result.h b/net/cert/cert_verify_result.h
index 9e67325..104fc6e 100644
--- a/net/cert/cert_verify_result.h
+++ b/net/cert/cert_verify_result.h
@@ -48,6 +48,7 @@
   bool has_md4;
   bool has_md5;
   bool has_sha1;
+  bool has_sha1_leaf;
 
   // If the certificate was successfully verified then this contains the
   // hashes, in several hash algorithms, of the SubjectPublicKeyInfos of the
diff --git a/net/data/ssl/certificates/README b/net/data/ssl/certificates/README
index 6eed2be..305528d 100644
--- a/net/data/ssl/certificates/README
+++ b/net/data/ssl/certificates/README
@@ -158,6 +158,10 @@
 - sha1_2016.pem
     Used to test the handling of SHA1 certificates expiring in 2016.
 
+- sha1_dec_2015.pem
+- sha1_jan_2016.pem
+    Used to test enforcement of the Baseline Requirements' policies on SHA-1.
+
 - 10_year_validity.pem
 - 11_year_validity.pem
 - 39_months_after_2015_04.pem
diff --git a/net/data/ssl/certificates/sha1_dec_2015.pem b/net/data/ssl/certificates/sha1_dec_2015.pem
new file mode 100644
index 0000000..b5047d2
--- /dev/null
+++ b/net/data/ssl/certificates/sha1_dec_2015.pem
@@ -0,0 +1,82 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 8 (0x8)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Test Root CA
+        Validity
+            Not Before: Dec 31 23:59:59 2015 GMT
+            Not After : Dec 30 00:00:00 2016 GMT
+        Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:da:6a:85:4f:e5:d7:73:82:af:a2:1e:85:49:d0:
+                    a9:ef:65:b9:29:e3:1d:32:d0:33:10:0d:67:a8:7d:
+                    22:d1:99:c1:c9:ab:e5:3e:06:9b:63:62:81:60:26:
+                    9c:70:b4:92:65:95:46:b2:fd:ad:e5:19:b1:30:6d:
+                    a5:00:7d:d8:4d:b3:e7:b6:a5:83:da:be:26:79:ee:
+                    58:0a:f8:dd:8a:ae:13:db:f7:9a:8a:2b:eb:9f:15:
+                    53:5d:ce:18:ac:03:f2:ed:30:f4:8c:af:d6:7e:76:
+                    97:aa:97:c4:24:a5:7e:28:dc:dc:22:ea:86:54:4f:
+                    15:bf:03:81:11:ea:f9:ca:17:db:5a:b8:f0:3d:1a:
+                    a5:c9:96:1b:d3:ed:99:ba:7a:55:e3:fa:9e:61:54:
+                    61:75:16:79:22:10:e9:e6:5a:b5:6b:b5:9d:32:bb:
+                    e8:10:de:66:d7:1a:59:6f:d7:42:bf:80:b5:b2:73:
+                    b9:a1:0b:5d:fe:0f:a1:6c:fc:de:99:d2:b3:ae:13:
+                    d6:7f:f3:a9:7e:c0:07:f1:e4:a2:27:1b:1f:6d:81:
+                    86:b4:0f:f7:2b:9a:3c:7b:76:dc:5d:3a:b0:9e:b7:
+                    64:5f:53:33:08:3a:51:77:df:d1:91:b5:54:b8:4e:
+                    7a:0c:29:d1:40:cb:47:a4:cc:3b:b4:6e:a2:4d:91:
+                    6b:75
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                16:04:CF:CB:65:43:70:72:46:1E:83:5B:87:5E:10:CB:CB:69:B2:60
+            X509v3 Authority Key Identifier: 
+                keyid:6C:29:1B:65:A9:3F:B8:19:9A:0F:FC:77:D6:95:55:2A:F2:4B:74:E6
+
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Subject Alternative Name: 
+                IP Address:127.0.0.1
+    Signature Algorithm: sha256WithRSAEncryption
+         58:b4:e7:31:15:4f:c4:70:1e:51:c6:ae:c3:47:3d:e8:17:92:
+         b9:8e:3b:76:c4:38:98:f7:c9:6e:be:0b:6a:2c:9d:fb:29:37:
+         e5:a7:4a:33:56:b5:2b:38:37:3e:65:8c:32:97:26:cf:47:94:
+         1c:35:d1:8b:83:67:33:60:35:ed:8d:84:51:21:84:fe:15:4b:
+         31:6d:6c:df:b2:24:ad:25:cd:f2:40:c5:bf:68:d8:62:db:ad:
+         d3:05:4b:71:0a:83:f5:12:d1:49:47:c5:44:a5:a5:08:1d:26:
+         35:a2:2e:42:f1:06:4d:79:8a:54:95:51:54:a7:d3:aa:33:86:
+         ab:c7:5f:81:03:76:c1:c3:61:9a:9f:d9:a4:0c:6e:9f:31:40:
+         0a:ee:b7:ae:e4:4a:17:aa:79:9c:17:1b:d4:49:65:52:57:f4:
+         52:bb:e4:12:0e:b0:1a:65:c4:8d:e4:02:26:ff:43:42:87:53:
+         7c:4b:10:7d:19:14:a9:c8:b7:9e:9a:e6:54:c1:f9:9e:2e:57:
+         58:8e:37:3b:66:25:ce:1c:5c:7c:55:e1:0c:3a:dc:ac:46:48:
+         e2:d6:f5:c9:dd:36:c3:4f:75:df:06:af:e4:dc:21:fd:73:14:
+         6d:51:1c:2d:b3:15:2e:1c:fb:b4:b9:b4:01:1f:82:ae:1d:20:
+         3d:5f:25:98
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgIBCDANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxUZXN0
+IFJvb3QgQ0EwHhcNMTUxMjMxMjM1OTU5WhcNMTYxMjMwMDAwMDAwWjBgMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g
+VmlldzEQMA4GA1UECgwHVGVzdCBDQTESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2mqFT+XXc4Kvoh6FSdCp72W5KeMd
+MtAzEA1nqH0i0ZnByavlPgabY2KBYCaccLSSZZVGsv2t5RmxMG2lAH3YTbPntqWD
+2r4mee5YCvjdiq4T2/eaiivrnxVTXc4YrAPy7TD0jK/WfnaXqpfEJKV+KNzcIuqG
+VE8VvwOBEer5yhfbWrjwPRqlyZYb0+2ZunpV4/qeYVRhdRZ5IhDp5lq1a7WdMrvo
+EN5m1xpZb9dCv4C1snO5oQtd/g+hbPzemdKzrhPWf/OpfsAH8eSiJxsfbYGGtA/3
+K5o8e3bcXTqwnrdkX1MzCDpRd9/RkbVUuE56DCnRQMtHpMw7tG6iTZFrdQIDAQAB
+o4GAMH4wDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUFgTPy2VDcHJGHoNbh14Qy8tp
+smAwHwYDVR0jBBgwFoAUbCkbZak/uBmaD/x31pVVKvJLdOYwHQYDVR0lBBYwFAYI
+KwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQEL
+BQADggEBAFi05zEVT8RwHlHGrsNHPegXkrmOO3bEOJj3yW6+C2osnfspN+WnSjNW
+tSs4Nz5ljDKXJs9HlBw10YuDZzNgNe2NhFEhhP4VSzFtbN+yJK0lzfJAxb9o2GLb
+rdMFS3EKg/US0UlHxUSlpQgdJjWiLkLxBk15ilSVUVSn06ozhqvHX4EDdsHDYZqf
+2aQMbp8xQArut67kSheqeZwXG9RJZVJX9FK75BIOsBplxI3kAib/Q0KHU3xLEH0Z
+FKnIt56a5lTB+Z4uV1iONztmJc4cXHxV4Qw63KxGSOLW9cndNsNPdd8Gr+TcIf1z
+FG1RHC2zFS4c+7S5tAEfgq4dID1fJZg=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/certificates/sha1_jan_2016.pem b/net/data/ssl/certificates/sha1_jan_2016.pem
new file mode 100644
index 0000000..efb9b016
--- /dev/null
+++ b/net/data/ssl/certificates/sha1_jan_2016.pem
@@ -0,0 +1,82 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number: 9 (0x9)
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: CN=Test Root CA
+        Validity
+            Not Before: Jan  1 00:00:00 2016 GMT
+            Not After : Dec 30 00:00:00 2016 GMT
+        Subject: C=US, ST=California, L=Mountain View, O=Test CA, CN=127.0.0.1
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:b6:93:55:29:0f:ea:d2:34:c0:71:6b:df:b4:f6:
+                    9f:12:72:65:e1:0c:ac:1a:7d:ab:3e:76:2e:64:5a:
+                    02:c7:bc:61:bd:1e:ed:f3:eb:30:76:bd:44:48:d0:
+                    15:fc:8b:f3:c5:bc:06:18:c2:8e:7b:99:a1:bc:f1:
+                    24:d4:17:05:39:51:bc:cc:1f:39:c7:0a:67:3b:76:
+                    8b:23:3f:9a:df:a9:21:70:71:17:40:c3:6f:b0:a2:
+                    ea:7b:e3:64:94:08:cd:4b:66:a4:00:27:2f:af:8e:
+                    ce:99:4c:c6:21:c6:4a:05:5e:08:17:41:3a:d4:31:
+                    a0:bc:a0:0a:2e:a1:b2:ff:08:d9:11:a6:40:fc:f0:
+                    0f:3e:9c:31:de:32:4b:23:c2:b8:d4:a3:2c:81:84:
+                    e7:64:c7:25:3b:e9:8e:aa:6c:7f:13:8a:66:35:2d:
+                    a6:3c:07:95:7f:26:75:16:24:c0:92:6e:cf:f3:c3:
+                    19:f4:66:f9:23:4f:75:de:2f:a5:cd:1a:15:94:23:
+                    8c:68:bc:32:74:1d:21:fa:5f:c9:88:48:9a:08:c7:
+                    1e:9c:31:27:fb:8e:d7:01:72:6e:60:bb:b4:b6:f3:
+                    d8:8b:6c:97:6c:ec:a0:42:b6:48:02:f1:f1:b7:15:
+                    0d:84:e5:96:64:9e:f4:59:a1:4f:df:cb:e6:58:51:
+                    bf:d7
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Basic Constraints: critical
+                CA:FALSE
+            X509v3 Subject Key Identifier: 
+                A6:36:4C:FB:11:3E:B2:79:D1:1F:94:96:A1:F0:14:03:01:BB:09:CE
+            X509v3 Authority Key Identifier: 
+                keyid:6C:29:1B:65:A9:3F:B8:19:9A:0F:FC:77:D6:95:55:2A:F2:4B:74:E6
+
+            X509v3 Extended Key Usage: 
+                TLS Web Server Authentication, TLS Web Client Authentication
+            X509v3 Subject Alternative Name: 
+                IP Address:127.0.0.1
+    Signature Algorithm: sha256WithRSAEncryption
+         6c:76:f5:b4:56:92:77:34:99:32:47:05:9b:23:93:8e:82:29:
+         d9:cd:7f:e8:81:65:19:4a:db:6c:c7:c3:ef:7d:47:43:30:24:
+         58:8a:9b:63:b6:88:d5:c4:57:09:89:79:ce:ac:4a:e2:bf:e5:
+         87:1e:5d:e5:99:37:b6:af:96:7b:0c:a4:6c:ff:1c:65:eb:36:
+         cd:5f:74:53:e9:28:ef:72:e1:9f:b6:b5:aa:0f:8f:60:91:f7:
+         79:62:85:d1:b2:19:84:26:9d:ff:e0:20:4c:71:7d:72:12:10:
+         7e:83:4e:e1:c5:6a:a7:d2:5c:c2:c4:ac:33:e1:02:c5:74:d3:
+         79:57:cd:8b:89:a2:17:b2:9a:97:83:ce:8a:b3:ae:50:e4:99:
+         d7:af:96:d2:d8:57:72:d3:22:67:17:52:7d:f0:4d:d3:48:95:
+         5a:ef:8a:d4:1d:43:bd:3b:65:49:5b:70:da:7f:2e:8a:aa:e0:
+         b5:ed:6d:8f:d0:1d:7a:cc:ee:c7:47:dc:66:de:cf:b0:19:07:
+         3f:44:d6:ce:db:1d:b1:1a:3e:54:60:16:93:df:85:76:62:9d:
+         0e:fa:27:1c:bd:6f:fe:20:9b:34:4a:b6:f8:f9:52:c4:bb:22:
+         92:01:69:8e:5b:da:0f:b9:f6:63:89:3f:f2:58:bc:59:9e:3d:
+         58:c6:fe:db
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgIBCTANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxUZXN0
+IFJvb3QgQ0EwHhcNMTYwMTAxMDAwMDAwWhcNMTYxMjMwMDAwMDAwWjBgMQswCQYD
+VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4g
+VmlldzEQMA4GA1UECgwHVGVzdCBDQTESMBAGA1UEAwwJMTI3LjAuMC4xMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtpNVKQ/q0jTAcWvftPafEnJl4Qys
+Gn2rPnYuZFoCx7xhvR7t8+swdr1ESNAV/IvzxbwGGMKOe5mhvPEk1BcFOVG8zB85
+xwpnO3aLIz+a36khcHEXQMNvsKLqe+NklAjNS2akACcvr47OmUzGIcZKBV4IF0E6
+1DGgvKAKLqGy/wjZEaZA/PAPPpwx3jJLI8K41KMsgYTnZMclO+mOqmx/E4pmNS2m
+PAeVfyZ1FiTAkm7P88MZ9Gb5I0913i+lzRoVlCOMaLwydB0h+l/JiEiaCMcenDEn
++47XAXJuYLu0tvPYi2yXbOygQrZIAvHxtxUNhOWWZJ70WaFP38vmWFG/1wIDAQAB
+o4GAMH4wDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUpjZM+xE+snnRH5SWofAUAwG7
+Cc4wHwYDVR0jBBgwFoAUbCkbZak/uBmaD/x31pVVKvJLdOYwHQYDVR0lBBYwFAYI
+KwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQEL
+BQADggEBAGx29bRWknc0mTJHBZsjk46CKdnNf+iBZRlK22zHw+99R0MwJFiKm2O2
+iNXEVwmJec6sSuK/5YceXeWZN7avlnsMpGz/HGXrNs1fdFPpKO9y4Z+2taoPj2CR
+93lihdGyGYQmnf/gIExxfXISEH6DTuHFaqfSXMLErDPhAsV003lXzYuJoheympeD
+zoqzrlDkmdevltLYV3LTImcXUn3wTdNIlVrvitQdQ707ZUlbcNp/Loqq4LXtbY/Q
+HXrM7sdH3Gbez7AZBz9E1s7bHbEaPlRgFpPfhXZinQ76Jxy9b/4gmzRKtvj5UsS7
+IpIBaY5b2g+59mOJP/JYvFmePVjG/ts=
+-----END CERTIFICATE-----
diff --git a/net/data/ssl/scripts/generate-test-certs.sh b/net/data/ssl/scripts/generate-test-certs.sh
index d777718c..b2481ad 100755
--- a/net/data/ssl/scripts/generate-test-certs.sh
+++ b/net/data/ssl/scripts/generate-test-certs.sh
@@ -183,6 +183,32 @@
     -out ../certificates/sha1_2016.pem \
     -config ca.cnf
 
+## SHA1 certificate issued the last second before the SHA-1 deprecation date.
+try openssl req -config ../scripts/ee.cnf -sha1 \
+  -newkey rsa:2048 -text -out out/sha1_dec_2015.req
+CA_COMMON_NAME="Test Root CA" \
+  try openssl ca \
+    -batch \
+    -extensions user_cert \
+    -startdate 151231235959Z \
+    -enddate   161230000000Z \
+    -in out/sha1_dec_2015.req \
+    -out ../certificates/sha1_dec_2015.pem \
+    -config ca.cnf
+
+## SHA1 certificate issued on the SHA-1 deprecation date.
+try openssl req -config ../scripts/ee.cnf -sha1 \
+  -newkey rsa:2048 -text -out out/sha1_jan_2016.req
+CA_COMMON_NAME="Test Root CA" \
+  try openssl ca \
+    -batch \
+    -extensions user_cert \
+    -startdate 160101000000Z \
+    -enddate   161230000000Z \
+    -in out/sha1_jan_2016.req \
+    -out ../certificates/sha1_jan_2016.pem \
+    -config ca.cnf
+
 ## Validity too long unit test support.
 try openssl req -config ../scripts/ee.cnf \
   -newkey rsa:2048 -text -out ../certificates/10_year_validity.req
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 0d587565..adb4705 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -119,7 +119,7 @@
       quic_threshold_timeouts_streams_open(0),
       quic_close_sessions_on_ip_change(false),
       proxy_delegate(NULL) {
-  quic_supported_versions.push_back(QUIC_VERSION_27);
+  quic_supported_versions.push_back(QUIC_VERSION_25);
 }
 
 HttpNetworkSession::Params::~Params() {}
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc
index c83d9575..a6982cb 100644
--- a/net/http/http_server_properties_impl.cc
+++ b/net/http/http_server_properties_impl.cc
@@ -294,7 +294,8 @@
         it = map_it->second.erase(it);
         continue;
       }
-      if (it->probability < alternative_service_probability_threshold_) {
+      if (it->probability == 0 ||
+          it->probability < alternative_service_probability_threshold_) {
         ++it;
         continue;
       }
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc
index b552576..96020590 100644
--- a/net/http/http_server_properties_impl_unittest.cc
+++ b/net/http/http_server_properties_impl_unittest.cc
@@ -358,6 +358,15 @@
   EXPECT_FALSE(HasAlternativeService(test_host_port_pair));
 }
 
+TEST_F(AlternateProtocolServerPropertiesTest, ZeroProbabilityAlwaysExcluded) {
+  impl_.SetAlternativeServiceProbabilityThreshold(0.0);
+
+  HostPortPair test_host_port_pair("foo", 80);
+  const AlternativeService alternative_service(NPN_HTTP_2, "foo", 443);
+  SetAlternativeService(test_host_port_pair, alternative_service, 0);
+  EXPECT_FALSE(HasAlternativeService(test_host_port_pair));
+}
+
 TEST_F(AlternateProtocolServerPropertiesTest, Initialize) {
   // |test_host_port_pair1| has one alternative service, which is non-broken,
   // and thus will be removed by InitializeAlternativeServiceServers().
diff --git a/net/http/transport_security_state_static.certs b/net/http/transport_security_state_static.certs
index 65f8fe0..266eda9 100644
--- a/net/http/transport_security_state_static.certs
+++ b/net/http/transport_security_state_static.certs
@@ -1373,3 +1373,9 @@
 
 SpiderOak3
 sha1/l5JoIXv4lztZ+C6TJWgxZCHQzS4=
+
+YahooBackup1
+sha1/uwnZN/atr9+khywDukPzmD9kFiY=
+
+YahooBackup2
+sha1/Ui85k1YWcCl0z/4IlMvrDmI5zEo=
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index 2a2f63e2..00ace15 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -277,6 +277,7 @@
   DOMAIN_WITHGOOGLE_COM,
   DOMAIN_G4W_CO,
   DOMAIN_BADSSL_COM,
+  DOMAIN_YAHOO_COM,
   // Boundary value for UMA_HISTOGRAM_ENUMERATION.
   DOMAIN_NUM_EVENTS,
 };
@@ -536,6 +537,14 @@
     "\x97\x92\x68\x21\x7b\xf8\x97\x3b\x59\xf8"
     "\x2e\x93\x25\x68\x31\x64\x21\xd0\xcd\x2e";
 
+static const char kSPKIHash_YahooBackup1[] =
+    "\xbb\x09\xd9\x37\xf6\xad\xaf\xdf\xa4\x87"
+    "\x2c\x03\xba\x43\xf3\x98\x3f\x64\x16\x26";
+
+static const char kSPKIHash_YahooBackup2[] =
+    "\x52\x2f\x39\x93\x56\x16\x70\x29\x74\xcf"
+    "\xfe\x08\x94\xcb\xeb\x0e\x62\x39\xcc\x4a";
+
 // The following is static data describing the hosts that are hardcoded with
 // certificate pins or HSTS information.
 
@@ -673,6 +682,24 @@
   kSPKIHash_SpiderOak3,
   NULL,
 };
+static const char* const kYahooAcceptableCerts[] = {
+  kSPKIHash_VeriSignClass2_G2,
+  kSPKIHash_VeriSignClass2_G3,
+  kSPKIHash_VeriSignClass3_G3,
+  kSPKIHash_VeriSignClass3_G4,
+  kSPKIHash_VeriSignClass3_G5,
+  kSPKIHash_VeriSignUniversal,
+  kSPKIHash_GeoTrustGlobal,
+  kSPKIHash_GeoTrustPrimary,
+  kSPKIHash_GeoTrustPrimary_G2,
+  kSPKIHash_GeoTrustPrimary_G3,
+  kSPKIHash_GeoTrustUniversal,
+  kSPKIHash_DigiCertGlobalRoot,
+  kSPKIHash_DigiCertEVRoot,
+  kSPKIHash_YahooBackup1,
+  kSPKIHash_YahooBackup2,
+  NULL,
+};
 
 struct Pinset {
   const char *const *const accepted_pins;
@@ -689,6 +716,7 @@
   {kDropboxAcceptableCerts, kNoRejectedPublicKeys, kDropboxReportURI},
   {kFacebookAcceptableCerts, kNoRejectedPublicKeys, kNoReportURI},
   {kSpideroakAcceptableCerts, kNoRejectedPublicKeys, kNoReportURI},
+  {kYahooAcceptableCerts, kNoRejectedPublicKeys, kNoReportURI},
 };
 
 // kHSTSHuffmanTree describes a Huffman tree. The nodes of the tree are pairs
@@ -2389,1390 +2417,1391 @@
     0xaa, 0x85, 0xfa, 0x59, 0xdc, 0x64, 0x7a, 0x12, 0x8c, 0x5b, 0x6b, 0x5e,
     0xe9, 0x08, 0xcc, 0xc6, 0x7b, 0x31, 0xcf, 0x21, 0x16, 0xb4, 0x8e, 0x9c,
     0x3b, 0x28, 0x0e, 0x85, 0xdb, 0x4c, 0xde, 0x61, 0xfd, 0xe7, 0x63, 0x2b,
-    0x29, 0x7b, 0x65, 0x9f, 0x49, 0x36, 0x92, 0x6f, 0xd2, 0x18, 0xcd, 0x14,
-    0xaa, 0x6a, 0xd7, 0x92, 0x16, 0x55, 0xf2, 0x35, 0xf8, 0x75, 0xe4, 0x0e,
-    0x1d, 0x65, 0x77, 0x44, 0x6f, 0x0e, 0x7a, 0x35, 0xe2, 0x0b, 0x46, 0xc6,
-    0x52, 0x1f, 0xda, 0x4f, 0xf5, 0xfe, 0xea, 0x32, 0x1e, 0x44, 0xe7, 0x5e,
-    0x4d, 0x8c, 0x13, 0xab, 0x74, 0x47, 0x4c, 0x73, 0xe3, 0x4b, 0xf6, 0x64,
-    0xcf, 0xf4, 0xeb, 0x81, 0x07, 0x5f, 0xdc, 0x71, 0xfb, 0x00, 0x3a, 0xe7,
-    0xe1, 0xd6, 0x43, 0x9a, 0x5a, 0xd9, 0xa7, 0x59, 0x67, 0x5d, 0xb6, 0xaa,
-    0x22, 0x57, 0x82, 0xbd, 0x42, 0x71, 0xef, 0xa2, 0x17, 0xfd, 0xd8, 0x5e,
-    0x4d, 0x03, 0x39, 0xd7, 0xff, 0x7c, 0x76, 0x87, 0xb0, 0x0c, 0x10, 0x1d,
-    0x70, 0x20, 0xea, 0xc3, 0xd9, 0x02, 0x25, 0x62, 0x61, 0x80, 0x5a, 0xfe,
-    0x12, 0x37, 0xff, 0x08, 0xc4, 0xe3, 0x89, 0xb2, 0x36, 0xce, 0xbd, 0x1b,
-    0xe8, 0xea, 0x73, 0xe1, 0xd2, 0x2d, 0xe7, 0xe4, 0x1d, 0x7e, 0x4d, 0xb7,
-    0x10, 0x1d, 0x52, 0x3c, 0x25, 0x8d, 0x5f, 0xf7, 0xd7, 0x0e, 0xb1, 0x70,
-    0xc6, 0x75, 0xec, 0xdd, 0x93, 0xaf, 0x6e, 0x0c, 0xe1, 0xec, 0x89, 0xe5,
-    0xf6, 0xcc, 0xe4, 0x8e, 0xbc, 0x17, 0x13, 0xa9, 0x0d, 0xeb, 0x91, 0xdf,
-    0xff, 0x47, 0xc7, 0xe7, 0x1c, 0x10, 0xab, 0x2c, 0xb2, 0x75, 0x42, 0x6b,
-    0xce, 0xf7, 0xa7, 0x0f, 0xc7, 0xe9, 0x80, 0xdc, 0xb3, 0x43, 0x94, 0xed,
-    0xf2, 0x8c, 0x94, 0x30, 0x9e, 0xc8, 0x5b, 0x36, 0x34, 0x8d, 0xd5, 0xd2,
-    0x52, 0xfb, 0x1a, 0x2c, 0xd0, 0xba, 0xe1, 0xba, 0xe1, 0x59, 0xd8, 0x55,
-    0xbd, 0x2b, 0xc4, 0x06, 0x43, 0x1e, 0x4e, 0xa1, 0x2f, 0xe8, 0xf0, 0x6f,
-    0x2f, 0x4d, 0x3a, 0xf0, 0xb6, 0x0e, 0xaf, 0x86, 0xd9, 0x07, 0x2f, 0xe6,
-    0x5f, 0x9c, 0x7d, 0xce, 0xbf, 0xff, 0x6b, 0x9c, 0x49, 0xb5, 0xc8, 0xf2,
-    0x35, 0x02, 0x75, 0x2d, 0x14, 0xa2, 0x44, 0xc9, 0x75, 0xf2, 0xfd, 0x1a,
-    0x3a, 0xff, 0x7a, 0x3f, 0x6f, 0x53, 0x87, 0x5f, 0xd8, 0xde, 0xc6, 0xf2,
-    0x3a, 0xfe, 0x5e, 0x91, 0x4f, 0x32, 0x75, 0xfa, 0x37, 0xec, 0x48, 0xea,
-    0x14, 0x5b, 0x78, 0xcf, 0xe9, 0x6e, 0xd1, 0x7d, 0xff, 0x66, 0xe3, 0x9e,
-    0xf6, 0x4e, 0x75, 0xdb, 0xf8, 0xeb, 0xf7, 0x9c, 0x7f, 0xc3, 0xaf, 0xf6,
-    0xb1, 0x69, 0xee, 0xb9, 0xd6, 0x8c, 0x3e, 0xe1, 0x17, 0xf1, 0x35, 0xf4,
-    0xbe, 0x2d, 0x0e, 0xbd, 0xb5, 0xc8, 0x3a, 0xff, 0x71, 0x26, 0x1c, 0xd8,
-    0xe7, 0x5d, 0xbe, 0xbe, 0x1f, 0xa4, 0x11, 0xf0, 0x7a, 0xff, 0x86, 0x1e,
-    0x7e, 0xc7, 0x00, 0x75, 0xfe, 0x4e, 0x0f, 0xbd, 0x93, 0x9d, 0x73, 0xec,
-    0x3a, 0xfe, 0x90, 0xa4, 0xbb, 0x87, 0x5f, 0xa7, 0x4e, 0x44, 0x8e, 0xa5,
-    0x11, 0x37, 0x31, 0x97, 0x05, 0xc4, 0xae, 0xfb, 0x02, 0x8a, 0x1d, 0x7f,
-    0xf9, 0xd3, 0xd1, 0xed, 0x75, 0xd3, 0xbf, 0x9d, 0x7c, 0x23, 0xfc, 0x8e,
-    0xbf, 0xf7, 0x63, 0x80, 0x1c, 0x65, 0xc0, 0x75, 0xec, 0xc9, 0x8e, 0xb6,
-    0x74, 0xf6, 0x00, 0x7b, 0x7f, 0x7f, 0xcf, 0xd6, 0xe2, 0x75, 0xf2, 0xe3,
-    0x27, 0x3a, 0xfd, 0x9b, 0x06, 0x37, 0x3a, 0x90, 0xf2, 0x74, 0x43, 0x7d,
-    0x03, 0xe6, 0x9d, 0x41, 0x55, 0xa3, 0x90, 0xd2, 0xe1, 0xf7, 0x48, 0x5d,
-    0x20, 0x5e, 0x74, 0x4f, 0xe7, 0x7d, 0xb2, 0x1b, 0xfc, 0x0f, 0xb8, 0x21,
-    0xec, 0x1d, 0x50, 0x8b, 0x87, 0x84, 0x2d, 0xfd, 0xac, 0x5a, 0x76, 0x0e,
-    0xbd, 0xbc, 0xb4, 0x75, 0x6e, 0x79, 0x1c, 0x2b, 0xbd, 0xa0, 0x32, 0x75,
-    0x41, 0xe0, 0x61, 0x1d, 0xf7, 0xef, 0xc9, 0x1d, 0x7d, 0x1f, 0xb0, 0x74,
-    0x55, 0xfa, 0x4a, 0xb2, 0xcb, 0x27, 0x50, 0x9e, 0x97, 0xe4, 0xd7, 0xcf,
-    0xe5, 0xf8, 0xea, 0x0a, 0x2d, 0xf1, 0xd0, 0x04, 0x57, 0xfb, 0xe8, 0x8b,
-    0xb2, 0xfd, 0x3a, 0xa1, 0x90, 0x83, 0x86, 0x09, 0x0d, 0x7e, 0x20, 0xae,
-    0x14, 0xcf, 0x0a, 0x60, 0x4b, 0xc6, 0x18, 0x57, 0x7f, 0x0d, 0x76, 0x4b,
-    0xef, 0x31, 0x0c, 0x51, 0x80, 0x75, 0xe9, 0x0b, 0x9d, 0x6d, 0xd8, 0x83,
-    0xc5, 0x82, 0xbb, 0xde, 0x70, 0x1d, 0x7f, 0x47, 0x27, 0x8e, 0x4e, 0x75,
-    0xff, 0xa0, 0x7d, 0xdf, 0xde, 0x52, 0x83, 0xaf, 0xdf, 0x83, 0x05, 0xa7,
-    0x5e, 0xe4, 0x4c, 0x75, 0xf2, 0x0b, 0xcc, 0x75, 0xf2, 0x6b, 0x98, 0x75,
-    0xfe, 0xf6, 0x7d, 0x89, 0x93, 0x47, 0x54, 0xe9, 0x9e, 0xc8, 0x6c, 0x25,
-    0xdc, 0x3d, 0x59, 0x3f, 0x47, 0x3c, 0x41, 0xb0, 0x82, 0xff, 0xa1, 0x3b,
-    0x0b, 0x9f, 0x19, 0x3a, 0xfe, 0x8e, 0xa4, 0xee, 0x27, 0x5f, 0xf4, 0xe3,
-    0x92, 0xee, 0x03, 0x47, 0x5f, 0xfb, 0x07, 0x79, 0x6b, 0x9f, 0xc0, 0x0e,
-    0xbf, 0x67, 0xb5, 0x8a, 0x1d, 0x48, 0x7c, 0xcb, 0x3f, 0xbf, 0x87, 0xdf,
-    0x3b, 0x9b, 0x47, 0x5e, 0x0c, 0x6c, 0x3a, 0xff, 0xfb, 0x04, 0x61, 0x90,
-    0x8c, 0x6f, 0x24, 0x13, 0xaf, 0xff, 0x3f, 0xc9, 0xa5, 0x1c, 0x9f, 0xe3,
-    0x39, 0xd3, 0xaa, 0x11, 0xd4, 0x13, 0x1e, 0x8e, 0x8a, 0x65, 0xff, 0x2f,
-    0xb9, 0xec, 0xff, 0x93, 0x9d, 0x7f, 0xfc, 0xa3, 0xfb, 0x48, 0x33, 0x43,
-    0x79, 0x9b, 0x9d, 0x7f, 0xd1, 0xec, 0xe3, 0x5d, 0xda, 0x68, 0xbe, 0x2f,
-    0xd9, 0xc8, 0xde, 0x47, 0x5e, 0xec, 0x2d, 0xa7, 0xd5, 0xe4, 0x3b, 0xff,
-    0xf0, 0xb7, 0xe7, 0x61, 0x38, 0x8b, 0x4d, 0xb8, 0x59, 0xd7, 0x9f, 0x93,
-    0x9a, 0x2f, 0xfa, 0x84, 0x59, 0xe1, 0x9b, 0x55, 0xef, 0xff, 0xf7, 0x5f,
-    0x49, 0x1a, 0xf9, 0xee, 0xe2, 0xf1, 0xaf, 0xc3, 0xae, 0x8d, 0xa3, 0xaf,
-    0xb5, 0xa7, 0x59, 0xd5, 0xd4, 0x4c, 0x81, 0x83, 0xc3, 0x17, 0xdb, 0xcb,
-    0xce, 0x75, 0xff, 0xf0, 0x5b, 0xd4, 0x1c, 0xd8, 0xf2, 0xd2, 0x04, 0xeb,
-    0x4b, 0x0f, 0xc5, 0xc8, 0xaf, 0xfa, 0x17, 0xf0, 0x39, 0x80, 0xd1, 0xd7,
-    0xfc, 0x98, 0x21, 0x51, 0x33, 0x87, 0x52, 0x1f, 0x7e, 0xd1, 0xcd, 0xef,
-    0x66, 0xe7, 0x5f, 0xcf, 0xcd, 0xe5, 0x9e, 0x3a, 0xff, 0xde, 0xd2, 0x73,
-    0xc3, 0xfb, 0xc8, 0xeb, 0xff, 0xcb, 0x8d, 0xbc, 0xfc, 0x73, 0x36, 0x46,
-    0xe7, 0x5f, 0xfa, 0x33, 0x99, 0xc0, 0x2d, 0x34, 0x75, 0xe7, 0xdf, 0x68,
-    0xeb, 0xf9, 0xfd, 0xa8, 0xc9, 0xce, 0xa8, 0x4c, 0xff, 0x0b, 0x50, 0xf8,
-    0x53, 0x76, 0x1e, 0x32, 0x3f, 0x7f, 0xdf, 0xc2, 0xf5, 0x8b, 0x86, 0x33,
-    0xaf, 0xfd, 0xc9, 0xf0, 0x39, 0xde, 0xe3, 0x19, 0xd7, 0xfe, 0xc1, 0xf6,
-    0xbe, 0xec, 0x8c, 0xdc, 0xea, 0xc4, 0x41, 0x69, 0x06, 0xff, 0xfa, 0x51,
-    0xc9, 0xfc, 0x8a, 0x6b, 0x4e, 0x32, 0x3a, 0xfe, 0x9f, 0x58, 0xb8, 0x63,
-    0x3a, 0xcc, 0xcc, 0x88, 0x0f, 0xaa, 0x17, 0x93, 0xa8, 0x75, 0xf4, 0xb8,
-    0x19, 0x1d, 0x7c, 0xbf, 0x24, 0xe7, 0x56, 0x1e, 0x22, 0x11, 0x5f, 0xfd,
-    0xb3, 0xca, 0x40, 0xcb, 0x3a, 0x8b, 0x3a, 0xe9, 0xfc, 0x75, 0xfe, 0xd9,
-    0xd7, 0x94, 0x60, 0x9d, 0x50, 0x79, 0x38, 0x2f, 0x7f, 0xfe, 0x97, 0x63,
-    0x8f, 0xef, 0xfc, 0x9e, 0xd7, 0x50, 0xeb, 0xfb, 0x19, 0xfb, 0xd7, 0xf1,
-    0xd7, 0xff, 0xef, 0x7d, 0x94, 0x6c, 0x41, 0x07, 0x12, 0x17, 0x85, 0x5f,
-    0x77, 0xee, 0xfe, 0x3a, 0xfd, 0x8b, 0xc4, 0xd8, 0x75, 0xe9, 0xe6, 0x63,
-    0x3a, 0xa1, 0x34, 0x79, 0xd5, 0x70, 0xbd, 0xaa, 0xc8, 0x4b, 0xf9, 0x3d,
-    0xde, 0xc3, 0xaf, 0xdc, 0x49, 0xdd, 0x66, 0x98, 0x4e, 0xfb, 0xdf, 0xc3,
-    0x9a, 0x61, 0x3b, 0x81, 0x06, 0xa0, 0x4e, 0xff, 0x0b, 0xa9, 0xe8, 0xe0,
-    0x0d, 0x40, 0x9d, 0xfe, 0xd6, 0x75, 0x35, 0xfc, 0xe6, 0x98, 0x4e, 0xec,
-    0x09, 0xa6, 0x13, 0xb9, 0x96, 0x4f, 0x30, 0x9d, 0x62, 0x69, 0x7b, 0x9a,
-    0x21, 0x72, 0xc8, 0xb4, 0x7f, 0xb1, 0x05, 0x92, 0x2b, 0x78, 0xb3, 0x09,
-    0x95, 0x3e, 0x7b, 0x26, 0xe9, 0xfb, 0xb3, 0x1e, 0x3d, 0x42, 0xe8, 0xfa,
-    0x16, 0xf5, 0x79, 0xc8, 0x06, 0x11, 0xda, 0x8d, 0x9f, 0xd2, 0x93, 0xaf,
-    0x08, 0x16, 0x75, 0xff, 0x47, 0xfe, 0x14, 0xd9, 0xf5, 0x67, 0x5e, 0x1c,
-    0xd6, 0x1e, 0xbf, 0x06, 0xef, 0x04, 0x13, 0x1d, 0x50, 0xce, 0xf6, 0x9e,
-    0x13, 0xc1, 0x8c, 0x2f, 0x0e, 0xd4, 0x3a, 0x6c, 0x6d, 0xa9, 0x0c, 0x79,
-    0xa1, 0x43, 0xc8, 0x4a, 0xac, 0x93, 0xb1, 0xad, 0x8a, 0xbe, 0xa1, 0x7b,
-    0xe9, 0xdc, 0x1d, 0x90, 0xcc, 0xfa, 0x63, 0x7e, 0x0e, 0x71, 0x14, 0x3a,
-    0xfe, 0xec, 0x7d, 0x1d, 0xc0, 0x75, 0xfb, 0xd9, 0x32, 0x2c, 0xeb, 0xf4,
-    0x6e, 0x00, 0x41, 0xd5, 0x07, 0x9c, 0x24, 0xf7, 0xe8, 0xd9, 0x03, 0xe3,
-    0xaf, 0xc9, 0xb3, 0xc9, 0x39, 0xd7, 0xe7, 0x97, 0xb1, 0xa7, 0x5f, 0x87,
-    0x3e, 0xe4, 0xc7, 0x5f, 0xff, 0x0b, 0x51, 0x61, 0xfd, 0xf9, 0x2c, 0xdf,
-    0xc7, 0x5f, 0xfe, 0xc0, 0x6b, 0xa9, 0xf3, 0x79, 0x46, 0x4e, 0x75, 0xff,
-    0x75, 0xd7, 0xd4, 0x8d, 0xe4, 0x75, 0xfd, 0xf4, 0x65, 0xb6, 0xf3, 0x9d,
-    0x50, 0x98, 0x34, 0x94, 0x11, 0x30, 0x07, 0x15, 0x3a, 0xa0, 0x00, 0x90,
-    0x34, 0x9f, 0x85, 0x22, 0x4d, 0xe8, 0xcb, 0xaf, 0xfd, 0x8f, 0xd9, 0x90,
-    0x7b, 0x9b, 0x9d, 0x7f, 0x02, 0x69, 0x47, 0xb4, 0x75, 0xff, 0xff, 0xfb,
-    0x3b, 0x82, 0x0c, 0x1f, 0x77, 0x3b, 0x19, 0x32, 0x72, 0x6e, 0xa6, 0xfe,
-    0x3a, 0xf8, 0x63, 0x19, 0x3a, 0xfa, 0x37, 0xd3, 0x9d, 0x50, 0xda, 0x8b,
-    0x4e, 0xea, 0x13, 0x8c, 0xa7, 0x90, 0xa4, 0x63, 0x0c, 0x64, 0xef, 0x29,
-    0xf4, 0x57, 0xfc, 0x7b, 0xf9, 0x76, 0xc8, 0x40, 0xfd, 0x20, 0xbf, 0xfe,
-    0x41, 0xc5, 0xc7, 0xd1, 0xfe, 0x43, 0x8b, 0x3a, 0xff, 0x82, 0x98, 0x3f,
-    0xcb, 0x34, 0x75, 0xff, 0x75, 0x25, 0xd7, 0x92, 0x2c, 0xeb, 0xff, 0x69,
-    0x07, 0x79, 0x79, 0x34, 0x87, 0x56, 0x1f, 0xa7, 0x8d, 0xef, 0xda, 0x5c,
-    0x06, 0x0e, 0xa9, 0x26, 0x81, 0x89, 0xcb, 0x85, 0x5f, 0x88, 0x6f, 0x86,
-    0x39, 0x23, 0xaf, 0xfb, 0xb1, 0x24, 0x11, 0xff, 0x73, 0xaf, 0xfa, 0x33,
-    0xdf, 0x40, 0x08, 0xdc, 0xeb, 0x72, 0x11, 0x25, 0x84, 0x0b, 0x38, 0xbf,
-    0xff, 0xfd, 0xd7, 0x4f, 0x4b, 0xf1, 0xf6, 0xba, 0xf2, 0xfa, 0x30, 0xde,
-    0x44, 0x8e, 0xbf, 0xf6, 0xbe, 0xf9, 0x07, 0xf9, 0x66, 0x8e, 0xb8, 0x3a,
-    0x3a, 0x98, 0xd1, 0x9d, 0xd7, 0x81, 0x40, 0xbf, 0xff, 0xb3, 0x7c, 0xd3,
-    0x8f, 0x52, 0x3d, 0xdf, 0xdd, 0x67, 0x54, 0x27, 0x1a, 0xf1, 0x81, 0x09,
-    0x95, 0xfc, 0x3f, 0xad, 0x3b, 0x07, 0x5f, 0xff, 0x9c, 0x7c, 0xef, 0xd1,
-    0x8f, 0x69, 0x9c, 0xe9, 0xd7, 0xfe, 0x9d, 0xc7, 0x5e, 0xea, 0x46, 0x8e,
-    0xbf, 0xe8, 0x06, 0x83, 0xfb, 0xf2, 0x47, 0x5e, 0xe6, 0xb4, 0x78, 0x80,
-    0xef, 0x9a, 0xee, 0xd3, 0x44, 0x06, 0xa9, 0xa9, 0xbf, 0xb9, 0x1d, 0x8f,
-    0x99, 0x24, 0x50, 0x71, 0x8a, 0x9d, 0x32, 0x3f, 0xb0, 0xdd, 0xa0, 0x27,
-    0x3f, 0xe8, 0xdd, 0x6f, 0x6c, 0x8e, 0x9d, 0x58, 0xa8, 0x49, 0x23, 0xcb,
-    0xfa, 0x55, 0x7b, 0xae, 0xc6, 0x75, 0xf4, 0x03, 0x6f, 0x0e, 0xa0, 0x1e,
-    0x0f, 0x87, 0xaf, 0x87, 0xc0, 0xfc, 0xeb, 0xf2, 0xd8, 0x86, 0x21, 0x88,
-    0x62, 0x4e, 0xbf, 0xff, 0xa5, 0x9a, 0x4e, 0x71, 0x17, 0xf7, 0xdd, 0xc6,
-    0x7c, 0x75, 0x62, 0x2e, 0xd0, 0x89, 0xcf, 0x2f, 0xff, 0x33, 0x83, 0xec,
-    0x19, 0x66, 0xbe, 0xac, 0xeb, 0xff, 0xd2, 0xcd, 0xe5, 0xf6, 0x00, 0xab,
-    0x2c, 0xb2, 0x55, 0xf9, 0x6c, 0xe2, 0x6c, 0x3a, 0xf4, 0xb0, 0x66, 0x3f,
-    0xaf, 0xaa, 0x35, 0x08, 0xf9, 0x78, 0x62, 0x54, 0x2a, 0x29, 0xec, 0x37,
-    0x46, 0x32, 0x6b, 0xfe, 0x41, 0x96, 0x98, 0xab, 0x12, 0xc4, 0x31, 0x27,
-    0x5f, 0x4d, 0xac, 0x98, 0xeb, 0xf0, 0x23, 0xd8, 0xc6, 0x75, 0xfe, 0x8c,
-    0xe3, 0x5d, 0xda, 0x68, 0x82, 0x6f, 0xfa, 0x3d, 0x9c, 0x6b, 0xbb, 0x4d,
-    0x17, 0xcd, 0xf9, 0xc3, 0xd8, 0x50, 0xeb, 0xc3, 0x9a, 0x0a, 0x29, 0xda,
-    0x7a, 0xb4, 0x3a, 0x14, 0xc4, 0x36, 0x43, 0x42, 0xff, 0xe8, 0xea, 0x29,
-    0x9c, 0x9d, 0x7f, 0xee, 0x75, 0x62, 0x74, 0x89, 0x19, 0x9f, 0x4a, 0xaf,
-    0xf7, 0xfd, 0xdb, 0xea, 0x37, 0xa7, 0x5f, 0xfa, 0x77, 0xdf, 0x6f, 0x3c,
-    0x2f, 0xb0, 0xeb, 0xff, 0xec, 0xf4, 0x0f, 0xb5, 0x98, 0xa2, 0x8f, 0x23,
-    0xaf, 0xfd, 0x81, 0x89, 0x47, 0x70, 0x0e, 0x75, 0xfc, 0xf2, 0xfe, 0x4e,
-    0x13, 0xaf, 0x32, 0xcb, 0x25, 0x5f, 0xbb, 0x8d, 0x7e, 0x14, 0xa9, 0x7f,
-    0x7f, 0xff, 0xa6, 0xe4, 0x6c, 0xf8, 0xa3, 0xfc, 0xfb, 0x36, 0xbe, 0x66,
-    0xfe, 0x3a, 0xbc, 0x8a, 0x5f, 0xa6, 0xd7, 0xff, 0x93, 0x89, 0xef, 0xf3,
-    0xce, 0xbc, 0x13, 0xaa, 0x75, 0x45, 0x2d, 0x43, 0x5a, 0x70, 0x0e, 0xc6,
-    0x1e, 0x3e, 0x25, 0xbf, 0xf2, 0xe3, 0x7d, 0x0e, 0x4f, 0xf6, 0x47, 0x5f,
-    0xff, 0xe4, 0xeb, 0x8e, 0xf2, 0xfb, 0x28, 0x19, 0x3a, 0xf0, 0x27, 0x5f,
-    0xfe, 0xcc, 0xe8, 0x7b, 0x1a, 0xce, 0xa0, 0x0e, 0xbf, 0xca, 0x7c, 0x9a,
-    0x51, 0xcd, 0x1d, 0x53, 0xa6, 0x3f, 0x24, 0x10, 0xb0, 0x22, 0x3d, 0xfc,
-    0xc7, 0x92, 0xec, 0x70, 0xeb, 0xfd, 0xe8, 0x4e, 0xa9, 0x1b, 0x9d, 0x7f,
-    0xfb, 0x71, 0xf8, 0xde, 0xa0, 0x01, 0x1c, 0x91, 0xd5, 0x08, 0xae, 0x42,
-    0xff, 0xa6, 0x77, 0xcc, 0x7a, 0x96, 0xc3, 0xaf, 0xff, 0x44, 0xff, 0x7b,
-    0x1b, 0xfb, 0x27, 0x10, 0x9d, 0x4e, 0x7e, 0x82, 0x4f, 0x7f, 0xa3, 0x07,
-    0xcc, 0x06, 0x5a, 0x75, 0xfe, 0xee, 0x6c, 0xf9, 0xa9, 0x34, 0xeb, 0x7f,
-    0xa3, 0xed, 0xf1, 0xb5, 0xfe, 0x71, 0xf9, 0xf7, 0x9d, 0x73, 0xaf, 0xd9,
-    0xc7, 0xdd, 0x93, 0xaf, 0xff, 0xf4, 0xf8, 0xc8, 0xe0, 0x78, 0x9f, 0xce,
-    0x1e, 0xc0, 0xce, 0x75, 0x4e, 0x88, 0xbd, 0x14, 0x5e, 0x65, 0x96, 0x4a,
-    0xbf, 0xdf, 0x41, 0x03, 0x9b, 0xf8, 0xa5, 0x4b, 0xfb, 0xff, 0xf9, 0x83,
-    0xf1, 0xbd, 0x40, 0x87, 0x19, 0xf9, 0xed, 0x64, 0xe7, 0x57, 0x51, 0x53,
-    0xfa, 0x25, 0x22, 0x62, 0x0f, 0x0e, 0xca, 0x9d, 0x94, 0x81, 0x28, 0xfc,
-    0x42, 0x6a, 0x92, 0x98, 0x39, 0x1b, 0xea, 0xe1, 0xd9, 0xd8, 0x52, 0x0c,
-    0x23, 0x74, 0x53, 0xe8, 0xf4, 0x2f, 0xfd, 0x88, 0x33, 0xb8, 0xfb, 0x16,
-    0x75, 0xff, 0xba, 0x8c, 0x87, 0xb9, 0xed, 0xbc, 0x3a, 0xf6, 0x08, 0x0e,
-    0xbe, 0xcf, 0x4d, 0x23, 0xaf, 0xfe, 0xda, 0x18, 0xda, 0xd3, 0x8f, 0xd0,
-    0x68, 0xea, 0xe9, 0xf6, 0x39, 0x15, 0xff, 0xb3, 0xd1, 0xcd, 0x76, 0x07,
-    0xc7, 0x88, 0x22, 0xfe, 0xce, 0x35, 0xdd, 0xa6, 0x88, 0x21, 0x53, 0xc9,
-    0xbd, 0x01, 0x43, 0xaa, 0x0f, 0x93, 0x49, 0x57, 0xb6, 0x42, 0xce, 0xbf,
-    0x9f, 0xbc, 0xe2, 0x32, 0x75, 0xfc, 0xc6, 0x16, 0x5c, 0x64, 0x75, 0x61,
-    0xfd, 0x08, 0xef, 0xe5, 0xb7, 0xff, 0xe8, 0x0c, 0xd2, 0x41, 0xf4, 0x02,
-    0x61, 0x49, 0x8e, 0xa5, 0x15, 0x39, 0x76, 0x10, 0xc0, 0x86, 0x70, 0xc2,
-    0x6f, 0x61, 0x75, 0xfd, 0xdc, 0xf7, 0x91, 0x67, 0x5f, 0xde, 0xfb, 0x9d,
-    0x7d, 0xce, 0xad, 0xcf, 0x6c, 0x4b, 0x2f, 0xec, 0xdf, 0xdc, 0xe4, 0x1d,
-    0x7f, 0xf6, 0x85, 0xfc, 0xeb, 0xfb, 0x13, 0xe1, 0xd4, 0x13, 0xf1, 0xd1,
-    0x6d, 0x42, 0x2d, 0x7f, 0x84, 0x9d, 0xfd, 0x8d, 0xfb, 0xb3, 0xb8, 0x75,
-    0xd0, 0xa1, 0xd7, 0x20, 0x9d, 0x66, 0x4e, 0xa0, 0x9a, 0x5f, 0xa2, 0x97,
-    0x87, 0xf9, 0xce, 0xbf, 0x75, 0xe5, 0x82, 0x75, 0xfc, 0x9e, 0x1c, 0xea,
-    0x1d, 0x76, 0x77, 0xe1, 0xe7, 0xc1, 0x2d, 0xce, 0xcf, 0xc4, 0x7c, 0x61,
-    0xdf, 0x48, 0xfc, 0xd9, 0x52, 0x4e, 0x6b, 0x0a, 0x06, 0x32, 0x8b, 0xfb,
-    0x48, 0x10, 0xe0, 0x9d, 0x7f, 0xff, 0x7b, 0xb9, 0xad, 0x66, 0x7f, 0xc9,
-    0xf3, 0xf1, 0xf1, 0xd7, 0xfd, 0xd8, 0xe7, 0x86, 0x33, 0x73, 0xaf, 0xff,
-    0xf9, 0x27, 0x89, 0x6b, 0x9c, 0x4d, 0xe6, 0x93, 0xf1, 0x79, 0xb9, 0xd7,
-    0xfa, 0x1e, 0x77, 0xe3, 0xfd, 0x3a, 0xf7, 0x70, 0x42, 0x8d, 0x3e, 0x9b,
-    0xf9, 0xa6, 0xb1, 0x39, 0xa4, 0x2b, 0xf4, 0x65, 0xf7, 0xfe, 0x6f, 0x63,
-    0x39, 0x2d, 0x7e, 0xb3, 0xae, 0x4d, 0x1d, 0x7f, 0xd9, 0x3b, 0xf8, 0x1f,
-    0x46, 0x47, 0x5f, 0xcf, 0xef, 0x91, 0x25, 0x0e, 0xbf, 0xbe, 0xaf, 0x4c,
-    0xbe, 0xe7, 0x54, 0x26, 0x47, 0x86, 0xaa, 0x1f, 0xf0, 0x55, 0xce, 0xbc,
-    0x5f, 0x7b, 0x99, 0xd3, 0xaf, 0x69, 0x16, 0x75, 0xa3, 0x86, 0xdb, 0xc3,
-    0x77, 0xc9, 0x32, 0x32, 0x75, 0xff, 0xcb, 0x7d, 0xfe, 0xf9, 0x39, 0x1f,
-    0xb0, 0x4e, 0xbf, 0xff, 0x7f, 0x38, 0xc6, 0x75, 0x58, 0xf6, 0x77, 0xfe,
-    0x1d, 0x7d, 0xed, 0x7d, 0xd0, 0x51, 0x89, 0x84, 0x5f, 0x52, 0xef, 0xda,
-    0x5e, 0x7b, 0x47, 0x5f, 0xfc, 0x8a, 0x67, 0x93, 0xb9, 0xe8, 0xe1, 0xd7,
-    0xe7, 0x90, 0xa4, 0x1d, 0x7f, 0x43, 0x8f, 0xb0, 0x4e, 0xa9, 0x27, 0xd7,
-    0x90, 0xea, 0x44, 0xbe, 0x13, 0xad, 0x08, 0x49, 0x2f, 0xe6, 0xf5, 0x36,
-    0xd1, 0x43, 0xaf, 0xff, 0x20, 0x23, 0x4b, 0x84, 0xe7, 0x11, 0x93, 0xaf,
-    0x98, 0xfb, 0x93, 0x9d, 0x7f, 0xa0, 0x39, 0xe4, 0xef, 0xe7, 0x59, 0x70,
-    0x7a, 0xe1, 0x25, 0xbf, 0xff, 0xf2, 0xdc, 0x41, 0x24, 0xd7, 0xeb, 0xea,
-    0x47, 0xbb, 0xfb, 0xac, 0xeb, 0xff, 0xe1, 0xff, 0xd2, 0x40, 0x75, 0xd3,
-    0xce, 0xb3, 0xae, 0xf8, 0xc6, 0x75, 0xff, 0xf9, 0xd3, 0xc8, 0x1c, 0x0e,
-    0x79, 0x16, 0x9c, 0x3a, 0xf7, 0x1f, 0x58, 0x8b, 0xae, 0x27, 0x74, 0x6e,
-    0xe4, 0xf3, 0xa6, 0xcd, 0xfc, 0x64, 0xd7, 0x4a, 0x0e, 0xbf, 0xfd, 0x38,
-    0x7b, 0x1d, 0xcd, 0xc1, 0x9e, 0xd1, 0xd4, 0xe7, 0xc1, 0xf8, 0xad, 0x05,
-    0x58, 0x9e, 0x18, 0x24, 0x27, 0xde, 0x38, 0xd1, 0x84, 0xad, 0xfd, 0xc8,
-    0x9d, 0x07, 0xc7, 0x5e, 0x0f, 0xd5, 0x9d, 0x7e, 0x18, 0x0e, 0x4c, 0x75,
-    0xf6, 0xbf, 0xe2, 0x87, 0x5f, 0xa3, 0xbe, 0x89, 0x1d, 0x7c, 0x1f, 0xfd,
-    0xa8, 0x3f, 0x0d, 0xc9, 0x80, 0x49, 0x7e, 0x06, 0x2e, 0x3a, 0x75, 0xfd,
-    0xfc, 0x7c, 0xe0, 0xc8, 0xeb, 0xcc, 0x1e, 0xe1, 0xd4, 0x14, 0xdd, 0xb0,
-    0xb1, 0x21, 0x1c, 0x29, 0x1e, 0x26, 0xfc, 0xbe, 0xf7, 0x3e, 0xe8, 0xeb,
-    0xa1, 0x87, 0x9d, 0x7f, 0xe7, 0x16, 0xe7, 0x1a, 0xee, 0xd3, 0x44, 0x23,
-    0x74, 0xa7, 0x3a, 0xa1, 0x13, 0x00, 0x1e, 0xfc, 0x6f, 0x62, 0x45, 0xfb,
-    0x27, 0xd0, 0x1c, 0xeb, 0xff, 0xff, 0xdd, 0xcf, 0xf8, 0xa7, 0x53, 0x78,
-    0xf7, 0xfd, 0x1c, 0xdf, 0xdf, 0xbe, 0x8e, 0xbf, 0xfb, 0x37, 0xfb, 0xe4,
-    0x1f, 0xe5, 0x9a, 0x3a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x83, 0x38,
-    0xb8, 0x60, 0x67, 0x8e, 0x07, 0x07, 0x3d, 0xa4, 0x6e, 0x0f, 0xd9, 0xf3,
-    0x91, 0xa1, 0x75, 0x35, 0x88, 0x00, 0x7e, 0x01, 0x70, 0xc0, 0xcf, 0x1c,
-    0x3a, 0xa1, 0x34, 0xec, 0x46, 0xbf, 0xfb, 0xce, 0x33, 0xef, 0x21, 0x8c,
-    0xd1, 0xd7, 0xfe, 0xfb, 0x9d, 0x75, 0xaa, 0xcb, 0x2c, 0x9d, 0x7f, 0xfe,
-    0xc6, 0xf6, 0x04, 0x22, 0x93, 0xe0, 0xa2, 0x87, 0x5c, 0xef, 0x3a, 0x25,
-    0xa4, 0x89, 0x7f, 0xff, 0x4c, 0x30, 0x0d, 0x37, 0xa9, 0xc9, 0x86, 0x01,
-    0xa3, 0xaf, 0xfe, 0xf7, 0x53, 0x67, 0x5e, 0x5c, 0x85, 0x0e, 0xbf, 0xbf,
-    0xf2, 0x7e, 0x2a, 0x1d, 0x7f, 0x63, 0x38, 0x3f, 0x80, 0xeb, 0xf4, 0xb3,
-    0xd0, 0x03, 0xae, 0x85, 0xce, 0x7a, 0x7b, 0x96, 0xdf, 0xff, 0xfc, 0x05,
-    0xbc, 0xba, 0xe9, 0xe4, 0x0e, 0x07, 0x3c, 0x8b, 0x4e, 0x1d, 0x5a, 0x44,
-    0xef, 0xe5, 0xf7, 0xff, 0xe1, 0xcd, 0x67, 0x5f, 0x69, 0xbd, 0x45, 0xc3,
-    0x4e, 0xbf, 0x4e, 0xb8, 0x0c, 0x1d, 0x52, 0x5d, 0x53, 0x0c, 0x79, 0x5b,
-    0x91, 0x4d, 0x0d, 0x9e, 0x17, 0x75, 0x6f, 0x48, 0xde, 0x8c, 0x7f, 0x61,
-    0x27, 0xd5, 0x5b, 0xfd, 0x1a, 0xd4, 0x4f, 0x8c, 0x9d, 0x7f, 0xbb, 0x8b,
-    0xce, 0xfe, 0x27, 0x50, 0x4f, 0x97, 0xc6, 0x77, 0xd9, 0xc5, 0x10, 0xea,
-    0x85, 0xec, 0x7c, 0x9d, 0x7a, 0x78, 0xc2, 0xbf, 0x22, 0xbc, 0xcb, 0x2c,
-    0x95, 0x7f, 0xd8, 0x07, 0xe6, 0x6c, 0xc0, 0x94, 0xa9, 0x7f, 0x73, 0x2c,
-    0x95, 0x79, 0x96, 0x59, 0x2a, 0xfe, 0x79, 0xc3, 0xd8, 0xd1, 0x4a, 0x97,
-    0xf4, 0x28, 0xbc, 0x65, 0x23, 0x6c, 0xde, 0xfc, 0xd4, 0x0f, 0xd5, 0x94,
-    0xa9, 0xb3, 0xbc, 0xcb, 0x2c, 0x95, 0x7b, 0x51, 0xc2, 0x95, 0x2f, 0xef,
-    0x9c, 0x77, 0xf1, 0xd6, 0x02, 0x22, 0x97, 0xcb, 0x2c, 0x95, 0xdf, 0xc1,
-    0x18, 0x93, 0xb4, 0xeb, 0xf6, 0xbf, 0x9f, 0x6c, 0x4e, 0xbf, 0x05, 0x36,
-    0x40, 0x4e, 0xbe, 0xc1, 0xc6, 0x33, 0xab, 0x87, 0x94, 0xb2, 0x8a, 0x44,
-    0x4c, 0x7d, 0x76, 0xbf, 0xfb, 0xaf, 0x21, 0x75, 0x26, 0x14, 0x98, 0xeb,
-    0xff, 0xb3, 0x93, 0xc6, 0xfa, 0x41, 0xc0, 0x1d, 0x7f, 0x77, 0x36, 0x67,
-    0xb4, 0x75, 0x35, 0x16, 0xa0, 0x44, 0xf2, 0x1d, 0x71, 0x3c, 0xce, 0xc3,
-    0x0c, 0x61, 0xb3, 0x74, 0xfe, 0x3a, 0xa1, 0x52, 0x9e, 0x4a, 0x02, 0x13,
-    0xab, 0xdb, 0xb1, 0x56, 0x24, 0xeb, 0xff, 0xd8, 0xc6, 0xe2, 0x0c, 0x6c,
-    0x76, 0x16, 0x75, 0xf6, 0xba, 0x93, 0x15, 0x7f, 0xcf, 0xbf, 0xb2, 0x6f,
-    0xf8, 0xa1, 0xd6, 0x6a, 0x1e, 0xf7, 0xe4, 0x57, 0xf8, 0x73, 0x79, 0x69,
-    0x14, 0x3a, 0xf9, 0xdf, 0x8a, 0x1d, 0x5f, 0x0f, 0x52, 0x73, 0x3b, 0xfe,
-    0xcc, 0x68, 0x23, 0x37, 0x91, 0xd7, 0xd0, 0xeb, 0xd8, 0x55, 0xff, 0xdd,
-    0x47, 0x00, 0x20, 0x11, 0xdd, 0x1d, 0x7f, 0x77, 0x16, 0xb7, 0x91, 0xd7,
-    0x99, 0x65, 0x92, 0xaf, 0xf0, 0xfb, 0xa9, 0x03, 0x39, 0x4a, 0x97, 0xf7,
-    0xa0, 0x19, 0x24, 0x46, 0x62, 0x5d, 0x79, 0x30, 0x0f, 0xb0, 0xce, 0xb6,
-    0x35, 0x34, 0xd5, 0xc6, 0x45, 0x7f, 0x02, 0x01, 0x1d, 0xd1, 0xd7, 0xfa,
-    0x3e, 0xf3, 0x89, 0xed, 0x1d, 0x50, 0xae, 0x0e, 0x45, 0x1b, 0xc2, 0x9d,
-    0x1f, 0x26, 0x25, 0xec, 0x70, 0x80, 0x2f, 0x12, 0xcb, 0xf0, 0x31, 0x3a,
-    0xa1, 0xd7, 0xff, 0xd8, 0xd8, 0x17, 0xf6, 0x83, 0xfb, 0xf2, 0x47, 0x56,
-    0xe7, 0xea, 0xb2, 0x7b, 0xff, 0xff, 0x85, 0xd7, 0x1c, 0x68, 0x7b, 0x1a,
-    0xfd, 0xd2, 0x5a, 0xeb, 0xc8, 0xeb, 0xdf, 0xfb, 0x47, 0x5e, 0x6c, 0x68,
-    0xeb, 0xff, 0xbe, 0xcb, 0x3a, 0xfd, 0x4e, 0x72, 0x0e, 0xac, 0x3d, 0xf0,
-    0x0d, 0xdf, 0xa3, 0xda, 0xd9, 0x87, 0x5f, 0xbf, 0xe2, 0x9d, 0x43, 0xaa,
-    0x13, 0x81, 0x72, 0x30, 0x38, 0x0b, 0xe7, 0x88, 0x76, 0xca, 0x2f, 0xf0,
-    0xbb, 0x38, 0x2e, 0xa1, 0xd7, 0xff, 0x67, 0xb5, 0xf7, 0x4b, 0x18, 0xe4,
-    0x1d, 0x7c, 0x9b, 0x30, 0x42, 0x7e, 0xab, 0x31, 0xbf, 0xff, 0xe0, 0xf5,
-    0x19, 0xcd, 0xa4, 0x5b, 0xfb, 0x5f, 0xcb, 0x37, 0xf1, 0xd5, 0x88, 0xa4,
-    0x73, 0x9b, 0xfe, 0x99, 0xbd, 0x45, 0xc7, 0x14, 0x3a, 0xfd, 0x3f, 0xcf,
-    0xe2, 0x63, 0xad, 0x23, 0xaf, 0x7d, 0x19, 0x8e, 0xa9, 0x1a, 0xe0, 0x08,
-    0x56, 0x22, 0xd5, 0xce, 0xb4, 0xb5, 0x50, 0xed, 0xff, 0xe7, 0x94, 0xc3,
-    0x29, 0x48, 0xc1, 0x95, 0x45, 0x94, 0xa7, 0xb5, 0x21, 0x6c, 0xd3, 0xb4,
-    0x95, 0x67, 0x34, 0xb0, 0x7e, 0x4a, 0xf2, 0x5c, 0xa7, 0x7e, 0xcb, 0x6d,
-    0x78, 0xf3, 0x81, 0x0f, 0x31, 0x9f, 0x06, 0xd4, 0xe2, 0x97, 0xa5, 0xdc,
-    0xff, 0x29, 0xcd, 0x98, 0xdc, 0x7e, 0xc3, 0x5a, 0xf6, 0xc8, 0x13, 0xaf,
-    0xff, 0xb0, 0x55, 0xf2, 0x89, 0xbe, 0xbb, 0x80, 0x73, 0xaa, 0x47, 0xd8,
-    0x11, 0xcb, 0xfc, 0xe2, 0xdc, 0xf7, 0x50, 0xeb, 0xff, 0xfe, 0xce, 0xbf,
-    0xdd, 0x62, 0x8e, 0x20, 0x81, 0x89, 0xbb, 0x07, 0x5a, 0x0e, 0xbf, 0xff,
-    0x47, 0x3b, 0x0b, 0xda, 0xfe, 0x06, 0x26, 0xec, 0x1d, 0x7e, 0x4e, 0x4d,
-    0x1d, 0xe2, 0x32, 0xc0, 0xca, 0x21, 0xf5, 0xba, 0x6d, 0x2b, 0x22, 0xfb,
-    0x0f, 0xbb, 0x30, 0xf3, 0xaf, 0xfc, 0xe2, 0x0f, 0x81, 0xfd, 0xf9, 0x23,
-    0xaf, 0x90, 0x67, 0x83, 0xaf, 0x7b, 0x90, 0x75, 0xff, 0x0c, 0x2d, 0x07,
-    0x17, 0x07, 0x5c, 0x81, 0xc3, 0xcf, 0x98, 0x6e, 0x98, 0xd1, 0xb9, 0xc4,
-    0x01, 0x6f, 0xa6, 0x28, 0x99, 0x26, 0x43, 0xca, 0xf4, 0x0c, 0xe7, 0x5f,
-    0x27, 0x51, 0x67, 0x5b, 0xa8, 0x6e, 0xe6, 0x1b, 0xbf, 0xa1, 0xb1, 0xaf,
-    0x21, 0xd7, 0xfd, 0x1e, 0xeb, 0x81, 0xf7, 0xd1, 0xd4, 0x13, 0xe3, 0x12,
-    0xbb, 0xff, 0x70, 0x1f, 0x3a, 0x8d, 0xff, 0x80, 0x3a, 0xf4, 0xdf, 0xf0,
-    0xeb, 0xff, 0x3a, 0x73, 0x37, 0x55, 0x96, 0x59, 0x3a, 0xa1, 0x14, 0x4e,
-    0x85, 0xa1, 0xeb, 0xff, 0xe1, 0x89, 0x7c, 0xfb, 0xe4, 0x1f, 0xe5, 0x9a,
-    0x3a, 0xb1, 0x3c, 0xd6, 0xc2, 0x2b, 0xb0, 0xc3, 0x01, 0x75, 0xe0, 0x3a,
-    0xce, 0xbb, 0x00, 0x75, 0xe1, 0x90, 0xc1, 0xb0, 0xc1, 0xbb, 0xed, 0x35,
-    0xa8, 0x75, 0x41, 0xe8, 0x39, 0x7d, 0xfb, 0x9a, 0x18, 0x9c, 0xeb, 0xff,
-    0xe6, 0x71, 0xba, 0xcf, 0x4d, 0x8a, 0x0e, 0x00, 0xea, 0xc3, 0xf7, 0x42,
-    0x7b, 0xf9, 0xfd, 0xd7, 0x10, 0x1d, 0x7f, 0xe7, 0xf6, 0x4c, 0xf0, 0x31,
-    0x31, 0xd7, 0xfe, 0xea, 0x67, 0xdc, 0x99, 0x98, 0xdc, 0xeb, 0x27, 0x11,
-    0x51, 0xd2, 0xbd, 0x1e, 0x5c, 0xd6, 0x9a, 0x30, 0x4a, 0x92, 0x64, 0x0d,
-    0x86, 0x40, 0x0d, 0x6e, 0xc1, 0x3a, 0xff, 0xf7, 0xa0, 0x5b, 0x9e, 0xea,
-    0x70, 0x0d, 0x3a, 0xfc, 0x14, 0xd7, 0x50, 0xeb, 0xf9, 0x07, 0x3d, 0xd4,
-    0x3a, 0xd1, 0x87, 0xa1, 0xa2, 0x6a, 0x0a, 0x34, 0xb0, 0x53, 0xf8, 0x4c,
-    0x5f, 0xe8, 0x5e, 0xb4, 0xe3, 0x39, 0xd7, 0xfc, 0x0d, 0x49, 0x3a, 0xe9,
-    0x39, 0xd7, 0xda, 0xc1, 0xf1, 0xd7, 0xb6, 0xa3, 0x87, 0x52, 0x1f, 0xb3,
-    0x9c, 0x7e, 0x41, 0x7b, 0xce, 0xc6, 0x75, 0xfe, 0xf7, 0x51, 0x50, 0x3a,
-    0x1d, 0x77, 0xdc, 0x3a, 0x82, 0x9b, 0x97, 0x4d, 0x46, 0x15, 0x1e, 0x2e,
-    0xfc, 0x7b, 0xe9, 0x95, 0xf7, 0x51, 0xe4, 0x75, 0xe0, 0xbc, 0x8e, 0xbb,
-    0xf0, 0x41, 0xbb, 0xc2, 0x0b, 0xfe, 0x6e, 0x7a, 0x36, 0x20, 0x80, 0xeb,
-    0xff, 0xfb, 0xf8, 0xf6, 0xb0, 0x7e, 0x72, 0x10, 0x22, 0xf2, 0x3a, 0xfc,
-    0xde, 0xee, 0xec, 0x67, 0x5f, 0xfc, 0x81, 0x1f, 0xfd, 0xa8, 0x18, 0xd1,
-    0xd4, 0x88, 0xff, 0x13, 0x8f, 0xd6, 0xb6, 0x15, 0xdf, 0xfc, 0x07, 0xe6,
-    0x6c, 0xc0, 0xf0, 0x59, 0x3a, 0xff, 0xfe, 0x1c, 0xd7, 0xff, 0x33, 0xae,
-    0x39, 0x34, 0xa3, 0x73, 0xaf, 0xdc, 0x6b, 0xbb, 0x4d, 0x10, 0x35, 0xfc,
-    0xf3, 0x81, 0xc4, 0x24, 0xac, 0x1f, 0x7b, 0x35, 0xfe, 0x1f, 0x6e, 0xd9,
-    0x9d, 0xee, 0xbc, 0xbe, 0x23, 0xfc, 0x61, 0x93, 0x7f, 0xdd, 0x4c, 0x1c,
-    0x68, 0x70, 0xea, 0x5a, 0x76, 0x7e, 0x8d, 0x13, 0x61, 0xd5, 0xef, 0x7f,
-    0x07, 0x5f, 0xe0, 0x79, 0x27, 0x5c, 0x34, 0xea, 0xdc, 0xf3, 0xc4, 0x72,
-    0xfc, 0x16, 0x2d, 0xc2, 0xc5, 0x9d, 0x50, 0xab, 0x33, 0x23, 0xf1, 0x48,
-    0x44, 0x39, 0x15, 0xfe, 0xcd, 0xfc, 0x1c, 0xc5, 0x0e, 0xbf, 0xb3, 0xd0,
-    0x28, 0x03, 0xaf, 0xf8, 0x3c, 0x17, 0x67, 0xee, 0xec, 0x9d, 0x79, 0xf9,
-    0x39, 0xa3, 0x05, 0xbf, 0xf3, 0xf3, 0x04, 0x1a, 0xf6, 0xb7, 0x3a, 0xff,
-    0xff, 0xfe, 0xcf, 0x75, 0xc5, 0x4f, 0x9a, 0xe3, 0xbf, 0xb6, 0x60, 0x7e,
-    0x62, 0xdc, 0x77, 0x91, 0xe2, 0x0b, 0xbf, 0xf3, 0xba, 0x8d, 0x70, 0xfc,
-    0x51, 0x93, 0xc4, 0x17, 0x7f, 0xf7, 0x53, 0xa9, 0x03, 0xef, 0x8a, 0x32,
-    0x78, 0x82, 0xef, 0xf4, 0x20, 0xfb, 0xe2, 0x8c, 0x9e, 0x20, 0xbb, 0xf9,
-    0x78, 0x1f, 0x8a, 0x32, 0x78, 0x82, 0xef, 0xff, 0xf9, 0xc4, 0x51, 0x7f,
-    0x34, 0xde, 0xa7, 0x11, 0x49, 0xf1, 0x93, 0xc4, 0x17, 0x76, 0xff, 0x02,
-    0x9c, 0xbb, 0x53, 0xf8, 0xa6, 0xe8, 0x42, 0x7d, 0x50, 0xab, 0x1f, 0xa7,
-    0xc3, 0x28, 0xc6, 0xff, 0x24, 0x29, 0xaf, 0x6b, 0x73, 0xaf, 0x9f, 0x80,
-    0x73, 0xaf, 0xfe, 0xea, 0x75, 0x20, 0x7d, 0xf1, 0x46, 0x4f, 0x10, 0x5d,
-    0xff, 0x4d, 0xa6, 0xa4, 0xff, 0x14, 0x64, 0xf1, 0x05, 0xdf, 0xbd, 0xa8,
-    0x5f, 0xc6, 0xa2, 0x7f, 0xea, 0x9d, 0xff, 0xef, 0x8d, 0xea, 0x36, 0x3d,
-    0xaf, 0x8a, 0x32, 0x78, 0x82, 0xef, 0xff, 0xfe, 0x11, 0x45, 0xfc, 0xff,
-    0x3e, 0x69, 0xbd, 0x4e, 0x22, 0x93, 0xe3, 0x27, 0x88, 0x2e, 0xb1, 0x32,
-    0x5d, 0xd1, 0x1d, 0x76, 0xff, 0xba, 0x9c, 0x45, 0x27, 0xc6, 0x4f, 0x10,
-    0x5d, 0xff, 0xf3, 0xbe, 0xf2, 0xd7, 0x50, 0x21, 0x8e, 0x41, 0x57, 0xfe,
-    0xc9, 0x4b, 0xfd, 0x70, 0x67, 0xdb, 0x3c, 0x41, 0x74, 0xd4, 0x72, 0xf1,
-    0x1f, 0x49, 0xd7, 0xfe, 0x6a, 0x73, 0xce, 0x0d, 0x7c, 0x64, 0xf1, 0x05,
-    0xdf, 0xdd, 0x4e, 0xf5, 0x00, 0x68, 0x02, 0xef, 0xd8, 0x0f, 0x8a, 0x32,
-    0x78, 0x82, 0xee, 0xcf, 0x34, 0xfc, 0x7a, 0x73, 0x5b, 0xa3, 0xb3, 0x50,
-    0xbf, 0xbf, 0x97, 0x81, 0xf8, 0xa3, 0x27, 0x88, 0x2e, 0xff, 0xcd, 0xea,
-    0x71, 0x14, 0x9f, 0x19, 0x3c, 0x41, 0x77, 0x67, 0xc7, 0x44, 0x5e, 0x8f,
-    0xaf, 0xf7, 0xe8, 0xb7, 0x1d, 0xe4, 0x78, 0x82, 0xef, 0xfd, 0x89, 0xb3,
-    0x07, 0x02, 0xf2, 0x3c, 0x41, 0x6b, 0x3c, 0x0a, 0x0a, 0xef, 0xef, 0x0d,
-    0xc0, 0x68, 0x31, 0xf2, 0x6a, 0x31, 0x5f, 0x46, 0x39, 0xfc, 0x2d, 0x19,
-    0x6f, 0xb8, 0x10, 0x68, 0x82, 0xd5, 0x44, 0x65, 0xce, 0xd3, 0xad, 0xa6,
-    0xb2, 0x70, 0xc1, 0x49, 0x79, 0xf1, 0xad, 0xd2, 0xda, 0x3a, 0xf4, 0x4b,
-    0x68, 0xea, 0x83, 0x6e, 0x23, 0x35, 0x3b, 0x2b, 0xd8, 0x26, 0x7b, 0x95,
-    0x02, 0x94, 0x00, 0x2f, 0x57, 0xff, 0x64, 0x87, 0x3d, 0xd4, 0xcd, 0xfc,
-    0x75, 0xfa, 0x3d, 0xae, 0xa1, 0xd7, 0xfe, 0xd4, 0xd2, 0xfc, 0x33, 0x4b,
-    0xf0, 0x9d, 0x52, 0x3e, 0xaf, 0x13, 0x5f, 0xfd, 0x1b, 0xcb, 0xea, 0xf5,
-    0xe8, 0xdd, 0x93, 0xaf, 0xd2, 0xda, 0xda, 0xfe, 0x73, 0xad, 0xd4, 0x3f,
-    0x97, 0x49, 0xbf, 0x72, 0x37, 0x96, 0x8e, 0xa9, 0x1e, 0x77, 0x09, 0xaf,
-    0xfe, 0x07, 0xfa, 0xdb, 0xce, 0x01, 0x69, 0xa3, 0xaf, 0xf0, 0x3f, 0xf0,
-    0xc7, 0xb4, 0x75, 0x00, 0xfe, 0xf4, 0x91, 0x50, 0x9d, 0x46, 0x43, 0xa5,
-    0xe1, 0x3b, 0x7f, 0x3c, 0xa3, 0x63, 0xf4, 0xeb, 0xff, 0xd3, 0xe6, 0xfe,
-    0xd2, 0x0c, 0x01, 0xd6, 0x75, 0xf6, 0xfa, 0x8d, 0xce, 0xbc, 0xb8, 0x91,
-    0xd7, 0xec, 0x0f, 0x7f, 0x64, 0xea, 0xf8, 0x7c, 0xee, 0x46, 0x23, 0x77,
-    0x82, 0xfe, 0x3a, 0xb8, 0x79, 0x4e, 0x5f, 0x79, 0x36, 0xf0, 0xeb, 0xcf,
-    0xc0, 0x1d, 0x6d, 0xe0, 0xdc, 0x78, 0x76, 0xf9, 0x9c, 0xeb, 0x9d, 0x7c,
-    0xa7, 0x11, 0x93, 0xaf, 0xd3, 0xbf, 0x61, 0x8c, 0xea, 0x62, 0x4f, 0x37,
-    0x08, 0xea, 0x15, 0x1d, 0xe1, 0x6a, 0x43, 0xe9, 0xd6, 0x40, 0x4e, 0x2d,
-    0xd7, 0xff, 0x84, 0x62, 0x75, 0xf5, 0x39, 0xc7, 0x91, 0xd7, 0xfa, 0x79,
-    0xe0, 0x77, 0xcf, 0x1d, 0x58, 0x7f, 0x88, 0x91, 0x7f, 0xf7, 0x07, 0xfd,
-    0xfc, 0x39, 0x3b, 0x89, 0xd7, 0x9f, 0x93, 0x9d, 0x70, 0x20, 0xeb, 0xe4,
-    0x85, 0xe1, 0xd4, 0x75, 0xfc, 0xea, 0x7a, 0x38, 0x03, 0xa8, 0x26, 0xdc,
-    0x42, 0xaf, 0xff, 0xf4, 0x20, 0x46, 0x3f, 0x6f, 0xb1, 0xa1, 0x86, 0xfd,
-    0x59, 0xd7, 0x02, 0x0e, 0xba, 0x14, 0x3a, 0xff, 0xb3, 0xda, 0x85, 0xfd,
-    0xc9, 0x8e, 0xbf, 0xda, 0xce, 0xa6, 0xbf, 0x9c, 0xeb, 0x99, 0x64, 0xab,
-    0xfe, 0x1c, 0xd8, 0xf2, 0xd2, 0x04, 0xea, 0x6a, 0x7e, 0x28, 0x39, 0xc1,
-    0x55, 0xab, 0x74, 0x80, 0x0c, 0x2c, 0x11, 0x51, 0x16, 0xd1, 0xd3, 0x26,
-    0x9f, 0x46, 0x2f, 0x32, 0xcb, 0x25, 0x59, 0x65, 0x2a, 0x5f, 0xdf, 0x4c,
-    0xef, 0xc2, 0x95, 0x46, 0xef, 0xd8, 0x5e, 0xd4, 0xea, 0xd6, 0x9e, 0x58,
-    0x95, 0xfd, 0xe8, 0xce, 0xe4, 0xe7, 0x5d, 0x8b, 0x3a, 0xb7, 0x3c, 0x1d,
-    0x16, 0x54, 0x3a, 0x25, 0x69, 0x46, 0xbb, 0x92, 0x8d, 0x94, 0x86, 0x3e,
-    0xf1, 0xdb, 0xa4, 0xa7, 0xae, 0x42, 0x6b, 0xb2, 0xfd, 0xde, 0x96, 0x78,
-    0x05, 0x81, 0x94, 0xa9, 0xa9, 0x4e, 0x7e, 0x86, 0xaf, 0xf2, 0xde, 0xb6,
-    0x36, 0xdf, 0xd8, 0x00, 0x27, 0x24, 0x75, 0xcd, 0xc3, 0xa8, 0x27, 0x82,
-    0xe5, 0x97, 0x63, 0x27, 0x5d, 0x1e, 0x3a, 0xa7, 0x35, 0x6d, 0x16, 0xb2,
-    0xce, 0xac, 0x36, 0x5e, 0x22, 0xbf, 0xd2, 0x41, 0xc5, 0xff, 0xd3, 0xaf,
-    0xfd, 0x9e, 0xd7, 0x51, 0x6f, 0x9c, 0x3a, 0xa0, 0xfb, 0x84, 0xca, 0xfb,
-    0xe7, 0xa3, 0x61, 0xd7, 0xd8, 0xbc, 0xf1, 0xd7, 0xbc, 0xea, 0x1d, 0x7f,
-    0xff, 0xf3, 0x5e, 0x6f, 0xe5, 0xfb, 0x7e, 0x75, 0x3d, 0xe8, 0xde, 0x27,
-    0x8d, 0x1d, 0x7f, 0xff, 0xcc, 0x62, 0xef, 0xb2, 0x25, 0xd8, 0xe4, 0xf1,
-    0xed, 0x3c, 0x8e, 0xbc, 0x9b, 0xcc, 0x75, 0xfb, 0x32, 0x7f, 0xf4, 0x75,
-    0xf7, 0x05, 0x00, 0x75, 0xf2, 0x35, 0xf8, 0x75, 0xd0, 0x03, 0xaf, 0xbf,
-    0x9f, 0xf5, 0x7a, 0x6d, 0x7e, 0x90, 0x52, 0x22, 0x53, 0xaa, 0xb7, 0xfd,
-    0xd7, 0xd7, 0x52, 0x77, 0x13, 0xaf, 0x9e, 0x7f, 0xb2, 0x3a, 0x98, 0x4a,
-    0xf1, 0x21, 0xfa, 0x50, 0x8e, 0xc2, 0x0d, 0xc9, 0x50, 0x83, 0x83, 0x8e,
-    0xf0, 0x06, 0x9d, 0x0e, 0xfa, 0x17, 0x9f, 0x48, 0xb6, 0x8d, 0xef, 0xe1,
-    0xfc, 0x2b, 0x79, 0x1d, 0x79, 0x27, 0xfc, 0xeb, 0xf4, 0x01, 0x37, 0xc3,
-    0xae, 0x5e, 0xc3, 0xac, 0x18, 0x37, 0xc2, 0x4d, 0x7f, 0xfa, 0x43, 0x1f,
-    0x16, 0x30, 0xa7, 0x92, 0x73, 0xaf, 0xce, 0xbc, 0xea, 0xce, 0xad, 0xcf,
-    0xc7, 0xc9, 0x77, 0xbd, 0xc8, 0x3a, 0xff, 0x6b, 0xdb, 0x30, 0x70, 0x27,
-    0x5e, 0xec, 0x6c, 0x3a, 0xf6, 0xa5, 0x39, 0xd5, 0x86, 0xeb, 0xe8, 0xed,
-    0x42, 0x7d, 0x72, 0x2d, 0xc5, 0xb4, 0x84, 0xb2, 0xc8, 0xdc, 0x6f, 0xcd,
-    0xb7, 0x9f, 0xe7, 0xd3, 0xaf, 0x4c, 0x9d, 0x3a, 0xfe, 0x8e, 0x3c, 0xc9,
-    0xd3, 0xaf, 0xda, 0x0c, 0x0c, 0xee, 0x79, 0x1a, 0x1c, 0xbc, 0xb8, 0x59,
-    0xd5, 0xb9, 0xec, 0xac, 0xfa, 0xff, 0xf8, 0x65, 0xf3, 0x02, 0x9a, 0xdf,
-    0xdf, 0xbe, 0x8e, 0xbf, 0x77, 0xf1, 0x8d, 0x87, 0x5f, 0xc2, 0xfe, 0x94,
-    0x28, 0x75, 0x41, 0xea, 0xfd, 0x29, 0xbe, 0xcc, 0xde, 0x47, 0x5e, 0xd2,
-    0x4c, 0x75, 0x94, 0x13, 0x7b, 0xa2, 0x1b, 0xff, 0x9e, 0x71, 0x8d, 0xd0,
-    0x23, 0x13, 0x9d, 0x5c, 0x3e, 0xa1, 0x27, 0xbf, 0x7c, 0xec, 0x72, 0x47,
-    0x57, 0xc5, 0x53, 0xd1, 0x0c, 0x0c, 0x23, 0x6c, 0x29, 0xde, 0x19, 0x4c,
-    0x90, 0xde, 0x5e, 0xa0, 0xeb, 0xfa, 0x79, 0xa4, 0xc2, 0xe4, 0xe7, 0x5f,
-    0x2f, 0x1f, 0xa7, 0x5d, 0x29, 0xce, 0xbd, 0xd0, 0xa1, 0xd7, 0xee, 0xe2,
-    0x4b, 0x47, 0x5f, 0xff, 0x76, 0x3e, 0xab, 0xe1, 0x70, 0x6b, 0x50, 0x02,
-    0xaf, 0xdc, 0x6b, 0xbb, 0x4f, 0x10, 0x25, 0xed, 0x46, 0xe7, 0x58, 0x18,
-    0x79, 0xfb, 0x99, 0xde, 0xf2, 0x4e, 0x75, 0xe9, 0xdc, 0x4e, 0xa9, 0x26,
-    0x4a, 0x12, 0x6e, 0x42, 0x81, 0x65, 0x1e, 0x1c, 0xbf, 0x85, 0xae, 0xa7,
-    0x50, 0xeb, 0xb6, 0xa4, 0x75, 0xf7, 0xa7, 0x71, 0x3a, 0xf0, 0xba, 0x87,
-    0x5e, 0x51, 0x3c, 0x75, 0xed, 0x3f, 0x8e, 0xa5, 0x0d, 0xbe, 0xe3, 0x97,
-    0x7c, 0xe9, 0xd7, 0xf2, 0xfc, 0x81, 0xfe, 0x0e, 0xbc, 0xbf, 0x34, 0xeb,
-    0x7a, 0x0f, 0x27, 0x0b, 0x6f, 0xe8, 0x5e, 0x29, 0x1a, 0x3a, 0xa7, 0x4d,
-    0x8b, 0x06, 0x5a, 0x43, 0xd5, 0x20, 0x11, 0x8b, 0x0f, 0x89, 0xae, 0xe7,
-    0xe7, 0x5f, 0xe1, 0x76, 0x75, 0xa8, 0x01, 0xd7, 0xb6, 0xdd, 0x43, 0xaf,
-    0xfa, 0x17, 0x2c, 0x9f, 0x3f, 0x60, 0x9d, 0x7c, 0xfe, 0x60, 0xce, 0x75,
-    0x62, 0x20, 0x90, 0x7d, 0xcf, 0x6f, 0x32, 0xcb, 0x27, 0xab, 0xea, 0xf3,
-    0x88, 0x4b, 0x57, 0xd5, 0x53, 0x59, 0x7d, 0x2f, 0xe1, 0x43, 0xac, 0x03,
-    0xab, 0x0d, 0x9b, 0x91, 0xd4, 0x27, 0x5e, 0x11, 0x7e, 0x42, 0xd0, 0x0b,
-    0x3e, 0x6c, 0xbe, 0x5f, 0x3f, 0x9c, 0xeb, 0xff, 0xe1, 0x45, 0x15, 0xd7,
-    0xbb, 0xfb, 0xca, 0x50, 0x75, 0x41, 0xfa, 0xe1, 0x25, 0x4e, 0x8e, 0x45,
-    0x21, 0x89, 0x7d, 0x81, 0x79, 0x1d, 0x7e, 0x71, 0x14, 0x59, 0xd7, 0xfd,
-    0xd4, 0xe6, 0x22, 0xe1, 0x8c, 0xeb, 0xf2, 0x2d, 0xc7, 0x0e, 0xaf, 0x8b,
-    0xec, 0xec, 0x40, 0xdc, 0x1a, 0xc8, 0x80, 0x22, 0xf9, 0x1a, 0x02, 0x8a,
-    0x09, 0x1c, 0x73, 0xca, 0xf7, 0x01, 0x50, 0x90, 0x7e, 0x49, 0xb6, 0x73,
-    0x7e, 0x4f, 0x47, 0xb4, 0x55, 0xf3, 0x63, 0xda, 0x2a, 0xe6, 0x59, 0x2a,
-    0xa4, 0x7b, 0xf8, 0x4c, 0xc9, 0x0d, 0xd8, 0xc9, 0x4a, 0x9a, 0xfb, 0xff,
-    0xef, 0x43, 0x73, 0x07, 0xdd, 0x48, 0x19, 0xce, 0xa3, 0xab, 0x0f, 0x5b,
-    0x49, 0x94, 0x04, 0x4f, 0x32, 0xfb, 0x7f, 0xef, 0x6b, 0x1b, 0xd7, 0x1f,
-    0x68, 0xeb, 0xf4, 0x6c, 0x41, 0x01, 0xdf, 0x0d, 0xed, 0xfa, 0x5d, 0xfe,
-    0x38, 0x75, 0xff, 0xce, 0xbe, 0x46, 0xc4, 0xd8, 0x3f, 0xe8, 0xea, 0xdc,
-    0xfb, 0xfa, 0x51, 0x7e, 0xcf, 0xd7, 0x1a, 0x3a, 0x8e, 0xbb, 0x26, 0xe1,
-    0xb1, 0xd1, 0x3d, 0xff, 0x27, 0xec, 0x1e, 0xc7, 0xd1, 0x9c, 0xeb, 0xfe,
-    0x89, 0xe3, 0x7f, 0x0e, 0x4e, 0x75, 0x62, 0x29, 0x5a, 0x5a, 0x87, 0xf7,
-    0xe7, 0x58, 0xc6, 0xe7, 0x54, 0xc9, 0xa6, 0xf2, 0x1f, 0x3d, 0x2e, 0xbe,
-    0xce, 0xe4, 0xe7, 0x5e, 0x93, 0xf0, 0xeb, 0xf4, 0xb3, 0xd8, 0x12, 0xaf,
-    0xa0, 0x46, 0x0e, 0xa9, 0x8f, 0x7f, 0xc3, 0x7f, 0x49, 0xaf, 0x81, 0xa5,
-    0xf0, 0xea, 0x51, 0x1a, 0x89, 0x08, 0x0f, 0x19, 0x5f, 0xf0, 0xe7, 0x73,
-    0xe7, 0x72, 0x73, 0xaf, 0xff, 0xfe, 0x04, 0x0b, 0x5f, 0xcf, 0xb8, 0x37,
-    0xf2, 0x2f, 0x5d, 0x8f, 0xa2, 0x75, 0xfd, 0xfb, 0x05, 0x39, 0xcc, 0x3a,
-    0xfb, 0xca, 0x67, 0x4e, 0xbf, 0xf0, 0xe7, 0xbd, 0xfc, 0xfe, 0xc6, 0x9d,
-    0x6d, 0x1d, 0x72, 0x00, 0xeb, 0xba, 0x87, 0x5d, 0xfe, 0xbe, 0x1a, 0xa9,
-    0x85, 0x69, 0xcf, 0xac, 0x07, 0x57, 0x02, 0x0e, 0xb8, 0x10, 0x75, 0xfb,
-    0xf9, 0x60, 0xaa, 0x86, 0xa8, 0x02, 0xb5, 0x09, 0xaa, 0xa8, 0x44, 0x08,
-    0x55, 0x0a, 0x5d, 0xff, 0xf6, 0x0b, 0xef, 0xa5, 0x14, 0x7f, 0x8d, 0x58,
-    0x0e, 0xbf, 0xfb, 0xdd, 0xc5, 0xfd, 0x80, 0x66, 0xfe, 0x3a, 0xff, 0x6e,
-    0xd4, 0xe7, 0xd8, 0x09, 0xd7, 0xc0, 0x5b, 0xcb, 0xe2, 0x33, 0xb4, 0xa7,
-    0xe4, 0x6b, 0xf8, 0x0b, 0xfb, 0xaf, 0xb3, 0x9d, 0x7f, 0x69, 0x04, 0x63,
-    0x73, 0xae, 0xcd, 0xce, 0xad, 0xcf, 0xd3, 0xc6, 0x7b, 0x65, 0x77, 0xc0,
-    0xe2, 0x70, 0xea, 0x84, 0xc4, 0x5e, 0x17, 0xac, 0x99, 0xdf, 0x6b, 0xfd,
-    0xfc, 0x75, 0xd8, 0xc9, 0xd7, 0xfd, 0x1b, 0xe0, 0x23, 0x66, 0x4e, 0x75,
-    0xfc, 0x39, 0xed, 0x38, 0x0e, 0xae, 0x1f, 0xd8, 0x05, 0xb4, 0x75, 0x7f,
-    0xe9, 0xa2, 0x7d, 0x73, 0x1b, 0x13, 0x9d, 0x7f, 0x62, 0xf0, 0x28, 0xc9,
-    0xd7, 0x2e, 0x0e, 0xa5, 0x9e, 0x0b, 0x96, 0x5f, 0xc3, 0x93, 0x75, 0x3c,
-    0x75, 0xf6, 0x67, 0x74, 0x75, 0x62, 0x3b, 0x9e, 0x10, 0x3e, 0x21, 0xda,
-    0x2c, 0xbc, 0xcb, 0x2c, 0x95, 0x7e, 0xc5, 0x07, 0xfd, 0x14, 0xa9, 0x7f,
-    0x7c, 0xab, 0x2c, 0xb2, 0x75, 0xd8, 0x03, 0xab, 0x0d, 0xdf, 0x89, 0xaa,
-    0x11, 0x27, 0xe7, 0x3b, 0xe4, 0xe0, 0x34, 0x75, 0xff, 0x6b, 0x91, 0xff,
-    0x85, 0x36, 0x1d, 0x7f, 0xe1, 0xcd, 0x37, 0xa8, 0xd8, 0x13, 0xaf, 0xff,
-    0xf2, 0x8c, 0xbf, 0x14, 0x57, 0x59, 0x21, 0xfd, 0xf5, 0x82, 0x75, 0x42,
-    0x36, 0x30, 0xe9, 0x0e, 0xef, 0x99, 0x71, 0x91, 0xd7, 0xfd, 0xe8, 0xdc,
-    0x0f, 0xde, 0xa1, 0xd6, 0xe9, 0xd5, 0x87, 0x90, 0xd3, 0x8b, 0xcc, 0xb2,
-    0xc9, 0x57, 0xf2, 0x3a, 0x9d, 0x4f, 0x14, 0xa9, 0x7f, 0x7b, 0xc8, 0xc9,
-    0xd7, 0xb4, 0xfc, 0x3a, 0xb7, 0x36, 0xfe, 0x1c, 0xbd, 0xd8, 0x09, 0xd4,
-    0x86, 0xf5, 0xc8, 0xaf, 0xd8, 0x0c, 0xc9, 0x8e, 0xb6, 0xbe, 0x26, 0x6b,
-    0xc4, 0x0e, 0xc2, 0xc0, 0x47, 0xee, 0xfe, 0x41, 0x4f, 0xa3, 0x23, 0x9e,
-    0xbf, 0x30, 0x7b, 0x13, 0xfe, 0x75, 0x4c, 0xad, 0xc7, 0xb0, 0xf9, 0x19,
-    0x42, 0xbf, 0x9b, 0x5e, 0x8d, 0x90, 0x75, 0x21, 0xf4, 0x0a, 0x65, 0xe1,
-    0x8d, 0x87, 0x5c, 0xc1, 0x43, 0xae, 0x4e, 0x9d, 0x67, 0x9c, 0xd7, 0x70,
-    0x66, 0xfb, 0xda, 0xfd, 0x8c, 0xeb, 0xfd, 0x03, 0x21, 0x48, 0xdc, 0xea,
-    0x86, 0x7d, 0x8c, 0x98, 0x72, 0x3f, 0x55, 0x23, 0x0b, 0x69, 0xae, 0xe7,
-    0x28, 0xe7, 0xc8, 0xe1, 0xbb, 0x28, 0x85, 0xcd, 0x41, 0x09, 0xf1, 0x8c,
-    0x77, 0x50, 0xf5, 0xf4, 0xbf, 0xbd, 0x84, 0x1b, 0x69, 0x5f, 0x49, 0xf6,
-    0x89, 0xaf, 0xc9, 0x34, 0x90, 0x4e, 0xb9, 0x89, 0x43, 0xaf, 0xfa, 0x6f,
-    0x6d, 0x6a, 0x26, 0xff, 0x87, 0x5f, 0xe0, 0xc0, 0xae, 0x03, 0x07, 0x54,
-    0x1f, 0x7b, 0x9f, 0xdf, 0xfd, 0x89, 0xd8, 0x0f, 0x7f, 0x8d, 0xf4, 0x75,
-    0xe0, 0xa8, 0x03, 0xaf, 0xcb, 0xe7, 0x1f, 0xc7, 0x57, 0xc3, 0xc4, 0x81,
-    0xdb, 0xff, 0xcd, 0x99, 0xdb, 0xd8, 0x97, 0x87, 0x16, 0x75, 0xff, 0xf2,
-    0x2f, 0x79, 0x6b, 0xe6, 0x08, 0xe2, 0x00, 0xeb, 0xc9, 0xdf, 0xce, 0xaf,
-    0x8a, 0x8b, 0x98, 0x82, 0x69, 0x42, 0x27, 0x84, 0x1d, 0x84, 0x43, 0x91,
-    0xf9, 0x27, 0x62, 0x7d, 0x95, 0x62, 0x63, 0x8a, 0x1f, 0x60, 0x43, 0x3d,
-    0x8b, 0x8d, 0x55, 0x84, 0xda, 0xc3, 0xe3, 0x1a, 0x62, 0x91, 0x8a, 0x31,
-    0x53, 0xa6, 0x19, 0x5a, 0x29, 0xb8, 0xd3, 0xce, 0x8b, 0x4a, 0x93, 0xf2,
-    0x1a, 0x56, 0x76, 0x5b, 0x9e, 0x15, 0x25, 0xae, 0xb6, 0x97, 0x2b, 0xbd,
-    0x21, 0xd9, 0x29, 0x3d, 0xac, 0x71, 0xb1, 0x4d, 0x4d, 0x72, 0xe5, 0x38,
-    0x69, 0x74, 0x8f, 0xde, 0xd6, 0xf7, 0xaf, 0x5d, 0x3e, 0x02, 0x94, 0xd8,
-    0xc1, 0x87, 0x88, 0xd6, 0xd0, 0x1a, 0xb7, 0x41, 0x1e, 0xb4, 0xb7, 0x5f,
-    0xce, 0x92, 0xec, 0x95, 0x5e, 0xcc, 0xb0, 0x4d, 0xb9, 0xfc, 0xff, 0xb5,
-    0x8d, 0x66, 0xd4, 0xb5, 0xca, 0x56, 0x38, 0xd7, 0x69, 0x67, 0x14, 0xdf,
-    0x7e, 0x54, 0x0b, 0xcf, 0x1d, 0x7f, 0x95, 0xce, 0x35, 0xdd, 0xa6, 0x8b,
-    0x8e, 0xff, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x17, 0x5d, 0xff, 0xca, 0xbc,
-    0x95, 0xce, 0x35, 0xdd, 0xa6, 0x89, 0x46, 0xa2, 0x39, 0x2a, 0xe9, 0x42,
-    0xf0, 0x25, 0x2a, 0x42, 0x3d, 0xa5, 0x09, 0x1d, 0x13, 0x1b, 0x8b, 0xe7,
-    0x1b, 0x9a, 0x03, 0xbd, 0x14, 0x78, 0xff, 0x68, 0xfe, 0xff, 0xf2, 0xab,
-    0x79, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x12, 0xd5, 0xff, 0x30, 0xee, 0xa3,
-    0x1b, 0xc6, 0xfb, 0x47, 0x5f, 0xb8, 0xd7, 0x76, 0x9a, 0x23, 0x7b, 0xff,
-    0x3c, 0x95, 0xce, 0x35, 0xdd, 0xa6, 0x89, 0x7e, 0xfe, 0x8f, 0x7d, 0xeb,
-    0xf8, 0xeb, 0xfd, 0x9f, 0x78, 0xa7, 0x7f, 0xd1, 0xd7, 0xa6, 0xd7, 0x0e,
-    0xb2, 0xac, 0x55, 0x34, 0x3c, 0x44, 0x59, 0x9f, 0x52, 0x84, 0xbb, 0xe9,
-    0xbd, 0xfe, 0x57, 0x38, 0xd7, 0x76, 0x9a, 0x2a, 0xbb, 0x93, 0x68, 0xeb,
-    0xe4, 0x5b, 0xec, 0x3a, 0x94, 0x37, 0x5e, 0x18, 0xbc, 0x3b, 0x4c, 0x9d,
-    0x7f, 0x3f, 0x66, 0x18, 0x09, 0xd7, 0xff, 0x7b, 0xb1, 0xa1, 0x7f, 0xd8,
-    0x29, 0xc3, 0xaf, 0x44, 0xb0, 0xea, 0x0a, 0x23, 0x77, 0x2c, 0x99, 0x1e,
-    0xff, 0x94, 0xc1, 0xcd, 0xfc, 0xeb, 0x3a, 0xe0, 0xa1, 0xd7, 0xf6, 0x71,
-    0xae, 0xed, 0x34, 0x48, 0x15, 0xf0, 0xf3, 0x55, 0x15, 0xbf, 0x69, 0xc5,
-    0xf7, 0x3a, 0xef, 0xe0, 0xea, 0x91, 0xf0, 0xee, 0x4b, 0xc2, 0x6b, 0xfd,
-    0x28, 0xe4, 0xf1, 0xc9, 0xce, 0xbf, 0xdc, 0x9d, 0x70, 0x32, 0xd1, 0xd5,
-    0x07, 0xcf, 0x86, 0x97, 0xd9, 0x3b, 0x84, 0xeb, 0xff, 0xd9, 0x37, 0x5d,
-    0x7e, 0xec, 0x7b, 0xf5, 0x9d, 0x53, 0xab, 0x09, 0x09, 0x16, 0x42, 0xb1,
-    0x43, 0x27, 0x87, 0x30, 0xc2, 0x5f, 0xc4, 0x1f, 0x48, 0x6f, 0xfe, 0x1c,
-    0x9d, 0x5d, 0xb8, 0x11, 0xcf, 0x1d, 0x4a, 0xa3, 0x23, 0x90, 0x83, 0xbf,
-    0xca, 0xe7, 0x1a, 0xee, 0xd3, 0x45, 0x91, 0x7f, 0x95, 0xce, 0x35, 0xdd,
-    0xa6, 0x8b, 0x5e, 0xff, 0xf6, 0x7d, 0x89, 0xd5, 0xc9, 0xbc, 0x18, 0x13,
-    0xaf, 0xf2, 0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x72, 0x5f, 0xb8, 0xd7, 0x76,
-    0x9a, 0x2e, 0xcb, 0xff, 0x3c, 0x95, 0xce, 0x35, 0xdd, 0xa6, 0x8a, 0x3a,
-    0xca, 0xe1, 0xfe, 0xac, 0xce, 0xf8, 0x62, 0x4b, 0x3a, 0xd2, 0x3a, 0xfd,
-    0xc6, 0xbb, 0xb4, 0xd1, 0x4a, 0xdf, 0xf3, 0x7a, 0x93, 0x76, 0x27, 0xc3,
-    0xaf, 0xff, 0x76, 0x27, 0x8e, 0xa6, 0xc7, 0x0f, 0x50, 0xe5, 0x4d, 0xcd,
-    0xd2, 0x57, 0x11, 0x8f, 0x33, 0x65, 0x6e, 0x98, 0x3b, 0xc3, 0x5e, 0xff,
-    0xce, 0x9e, 0x97, 0xe1, 0x71, 0x01, 0xd6, 0x54, 0x29, 0xc6, 0xae, 0x32,
-    0x7e, 0x94, 0xd4, 0xec, 0x9e, 0xb9, 0x47, 0x35, 0xbb, 0x2a, 0x4e, 0x25,
-    0x2c, 0xa4, 0x07, 0xe2, 0x7f, 0xa4, 0xcf, 0x42, 0xf3, 0x64, 0x76, 0xb7,
-    0xfd, 0x25, 0x73, 0x8d, 0x77, 0x69, 0xa2, 0x38, 0xbf, 0xe4, 0x57, 0x38,
-    0xd7, 0x76, 0x9a, 0x2b, 0x5b, 0x2a, 0xe8, 0x89, 0xf2, 0x2d, 0xff, 0xe5,
-    0x56, 0xf2, 0x57, 0x38, 0xd7, 0x76, 0x9a, 0x25, 0xbb, 0xdf, 0xf0, 0x07,
-    0x5d, 0x9b, 0x9d, 0x7f, 0x83, 0x8b, 0x5c, 0x26, 0x8e, 0xbd, 0xb3, 0xf9,
-    0x1d, 0x4d, 0x44, 0x1e, 0xe3, 0xa8, 0x2d, 0xb0, 0xc6, 0xf7, 0x43, 0x23,
-    0xaf, 0xfb, 0x37, 0x1c, 0x00, 0x1e, 0x47, 0x5c, 0xb6, 0x9d, 0x50, 0x79,
-    0xb2, 0x37, 0xbe, 0x18, 0xde, 0x47, 0x5f, 0xff, 0x9f, 0x70, 0x07, 0xaf,
-    0x2c, 0xd0, 0xfe, 0xff, 0x4e, 0xa6, 0x9f, 0xc7, 0x48, 0x6c, 0xa1, 0xd7,
-    0xf2, 0x70, 0x53, 0xda, 0x3a, 0xfd, 0xc7, 0x1c, 0x83, 0xa8, 0xd1, 0x0d,
-    0xa1, 0xf0, 0x74, 0x45, 0xca, 0xee, 0x81, 0x3a, 0xfe, 0x41, 0x0e, 0x20,
-    0x4e, 0xa8, 0x37, 0xd2, 0x14, 0xbe, 0xc9, 0xa5, 0x87, 0x5f, 0xf9, 0xe4,
-    0xae, 0x71, 0xae, 0xed, 0x34, 0x4c, 0x17, 0xe0, 0x69, 0xc4, 0x07, 0x5f,
-    0xef, 0xf7, 0xe2, 0x42, 0xf0, 0xeb, 0xfe, 0x89, 0xfc, 0x31, 0xff, 0xb4,
-    0x75, 0xbd, 0xd3, 0xec, 0xdb, 0x33, 0xbe, 0xdd, 0xa8, 0xa1, 0xd5, 0x87,
-    0x9d, 0xe2, 0xbb, 0xfd, 0xa4, 0xea, 0x2f, 0x14, 0x3a, 0xff, 0xf3, 0xcf,
-    0xd4, 0x81, 0xc9, 0x93, 0x88, 0x75, 0x78, 0xfe, 0x59, 0x32, 0xb9, 0xb8,
-    0x75, 0xdf, 0x80, 0xaa, 0x43, 0x59, 0xc1, 0x5b, 0xfd, 0x81, 0x1c, 0xf7,
-    0x70, 0xeb, 0x98, 0x4d, 0x3c, 0x61, 0x57, 0xf4, 0xff, 0x76, 0xdc, 0x40,
-    0x75, 0xfd, 0x9e, 0xf4, 0x73, 0x47, 0x5f, 0xce, 0x20, 0x9c, 0x1e, 0x3a,
-    0xa1, 0x11, 0x62, 0x65, 0xb6, 0x59, 0x65, 0x61, 0x77, 0x22, 0x73, 0xf0,
-    0xb4, 0xe4, 0x26, 0x5b, 0x08, 0x2d, 0xdf, 0xb8, 0x40, 0xb2, 0x17, 0x4a,
-    0x18, 0x70, 0x6a, 0x13, 0x5e, 0x4f, 0xd8, 0x40, 0xc9, 0x87, 0xd8, 0x59,
-    0x5e, 0x5f, 0xfc, 0x2a, 0xff, 0xcf, 0x25, 0x73, 0x8d, 0x77, 0x69, 0xa2,
-    0x63, 0xbe, 0x8e, 0x46, 0xd1, 0xd6, 0x55, 0x11, 0x14, 0xb1, 0xde, 0xa5,
-    0x5f, 0x44, 0xf1, 0xc3, 0xaf, 0xd9, 0x13, 0x22, 0xce, 0xa4, 0x3c, 0x7e,
-    0x10, 0xdf, 0xc1, 0x5c, 0x67, 0xb4, 0x75, 0xfe, 0xec, 0x72, 0x7f, 0xbf,
-    0x80, 0xeb, 0x9f, 0x47, 0x5f, 0x7c, 0xf6, 0x74, 0xeb, 0x47, 0x4d, 0xc6,
-    0x85, 0x6f, 0x40, 0xce, 0x75, 0xff, 0xff, 0xf4, 0xb5, 0xdc, 0xfd, 0x9d,
-    0x77, 0x1b, 0x9a, 0xf9, 0x9b, 0xcb, 0x48, 0x28, 0x75, 0xe7, 0x76, 0x9a,
-    0x2b, 0x1b, 0xe7, 0xfb, 0x0a, 0x1d, 0x4d, 0x3c, 0xae, 0x13, 0xdf, 0xfb,
-    0x6f, 0x3c, 0x39, 0xfc, 0x0f, 0x8e, 0xa5, 0x13, 0x6c, 0x69, 0x36, 0xe3,
-    0x7c, 0x86, 0x57, 0x88, 0xaf, 0xfe, 0x1f, 0x29, 0xfc, 0x0e, 0x36, 0x38,
-    0x75, 0xfe, 0xe4, 0xfe, 0xd3, 0xee, 0xd3, 0xaa, 0x0f, 0xe1, 0xd0, 0xef,
-    0xe8, 0xda, 0xf6, 0x6f, 0x31, 0xd7, 0xf7, 0xfb, 0x6d, 0xea, 0x30, 0x4e,
-    0xbf, 0xb3, 0x5b, 0xca, 0x3a, 0x75, 0xd1, 0xb0, 0xeb, 0x07, 0xa7, 0x88,
-    0x25, 0xb7, 0xfd, 0x1b, 0xca, 0x69, 0x3f, 0x27, 0x3a, 0xa1, 0x1b, 0x78,
-    0xf2, 0x84, 0xf7, 0xa2, 0x5e, 0x3a, 0xff, 0xd8, 0x1e, 0x27, 0xf3, 0x83,
-    0x52, 0x3a, 0xf9, 0x6f, 0xbf, 0x8e, 0xbf, 0xfa, 0x78, 0xf7, 0xcf, 0xad,
-    0xfb, 0xb5, 0xf7, 0x47, 0x5f, 0xf7, 0x23, 0x4f, 0xc1, 0x89, 0x1d, 0x5c,
-    0x44, 0x3e, 0xc5, 0x1b, 0xd2, 0x79, 0xce, 0xbd, 0xf2, 0x75, 0x9d, 0x70,
-    0x7c, 0x75, 0x30, 0x93, 0x1f, 0xc8, 0x54, 0xee, 0x4a, 0x83, 0x82, 0x3f,
-    0x7f, 0xe1, 0x70, 0xf6, 0x36, 0x75, 0xc4, 0xeb, 0xff, 0xff, 0x7f, 0x3e,
-    0x37, 0xe0, 0xff, 0xb5, 0xf3, 0x37, 0x96, 0x7e, 0x20, 0xd1, 0xd7, 0xff,
-    0xa7, 0xcd, 0xfd, 0xa4, 0x18, 0x03, 0xac, 0xeb, 0xfd, 0xb8, 0xe0, 0x7a,
-    0xec, 0x9d, 0x58, 0x7f, 0x8e, 0x93, 0x41, 0x4d, 0x40, 0x4f, 0x75, 0x0f,
-    0x3b, 0xfa, 0x79, 0xa4, 0xc2, 0xe4, 0xe7, 0x5f, 0x08, 0xe7, 0x8e, 0xbf,
-    0x23, 0x1f, 0x38, 0x87, 0x53, 0x10, 0x7f, 0xb0, 0x6b, 0xd1, 0xfb, 0xfa,
-    0x7f, 0xbb, 0x6e, 0x20, 0x3a, 0xf9, 0x8e, 0x34, 0x27, 0x5f, 0xfb, 0xae,
-    0xbf, 0x76, 0x3d, 0xfa, 0xce, 0xac, 0x3e, 0x29, 0x88, 0xef, 0xf9, 0x24,
-    0x9d, 0xfd, 0x6b, 0x43, 0xaa, 0x11, 0xdd, 0x90, 0x94, 0xf1, 0x15, 0xee,
-    0xa2, 0xb0, 0xc9, 0x6d, 0x9c, 0x86, 0x45, 0x99, 0x1e, 0xdb, 0x61, 0x95,
-    0xc2, 0x0e, 0xc6, 0x18, 0xe5, 0xa2, 0x37, 0xa8, 0xd7, 0xfd, 0x1d, 0x16,
-    0xdc, 0x2c, 0xbe, 0xc6, 0x43, 0x74, 0x84, 0xeb, 0xfb, 0x9c, 0x80, 0xe2,
-    0xce, 0xbe, 0x9f, 0x91, 0x39, 0xd7, 0x7d, 0x01, 0xd7, 0xba, 0x8b, 0x3a,
-    0xd3, 0x1d, 0x4e, 0x6b, 0x3f, 0x1b, 0xbf, 0x38, 0xcf, 0xfe, 0x8e, 0xbf,
-    0xe8, 0x0f, 0x70, 0x3c, 0x76, 0x9d, 0x48, 0x98, 0x9b, 0x96, 0x00, 0x8c,
-    0x51, 0x34, 0x43, 0xe2, 0x8b, 0x74, 0xeb, 0xda, 0xfb, 0xa3, 0xaf, 0xb7,
-    0x9e, 0x14, 0x3a, 0xa7, 0x3d, 0x20, 0x88, 0x7e, 0x3d, 0x77, 0xa0, 0xeb,
-    0xfd, 0xbf, 0x21, 0x24, 0xfa, 0x3a, 0xfb, 0x06, 0x24, 0x75, 0x61, 0xe8,
-    0xac, 0xca, 0xff, 0x60, 0x35, 0x9e, 0x4e, 0x1d, 0x7d, 0xff, 0xb3, 0x47,
-    0x5f, 0x47, 0x1c, 0x4e, 0xbf, 0xcf, 0xc9, 0x01, 0x37, 0xd1, 0xd7, 0xda,
-    0xd4, 0x00, 0xea, 0x84, 0x73, 0xe1, 0x0a, 0x18, 0xf4, 0x8b, 0xf1, 0xf6,
-    0x4c, 0xef, 0xa4, 0x0f, 0xe4, 0x75, 0xf7, 0x3e, 0xc0, 0x0e, 0xa8, 0x3c,
-    0x64, 0x23, 0xbf, 0xc9, 0x3b, 0xac, 0x00, 0x83, 0xaf, 0xf9, 0x1b, 0xdc,
-    0x98, 0x60, 0x27, 0x5f, 0x4b, 0xd9, 0xf4, 0xeb, 0xcd, 0x80, 0x1d, 0x7b,
-    0x90, 0xb3, 0xa9, 0xcf, 0x67, 0xf2, 0x36, 0x46, 0xef, 0xd1, 0x3f, 0xdc,
-    0x98, 0xeb, 0xd0, 0x32, 0x3a, 0xa6, 0x4d, 0x5b, 0x84, 0x1d, 0x32, 0x18,
-    0x48, 0x68, 0xc3, 0xc5, 0x57, 0xfe, 0x8c, 0xd7, 0xc8, 0x40, 0xfd, 0x91,
-    0xd7, 0xf2, 0x33, 0xa9, 0xf1, 0x93, 0xa8, 0x4f, 0xbf, 0xc8, 0x17, 0xe8,
-    0x0f, 0xb1, 0xa7, 0x5f, 0x76, 0x05, 0xa7, 0x54, 0x8f, 0x9f, 0x44, 0x3e,
-    0x26, 0xbe, 0x71, 0x79, 0x8e, 0xbf, 0x27, 0x87, 0x24, 0x75, 0xf4, 0x33,
-    0x13, 0x1d, 0x77, 0xd5, 0x9d, 0x7f, 0x78, 0x5c, 0x18, 0x27, 0x5f, 0x85,
-    0xc1, 0x82, 0x75, 0xbf, 0xf8, 0x79, 0xde, 0x2a, 0xa9, 0xd1, 0xf0, 0xa1,
-    0x02, 0x12, 0xf4, 0x88, 0x59, 0xaf, 0xf4, 0x32, 0x1f, 0xdf, 0x92, 0x3a,
-    0xfe, 0x4e, 0x6f, 0xa8, 0x91, 0xd6, 0xd8, 0x75, 0x70, 0xfc, 0xfa, 0x69,
-    0xb4, 0x5b, 0x78, 0x51, 0x43, 0xaf, 0xb0, 0x29, 0xb0, 0xeb, 0xa1, 0x78,
-    0x6f, 0x5c, 0x6e, 0xff, 0xb1, 0x97, 0xdf, 0xb1, 0xf4, 0x4e, 0xb6, 0x8e,
-    0xa4, 0x3f, 0x4e, 0x15, 0x39, 0xd5, 0xc0, 0x82, 0xae, 0x65, 0x92, 0xa9,
-    0x0d, 0x6b, 0x22, 0xb7, 0xf9, 0xe4, 0x39, 0xee, 0xa1, 0x4a, 0x9a, 0x1b,
-    0xcf, 0xbe, 0x8e, 0xbe, 0xfb, 0xd7, 0xf1, 0xd4, 0x13, 0x7f, 0xe1, 0xcb,
-    0xd0, 0x33, 0x1d, 0x70, 0xc1, 0xd6, 0x98, 0xea, 0x98, 0xf0, 0x38, 0x36,
-    0xe2, 0x97, 0xff, 0x28, 0x82, 0xdd, 0x42, 0xdf, 0x7f, 0x1d, 0x78, 0x19,
-    0xb4, 0x75, 0x28, 0x7c, 0x5c, 0x44, 0xbe, 0x5e, 0xbf, 0x59, 0xd6, 0x50,
-    0xeb, 0x6d, 0x9d, 0x77, 0x14, 0x3a, 0xa0, 0xf7, 0x90, 0x8f, 0xf1, 0x1f,
-    0xa2, 0x77, 0xff, 0xdd, 0xc9, 0x6a, 0x3d, 0x2c, 0x63, 0x71, 0x01, 0xd7,
-    0xfe, 0x92, 0x7b, 0xb9, 0xbf, 0xbf, 0x83, 0xae, 0xcd, 0x1d, 0x50, 0x7a,
-    0x92, 0x3f, 0xad, 0x23, 0x17, 0xd0, 0xa4, 0xbf, 0x24, 0x2e, 0x16, 0x75,
-    0xb0, 0xea, 0x43, 0xdc, 0xd1, 0x46, 0xd9, 0x2d, 0x42, 0xb0, 0x2c, 0x61,
-    0x48, 0x48, 0xf6, 0x10, 0x2f, 0x1a, 0xf5, 0xed, 0x44, 0xc7, 0x51, 0xd6,
-    0x59, 0xd5, 0xe2, 0xeb, 0x60, 0x55, 0xf8, 0x09, 0xc4, 0x50, 0xeb, 0x9d,
-    0x43, 0xaa, 0x64, 0x4a, 0xf4, 0xd8, 0x04, 0x42, 0x4f, 0x77, 0xa0, 0xeb,
-    0xf4, 0x77, 0x36, 0x39, 0xd4, 0xe6, 0xf0, 0x02, 0xb7, 0xf2, 0x7b, 0x3a,
-    0xea, 0x1d, 0x7f, 0x77, 0xf7, 0x9f, 0xa8, 0x75, 0xe6, 0x59, 0x64, 0xab,
-    0xfe, 0x0c, 0x4f, 0xf7, 0x3a, 0xfb, 0x94, 0xa9, 0x7f, 0x76, 0x4e, 0x75,
-    0x05, 0x15, 0xcd, 0x4d, 0x44, 0xbb, 0xd0, 0xb4, 0x3a, 0xb0, 0xf2, 0x5a,
-    0x5f, 0x7c, 0x9c, 0xda, 0x09, 0xd7, 0xee, 0xc6, 0xee, 0xc6, 0x75, 0xff,
-    0xf4, 0x7b, 0x41, 0xcf, 0x27, 0x7f, 0xcd, 0xfc, 0x75, 0x74, 0xfe, 0xbc,
-    0x55, 0x6e, 0x1d, 0x7f, 0xb3, 0x1b, 0xf7, 0x67, 0x70, 0xeb, 0xbf, 0xd1,
-    0xd7, 0xff, 0xec, 0x0c, 0x66, 0xff, 0x7c, 0x83, 0xfc, 0xb3, 0x47, 0x5c,
-    0xb0, 0x1d, 0x73, 0x89, 0xd5, 0xd3, 0x54, 0xe2, 0xd7, 0xe5, 0xa7, 0x80,
-    0xe7, 0x54, 0xe9, 0xf1, 0x64, 0x27, 0x98, 0xc8, 0xa6, 0x10, 0x73, 0x51,
-    0x17, 0xf4, 0x20, 0x3f, 0x20, 0xbe, 0xef, 0x92, 0x73, 0xaf, 0xf3, 0x53,
-    0x43, 0x9b, 0x1c, 0xeb, 0xe8, 0x9d, 0xe4, 0x75, 0xd9, 0xe3, 0xaf, 0xd9,
-    0x38, 0xe6, 0xe7, 0x56, 0x22, 0xc7, 0x72, 0x2e, 0x19, 0x74, 0x84, 0x45,
-    0x6f, 0xa0, 0x51, 0x8c, 0xeb, 0xdd, 0x80, 0x9d, 0x77, 0x34, 0x75, 0x1c,
-    0x85, 0xb5, 0xfe, 0x81, 0x93, 0xaf, 0x02, 0x75, 0xf7, 0x96, 0xbe, 0x1d,
-    0x7f, 0xf0, 0x20, 0x5a, 0xfe, 0x07, 0xd1, 0x91, 0xd7, 0xa4, 0x9d, 0x3a,
-    0xfb, 0xc3, 0x92, 0x3a, 0xfd, 0x9f, 0xb0, 0x74, 0xe7, 0x5f, 0xfe, 0x4d,
-    0x77, 0x02, 0x39, 0xb0, 0x73, 0x47, 0x54, 0x93, 0x44, 0x50, 0xc3, 0x72,
-    0x29, 0x91, 0x38, 0x36, 0x24, 0x1e, 0x2b, 0xa6, 0x13, 0x6a, 0xe3, 0x11,
-    0x94, 0x4f, 0x0a, 0x79, 0x18, 0x86, 0x34, 0xdc, 0x8f, 0xcb, 0x78, 0xcc,
-    0xd2, 0x32, 0x79, 0xa1, 0x7b, 0xc8, 0x71, 0xad, 0xef, 0xb2, 0xe0, 0x9e,
-    0x1d, 0xa0, 0x79, 0x60, 0x90, 0x0c, 0x64, 0x7a, 0x94, 0x07, 0xe8, 0xcc,
-    0x36, 0x24, 0xb2, 0x45, 0xb6, 0x63, 0xf6, 0x35, 0xcb, 0xfe, 0x57, 0xc9,
-    0x9b, 0x5a, 0xfe, 0x0e, 0xbf, 0xff, 0xef, 0xe1, 0x5f, 0x69, 0x3a, 0xe9,
-    0xec, 0xe0, 0x16, 0xf2, 0x3a, 0x95, 0x54, 0x5d, 0x3c, 0x71, 0x81, 0x3c,
-    0xbf, 0x71, 0xae, 0xed, 0x34, 0x56, 0xf7, 0xfe, 0x79, 0x2b, 0x9c, 0x6b,
-    0xbb, 0x4d, 0x13, 0x85, 0x95, 0xc3, 0xfd, 0x59, 0x9d, 0xcc, 0x20, 0x9d,
-    0x6e, 0x9d, 0x6d, 0x1d, 0x5f, 0x9a, 0x0d, 0xb1, 0x0b, 0xe6, 0xbb, 0xb4,
-    0xd1, 0x68, 0xdf, 0xfe, 0xc0, 0xf5, 0xd4, 0x9a, 0x64, 0xd7, 0xeb, 0x3a,
-    0xb8, 0x7f, 0x5d, 0x2d, 0xbe, 0x6b, 0x88, 0x0e, 0xbf, 0xe9, 0xb1, 0x8f,
-    0x5c, 0xe3, 0xf8, 0xeb, 0xfa, 0x1c, 0x7f, 0x0e, 0x1d, 0x72, 0x28, 0x75,
-    0xff, 0xfa, 0x78, 0xf4, 0x07, 0x91, 0xd7, 0xd0, 0xe0, 0x0e, 0xbf, 0xf4,
-    0x6e, 0xec, 0x7d, 0x17, 0x63, 0x9c, 0xeb, 0xff, 0x47, 0x01, 0x89, 0x9c,
-    0xf7, 0xe7, 0x54, 0x23, 0x53, 0xaa, 0x7a, 0x44, 0xb6, 0x4c, 0x98, 0xce,
-    0xa1, 0xd5, 0x7f, 0xbb, 0xdf, 0xd4, 0x5c, 0x68, 0xeb, 0xff, 0xf2, 0x68,
-    0x73, 0x63, 0xf8, 0x73, 0x5d, 0x79, 0x8e, 0xac, 0x44, 0x4c, 0xc6, 0xb7,
-    0xd8, 0x07, 0xe9, 0xd7, 0x77, 0x47, 0x59, 0x56, 0x02, 0xba, 0xc6, 0x2c,
-    0xeb, 0x21, 0x3e, 0xd2, 0x29, 0x88, 0x16, 0x79, 0xd8, 0xd1, 0x3d, 0x0b,
-    0x8d, 0xb2, 0x3f, 0xa4, 0x17, 0xcd, 0x77, 0x69, 0xa2, 0xda, 0xbf, 0xff,
-    0xa1, 0xfd, 0x1d, 0x8d, 0x22, 0x49, 0x39, 0x81, 0x3a, 0xfe, 0xec, 0x2e,
-    0x10, 0x27, 0x57, 0x11, 0x5d, 0xa2, 0xdf, 0x2b, 0x5f, 0xfb, 0xa8, 0x17,
-    0x90, 0x7a, 0x8b, 0x3a, 0xff, 0xb3, 0x1b, 0xb7, 0xff, 0x53, 0x87, 0x5f,
-    0x46, 0xcc, 0x43, 0xaf, 0xfa, 0x25, 0x1c, 0x9e, 0x39, 0x39, 0xd7, 0xfd,
-    0x1c, 0xf9, 0xa8, 0xeb, 0xa1, 0xd7, 0xfb, 0xa8, 0xf2, 0xf2, 0x4e, 0x75,
-    0x62, 0x6d, 0x8d, 0x30, 0x98, 0xf7, 0x87, 0x62, 0x42, 0xc9, 0xce, 0xd9,
-    0xc5, 0xfc, 0xa3, 0xf0, 0x3f, 0x89, 0xd7, 0xf0, 0xed, 0xa7, 0x31, 0x43,
-    0xaf, 0xc9, 0x3a, 0xe1, 0xa7, 0x5f, 0x9f, 0x79, 0x7d, 0xd1, 0xd7, 0xfe,
-    0x49, 0xb5, 0xb1, 0xc6, 0x7f, 0xc2, 0x75, 0x95, 0x51, 0x1e, 0x02, 0x5d,
-    0xe2, 0xfd, 0x84, 0xff, 0x4a, 0xa9, 0x54, 0xeb, 0x41, 0x1a, 0xc5, 0xcb,
-    0xe9, 0xd7, 0xee, 0x35, 0xdd, 0xa6, 0x8b, 0x96, 0xca, 0x84, 0xf2, 0x70,
-    0x5a, 0xfd, 0xc6, 0xbb, 0xb4, 0xd1, 0x76, 0xdf, 0xf2, 0x4a, 0x48, 0x20,
-    0x89, 0x1d, 0x65, 0x70, 0xfa, 0x5c, 0xce, 0xa1, 0xda, 0x79, 0x4e, 0x53,
-    0x29, 0xea, 0x20, 0xc6, 0xf8, 0xa5, 0x27, 0xa9, 0x2b, 0x89, 0x16, 0x38,
-    0x5b, 0xf6, 0x5e, 0xa0, 0xce, 0x3c, 0xe9, 0xd3, 0xd0, 0x91, 0xbf, 0xca,
-    0xe7, 0x1a, 0xee, 0xd3, 0x45, 0x4f, 0x7e, 0x15, 0x79, 0xad, 0x1d, 0x74,
-    0xeb, 0x3a, 0xfd, 0xba, 0xdd, 0xc4, 0xea, 0x09, 0xbd, 0xfc, 0x5e, 0xde,
-    0x3a, 0xff, 0xa1, 0xe7, 0xf9, 0xbe, 0xa0, 0x27, 0x52, 0x1e, 0x58, 0x88,
-    0x5f, 0x35, 0xdd, 0xa6, 0x8a, 0xe6, 0xff, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d,
-    0x16, 0x75, 0xe7, 0x79, 0x1d, 0x7f, 0x26, 0xb0, 0x5d, 0x93, 0xab, 0x88,
-    0xb1, 0xe9, 0x68, 0x9f, 0xf8, 0x6a, 0xff, 0xf7, 0xa3, 0x5f, 0x3f, 0xd7,
-    0xa2, 0x69, 0x90, 0xeb, 0xf9, 0x17, 0x3f, 0xfc, 0x91, 0xd7, 0xfa, 0x3b,
-    0xf1, 0x6c, 0x5b, 0x03, 0xc7, 0x56, 0x22, 0xef, 0xa9, 0xdb, 0x0b, 0xef,
-    0xdc, 0xcf, 0x22, 0xce, 0xbe, 0x71, 0x80, 0x9d, 0x7e, 0x9a, 0x17, 0x1f,
-    0x4e, 0xba, 0x4b, 0x3a, 0xb0, 0xdf, 0x89, 0x4d, 0xfb, 0x8d, 0x77, 0x69,
-    0xa2, 0x42, 0xbf, 0xf6, 0x2f, 0x1f, 0x93, 0xfc, 0xdd, 0x67, 0x5f, 0xf2,
-    0x6f, 0xaf, 0x0c, 0x2f, 0x47, 0x5d, 0x25, 0x71, 0x15, 0x9d, 0x33, 0x02,
-    0x0d, 0xff, 0xdd, 0x45, 0xe6, 0xbe, 0x6f, 0x2c, 0xf1, 0xd7, 0xd2, 0xef,
-    0xdd, 0x1d, 0x50, 0x7d, 0x58, 0x8d, 0x7c, 0xc5, 0xf6, 0x16, 0x75, 0xfd,
-    0xdd, 0x6b, 0x39, 0x39, 0xd7, 0x43, 0x27, 0x56, 0x1e, 0x22, 0x17, 0x5e,
-    0x5e, 0xc9, 0x1d, 0x7f, 0xfb, 0xb0, 0x05, 0xbc, 0xb5, 0xec, 0xc5, 0x9d,
-    0x65, 0x67, 0x5d, 0x6b, 0x0b, 0x6e, 0x43, 0x45, 0x21, 0xef, 0xc3, 0x15,
-    0x93, 0x75, 0x79, 0xe1, 0x96, 0x30, 0xa6, 0xd1, 0x07, 0x9a, 0xbf, 0x20,
-    0xfa, 0x3d, 0x7f, 0xf2, 0xbd, 0x7d, 0x0e, 0x7b, 0xd0, 0x03, 0xaf, 0xff,
-    0x2a, 0xb7, 0x92, 0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x3e, 0x53, 0x57, 0xde,
-    0x50, 0xfd, 0x8e, 0x77, 0x41, 0x70, 0xd0, 0xea, 0x1d, 0xc9, 0xb9, 0xd7,
-    0xff, 0xd2, 0x9d, 0x86, 0x86, 0x2e, 0x76, 0xf3, 0xe7, 0xce, 0xed, 0x9d,
-    0x52, 0x3f, 0xa0, 0x0b, 0x5f, 0xb3, 0x99, 0x93, 0x1d, 0x65, 0x7a, 0x79,
-    0x1f, 0x48, 0xaf, 0xdc, 0x6b, 0xbb, 0x4d, 0x15, 0x95, 0xff, 0x9e, 0x4a,
-    0xe7, 0x1a, 0xee, 0xd3, 0x44, 0xdd, 0x65, 0x70, 0xff, 0x56, 0x67, 0x4d,
-    0x46, 0x82, 0x42, 0xa2, 0xfd, 0xc6, 0xbb, 0xb4, 0xd1, 0x2b, 0x5f, 0x86,
-    0x02, 0xfd, 0x3a, 0xfc, 0xaa, 0xde, 0x4a, 0xe1, 0xec, 0x21, 0x9d, 0xff,
-    0xbd, 0x8a, 0xe7, 0x12, 0x77, 0x59, 0xd7, 0xff, 0x98, 0x96, 0x21, 0x81,
-    0xac, 0x79, 0x26, 0x73, 0x0e, 0xbf, 0xf2, 0x6b, 0xf5, 0x8a, 0x6c, 0xfd,
-    0xce, 0xbf, 0xa0, 0x5d, 0xae, 0xc6, 0x75, 0x48, 0xfb, 0x56, 0x81, 0x70,
-    0x78, 0x75, 0xfb, 0x8d, 0x77, 0x69, 0xa2, 0x5c, 0xbf, 0xe4, 0x79, 0x78,
-    0x61, 0x7a, 0x3a, 0xfd, 0x2d, 0xb4, 0xeb, 0x9d, 0x7a, 0x36, 0xe0, 0xeb,
-    0xc8, 0x30, 0x75, 0x48, 0xf7, 0xc2, 0x53, 0xb0, 0x76, 0xff, 0xfc, 0xfe,
-    0x4f, 0xe4, 0x29, 0x28, 0xf0, 0xff, 0x23, 0xaf, 0xe9, 0x77, 0x07, 0x1a,
-    0x75, 0xe9, 0x77, 0xc7, 0x5d, 0xd8, 0x43, 0xc7, 0xe9, 0x5d, 0xff, 0xc2,
-    0x80, 0xd7, 0x21, 0x24, 0xfa, 0x3a, 0xb0, 0xfb, 0x50, 0xb2, 0xf3, 0xc9,
-    0x56, 0x28, 0xac, 0x6e, 0x21, 0x85, 0x22, 0x2c, 0x16, 0xe9, 0x9b, 0xc2,
-    0x57, 0x46, 0x3e, 0x8c, 0x22, 0xca, 0xa2, 0xbf, 0x15, 0xcb, 0x59, 0xbf,
-    0xf9, 0x57, 0x92, 0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x1d, 0xdf, 0xf7, 0xbb,
-    0x92, 0x55, 0xc7, 0x47, 0x5f, 0xcc, 0x21, 0x86, 0xe0, 0x9d, 0x77, 0xfd,
-    0x3a, 0xfe, 0x60, 0x0e, 0x75, 0xfc, 0x75, 0xff, 0xfd, 0xe9, 0x20, 0x7a,
-    0x9b, 0x3e, 0x60, 0x78, 0x9f, 0xb4, 0xeb, 0xfd, 0x8c, 0xea, 0x07, 0xda,
-    0x3a, 0xfe, 0x00, 0xe6, 0xfe, 0xc3, 0xaf, 0xce, 0xa7, 0x70, 0x07, 0x5f,
-    0xc2, 0x07, 0xe3, 0xfd, 0x3a, 0xa1, 0x10, 0x1c, 0x2c, 0x72, 0x7b, 0xff,
-    0x27, 0x3e, 0x68, 0x71, 0x70, 0xd3, 0xaf, 0xfd, 0x03, 0xff, 0x91, 0xf6,
-    0x3c, 0x8e, 0xbf, 0xf0, 0xff, 0x2f, 0x98, 0x83, 0x0b, 0x3a, 0xf9, 0xae,
-    0xed, 0x34, 0x54, 0x37, 0xfd, 0x9d, 0xc1, 0x7e, 0x71, 0x0e, 0xa5, 0x13,
-    0x1c, 0x69, 0xf2, 0x1f, 0x70, 0xfb, 0x45, 0xb7, 0x98, 0xde, 0x0e, 0xba,
-    0x58, 0x75, 0xff, 0x4b, 0xc9, 0xc7, 0x6a, 0x09, 0xd7, 0xd2, 0x06, 0xb0,
-    0xeb, 0xff, 0xce, 0xbc, 0xe0, 0xe2, 0x6c, 0x4e, 0x39, 0xd7, 0xff, 0x74,
-    0x72, 0x6f, 0x77, 0x38, 0x9a, 0x3a, 0xfd, 0xb8, 0xa2, 0xd0, 0xea, 0x84,
-    0x58, 0x62, 0x3a, 0x21, 0xdf, 0xe8, 0xf3, 0xf7, 0xe0, 0x60, 0xeb, 0xff,
-    0x67, 0xb5, 0xcc, 0x9b, 0xa8, 0xa1, 0xd7, 0xfd, 0xf1, 0xc7, 0x36, 0xbe,
-    0x77, 0xf3, 0xa9, 0x0f, 0xfb, 0xf3, 0xfb, 0xfd, 0x28, 0xe4, 0xf1, 0xc9,
-    0xce, 0xbf, 0xf6, 0xb0, 0x7d, 0xac, 0x92, 0x74, 0xeb, 0xfb, 0x59, 0xb0,
-    0x63, 0x73, 0xab, 0x47, 0xd5, 0xe3, 0xcb, 0xff, 0xe8, 0x06, 0x0f, 0xc7,
-    0xf7, 0xce, 0xe0, 0x1c, 0xeb, 0x86, 0x73, 0xaa, 0x13, 0x26, 0xc8, 0x4f,
-    0x21, 0x10, 0xa8, 0x5f, 0xdb, 0x1d, 0x7d, 0x65, 0xce, 0xbf, 0xff, 0xc9,
-    0x1e, 0x7e, 0xab, 0xae, 0xe0, 0xfb, 0xe0, 0x25, 0xa3, 0xad, 0x88, 0x89,
-    0x11, 0x2f, 0xbe, 0xef, 0xb2, 0x73, 0xaf, 0xd9, 0x3b, 0x8e, 0xc3, 0xaf,
-    0xff, 0xff, 0xf4, 0x4b, 0xe7, 0xba, 0x91, 0xaf, 0x99, 0xfb, 0x63, 0x67,
-    0xcc, 0xe7, 0x33, 0x67, 0xef, 0xd3, 0xaf, 0xba, 0x2f, 0xb4, 0x75, 0x62,
-    0x60, 0xa2, 0x45, 0xa2, 0x8f, 0x42, 0x62, 0xff, 0xff, 0xbf, 0x76, 0x34,
-    0x9f, 0xae, 0x9e, 0x8e, 0xa7, 0xb5, 0x81, 0x3a, 0xca, 0xb0, 0x19, 0x23,
-    0xac, 0x59, 0x73, 0x08, 0x5e, 0x0b, 0xe7, 0x5f, 0x0c, 0x2c, 0xb2, 0x34,
-    0xa5, 0x12, 0xda, 0x3b, 0xb8, 0xaa, 0x1b, 0x72, 0x1a, 0x2b, 0x2d, 0xec,
-    0x2c, 0x46, 0x34, 0x8d, 0x43, 0x43, 0xd1, 0x95, 0xed, 0xa0, 0xdf, 0x35,
-    0xdd, 0xa6, 0x8a, 0xa2, 0xff, 0x72, 0x36, 0x6f, 0x2c, 0xf1, 0xd5, 0xc3,
-    0xe2, 0xfc, 0xb6, 0xff, 0xcf, 0x25, 0x73, 0x8d, 0x77, 0x69, 0xa2, 0x6b,
-    0xbc, 0xb7, 0xf1, 0xd6, 0x57, 0x11, 0x10, 0xb2, 0x37, 0x4a, 0xbf, 0x71,
-    0xae, 0xed, 0x34, 0x55, 0x97, 0xfd, 0x12, 0x8e, 0x4f, 0x1c, 0x9c, 0xeb,
-    0x2b, 0x87, 0xd8, 0x26, 0x77, 0xfd, 0xd8, 0xdf, 0xd1, 0xd7, 0x63, 0x3a,
-    0xff, 0xe0, 0x60, 0xab, 0x20, 0x6a, 0x77, 0x13, 0xa9, 0x53, 0xff, 0x83,
-    0xbb, 0xff, 0x95, 0x79, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x12, 0x25, 0xfb,
-    0x8d, 0x77, 0x69, 0xa2, 0xd2, 0xbf, 0xf3, 0xc9, 0x5c, 0xe3, 0x5d, 0xda,
-    0x68, 0x9f, 0x6c, 0xae, 0x1f, 0xea, 0xcc, 0xef, 0xff, 0x2a, 0xb7, 0x92,
-    0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x42, 0x5f, 0xfd, 0x8c, 0xab, 0xe5, 0x1f,
-    0x49, 0xe8, 0x3a, 0xfd, 0xef, 0xda, 0xfa, 0x3a, 0xf9, 0x27, 0x8e, 0x1d,
-    0x4b, 0x3c, 0x9e, 0x94, 0x5f, 0xb8, 0xd7, 0x76, 0x9a, 0x28, 0xfb, 0xfe,
-    0x89, 0x47, 0x27, 0x8e, 0x4e, 0x75, 0xff, 0xff, 0xfe, 0xfa, 0x9c, 0x9a,
-    0x3b, 0xcc, 0xeb, 0xfd, 0xd6, 0x28, 0xe2, 0x08, 0x18, 0x9b, 0xb0, 0x75,
-    0xf9, 0xf4, 0x9e, 0x83, 0xaf, 0xfa, 0x26, 0x81, 0x89, 0xbb, 0x07, 0x54,
-    0x23, 0xb1, 0x48, 0x48, 0x09, 0x2d, 0xff, 0xfd, 0x81, 0xec, 0x7d, 0x57,
-    0xc2, 0xe0, 0xd6, 0xa0, 0x05, 0x5e, 0x79, 0x2b, 0x0a, 0x82, 0xb0, 0x88,
-    0x4c, 0xfd, 0x19, 0x2e, 0xd9, 0xa5, 0xff, 0xd9, 0xd5, 0x7c, 0xa3, 0xe9,
-    0x3d, 0x07, 0x59, 0x59, 0xd5, 0xa0, 0x2e, 0x54, 0xc7, 0x99, 0x2a, 0x1b,
-    0x65, 0xc9, 0xe7, 0x0c, 0x24, 0x65, 0x8a, 0x2a, 0x52, 0x55, 0x5b, 0x28,
-    0x77, 0x78, 0x50, 0xa4, 0x29, 0xa6, 0x22, 0xec, 0x33, 0x80, 0x51, 0xe9,
-    0x72, 0xf7, 0xf9, 0x5c, 0xe3, 0x5d, 0xda, 0x68, 0x88, 0xaf, 0xec, 0xe3,
-    0x5d, 0xda, 0x68, 0x8a, 0xef, 0xf9, 0x8d, 0x5c, 0xe3, 0x5d, 0xda, 0x68,
-    0xae, 0x29, 0x54, 0x40, 0x39, 0xc5, 0xff, 0xe0, 0x40, 0xb5, 0x57, 0xf0,
-    0x3e, 0x8c, 0x8e, 0xbe, 0x56, 0x79, 0x98, 0xce, 0xb2, 0x6e, 0x7e, 0x60,
-    0x4b, 0xbe, 0xce, 0xbf, 0x8e, 0xbf, 0xd8, 0x9c, 0x00, 0x3f, 0xd1, 0xd6,
-    0x60, 0x09, 0xe9, 0xe8, 0x82, 0xff, 0xfe, 0xf6, 0x93, 0xae, 0x92, 0x41,
-    0xf7, 0xfd, 0xe6, 0x1d, 0x7e, 0xe3, 0x5d, 0xda, 0x68, 0xa7, 0xaf, 0xf2,
-    0xd0, 0x3f, 0xbf, 0x24, 0x75, 0xcb, 0x43, 0xaa, 0x0f, 0x21, 0xa6, 0x77,
-    0xff, 0xfa, 0x51, 0xed, 0x7e, 0xb6, 0xa0, 0x23, 0x3a, 0x9f, 0xb4, 0xeb,
-    0xff, 0xfb, 0x9c, 0xff, 0x9c, 0x81, 0xc5, 0x13, 0xbd, 0xcf, 0xa7, 0x5f,
-    0xfc, 0x92, 0xc1, 0x04, 0x2d, 0x39, 0x23, 0xaf, 0xf4, 0xa3, 0x93, 0xc7,
-    0x27, 0x3a, 0xfb, 0xe0, 0xbc, 0x8e, 0xbf, 0x3e, 0x75, 0x16, 0x75, 0x68,
-    0xf1, 0xf6, 0x11, 0x54, 0x22, 0x7f, 0x1e, 0xef, 0xfa, 0x05, 0xb9, 0xb3,
-    0x3d, 0xa3, 0xaf, 0xcf, 0x3c, 0x73, 0xf3, 0xa9, 0x84, 0xac, 0xfe, 0x0a,
-    0xf1, 0x65, 0xaf, 0x7b, 0x90, 0xa3, 0x0b, 0xae, 0x8c, 0x38, 0x36, 0x10,
-    0xed, 0x9c, 0x5f, 0xfe, 0x79, 0x2a, 0x11, 0x76, 0x75, 0xa8, 0x01, 0xd7,
-    0xff, 0x80, 0x0f, 0xf4, 0xaf, 0xd1, 0x75, 0x8c, 0x1d, 0x7f, 0xf0, 0xe0,
-    0x1c, 0x40, 0xaa, 0xd1, 0x67, 0x57, 0x11, 0x1d, 0xe4, 0xca, 0x55, 0x39,
-    0x20, 0xc2, 0x5d, 0x21, 0xb1, 0x6c, 0x3a, 0xfc, 0x31, 0xfb, 0x07, 0x47,
-    0x5f, 0xca, 0x71, 0xc2, 0xe2, 0x75, 0x04, 0xf9, 0xb0, 0x3d, 0xca, 0xef,
-    0xfe, 0x40, 0xf1, 0xf7, 0x57, 0x9c, 0x89, 0xce, 0xa5, 0x4f, 0xcf, 0xa5,
-    0xb7, 0x06, 0x0e, 0xbf, 0xff, 0x76, 0x39, 0x92, 0x47, 0xf6, 0x05, 0x3f,
-    0x69, 0x57, 0xe8, 0x90, 0x3f, 0x91, 0xd7, 0xcd, 0x77, 0x69, 0xa2, 0xb3,
-    0xa9, 0x8f, 0x57, 0x85, 0x17, 0xde, 0x45, 0xe8, 0xeb, 0xfa, 0x75, 0xc0,
-    0xcb, 0x47, 0x5f, 0xb3, 0xda, 0xfb, 0xa3, 0xaf, 0x44, 0xe8, 0x75, 0xfb,
-    0xc0, 0xfa, 0x32, 0x3a, 0xf7, 0xef, 0xa3, 0xaf, 0xfb, 0x24, 0x9f, 0xb1,
-    0xb1, 0x60, 0x59, 0xd7, 0xec, 0x9a, 0x7f, 0xc0, 0x75, 0x95, 0x85, 0x44,
-    0x41, 0x15, 0xc8, 0x54, 0x6e, 0x47, 0xc2, 0x15, 0x96, 0xf4, 0xa5, 0xc6,
-    0xc4, 0xa7, 0x43, 0x9f, 0x50, 0x6f, 0xfd, 0xd4, 0xf3, 0xf2, 0x78, 0x40,
-    0x9d, 0x7e, 0xf2, 0x0e, 0x2c, 0xeb, 0xe9, 0x38, 0xab, 0x87, 0xc5, 0xb4,
-    0x7b, 0x7f, 0xe7, 0x92, 0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x22, 0xdf, 0xff,
-    0xbd, 0xdc, 0x15, 0x7c, 0xef, 0xbe, 0x94, 0x51, 0xce, 0xbf, 0xf3, 0xf9,
-    0x58, 0x4e, 0x27, 0xbf, 0x3a, 0x95, 0x46, 0xfc, 0x25, 0x3a, 0xbd, 0xfd,
-    0x9c, 0x6b, 0xbb, 0x4d, 0x16, 0x4d, 0xff, 0xef, 0x6b, 0xee, 0x95, 0xc9,
-    0xd0, 0x65, 0xa3, 0xa9, 0x54, 0x42, 0xe1, 0xc5, 0xff, 0xfe, 0x74, 0xf7,
-    0xfc, 0x7d, 0x2a, 0xde, 0xa7, 0x22, 0x5a, 0x3a, 0xfe, 0xce, 0x35, 0xdd,
-    0xa6, 0x8b, 0x62, 0xff, 0xfe, 0x60, 0x77, 0xe0, 0xe7, 0x3d, 0xae, 0xcd,
-    0xf3, 0xe7, 0x76, 0xce, 0xbd, 0xcf, 0xfa, 0x75, 0xde, 0x56, 0x11, 0x0f,
-    0xc6, 0xaa, 0x55, 0x1d, 0xc9, 0x0b, 0xfb, 0xd9, 0xac, 0x3a, 0xf9, 0xae,
-    0xed, 0x34, 0x5b, 0x77, 0xda, 0x9d, 0xf8, 0x75, 0x70, 0xf3, 0xfc, 0x5b,
-    0x7f, 0x27, 0x7c, 0x80, 0xfc, 0xeb, 0xfe, 0x89, 0x47, 0x27, 0x8e, 0x4e,
-    0x75, 0x95, 0x92, 0x3c, 0x71, 0xa6, 0x62, 0x21, 0x2d, 0xbf, 0xfd, 0x82,
-    0x05, 0x56, 0xe1, 0xcc, 0x15, 0x0e, 0xbc, 0xc2, 0xe8, 0x4e, 0xbd, 0x3f,
-    0x50, 0xeb, 0xff, 0x30, 0x98, 0x4c, 0x3f, 0xdd, 0xc1, 0x80, 0x1d, 0x7f,
-    0x40, 0xc8, 0x3f, 0xac, 0xeb, 0xe6, 0xbb, 0xb4, 0xd1, 0x78, 0x5f, 0xf9,
-    0xfd, 0x1b, 0x39, 0xcc, 0xdf, 0x47, 0x57, 0x0f, 0xb4, 0x4b, 0x6f, 0xbd,
-    0xb7, 0x9d, 0x3a, 0xfc, 0xb8, 0x19, 0x39, 0xd7, 0xfa, 0x50, 0x3e, 0xd8,
-    0xed, 0x3a, 0xff, 0x47, 0x9f, 0xbf, 0x03, 0x07, 0x5f, 0xfb, 0xea, 0xf7,
-    0x97, 0xb0, 0x7d, 0xa3, 0xae, 0xc5, 0x0e, 0xa8, 0x3d, 0x7c, 0x41, 0xbe,
-    0x49, 0xf1, 0x67, 0x5f, 0xb0, 0x41, 0xb5, 0x07, 0x5f, 0xa3, 0xef, 0xef,
-    0xa3, 0xaf, 0xfe, 0x5c, 0x37, 0xe6, 0x0f, 0xf2, 0xcd, 0x1d, 0x7f, 0xff,
-    0xe7, 0x4f, 0x3a, 0xdc, 0x40, 0xde, 0xa7, 0x25, 0xf6, 0x58, 0x27, 0x56,
-    0x22, 0xbf, 0xa8, 0xb7, 0xff, 0x67, 0x7a, 0xf2, 0x5a, 0x47, 0x24, 0x75,
-    0xd0, 0x03, 0xaa, 0x47, 0xaf, 0xe4, 0x2a, 0x60, 0x2e, 0x12, 0x30, 0x88,
-    0x18, 0xa0, 0xe4, 0xe9, 0x79, 0x09, 0xad, 0xc8, 0x50, 0x92, 0x62, 0x55,
-    0x99, 0xf6, 0x11, 0x4e, 0x40, 0x02, 0x11, 0x28, 0xd4, 0x36, 0x3c, 0xf3,
-    0x7f, 0xb7, 0x57, 0x00, 0xfc, 0xd1, 0xd7, 0xf8, 0x0a, 0xcd, 0x28, 0x1f,
-    0x1d, 0x4a, 0xa6, 0xa7, 0x10, 0xeb, 0xe1, 0xa5, 0xe4, 0xcd, 0xce, 0xbe,
-    0x6b, 0xbb, 0x4d, 0x17, 0xa5, 0xff, 0x93, 0xdd, 0x17, 0x90, 0x1c, 0x07,
-    0x57, 0x0f, 0xa5, 0x65, 0xb7, 0x96, 0x9e, 0x3a, 0xff, 0x9f, 0xd2, 0x85,
-    0x3c, 0x93, 0x9d, 0x4b, 0x3d, 0x41, 0x1b, 0xbf, 0x62, 0xfa, 0xe1, 0x3a,
-    0x82, 0x9a, 0x0e, 0x42, 0x13, 0xeb, 0xb6, 0xd1, 0x0d, 0xff, 0xfe, 0xd9,
-    0x82, 0xa8, 0x70, 0x3d, 0xc5, 0xad, 0xe5, 0x82, 0x75, 0xfe, 0x57, 0xd9,
-    0x34, 0x9c, 0x27, 0x52, 0x22, 0x53, 0xac, 0x14, 0xaa, 0x3f, 0x72, 0x1b,
-    0x75, 0x0d, 0xbf, 0xc4, 0xf0, 0xbf, 0x94, 0x25, 0xb2, 0x75, 0x31, 0xb1,
-    0x8a, 0x24, 0xa4, 0x59, 0xa3, 0x07, 0xe4, 0x63, 0x4b, 0x85, 0xa7, 0x48,
-    0xc1, 0x1a, 0x78, 0xc6, 0x33, 0xa4, 0x3f, 0xe7, 0x6f, 0xd9, 0x94, 0xe9,
-    0x77, 0xfd, 0x3a, 0xff, 0xef, 0xe2, 0x61, 0xcd, 0x8e, 0xb5, 0xa1, 0xd7,
-    0xd9, 0xd7, 0xf1, 0xd7, 0xfb, 0x13, 0x80, 0x07, 0xfa, 0x3a, 0xcc, 0x05,
-    0x11, 0x30, 0x28, 0xba, 0x20, 0xbe, 0xf4, 0x6f, 0x39, 0xd7, 0xfd, 0xed,
-    0x66, 0xf2, 0xef, 0xea, 0x1d, 0x48, 0x7b, 0xe2, 0x47, 0x7d, 0x1b, 0x22,
-    0x47, 0x5f, 0xb8, 0xd7, 0x76, 0x9a, 0x22, 0x3b, 0xff, 0xee, 0xff, 0xad,
-    0x62, 0xc7, 0x36, 0x7c, 0x86, 0x24, 0xeb, 0xfe, 0x89, 0xf9, 0x9e, 0xf2,
-    0x78, 0xeb, 0xc3, 0x1b, 0x9d, 0x52, 0x3d, 0x30, 0x9c, 0x5f, 0xf6, 0x73,
-    0x35, 0x8e, 0x33, 0x9d, 0x7b, 0x02, 0xb3, 0xaf, 0xff, 0xf7, 0x5d, 0x3d,
-    0x1d, 0x1c, 0xf7, 0x53, 0xb8, 0x8c, 0x9d, 0x7f, 0xff, 0xfb, 0xde, 0x45,
-    0xf1, 0x33, 0x71, 0xff, 0xd1, 0xdf, 0x9b, 0x13, 0xd3, 0x41, 0xd5, 0x08,
-    0xd9, 0xc5, 0xdb, 0xfc, 0xeb, 0xce, 0x4a, 0x16, 0x75, 0xd3, 0xac, 0xab,
-    0x99, 0x64, 0xab, 0xff, 0x2a, 0xde, 0xa4, 0xdd, 0x89, 0xd5, 0x01, 0xaf,
-    0x64, 0x5e, 0xfb, 0x64, 0x7a, 0x0e, 0xa9, 0x1f, 0xe2, 0x2d, 0x5f, 0xd8,
-    0xeb, 0xcd, 0xfc, 0x75, 0xfe, 0x75, 0x74, 0x9c, 0x70, 0x1d, 0x66, 0x33,
-    0xaf, 0xfa, 0x33, 0x78, 0x79, 0x3c, 0x8e, 0xa6, 0x20, 0xf2, 0x42, 0x27,
-    0x7f, 0x31, 0x8e, 0x75, 0xfc, 0x75, 0xfd, 0x0a, 0x60, 0xa2, 0x87, 0x5f,
-    0xd9, 0xed, 0xaf, 0x67, 0x4e, 0xac, 0x44, 0x48, 0x97, 0x68, 0xb2, 0xff,
-    0xfe, 0x6a, 0xbc, 0x71, 0x4f, 0x2b, 0xc8, 0xf0, 0xb8, 0x0e, 0xa6, 0x2d,
-    0x7a, 0xc5, 0x85, 0x0a, 0xf8, 0x84, 0xcc, 0x88, 0x30, 0x89, 0xa6, 0x7b,
-    0xc2, 0xad, 0x08, 0xa6, 0x36, 0xe4, 0x3d, 0x3a, 0x42, 0xf0, 0xdc, 0x01,
-    0x08, 0x96, 0x69, 0xef, 0xd0, 0xb0, 0xd8, 0x5d, 0x76, 0xd7, 0x4e, 0xbf,
-    0x71, 0xae, 0xed, 0x34, 0x45, 0xd7, 0xef, 0x03, 0xe8, 0xc8, 0xab, 0xf6,
-    0xbd, 0xd8, 0x01, 0xd7, 0xe7, 0x9e, 0x39, 0xf9, 0xd6, 0x56, 0x74, 0x62,
-    0x60, 0xcb, 0x99, 0xfe, 0x53, 0xb6, 0x4f, 0x4a, 0xaa, 0x27, 0x94, 0x7a,
-    0x77, 0xff, 0x2d, 0xe4, 0xae, 0x71, 0xae, 0xed, 0x34, 0x4c, 0xd7, 0xf3,
-    0x0c, 0xc3, 0xd8, 0x1a, 0x8f, 0x1d, 0x7b, 0x78, 0xd1, 0xd7, 0x9a, 0x8b,
-    0x3a, 0xf9, 0x85, 0xe7, 0x13, 0xae, 0xdb, 0x62, 0x0e, 0xbb, 0x3f, 0x3a,
-    0xff, 0xf7, 0x61, 0x6f, 0xec, 0xdc, 0x0b, 0xfb, 0xd3, 0xaf, 0x92, 0x7f,
-    0xc4, 0xeb, 0xf6, 0x4f, 0x80, 0x98, 0xea, 0xf8, 0x79, 0x5e, 0x22, 0xbf,
-    0xdf, 0x30, 0x5f, 0x80, 0xdb, 0x3a, 0xff, 0xfc, 0xb7, 0xee, 0x6e, 0x0e,
-    0xb2, 0xfd, 0x9b, 0xbf, 0x9d, 0x7f, 0x66, 0xa3, 0xe8, 0xc1, 0xd4, 0x14,
-    0x5d, 0xe1, 0xb7, 0x56, 0x6e, 0xd6, 0x1d, 0x76, 0xd7, 0x8e, 0xb3, 0x04,
-    0xeb, 0x02, 0x0d, 0x6f, 0xe3, 0x37, 0xff, 0xfe, 0x41, 0x86, 0x8c, 0x2f,
-    0xe4, 0x73, 0x89, 0xb3, 0x8e, 0xe0, 0x3a, 0x98, 0x85, 0x55, 0x8d, 0x1e,
-    0x41, 0x69, 0xa1, 0x2d, 0xd8, 0x6f, 0xb9, 0x78, 0x10, 0xbc, 0x4f, 0x7f,
-    0x33, 0x02, 0x39, 0xe3, 0xaf, 0x9f, 0xa9, 0x31, 0xd7, 0xdd, 0x9a, 0x02,
-    0x75, 0x61, 0xf7, 0x34, 0xad, 0xc8, 0x6f, 0xf3, 0x53, 0x04, 0x3d, 0x83,
-    0xa8, 0xeb, 0xf7, 0x5f, 0xd2, 0x01, 0xd7, 0xff, 0xbe, 0x75, 0xd3, 0xc0,
-    0xfc, 0x45, 0xe4, 0x75, 0x62, 0x2a, 0xda, 0x60, 0x81, 0x4b, 0x27, 0xbf,
-    0xff, 0xff, 0xff, 0xfc, 0xc5, 0x18, 0x18, 0xc5, 0x18, 0x4c, 0x3d, 0x87,
-    0xb5, 0x83, 0x0c, 0x39, 0x85, 0xc9, 0xf6, 0xb3, 0xf0, 0xb1, 0x58, 0xdb,
-    0xdf, 0xef, 0x58, 0x51, 0x0c, 0x26, 0x36, 0x1b, 0xdf, 0x3e, 0x77, 0x6c,
-    0xeb, 0xff, 0xf0, 0x37, 0x97, 0x7f, 0x8e, 0x2b, 0xd4, 0x6b, 0xf0, 0xeb,
-    0xff, 0xb7, 0x66, 0x3c, 0x14, 0x63, 0xd4, 0x2c, 0xeb, 0xff, 0xff, 0x22,
-    0xd3, 0x9d, 0xff, 0x52, 0x8d, 0x9c, 0x81, 0xf7, 0x72, 0x47, 0x5f, 0xf9,
-    0x3c, 0x8d, 0x40, 0xfb, 0x1a, 0x75, 0x62, 0x3c, 0x7c, 0x91, 0xb4, 0xdb,
-    0x7d, 0xed, 0xbc, 0xe9, 0xd7, 0xff, 0xf9, 0xc5, 0xa3, 0x81, 0xef, 0xff,
-    0x3b, 0x12, 0xe4, 0x4e, 0x75, 0x62, 0x21, 0xbf, 0x24, 0xbf, 0xff, 0xce,
-    0xa0, 0xe0, 0x3f, 0xd7, 0xc9, 0x27, 0x61, 0xa2, 0xe7, 0x5f, 0x79, 0x3a,
-    0x87, 0x5f, 0xf3, 0xf2, 0x5f, 0x31, 0xa1, 0xc3, 0xa9, 0x84, 0xb8, 0x15,
-    0x11, 0x96, 0x64, 0x69, 0x3d, 0x85, 0xc3, 0x91, 0x8b, 0x0f, 0xe4, 0x16,
-    0xe1, 0xd7, 0xf7, 0xb1, 0x7b, 0xe2, 0xce, 0xb7, 0x70, 0xde, 0xa0, 0x85,
-    0xfe, 0xfc, 0x2f, 0x2d, 0x24, 0x8e, 0xbf, 0xff, 0x05, 0x06, 0x7c, 0xd2,
-    0x3f, 0x55, 0x65, 0x96, 0x4a, 0xbf, 0xbd, 0xd8, 0x9f, 0xbf, 0x9d, 0x7f,
-    0x6f, 0x2d, 0x03, 0xf9, 0x8e, 0xbf, 0xe9, 0xf0, 0x01, 0xfd, 0xf9, 0x23,
-    0xaf, 0xe7, 0x70, 0xec, 0xc0, 0x9d, 0x79, 0xdd, 0xa6, 0x8b, 0x3e, 0xfe,
-    0x03, 0x8c, 0x91, 0x67, 0x54, 0xe8, 0xb9, 0x09, 0xd3, 0x4b, 0x40, 0x4f,
-    0x7f, 0xe4, 0xec, 0x49, 0x3d, 0x1e, 0xd1, 0xd7, 0xff, 0xb9, 0xd7, 0xf9,
-    0x9b, 0x07, 0x35, 0x82, 0x75, 0xff, 0x42, 0x07, 0x16, 0xce, 0x74, 0xeb,
-    0xff, 0xb5, 0xe4, 0x99, 0x97, 0x0c, 0x6f, 0xa3, 0xa9, 0x11, 0x8e, 0xe9,
-    0x5f, 0x9b, 0xde, 0x65, 0x96, 0x4a, 0xbf, 0xf3, 0xcb, 0x43, 0x8d, 0x0e,
-    0x70, 0xa5, 0x4b, 0xfb, 0xf6, 0xd7, 0xeb, 0xc0, 0x9d, 0x7f, 0xbd, 0xdc,
-    0xd9, 0xf2, 0x4b, 0x3a, 0xb0, 0xf8, 0xbf, 0x2b, 0xbf, 0xf6, 0xf2, 0x1f,
-    0xc1, 0xf1, 0xab, 0x01, 0xd7, 0x42, 0x87, 0x5f, 0xf0, 0x60, 0x60, 0x12,
-    0xea, 0x1d, 0x50, 0x88, 0xf9, 0xd0, 0xd0, 0x5a, 0xff, 0x75, 0x02, 0x2e,
-    0xf3, 0x1d, 0x7f, 0x83, 0xdf, 0xdc, 0x1b, 0x78, 0x75, 0x41, 0xf3, 0xa1,
-    0x8d, 0xff, 0x20, 0x87, 0xe8, 0x7f, 0xf6, 0x8e, 0xbd, 0x02, 0xa1, 0xd5,
-    0x25, 0xdc, 0x30, 0x92, 0xb4, 0xcf, 0x75, 0x89, 0x8b, 0xf9, 0x0e, 0xa5,
-    0x9f, 0x76, 0x30, 0x30, 0x27, 0x0c, 0x2b, 0xb5, 0x0b, 0x1f, 0x42, 0x5b,
-    0x61, 0x07, 0xd3, 0xbb, 0xfe, 0xff, 0xda, 0x1c, 0x9a, 0x16, 0x75, 0xfe,
-    0x76, 0x7a, 0x91, 0xc8, 0x3a, 0x94, 0x3e, 0xae, 0x1c, 0xdf, 0xfb, 0x89,
-    0xa9, 0x7d, 0xec, 0x0c, 0x1d, 0x7d, 0xc4, 0x85, 0x9d, 0x7f, 0xfe, 0xf2,
-    0x9f, 0xc6, 0x07, 0xb9, 0xad, 0xe5, 0x1d, 0x3a, 0xb8, 0x8b, 0x55, 0x9f,
-    0x09, 0x05, 0xcf, 0x23, 0xaf, 0xff, 0xff, 0xe1, 0x76, 0x7d, 0x9d, 0x1c,
-    0xf7, 0xe0, 0x5b, 0xc9, 0xc3, 0x02, 0xfc, 0x79, 0x1d, 0x7f, 0xb3, 0xbd,
-    0xff, 0xce, 0x27, 0x5f, 0xf3, 0x73, 0xad, 0x7e, 0x3c, 0x8e, 0xbc, 0x93,
-    0x68, 0xea, 0x83, 0xd3, 0x59, 0xbd, 0x90, 0x29, 0xa0, 0x4c, 0x2b, 0xc8,
-    0x42, 0xae, 0x10, 0xb7, 0xf7, 0xc4, 0xeb, 0xad, 0x0e, 0xbd, 0xb3, 0x02,
-    0x75, 0xb9, 0x39, 0xe5, 0x4c, 0x5b, 0x7f, 0xec, 0x67, 0x6b, 0x99, 0xb4,
-    0x3f, 0xb2, 0x75, 0x42, 0xa7, 0x7e, 0xc6, 0xde, 0xf0, 0x98, 0x12, 0xab,
-    0xff, 0xff, 0xe0, 0x6b, 0x30, 0x54, 0xfb, 0xc1, 0x8c, 0xea, 0xba, 0x1c,
-    0x9d, 0x78, 0xb3, 0xaf, 0xdf, 0x60, 0x7e, 0xac, 0xea, 0xc4, 0x54, 0x79,
-    0xfa, 0xfd, 0xb1, 0xfb, 0x1f, 0x4e, 0xbf, 0xfe, 0xff, 0x79, 0x68, 0x3d,
-    0x8e, 0x05, 0xdd, 0x93, 0xab, 0x11, 0x3c, 0x84, 0x42, 0x55, 0x7b, 0x51,
-    0x39, 0xd7, 0xfd, 0x18, 0xde, 0xa6, 0xc7, 0xe1, 0xd7, 0x67, 0x4e, 0xa1,
-    0x3c, 0xdd, 0xb3, 0x8a, 0x92, 0x2e, 0xb4, 0x5b, 0xe6, 0x9b, 0xdd, 0xfd,
-    0x93, 0xaf, 0x03, 0xf6, 0x9d, 0x7b, 0xd9, 0xf4, 0xeb, 0xfa, 0x37, 0xd7,
-    0xce, 0x41, 0xd7, 0x83, 0xfb, 0x4e, 0xbe, 0x08, 0xc4, 0x8e, 0xa4, 0x37,
-    0xae, 0x3b, 0x41, 0x47, 0x1e, 0xe3, 0xc8, 0x3a, 0xb1, 0xde, 0xb6, 0x5d,
-    0x8d, 0x3a, 0xfe, 0xe2, 0x6c, 0xc1, 0xd1, 0xd7, 0xf6, 0xfe, 0xce, 0xfe,
-    0xc6, 0x75, 0xfd, 0xcc, 0xef, 0x7f, 0xf1, 0xd7, 0xee, 0x8c, 0x67, 0x0c,
-    0xbf, 0xb3, 0x93, 0xfe, 0xe1, 0x34, 0x41, 0xaa, 0x9a, 0x5b, 0x72, 0x74,
-    0x4f, 0xc9, 0x4e, 0xa1, 0x1f, 0x69, 0x0d, 0x1b, 0xf3, 0xb5, 0x17, 0x07,
-    0x5f, 0xd2, 0xe8, 0xbe, 0xfe, 0x3a, 0x9a, 0x7a, 0x42, 0x4b, 0x7d, 0xf4,
-    0x5e, 0x73, 0xab, 0x0f, 0x13, 0x44, 0x37, 0xe8, 0xf7, 0xc5, 0xb2, 0x75,
-    0xfe, 0x92, 0x2e, 0x3b, 0xf4, 0x27, 0x5f, 0xfe, 0x8c, 0x1d, 0xfd, 0x9c,
-    0x49, 0xdd, 0x67, 0x5f, 0x9d, 0x9f, 0x67, 0x74, 0x7f, 0x9e, 0x34, 0xa6,
-    0x2d, 0x57, 0xfc, 0x0a, 0xca, 0x32, 0x8c, 0x85, 0xe7, 0x08, 0x46, 0x14,
-    0xd7, 0xb5, 0x92, 0x3a, 0xfc, 0x9b, 0xc9, 0x04, 0xeb, 0xc9, 0xdc, 0x3a,
-    0xe8, 0x5e, 0x1e, 0x03, 0x49, 0xaf, 0xe6, 0x71, 0x71, 0xc5, 0x0e, 0xbe,
-    0x0e, 0xbb, 0x07, 0x5f, 0x87, 0x8c, 0xbc, 0xe7, 0x54, 0x1f, 0xbe, 0x17,
-    0x39, 0x0d, 0xdf, 0x89, 0xd5, 0x09, 0xa0, 0x22, 0xdf, 0x21, 0x47, 0xa2,
-    0xcb, 0xdd, 0xc1, 0x3a, 0xff, 0x4d, 0x13, 0xad, 0xe6, 0x83, 0xaf, 0xff,
-    0x9d, 0x4f, 0x47, 0x01, 0xc8, 0xf0, 0xb8, 0x0e, 0xbf, 0x87, 0x01, 0x83,
-    0x23, 0xaf, 0xff, 0x94, 0xf9, 0xf4, 0x5f, 0xda, 0x4d, 0xfa, 0x8c, 0x9d,
-    0x61, 0xc3, 0xff, 0x72, 0xaa, 0xc4, 0xd0, 0x1c, 0x68, 0x4d, 0x3f, 0x86,
-    0x6d, 0xda, 0xd8, 0x75, 0xf2, 0x0b, 0x84, 0xeb, 0xff, 0x2f, 0x3d, 0xaf,
-    0xba, 0x79, 0x61, 0xd7, 0xed, 0x47, 0x3d, 0x07, 0x2a, 0x6f, 0xe8, 0x28,
-    0x95, 0xd2, 0xf5, 0xfb, 0xec, 0xce, 0xfc, 0x3a, 0xfb, 0xb8, 0x9b, 0x0e,
-    0xbf, 0xb4, 0x9c, 0xcf, 0xf8, 0x75, 0xff, 0xfe, 0x89, 0xbe, 0x23, 0x7f,
-    0xe6, 0xbf, 0xf8, 0xb4, 0xf7, 0x50, 0xea, 0xc4, 0xeb, 0xd2, 0x15, 0xab,
-    0x23, 0xe9, 0x4f, 0x88, 0xb6, 0x8b, 0x6e, 0x5b, 0x00, 0xd1, 0x7e, 0x5f,
-    0x6b, 0x99, 0x87, 0x5f, 0xfd, 0x2f, 0x7f, 0x29, 0x2f, 0xde, 0x85, 0x9d,
-    0x7f, 0xbd, 0xa8, 0x9f, 0x34, 0x13, 0xae, 0xee, 0x1d, 0x7f, 0xfd, 0xd8,
-    0x0e, 0x37, 0xe6, 0x0e, 0x07, 0xb0, 0x75, 0xff, 0xc9, 0x83, 0x99, 0xaf,
-    0x92, 0xd2, 0xce, 0xbf, 0xf3, 0xc6, 0xf2, 0xf9, 0xad, 0xc3, 0x07, 0x50,
-    0x53, 0x80, 0xdc, 0x81, 0x11, 0x98, 0xcc, 0xe6, 0x15, 0xd2, 0x77, 0x90,
-    0xef, 0x29, 0x1c, 0x3a, 0xfe, 0x0c, 0x03, 0x99, 0xb9, 0xd4, 0xa9, 0xe4,
-    0xac, 0x72, 0xff, 0x42, 0xf1, 0x39, 0x34, 0x8e, 0xb9, 0x26, 0x3a, 0xff,
-    0xf7, 0xa3, 0xa2, 0xf3, 0xc7, 0x38, 0xf2, 0x3a, 0xf7, 0x92, 0x73, 0xaf,
-    0xc0, 0x7d, 0xe2, 0x63, 0xaf, 0x0c, 0x34, 0xeb, 0xff, 0x82, 0x93, 0x76,
-    0x39, 0xbc, 0xa3, 0x87, 0x5f, 0xfe, 0x41, 0x7d, 0xf5, 0xac, 0xe0, 0x7b,
-    0x87, 0x57, 0xc4, 0xd2, 0x50, 0x59, 0x69, 0x0e, 0x38, 0x25, 0x1a, 0x1a,
-    0xda, 0x45, 0xb4, 0x1d, 0x7b, 0xa9, 0xe3, 0xad, 0xb3, 0x0d, 0x57, 0xd0,
-    0xfa, 0x85, 0xd1, 0x00, 0xaf, 0x64, 0x74, 0xe9, 0x0b, 0x2e, 0x91, 0xbc,
-    0x6f, 0x60, 0x84, 0x8d, 0xff, 0x60, 0xc8, 0x71, 0x70, 0xd3, 0xaf, 0xdd,
-    0x4d, 0x98, 0x13, 0xaf, 0xfc, 0x18, 0x1c, 0x1f, 0xe5, 0x9a, 0x3a, 0xfc,
-    0xeb, 0x4d, 0xac, 0x3a, 0xf7, 0xa3, 0x73, 0xab, 0x0f, 0x11, 0xca, 0x2f,
-    0x42, 0x4c, 0x75, 0xe1, 0x62, 0x36, 0x8e, 0xbf, 0x64, 0xeb, 0x8d, 0x1d,
-    0x7f, 0xff, 0xe8, 0xea, 0x2d, 0x59, 0xa4, 0xfc, 0xfb, 0xd4, 0xdf, 0x4d,
-    0x49, 0xce, 0xa0, 0xa7, 0xa6, 0xa1, 0xaa, 0x14, 0x4d, 0x08, 0x0e, 0x90,
-    0x08, 0xde, 0x88, 0xf6, 0x89, 0xef, 0xbe, 0x3c, 0x98, 0x93, 0xaf, 0xfe,
-    0xcd, 0x98, 0x1c, 0x1f, 0xe5, 0x9a, 0x3a, 0xfd, 0xc8, 0xef, 0xd0, 0x9d,
-    0x5c, 0x3e, 0xd7, 0x44, 0xbe, 0x84, 0x9e, 0x0e, 0xbe, 0x65, 0xf3, 0x47,
-    0x5f, 0xf4, 0x96, 0xf2, 0xf6, 0xa1, 0x43, 0xaa, 0x0f, 0x69, 0xc8, 0x6f,
-    0x69, 0x04, 0xeb, 0xf0, 0xb7, 0xe6, 0xb7, 0x3a, 0xb0, 0xf1, 0x1c, 0x6a,
-    0x98, 0xd3, 0xb4, 0x78, 0x4a, 0x80, 0x84, 0x5e, 0xbf, 0x64, 0xba, 0x79,
-    0x1d, 0x79, 0x3a, 0x87, 0x56, 0xe6, 0xc7, 0xc2, 0xf7, 0xdf, 0x7f, 0x7d,
-    0x1d, 0x7f, 0x7f, 0xa8, 0x9b, 0xfe, 0x1d, 0x7b, 0xfc, 0xdc, 0xea, 0xe9,
-    0xe6, 0xf8, 0xc2, 0xff, 0x4b, 0xf1, 0x9f, 0x49, 0xb9, 0xd7, 0xc0, 0x06,
-    0x6e, 0x75, 0xfd, 0xb5, 0xec, 0x71, 0x69, 0xd7, 0xfd, 0xfb, 0xc8, 0x39,
-    0x80, 0xd1, 0xd7, 0xf8, 0x09, 0xbe, 0xf2, 0xcf, 0x1d, 0x5d, 0x3e, 0xcd,
-    0x1c, 0x5f, 0xb7, 0xd2, 0xd1, 0x8c, 0xeb, 0xff, 0xf6, 0x6b, 0xe7, 0x5d,
-    0x3c, 0x0f, 0xc4, 0x5e, 0x47, 0x54, 0x22, 0x00, 0x4a, 0xef, 0xe7, 0x9c,
-    0x0e, 0x21, 0x3a, 0x9a, 0xa8, 0x0a, 0x62, 0x2e, 0x1a, 0xf4, 0x8b, 0xd0,
-    0x9a, 0xd9, 0x0a, 0x2d, 0xb2, 0x1b, 0xfd, 0xf6, 0x1b, 0xb7, 0x9c, 0x83,
-    0xaf, 0xe8, 0xea, 0x72, 0x16, 0x75, 0x74, 0xf8, 0x7c, 0x6d, 0x50, 0xad,
-    0xb3, 0x25, 0x39, 0xbc, 0x35, 0xee, 0x9b, 0xf3, 0xac, 0xb3, 0xab, 0x73,
-    0x50, 0xc1, 0x18, 0xbf, 0xfa, 0x39, 0x9b, 0x1e, 0x40, 0xcc, 0x09, 0xd7,
-    0xf3, 0xef, 0x21, 0x80, 0x9d, 0x7f, 0xd1, 0xbc, 0x90, 0x56, 0xfe, 0x3a,
-    0x9c, 0xf8, 0xc4, 0xb2, 0xfc, 0xf2, 0xc9, 0xe0, 0xeb, 0xff, 0xa3, 0x5a,
-    0xc5, 0xf8, 0x61, 0x7a, 0x3a, 0xff, 0xe4, 0x8d, 0x0b, 0xcb, 0xe6, 0xb3,
-    0x87, 0x5f, 0xff, 0xe4, 0xd4, 0xf8, 0xce, 0x0f, 0xfb, 0x50, 0xae, 0x0b,
-    0xf0, 0xeb, 0xfd, 0xbc, 0xb5, 0x34, 0xa2, 0x73, 0xa8, 0x29, 0xa2, 0x34,
-    0x98, 0x50, 0xbc, 0x87, 0xfb, 0x1d, 0xff, 0xff, 0xba, 0x9b, 0xfb, 0x37,
-    0xf7, 0x39, 0x1e, 0x07, 0xd1, 0x97, 0x70, 0xeb, 0xc1, 0x71, 0x3a, 0xf7,
-    0x23, 0x61, 0xd4, 0x13, 0x6f, 0xc1, 0xab, 0xff, 0x4a, 0x07, 0xdc, 0x4d,
-    0x98, 0x13, 0xaf, 0xfc, 0xfd, 0x6a, 0x3f, 0xcd, 0x3f, 0x4e, 0xbf, 0xba,
-    0xe3, 0xbc, 0x90, 0xeb, 0xff, 0xf6, 0x87, 0xe7, 0x5d, 0x3c, 0x0f, 0xc4,
-    0x5e, 0x47, 0x5f, 0xee, 0xa2, 0x9b, 0x7f, 0xf1, 0x43, 0xaf, 0xfa, 0x19,
-    0x5f, 0x61, 0x06, 0x73, 0xaf, 0xff, 0x87, 0x35, 0x8b, 0x86, 0xe7, 0x93,
-    0x98, 0x75, 0xb1, 0xa8, 0xbc, 0xf1, 0xce, 0xc3, 0x8b, 0xfa, 0x7c, 0xe2,
-    0x36, 0x0e, 0xbe, 0x10, 0xc2, 0xce, 0xbf, 0xfe, 0xfc, 0x7d, 0xae, 0xa4,
-    0xc3, 0x0b, 0x79, 0x1d, 0x7d, 0x83, 0xfb, 0x9d, 0x4b, 0x3e, 0xfd, 0x89,
-    0xf7, 0xf3, 0x83, 0x02, 0xf2, 0x3a, 0xa1, 0x1b, 0xd9, 0x08, 0xf4, 0x24,
-    0xa4, 0x4c, 0xf3, 0xb1, 0x85, 0x54, 0x2f, 0x4b, 0xce, 0x4c, 0x18, 0x53,
-    0x64, 0x6c, 0x8d, 0x4b, 0x48, 0x53, 0x4c, 0x43, 0xd3, 0xe7, 0x3e, 0x01,
-    0x60, 0xc6, 0x23, 0xe8, 0xdc, 0xef, 0xfe, 0xc1, 0x06, 0x67, 0x35, 0xe8,
-    0xc3, 0xaf, 0xfb, 0x7f, 0x67, 0x12, 0x77, 0x59, 0xd6, 0xc0, 0x1f, 0xc8,
-    0xa0, 0x5e, 0x60, 0xc9, 0x0e, 0xbe, 0x81, 0x79, 0x1d, 0x7e, 0xc6, 0x37,
-    0x10, 0x7c, 0x37, 0xdc, 0x1f, 0xbf, 0xb6, 0x75, 0x23, 0x9a, 0x3a, 0xff,
-    0xdd, 0x45, 0x87, 0x26, 0x8c, 0xe1, 0xd7, 0xd0, 0x07, 0x59, 0xd7, 0x0c,
-    0xb0, 0xf7, 0x44, 0xf6, 0xfb, 0x49, 0xe8, 0x3a, 0xa0, 0xf2, 0xdc, 0xae,
-    0xf9, 0xbd, 0x49, 0x8e, 0xbf, 0xff, 0x0e, 0x28, 0xa2, 0x07, 0xa9, 0x37,
-    0x53, 0x7f, 0x1d, 0x50, 0x7f, 0x38, 0x45, 0x79, 0xaf, 0xc3, 0xaf, 0xda,
-    0x6c, 0x71, 0x43, 0xab, 0xa7, 0x86, 0x01, 0xbb, 0xfd, 0x92, 0xc4, 0x0f,
-    0x50, 0xeb, 0xff, 0xb3, 0x7f, 0x69, 0x06, 0x00, 0xeb, 0x3a, 0xf4, 0x97,
-    0xd3, 0xaa, 0x73, 0xde, 0xf2, 0x15, 0xf2, 0x28, 0x8c, 0x9d, 0x58, 0x78,
-    0xa2, 0x47, 0x77, 0xcc, 0x3a, 0xfb, 0x43, 0x0b, 0x3a, 0xa0, 0xdb, 0xee,
-    0x2f, 0x7b, 0xb2, 0x59, 0xd7, 0x75, 0x0e, 0xac, 0x36, 0x3e, 0x1c, 0xa8,
-    0x5c, 0x35, 0x93, 0x26, 0x20, 0xa9, 0x0d, 0x6e, 0xc2, 0x65, 0xd8, 0xc4,
-    0x8b, 0x50, 0xd3, 0xfd, 0x5f, 0x6d, 0x4a, 0xf0, 0x56, 0xd3, 0xad, 0xd3,
-    0xac, 0x03, 0xae, 0xd4, 0x8e, 0xa0, 0x1b, 0x6d, 0x08, 0x7e, 0x21, 0x7f,
-    0x4f, 0x34, 0x98, 0x5c, 0x9c, 0xeb, 0xcf, 0x9c, 0x3a, 0xf0, 0xe7, 0x8e,
-    0xae, 0x9b, 0x41, 0x1a, 0xbb, 0xc2, 0x75, 0xe8, 0xdf, 0x47, 0x5f, 0x20,
-    0xcb, 0x0e, 0xbd, 0x3b, 0x89, 0xd4, 0x13, 0xd6, 0x58, 0xe7, 0x87, 0xef,
-    0xd9, 0xee, 0xa7, 0x8e, 0xbf, 0x3e, 0xf9, 0xbf, 0x8e, 0xb2, 0x9d, 0x3c,
-    0xef, 0x13, 0x5c, 0x9c, 0x3a, 0xfe, 0x9f, 0xe4, 0xee, 0xfd, 0x3a, 0x98,
-    0x84, 0xf7, 0xe1, 0xa6, 0x44, 0x18, 0xd6, 0x8f, 0xbd, 0x29, 0x71, 0x5b,
-    0xfe, 0xc0, 0x85, 0x37, 0xcd, 0xfc, 0x75, 0xf3, 0x46, 0x24, 0x75, 0x74,
-    0xf6, 0x5c, 0xe6, 0xff, 0x46, 0x7a, 0x3a, 0xe1, 0x3a, 0xa7, 0x3d, 0x10,
-    0x90, 0xdf, 0xfc, 0x18, 0x0f, 0x23, 0xc8, 0xd4, 0x09, 0xd7, 0xd3, 0x46,
-    0xd4, 0x8e, 0xbf, 0xbc, 0xd0, 0x85, 0x7c, 0x3a, 0xff, 0xa6, 0xd6, 0xc7,
-    0x19, 0xff, 0x09, 0xd7, 0xd9, 0xec, 0x59, 0xd7, 0x0a, 0x87, 0x5b, 0x4e,
-    0x6d, 0xbf, 0x20, 0xbf, 0xbb, 0xfc, 0xf3, 0x75, 0x0e, 0xbe, 0x11, 0xcf,
-    0x1d, 0x50, 0x9d, 0x08, 0x48, 0xf1, 0x09, 0x42, 0x54, 0x2e, 0x99, 0xcf,
-    0xa4, 0xfe, 0x30, 0xbf, 0xbe, 0x4d, 0x1e, 0x1d, 0x87, 0x5f, 0xfe, 0x18,
-    0xd9, 0xc8, 0xe6, 0x27, 0x60, 0x27, 0x5e, 0x17, 0x59, 0xd5, 0x24, 0x49,
-    0xe1, 0x8a, 0x24, 0x59, 0x56, 0x21, 0xf0, 0x41, 0x98, 0xb3, 0xc6, 0x1e,
-    0x38, 0xc5, 0x46, 0xe2, 0x56, 0x84, 0xf0, 0xef, 0x94, 0x36, 0x03, 0x38,
-    0x8b, 0x93, 0xcf, 0x2a, 0x46, 0x96, 0xd9, 0x69, 0xfb, 0xca, 0x47, 0x48,
-    0xc4, 0xe6, 0x96, 0x93, 0xc8, 0xea, 0xd7, 0x1c, 0x0f, 0x67, 0xc0, 0x1e,
-    0x52, 0x60, 0x25, 0x17, 0x30, 0x61, 0x06, 0x32, 0xe3, 0xb5, 0x3d, 0xf5,
-    0xe9, 0xd6, 0xff, 0xe1, 0x3c, 0xca, 0x96, 0xdc, 0xa0, 0xef, 0xb2, 0xac,
-    0x76, 0xa3, 0x04, 0xa5, 0x5f, 0x0e, 0x57, 0xb7, 0x82, 0xad, 0x7f, 0xf9,
-    0x55, 0xbc, 0x95, 0xce, 0x35, 0xdd, 0xa6, 0x89, 0xb2, 0xff, 0x2b, 0x9c,
-    0x6b, 0xbb, 0x4d, 0x15, 0x6d, 0xfe, 0x94, 0xbf, 0xf0, 0xc4, 0x8e, 0xbe,
-    0xce, 0xbf, 0x8e, 0xb3, 0x03, 0x0f, 0x4c, 0x4c, 0xef, 0xfb, 0x07, 0x17,
-    0x12, 0xff, 0x87, 0x5f, 0xee, 0x63, 0x60, 0x1f, 0x56, 0x75, 0xff, 0x47,
-    0x62, 0x7e, 0x46, 0x04, 0xea, 0x6a, 0x28, 0xb8, 0x6f, 0xd3, 0x4b, 0xf4,
-    0x71, 0x7d, 0x09, 0xd7, 0x83, 0x82, 0x75, 0xe7, 0x76, 0x9a, 0x2b, 0x4b,
-    0xf2, 0x9b, 0xeb, 0xfd, 0xce, 0xa6, 0x9e, 0x9a, 0x13, 0xdf, 0xfe, 0x4f,
-    0x4a, 0x1b, 0xd4, 0xf6, 0x9f, 0x73, 0xab, 0x87, 0xd5, 0xb0, 0x86, 0xff,
-    0xf7, 0x51, 0x70, 0xdc, 0x5e, 0x0f, 0xb6, 0xce, 0xbf, 0xfe, 0x6c, 0x73,
-    0x00, 0xeb, 0x79, 0x42, 0x34, 0xeb, 0xff, 0xe9, 0x6b, 0x06, 0x16, 0xf9,
-    0xef, 0x42, 0xce, 0xbb, 0xde, 0x84, 0x4c, 0x3a, 0x65, 0xff, 0xff, 0xe8,
-    0xd8, 0x9e, 0xd6, 0x28, 0xde, 0xa7, 0xb2, 0x61, 0x85, 0xcf, 0x8c, 0x9d,
-    0x7f, 0xa3, 0xcf, 0xdf, 0x81, 0x83, 0xaf, 0xa5, 0xe4, 0x9c, 0xeb, 0xf7,
-    0xdf, 0x0c, 0x00, 0xea, 0xdc, 0xf2, 0xb6, 0x11, 0x5f, 0xe7, 0x97, 0x92,
-    0x7e, 0xa1, 0xd5, 0x07, 0xae, 0x84, 0xb7, 0xec, 0xea, 0x62, 0xce, 0xbf,
-    0xf8, 0x5d, 0x1b, 0xd7, 0xfe, 0x7e, 0x21, 0xd5, 0x39, 0xf4, 0x74, 0x96,
-    0xff, 0x4a, 0x39, 0x3c, 0x72, 0x73, 0xaf, 0x67, 0x00, 0x75, 0xfa, 0x6c,
-    0x0a, 0xd8, 0xce, 0xbf, 0x86, 0x19, 0xde, 0x5a, 0x3a, 0x90, 0xfd, 0x26,
-    0x1b, 0xda, 0x2b, 0xa8, 0x46, 0xd6, 0x42, 0xa2, 0xff, 0xff, 0xfe, 0xc4,
-    0x6e, 0x7a, 0x07, 0xda, 0xf9, 0x08, 0x1c, 0x5f, 0xce, 0x42, 0x49, 0xf4,
-    0x75, 0xfd, 0x9e, 0x71, 0x07, 0xe7, 0x5f, 0xdd, 0xf8, 0x93, 0xb8, 0x9d,
-    0x7f, 0xa1, 0x7a, 0x08, 0xbb, 0x27, 0x54, 0x91, 0x19, 0x85, 0x82, 0x5d,
-    0x65, 0x58, 0x4b, 0xec, 0xf1, 0x0c, 0xc9, 0xcc, 0x02, 0x4f, 0x90, 0xd7,
-    0x69, 0x22, 0x43, 0x8b, 0x85, 0xab, 0x7a, 0xec, 0x35, 0x1e, 0x11, 0x03,
-    0x0f, 0xdd, 0x13, 0x7a, 0x31, 0x3b, 0xf7, 0x1a, 0xee, 0xd3, 0x45, 0x81,
-    0x7e, 0x76, 0xfd, 0xec, 0xc7, 0x59, 0x5c, 0x3d, 0xdd, 0x19, 0xdf, 0xb8,
-    0xd7, 0x76, 0x9a, 0x27, 0x5b, 0xff, 0xfd, 0xd8, 0x9c, 0x38, 0xb5, 0x75,
-    0xac, 0xea, 0x6b, 0xf9, 0xce, 0xbf, 0x2a, 0xb7, 0x92, 0xb8, 0x89, 0x79,
-    0x8c, 0xef, 0x29, 0x0b, 0x3a, 0xf9, 0xdb, 0xf5, 0x67, 0x5e, 0x96, 0x95,
-    0x50, 0xdf, 0xec, 0x1c, 0xbf, 0x71, 0xae, 0xed, 0x34, 0x5b, 0x37, 0xf7,
-    0x9f, 0xbf, 0x03, 0x07, 0x5f, 0xff, 0xd2, 0x57, 0x50, 0x98, 0x14, 0xcd,
-    0x67, 0x86, 0x0e, 0xa8, 0x44, 0x2b, 0x97, 0x5f, 0xf8, 0x11, 0xa5, 0x7a,
-    0x8d, 0x7e, 0x1d, 0x7f, 0xd1, 0x28, 0xe4, 0xf1, 0xc9, 0xce, 0xb2, 0xb8,
-    0x9a, 0x82, 0xe1, 0x70, 0xe4, 0x22, 0x7d, 0x7f, 0xe1, 0x55, 0x7f, 0xa7,
-    0x85, 0xf6, 0x8e, 0xbf, 0xfb, 0xfd, 0x2b, 0x9c, 0x7d, 0x75, 0xe4, 0x75,
-    0xce, 0x0c, 0x44, 0x30, 0x10, 0x6f, 0x9a, 0xee, 0xd3, 0x45, 0xcd, 0x65,
-    0x9d, 0x5c, 0x37, 0xac, 0x96, 0xdf, 0xee, 0x0e, 0x6e, 0x04, 0x91, 0xd7,
-    0x4c, 0xb3, 0xa8, 0xeb, 0x2b, 0x87, 0xea, 0x84, 0x4c, 0x99, 0x6d, 0x8b,
-    0xdf, 0xb8, 0xd7, 0x76, 0x9a, 0x2e, 0xfb, 0xfd, 0x25, 0x75, 0xce, 0x23,
-    0x27, 0x59, 0x5c, 0x3e, 0x87, 0x33, 0xbe, 0x55, 0x40, 0x80, 0xea, 0x87,
-    0xd2, 0xfd, 0xcb, 0xc3, 0xc1, 0x69, 0xbe, 0xea, 0xe9, 0x3f, 0xf3, 0xc8,
-    0xd2, 0x97, 0x0b, 0xf7, 0x84, 0x08, 0x23, 0x87, 0x18, 0x66, 0xea, 0x1b,
-    0xfe, 0x85, 0x6f, 0xd2, 0x7b, 0xff, 0x32, 0xe3, 0x3e, 0x90, 0x77, 0x91,
-    0xd7, 0xff, 0x64, 0xf8, 0xcf, 0x73, 0x58, 0x82, 0x75, 0xc8, 0xaf, 0x51,
-    0x02, 0x27, 0xf7, 0xed, 0x69, 0x6f, 0x23, 0xaf, 0xff, 0xff, 0xfd, 0xd4,
-    0xea, 0x40, 0xf8, 0x5d, 0x4c, 0xf7, 0xfe, 0x4f, 0x6b, 0xa9, 0xc8, 0x9d,
-    0xf8, 0xd3, 0xae, 0xd4, 0x1d, 0x7f, 0xf6, 0xed, 0xfd, 0xf7, 0xf6, 0x60,
-    0xa8, 0x75, 0xe1, 0x75, 0x61, 0x31, 0xa6, 0x93, 0xea, 0x13, 0x1e, 0x15,
-    0xbd, 0xfb, 0xac, 0xeb, 0xf6, 0x6d, 0x7a, 0x14, 0x3a, 0xdb, 0x47, 0x54,
-    0xe6, 0xf7, 0x0a, 0xab, 0x87, 0xf4, 0x2b, 0x37, 0xfe, 0xd3, 0xa9, 0xd4,
-    0x81, 0xfe, 0x0e, 0xbf, 0xf7, 0x5f, 0xcf, 0xdd, 0xe5, 0x9e, 0x3a, 0xb0,
-    0xfe, 0xd0, 0xf6, 0xe7, 0x01, 0xd7, 0xff, 0xff, 0x85, 0xd9, 0x1c, 0xf7,
-    0xb2, 0x78, 0x17, 0x53, 0x4b, 0x8c, 0x10, 0x9d, 0x7b, 0x3e, 0xe8, 0xea,
-    0xc4, 0x53, 0x70, 0x57, 0x69, 0xd2, 0xff, 0x77, 0x02, 0x9b, 0x39, 0x87,
-    0x5e, 0x77, 0x69, 0xa2, 0x57, 0xbf, 0xca, 0x38, 0x83, 0xd9, 0xd3, 0xa9,
-    0xa7, 0xb2, 0x84, 0xf7, 0xff, 0xbd, 0xdc, 0x93, 0x7a, 0x81, 0x81, 0xf1,
-    0xd5, 0x24, 0x7a, 0xf2, 0x11, 0x82, 0x43, 0x74, 0xa7, 0x3a, 0xff, 0xff,
-    0x3e, 0xfa, 0xce, 0x7b, 0xcf, 0x3f, 0xd5, 0x87, 0xa8, 0xa1, 0xd7, 0xf7,
-    0xfb, 0xfb, 0xb0, 0x03, 0xaf, 0xfc, 0x2e, 0xc8, 0x7b, 0x13, 0xe3, 0x27,
-    0x5f, 0xff, 0xb1, 0x01, 0x8b, 0x4f, 0x6a, 0x16, 0xfb, 0xf8, 0xeb, 0xfe,
-    0x85, 0xfb, 0x26, 0x92, 0x78, 0xea, 0x92, 0x22, 0xfc, 0xa7, 0x7d, 0xfb,
-    0xf2, 0x47, 0x5f, 0xf4, 0x34, 0x62, 0x70, 0x3f, 0x8e, 0xbf, 0xff, 0xc9,
-    0xe7, 0x5b, 0x88, 0x3a, 0xcb, 0x8c, 0xed, 0x49, 0xce, 0xa0, 0xa2, 0xe5,
-    0x08, 0x9c, 0xde, 0xff, 0xbf, 0x02, 0xde, 0x5a, 0xe0, 0x4e, 0xbf, 0xff,
-    0xd8, 0x83, 0xec, 0x1f, 0x82, 0xe1, 0x81, 0x9e, 0x38, 0x75, 0xb3, 0xc8,
-    0x97, 0xd8, 0x75, 0x7f, 0xdb, 0x83, 0x39, 0x99, 0xed, 0x1d, 0x41, 0x55,
-    0x9b, 0x90, 0xca, 0xec, 0x37, 0x06, 0x18, 0xbf, 0x4a, 0xaf, 0xfb, 0x37,
-    0xd0, 0x61, 0xc6, 0x73, 0xaf, 0xf9, 0xe5, 0xae, 0xc7, 0x3e, 0x84, 0xea,
-    0xc3, 0xf2, 0xf1, 0xc5, 0xff, 0xde, 0x4d, 0x89, 0xe9, 0xa5, 0x03, 0xe3,
-    0xaf, 0xff, 0x3e, 0x4b, 0xb8, 0x83, 0x80, 0xdb, 0xc3, 0xaf, 0x3c, 0x95,
-    0x85, 0xfb, 0x09, 0x42, 0x70, 0x30, 0xc6, 0xc8, 0xc9, 0xd6, 0x68, 0x01,
-    0x71, 0x65, 0xd4, 0xaf, 0xcf, 0x43, 0x37, 0xe9, 0x0e, 0xd2, 0x2d, 0xff,
-    0xec, 0xea, 0xa3, 0x81, 0x41, 0xf6, 0x74, 0xeb, 0xde, 0x80, 0x95, 0x7f,
-    0xfb, 0xae, 0x9e, 0x89, 0x27, 0x27, 0xfc, 0x05, 0x5f, 0xe7, 0x6a, 0xa1,
-    0xe3, 0x05, 0x58, 0x3e, 0x5d, 0x0d, 0xd9, 0x50, 0xb2, 0xe3, 0x1b, 0x1a,
-    0x42, 0xe9, 0x0f, 0xbe, 0x86, 0x5e, 0xc8, 0x56, 0x5f, 0xfe, 0x55, 0x6f,
-    0x25, 0x73, 0x8d, 0x77, 0x69, 0xa2, 0x61, 0xbf, 0xff, 0xb3, 0x63, 0x87,
-    0xb0, 0xaf, 0xbb, 0x81, 0xff, 0xda, 0x3a, 0xff, 0xf7, 0x1c, 0x0a, 0xa9,
-    0xe9, 0x33, 0x1a, 0x91, 0xd7, 0x62, 0xa2, 0x8a, 0xbf, 0xab, 0xd7, 0xff,
-    0x30, 0x33, 0x79, 0x7e, 0xfe, 0x18, 0x91, 0xd7, 0xec, 0x5f, 0xcd, 0xd8,
-    0xce, 0xbf, 0xa1, 0x78, 0x08, 0xd8, 0x75, 0x04, 0xf6, 0xba, 0x5b, 0x7f,
-    0xb9, 0x8d, 0x80, 0x7d, 0x59, 0xd7, 0xee, 0xc0, 0x51, 0x43, 0xa9, 0x0f,
-    0xf7, 0x84, 0x5b, 0x46, 0x97, 0xfa, 0x1e, 0x7f, 0x28, 0xfc, 0x3a, 0xfc,
-    0xfc, 0x93, 0xac, 0xea, 0x13, 0xd9, 0xfc, 0xce, 0xff, 0x6a, 0x30, 0x43,
-    0xd8, 0x3a, 0xfe, 0x8c, 0x10, 0xf6, 0x0e, 0xbd, 0xff, 0x26, 0xf8, 0x7b,
-    0x5a, 0x30, 0xbf, 0xfd, 0xc4, 0xff, 0x14, 0xcf, 0x7f, 0x1b, 0x84, 0xeb,
-    0xff, 0xf2, 0x73, 0xaf, 0xf0, 0x39, 0x2e, 0xc6, 0xc0, 0xc1, 0xd7, 0xfc,
-    0xcf, 0xde, 0xc3, 0x7a, 0x93, 0x1d, 0x7d, 0xfa, 0xf0, 0x27, 0x5b, 0x37,
-    0x3d, 0xed, 0xa3, 0xcb, 0xfa, 0x39, 0x12, 0xd6, 0x1d, 0x4d, 0x4e, 0x3f,
-    0x87, 0x1d, 0x4c, 0x18, 0x5a, 0xf8, 0xae, 0xfe, 0x5c, 0x60, 0xfb, 0x6c,
-    0xeb, 0x68, 0xeb, 0xf4, 0x60, 0xfb, 0x6c, 0xeb, 0xfb, 0xa9, 0xed, 0x3e,
-    0xff, 0x0f, 0x9a, 0x62, 0xe5, 0x88, 0x5f, 0xe9, 0x7a, 0x17, 0xb0, 0x12,
-    0x3a, 0xff, 0xff, 0x33, 0xb5, 0xec, 0xef, 0xc1, 0xc9, 0xd3, 0x07, 0x79,
-    0x68, 0xeb, 0xf3, 0x3e, 0xce, 0xb4, 0xeb, 0x0e, 0x22, 0x39, 0xd9, 0xaf,
-    0xff, 0x78, 0x5c, 0x1d, 0xc4, 0x0f, 0xfe, 0xd1, 0xd7, 0xfd, 0x13, 0xfd,
-    0x97, 0x7f, 0x79, 0xce, 0xa8, 0x44, 0x37, 0x12, 0x6f, 0xfe, 0xcd, 0xe5,
-    0xf3, 0xae, 0xd8, 0x10, 0x9d, 0x7f, 0x6c, 0xfb, 0xe1, 0x80, 0x1d, 0x7f,
-    0xfa, 0x3c, 0x08, 0x96, 0x6f, 0xe9, 0xff, 0x64, 0xeb, 0xda, 0x70, 0x1d,
-    0x50, 0x89, 0x84, 0x30, 0xf2, 0x6d, 0xfc, 0xe0, 0xe7, 0x13, 0x87, 0x5e,
-    0xf7, 0xcc, 0x3a, 0x80, 0x79, 0x3f, 0x4b, 0x2f, 0xed, 0x22, 0x8b, 0x7f,
-    0x1d, 0x7f, 0xff, 0xee, 0x66, 0xc8, 0x1f, 0x7c, 0xfa, 0x31, 0xd7, 0x4f,
-    0x47, 0xb4, 0x75, 0xfc, 0x39, 0xaf, 0x8d, 0x61, 0x1d, 0x5b, 0xa3, 0x37,
-    0x85, 0xbb, 0x1b, 0xaf, 0xbe, 0x6c, 0xda, 0x9c, 0xea, 0xc3, 0xdd, 0x50,
-    0xce, 0xcc, 0x67, 0x5d, 0xec, 0x3a, 0xff, 0xf3, 0x04, 0x61, 0x6e, 0x9d,
-    0x7f, 0x76, 0x0e, 0xa8, 0x3d, 0xff, 0xc5, 0x6f, 0xf7, 0x52, 0x67, 0x6e,
-    0xa4, 0x75, 0xfc, 0x3e, 0x75, 0xa7, 0x8e, 0xbf, 0xf2, 0x7b, 0xfe, 0x3e,
-    0xbe, 0x2f, 0xc7, 0x54, 0x1f, 0x63, 0x95, 0xdf, 0xf6, 0x26, 0x2c, 0x72,
-    0x77, 0x3a, 0xfd, 0x1e, 0xd0, 0x3f, 0x3a, 0x98, 0x84, 0xec, 0x31, 0xc9,
-    0xa4, 0x5d, 0x84, 0xf8, 0x90, 0x78, 0xd6, 0xff, 0xfd, 0xd1, 0xcf, 0x75,
-    0x33, 0x7f, 0x66, 0xc8, 0xd1, 0xd7, 0xff, 0x38, 0xf6, 0x10, 0x29, 0xac,
-    0x91, 0xd7, 0xa0, 0x1f, 0x4e, 0xbf, 0xb3, 0x67, 0x50, 0x13, 0x1d, 0x58,
-    0x8e, 0x17, 0x55, 0x14, 0x0d, 0x0e, 0xde, 0xfa, 0x1c, 0x3a, 0xf3, 0x07,
-    0x4c, 0x23, 0xa9, 0xcf, 0x07, 0x43, 0xb7, 0xdf, 0x17, 0xf1, 0xa7, 0x5f,
-    0xe1, 0x76, 0x63, 0xd9, 0x39, 0xd7, 0xed, 0xd9, 0x9b, 0x50, 0x75, 0x95,
-    0x61, 0x33, 0x48, 0xa2, 0x31, 0xf0, 0xc2, 0x2b, 0x25, 0x05, 0xb6, 0x16,
-    0xbb, 0xaa, 0xcd, 0x0c, 0x3e, 0x42, 0xb1, 0x64, 0x5d, 0x86, 0xe8, 0x1d,
-    0xc6, 0x34, 0xed, 0x47, 0xa5, 0xe8, 0xd0, 0x7f, 0x7b, 0x64, 0x87, 0x6c,
-    0x9b, 0xe9, 0x95, 0xff, 0xf7, 0x13, 0x79, 0x69, 0x3d, 0xd8, 0xe7, 0xa0,
-    0xeb, 0xf7, 0x1a, 0xee, 0xd3, 0x45, 0x5d, 0x7b, 0x90, 0xb3, 0xaf, 0xfa,
-    0x4a, 0xe7, 0x1a, 0xee, 0xd3, 0x44, 0x79, 0x7f, 0xd1, 0x28, 0xe4, 0xf1,
-    0xc9, 0xce, 0xbf, 0xf4, 0x79, 0x3f, 0x60, 0xe4, 0xa7, 0x98, 0xeb, 0x2a,
-    0x14, 0xd7, 0xf1, 0x3f, 0x86, 0x6e, 0x36, 0x28, 0xba, 0x39, 0xbf, 0x71,
-    0xae, 0xed, 0x34, 0x58, 0x37, 0x94, 0x89, 0xce, 0xbf, 0xff, 0x87, 0xf7,
-    0x9d, 0x79, 0xb7, 0xff, 0x33, 0x92, 0xfb, 0x23, 0xaf, 0xd8, 0x39, 0xed,
-    0x1d, 0x7f, 0xb8, 0xeb, 0xfb, 0xc7, 0xdc, 0xeb, 0x2b, 0x89, 0x86, 0x28,
-    0x66, 0xd1, 0xd7, 0x62, 0xfa, 0x4b, 0x7f, 0x95, 0xce, 0x35, 0xdd, 0xa6,
-    0x8b, 0x2a, 0xfd, 0xc6, 0xbb, 0xb4, 0xd1, 0x69, 0xdf, 0xf3, 0x87, 0xaf,
-    0x37, 0x51, 0x67, 0x59, 0x5c, 0x3e, 0xb5, 0x99, 0xdf, 0x98, 0x7b, 0x14,
-    0x62, 0x18, 0x86, 0x2c, 0xeb, 0xfe, 0x61, 0x75, 0x19, 0x0b, 0xbb, 0x4e,
-    0xbf, 0x30, 0xf6, 0x06, 0xb2, 0x0e, 0xbf, 0xdf, 0x57, 0x9e, 0xd2, 0x68,
-    0xeb, 0x21, 0xd4, 0xc2, 0x3c, 0x3d, 0xb3, 0x4b, 0xff, 0xf9, 0x3a, 0xe3,
-    0xe9, 0x67, 0x32, 0x04, 0x73, 0xc7, 0x5f, 0xb6, 0x38, 0x71, 0x67, 0x5f,
-    0x2e, 0x37, 0xd1, 0xd7, 0xff, 0x26, 0x38, 0x22, 0x5c, 0x8c, 0x13, 0xaa,
-    0x48, 0xde, 0xc5, 0x59, 0x8a, 0x04, 0x8a, 0xfd, 0xf3, 0x9c, 0xff, 0xa7,
-    0x5f, 0x91, 0x48, 0x16, 0x9d, 0x6c, 0xd1, 0xe8, 0xf8, 0xae, 0xff, 0xf8,
-    0x5b, 0xd4, 0xea, 0x72, 0x26, 0x67, 0x3a, 0x75, 0xff, 0x96, 0xb7, 0x96,
-    0xdf, 0xfd, 0x4e, 0x1d, 0x7e, 0x7d, 0x7a, 0x02, 0x75, 0x41, 0xf4, 0x7e,
-    0x85, 0x50, 0x8d, 0x9e, 0xc2, 0xde, 0xfa, 0x3e, 0xc7, 0x4e, 0xbe, 0x6b,
-    0xbb, 0x4d, 0x16, 0xe5, 0xf4, 0xd0, 0x1c, 0x3a, 0xff, 0xd9, 0xcc, 0x1f,
-    0x9d, 0xcd, 0xd9, 0x3a, 0xfc, 0x20, 0x7d, 0xf4, 0x75, 0x41, 0xf3, 0xba,
-    0x05, 0x6e, 0x8f, 0x7e, 0x11, 0x39, 0x6e, 0xa1, 0x11, 0x7f, 0x9c, 0x41,
-    0x30, 0xc2, 0xce, 0xbc, 0xb1, 0x43, 0xac, 0x27, 0x5f, 0xf7, 0x7f, 0x7d,
-    0x66, 0x0a, 0x87, 0x5f, 0xb4, 0xfb, 0xb8, 0x4e, 0xb2, 0x04, 0xf7, 0xfc,
-    0x71, 0x50, 0x8a, 0xfc, 0x1a, 0xeb, 0x75, 0xff, 0x43, 0x8f, 0x73, 0x05,
-    0xa7, 0x5f, 0xef, 0x79, 0x27, 0x5c, 0x09, 0xd5, 0x23, 0xe6, 0xc3, 0x4b,
-    0xfe, 0x81, 0xfd, 0x71, 0xaf, 0x21, 0xd7, 0xa3, 0x38, 0x75, 0xfe, 0xec,
-    0x49, 0x36, 0xf1, 0x67, 0x50, 0x4f, 0x3b, 0x43, 0x57, 0xef, 0x9b, 0xe9,
-    0x14, 0x3a, 0xcf, 0x39, 0xe6, 0xee, 0x45, 0x7f, 0xf4, 0xb3, 0xa9, 0xc0,
-    0xf6, 0x05, 0xa7, 0x5f, 0xed, 0xe5, 0x03, 0xec, 0x01, 0xd7, 0xda, 0x02,
-    0x78, 0xea, 0x74, 0x5f, 0x68, 0xa7, 0xf4, 0x2f, 0xa6, 0x57, 0xff, 0x79,
-    0x01, 0x12, 0x0f, 0x60, 0x5a, 0x75, 0xfd, 0xe9, 0x67, 0x33, 0x47, 0x51,
-    0xd7, 0xbf, 0x7f, 0x1d, 0x77, 0xf0, 0x75, 0x48, 0xd9, 0x78, 0x72, 0x8e,
-    0xbe, 0xdd, 0xa9, 0xc3, 0xaf, 0x42, 0xd5, 0xc4, 0x44, 0xee, 0x78, 0xb2,
-    0x1f, 0x05, 0x54, 0x26, 0x8d, 0x88, 0x49, 0x0b, 0x5b, 0xc3, 0xed, 0xb3,
-    0xaf, 0x7c, 0x62, 0xd8, 0xb3, 0xaf, 0xfa, 0x4a, 0xe7, 0x1a, 0xee, 0xd3,
-    0x45, 0x0f, 0x48, 0x88, 0xb9, 0x87, 0x9c, 0xa2, 0xfc, 0x08, 0x6e, 0x2c,
-    0xeb, 0xe8, 0x9b, 0x02, 0x75, 0x70, 0xf1, 0xf4, 0x4d, 0x7f, 0xd9, 0x01,
-    0xec, 0x6d, 0x44, 0xc7, 0x5f, 0xe0, 0x27, 0x7b, 0x80, 0x73, 0xa9, 0x67,
-    0xd6, 0x03, 0xaa, 0x84, 0x57, 0xbc, 0x23, 0x6f, 0xfc, 0xe1, 0x80, 0xf5,
-    0x05, 0x16, 0x75, 0xff, 0xb6, 0x3f, 0x34, 0xfd, 0xd4, 0x4e, 0x75, 0xfe,
-    0xd7, 0xed, 0xcf, 0x0c, 0x1d, 0x4b, 0x45, 0x6f, 0x4e, 0xfc, 0x81, 0x7f,
-    0xf7, 0xf2, 0xeb, 0xf3, 0x7f, 0x42, 0x4e, 0x75, 0xfe, 0x94, 0x72, 0x78,
-    0xe4, 0xe7, 0x5f, 0x9f, 0x5b, 0x33, 0x47, 0x54, 0x1e, 0xe0, 0x0d, 0x2f,
-    0xc9, 0xed, 0x3a, 0x1d, 0x7f, 0xdc, 0x07, 0x1c, 0x7d, 0x80, 0x3a, 0x80,
-    0x7b, 0x9f, 0x92, 0xde, 0xfb, 0xc9, 0x1d, 0x7f, 0x7d, 0xf7, 0xf1, 0x93,
-    0x9d, 0x52, 0x3c, 0xe9, 0x87, 0xaf, 0xfe, 0x68, 0xc7, 0x87, 0x36, 0x67,
-    0x24, 0x75, 0xff, 0x7e, 0x2a, 0x7d, 0xef, 0x7f, 0xd1, 0xd7, 0xf8, 0x45,
-    0xfd, 0xf6, 0x1a, 0x75, 0xf0, 0x82, 0x70, 0x1d, 0x58, 0x7a, 0x88, 0x65,
-    0x7f, 0xb5, 0xf3, 0xdf, 0x03, 0x82, 0x75, 0x80, 0x75, 0x93, 0x73, 0xc6,
-    0xe1, 0xb5, 0xf9, 0xf7, 0xd7, 0x90, 0xea, 0x84, 0xeb, 0x70, 0x8d, 0x10,
-    0xfb, 0x09, 0x21, 0x66, 0xd1, 0x45, 0xf9, 0xff, 0x52, 0x3e, 0x9d, 0x7e,
-    0x61, 0x67, 0x23, 0x47, 0x54, 0xc7, 0xa8, 0x25, 0x57, 0xfc, 0xfa, 0x89,
-    0xb7, 0x96, 0x6c, 0x3a, 0xff, 0xfc, 0x1e, 0xc7, 0xd5, 0x7c, 0x2e, 0x0d,
-    0x6a, 0x00, 0x55, 0xc1, 0xc3, 0xaf, 0xd3, 0xc4, 0xef, 0xa3, 0xab, 0x11,
-    0x28, 0x8a, 0xee, 0x2b, 0x70, 0x3f, 0x3a, 0xfe, 0x70, 0x4c, 0x30, 0x13,
-    0xaf, 0xf8, 0x72, 0x70, 0xf7, 0x07, 0xc7, 0x54, 0x1f, 0xd7, 0x45, 0xc4,
-    0xb2, 0xca, 0xb1, 0x2d, 0x91, 0x2b, 0x16, 0x86, 0xc5, 0x0f, 0x18, 0x67,
-    0x38, 0x8c, 0x1e, 0x50, 0x8d, 0x0c, 0x60, 0x19, 0x18, 0xf2, 0x88, 0x4d,
-    0x87, 0x06, 0xf0, 0x94, 0x42, 0x19, 0xa3, 0x90, 0xe4, 0x70, 0xab, 0x85,
-    0xf7, 0x63, 0x25, 0x78, 0x69, 0x80, 0xc0, 0x61, 0x45, 0xa7, 0xdf, 0x4a,
-    0x1e, 0xfe, 0x15, 0xbb, 0x08, 0xb6, 0xe1, 0x9f, 0xf6, 0x14, 0xf7, 0xd1,
-    0xc9, 0x2c, 0xeb, 0xcf, 0xc5, 0x0e, 0xb2, 0xb3, 0x9b, 0xd6, 0x48, 0x6f,
-    0xf2, 0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x79, 0xd4, 0x3a, 0x88, 0x89, 0x38,
-    0x06, 0x30, 0x2c, 0xa6, 0xa9, 0x6f, 0x2a, 0x7f, 0x91, 0xb4, 0x2d, 0x4f,
-    0xb0, 0xaa, 0x1a, 0xc9, 0x37, 0x52, 0x82, 0xb6, 0x15, 0x5f, 0xe5, 0x73,
-    0x8d, 0x77, 0x69, 0xa2, 0x96, 0xbf, 0x71, 0xae, 0xed, 0x34, 0x58, 0x57,
-    0xff, 0xe8, 0xc1, 0x0c, 0x76, 0x37, 0xf6, 0x0b, 0xac, 0xeb, 0xfb, 0xfe,
-    0x24, 0xee, 0xb3, 0xac, 0xae, 0x22, 0xc9, 0x66, 0x7b, 0x6a, 0x37, 0xf9,
-    0x5c, 0xe3, 0x5d, 0xda, 0x68, 0xb2, 0xee, 0xe2, 0x87, 0x5f, 0x2a, 0xa3,
-    0x0c, 0xc4, 0x9d, 0x45, 0x5e, 0x57, 0xea, 0xce, 0xa6, 0x9e, 0xbe, 0x8b,
-    0xbf, 0x0a, 0xa1, 0x44, 0xf6, 0x9b, 0xae, 0x8e, 0x9d, 0x60, 0x1d, 0x72,
-    0x93, 0x9d, 0x6e, 0x48, 0xd4, 0x60, 0x85, 0x34, 0xf8, 0xdc, 0xf6, 0xff,
-    0x9f, 0x71, 0xcd, 0xfd, 0x0a, 0x1d, 0x7f, 0xa7, 0xdf, 0x50, 0x1f, 0x21,
-    0xd7, 0xe8, 0xcd, 0x91, 0xa3, 0xad, 0x0e, 0x7b, 0x6c, 0x9a, 0x53, 0xa2,
-    0xec, 0x61, 0x29, 0x7c, 0xf2, 0x90, 0x4e, 0xbf, 0x9f, 0x91, 0xe7, 0xe9,
-    0xd7, 0x99, 0x65, 0x92, 0xaf, 0xfa, 0x25, 0xbf, 0xb9, 0x19, 0xb9, 0x4a,
-    0x97, 0xf7, 0xfd, 0xfb, 0xef, 0x9e, 0x4d, 0xd9, 0x3a, 0xe8, 0xd1, 0xd4,
-    0x14, 0xc1, 0x3a, 0x42, 0x29, 0x5a, 0x49, 0xd8, 0x77, 0x73, 0x0c, 0xc4,
-    0x9d, 0x7f, 0x23, 0xe8, 0x1a, 0xfc, 0xeb, 0xff, 0x92, 0x4f, 0xa7, 0x1f,
-    0xdb, 0x9a, 0x2a, 0xff, 0xfe, 0xea, 0x7b, 0xb9, 0xa1, 0xc5, 0xff, 0xae,
-    0xbc, 0x8e, 0xbf, 0xd1, 0x2f, 0x3f, 0x5c, 0x27, 0x54, 0x23, 0x37, 0x10,
-    0xb8, 0xb5, 0x69, 0x1d, 0x69, 0x1d, 0x69, 0x1d, 0x50, 0x6c, 0x14, 0x10,
-    0x41, 0x0b, 0xfb, 0xfd, 0x75, 0xe5, 0x87, 0x5f, 0xff, 0x69, 0x1b, 0x83,
-    0xc8, 0x1c, 0x0e, 0x28, 0x75, 0x2c, 0xfe, 0x7c, 0x5b, 0x6d, 0xce, 0xb2,
-    0x87, 0x5b, 0xf3, 0xa8, 0x4d, 0x16, 0x84, 0x6b, 0x0f, 0xd7, 0x44, 0x5e,
-    0x33, 0xb9, 0x20, 0xeb, 0xf8, 0x61, 0x63, 0x18, 0x75, 0xd2, 0x83, 0xa8,
-    0x27, 0xa5, 0x30, 0xa7, 0xe5, 0x37, 0xff, 0xff, 0xdd, 0x8f, 0x69, 0x35,
-    0xa8, 0xf7, 0x52, 0x38, 0x05, 0xbc, 0xa5, 0xe5, 0x0e, 0xb9, 0x37, 0x3a,
-    0xe8, 0x59, 0xd7, 0xff, 0xe8, 0x1f, 0xe5, 0x28, 0xf7, 0x71, 0x7f, 0x60,
-    0x07, 0x5f, 0xff, 0x20, 0xff, 0x2c, 0xd7, 0x21, 0x24, 0xfa, 0x2a, 0xa4,
-    0x8a, 0x3f, 0x2b, 0x5c, 0xd5, 0x61, 0x7e, 0x26, 0x78, 0x42, 0x86, 0x1b,
-    0x99, 0x19, 0x52, 0x89, 0x8d, 0x20, 0xe4, 0x3e, 0x9d, 0x78, 0x63, 0x1b,
-    0xd4, 0x20, 0x3c, 0x63, 0xb1, 0xf7, 0x6c, 0x5b, 0xec, 0x2e, 0x2f, 0xff,
-    0x2a, 0xb7, 0x92, 0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x46, 0x5f, 0xb6, 0x47,
-    0x20, 0x07, 0x5f, 0x85, 0xc1, 0x1f, 0x4e, 0xbf, 0xfb, 0x76, 0xa7, 0x3b,
-    0x98, 0x32, 0xd1, 0xd6, 0x56, 0x11, 0x25, 0xd2, 0x8f, 0x13, 0xd4, 0x99,
-    0x75, 0x1c, 0x87, 0x8a, 0xce, 0x5e, 0x90, 0xcd, 0xa8, 0x7c, 0xfa, 0x1d,
-    0x37, 0xff, 0x2a, 0xf2, 0x57, 0x38, 0xd7, 0x76, 0x9a, 0x23, 0x9b, 0xff,
-    0xca, 0xad, 0xe4, 0xae, 0x71, 0xae, 0xed, 0x34, 0x4e, 0x57, 0xf9, 0x5c,
-    0xe3, 0x5d, 0xda, 0x68, 0xb3, 0x2f, 0xfa, 0x5a, 0x75, 0xab, 0xdf, 0x00,
-    0xeb, 0xfe, 0x61, 0xc1, 0xc5, 0xc6, 0xf0, 0xb3, 0xaf, 0xf7, 0x23, 0xdd,
-    0x7d, 0xe4, 0x75, 0xff, 0xff, 0xf4, 0x4d, 0xd8, 0xf4, 0x7d, 0x4e, 0x4d,
-    0x1d, 0xcd, 0x99, 0xdc, 0x0e, 0xcc, 0x3a, 0x80, 0x8b, 0x41, 0x33, 0xbf,
-    0xd9, 0xae, 0x73, 0x37, 0xd1, 0xd7, 0xec, 0xf7, 0x31, 0x67, 0x5f, 0xf9,
-    0x06, 0x35, 0x1e, 0x9f, 0x19, 0x3a, 0xfe, 0xe3, 0x7a, 0xe8, 0xc1, 0x3a,
-    0xed, 0xd6, 0x75, 0x95, 0x62, 0x53, 0xf1, 0x88, 0x79, 0x48, 0x88, 0x26,
-    0x6b, 0x26, 0xfc, 0xf7, 0x6c, 0xc2, 0xff, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d,
-    0x16, 0xed, 0xfc, 0x2e, 0xaf, 0x27, 0xe9, 0xd7, 0x93, 0x70, 0x1d, 0x7e,
-    0xe3, 0x5d, 0xda, 0x68, 0xa4, 0x2f, 0xfd, 0x9d, 0x4d, 0x9d, 0xcc, 0x16,
-    0x9d, 0x79, 0xe4, 0xae, 0x1f, 0x86, 0x8c, 0xec, 0xab, 0x51, 0xdb, 0xc2,
-    0xe5, 0xc2, 0x32, 0xff, 0xe5, 0x5e, 0x4a, 0xe7, 0x1a, 0xee, 0xd3, 0x44,
-    0xa5, 0x53, 0xae, 0xa2, 0x4c, 0xa2, 0xb5, 0x77, 0x3f, 0x04, 0xa2, 0xb1,
-    0x79, 0xf4, 0x65, 0x9b, 0x47, 0x97, 0xfa, 0x48, 0x3e, 0xc4, 0x09, 0xd7,
-    0xb5, 0xfa, 0xce, 0xb2, 0xbb, 0x9e, 0x6a, 0x18, 0x5e, 0x17, 0x91, 0xd7,
-    0xfe, 0x79, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x13, 0xb5, 0xd3, 0xb1, 0x9d,
-    0x7f, 0xfe, 0x40, 0xfe, 0xb8, 0xda, 0x70, 0x8c, 0x0e, 0x34, 0xeb, 0xfd,
-    0x28, 0xe4, 0xf1, 0xc9, 0xce, 0xbf, 0xf7, 0x45, 0xe5, 0xf8, 0x16, 0xf2,
-    0x3a, 0xa0, 0xfc, 0xb0, 0xd2, 0xca, 0xe2, 0x6c, 0xab, 0x1a, 0xea, 0x53,
-    0x8d, 0x0c, 0x31, 0xef, 0xff, 0x95, 0xfb, 0xb6, 0xe2, 0x0c, 0xf4, 0x0a,
-    0x00, 0xeb, 0xff, 0x9d, 0x7d, 0xc6, 0xbf, 0x63, 0xec, 0x8e, 0xbc, 0x81,
-    0x73, 0xaf, 0xfe, 0x1c, 0xeb, 0xcf, 0x9a, 0x17, 0xdc, 0xeb, 0xb6, 0xd5,
-    0x0a, 0x28, 0x3a, 0x89, 0xa1, 0xaa, 0x92, 0xb1, 0x45, 0xc7, 0x1d, 0xa5,
-    0x4d, 0xb8, 0x79, 0x5f, 0xff, 0xc1, 0x7f, 0x2b, 0x9a, 0x81, 0xdc, 0x1a,
-    0xd4, 0x00, 0xeb, 0xf7, 0x1a, 0xee, 0xd3, 0x44, 0x59, 0x7f, 0xe7, 0x92,
-    0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x2e, 0xdf, 0xff, 0xd8, 0x1e, 0xc7, 0xd5,
-    0x7c, 0x2e, 0x0d, 0x6a, 0x00, 0x55, 0x95, 0xc4, 0x6c, 0xac, 0xcf, 0x6d,
-    0x2a, 0xff, 0xe5, 0xbc, 0x95, 0xce, 0x35, 0xdd, 0xa6, 0x89, 0x8a, 0xff,
-    0xfb, 0x1b, 0x0a, 0xf5, 0xd3, 0x6d, 0x01, 0x81, 0x3a, 0x95, 0x45, 0x07,
-    0x54, 0x2f, 0xdc, 0x6b, 0xbb, 0x4d, 0x15, 0x4d, 0xb0, 0xea, 0xc3, 0xc2,
-    0x50, 0xce, 0xff, 0xdf, 0xbf, 0x24, 0x38, 0xcb, 0x80, 0xeb, 0xff, 0x9f,
-    0x5c, 0x46, 0x7d, 0xd4, 0xe4, 0x8e, 0xbf, 0xee, 0x3f, 0x77, 0x96, 0x79,
-    0x50, 0xa2, 0x0b, 0xa7, 0xd4, 0xaa, 0x3d, 0xde, 0x14, 0x97, 0xff, 0x95,
-    0x5b, 0xc9, 0x5c, 0xe3, 0x5d, 0xda, 0x68, 0x9d, 0x2f, 0xf2, 0x3f, 0x22,
-    0x4f, 0xb0, 0xeb, 0xf4, 0xd1, 0x34, 0x68, 0xeb, 0xf9, 0x9c, 0x4d, 0x98,
-    0x27, 0x52, 0x1e, 0xae, 0x8a, 0x2f, 0x27, 0x60, 0xe5, 0x4d, 0x0d, 0xff,
-    0xdf, 0xeb, 0xd1, 0xba, 0xbf, 0xcc, 0x8b, 0x3a, 0x96, 0x7e, 0x9d, 0x2b,
-    0xbf, 0xf3, 0xc9, 0x5c, 0xe3, 0x5d, 0xda, 0x68, 0x9d, 0xef, 0xde, 0xfd,
-    0xd6, 0x85, 0x5f, 0xf8, 0x63, 0xd9, 0xac, 0xcd, 0xe4, 0x75, 0x05, 0x3e,
-    0xbc, 0x8c, 0x71, 0x64, 0x4e, 0x95, 0xe2, 0x7b, 0xfe, 0x0c, 0x4a, 0x15,
-    0x67, 0x40, 0x3a, 0xfe, 0x85, 0x40, 0x38, 0x13, 0xa9, 0x54, 0x5a, 0xe2,
-    0x78, 0x9d, 0x5f, 0xfe, 0x55, 0x6f, 0x25, 0x73, 0x8d, 0x77, 0x69, 0xa2,
-    0x85, 0xbf, 0xff, 0xfd, 0xdf, 0xd6, 0xb7, 0x92, 0xad, 0xef, 0xfe, 0x81,
-    0xc9, 0xd4, 0xfe, 0x26, 0x3a, 0xfd, 0xfe, 0xfe, 0x46, 0x9d, 0x7e, 0xc0,
-    0x63, 0x89, 0xd7, 0xda, 0x46, 0x7c, 0x75, 0xe8, 0x02, 0xb3, 0x9f, 0x78,
-    0x94, 0xf8, 0x92, 0x91, 0x32, 0xe1, 0x87, 0x6d, 0xff, 0xe5, 0x56, 0xf2,
-    0x57, 0x38, 0xd7, 0x76, 0x9a, 0x29, 0x2b, 0xff, 0xfd, 0x9a, 0x57, 0xee,
-    0x4d, 0xd7, 0x5f, 0xbb, 0x1e, 0xfd, 0x67, 0x54, 0x32, 0x48, 0x27, 0x8c,
-    0xd2, 0x50, 0xd9, 0x6c, 0x6b, 0xbc, 0x28, 0x5c, 0xaf, 0x70, 0x17, 0xfa,
-    0x38, 0x5f, 0xc9, 0xf6, 0xd5, 0xef, 0xf2, 0xb9, 0xc6, 0xbb, 0xb4, 0xd1,
-    0x12, 0x5f, 0xfe, 0x55, 0x6f, 0x25, 0x73, 0x8d, 0x77, 0x69, 0xa2, 0x5e,
-    0xbc, 0xc4, 0xac, 0x07, 0x5f, 0x73, 0xff, 0x68, 0xeb, 0xf7, 0x00, 0xb4,
-    0xd1, 0xd7, 0xa0, 0x77, 0x3a, 0xfd, 0xef, 0xab, 0x18, 0x3a, 0xc9, 0xd3,
-    0xc3, 0x11, 0xbb, 0xff, 0xdd, 0xd9, 0x02, 0x06, 0x3c, 0x0e, 0x73, 0x73,
-    0xae, 0x8f, 0x1d, 0x7f, 0xfb, 0xf0, 0xa7, 0x3e, 0xcd, 0xb5, 0xfb, 0x8c,
-    0xc7, 0x54, 0x91, 0xb6, 0x84, 0xc0, 0x4e, 0xd0, 0xad, 0xfc, 0x0e, 0xc7,
-    0x11, 0x67, 0x5f, 0xfa, 0x6d, 0x46, 0xc7, 0xec, 0x6f, 0x31, 0xd5, 0x07,
-    0xdc, 0xe5, 0x97, 0xec, 0x9f, 0x34, 0xb3, 0xaf, 0xfe, 0x9b, 0xe7, 0xd1,
-    0x8d, 0x8f, 0xb2, 0x26, 0x3a, 0x8e, 0xbf, 0xa6, 0x93, 0xf9, 0xf6, 0x1d,
-    0x50, 0x88, 0x5c, 0x4c, 0x70, 0xab, 0xb9, 0x07, 0x50, 0x55, 0x90, 0x21,
-    0x1c, 0xd1, 0xa2, 0xf2, 0x15, 0x42, 0x41, 0xb2, 0x15, 0x9b, 0x45, 0xb7,
-    0x83, 0x82, 0x75, 0xc1, 0xdc, 0xeb, 0xf8, 0x7f, 0xf4, 0xd0, 0xa1, 0xd7,
-    0x98, 0x29, 0xc3, 0xac, 0x8e, 0x79, 0xdf, 0x97, 0xdf, 0x87, 0x27, 0xfb,
-    0xb0, 0xeb, 0xec, 0x9f, 0xee, 0xc3, 0xaf, 0xc1, 0x8d, 0xc2, 0xff, 0x0f,
-    0x44, 0x4a, 0xef, 0xff, 0x93, 0x9f, 0x3b, 0x09, 0xed, 0x7e, 0xdf, 0xe0,
-    0xeb, 0xe4, 0x9c, 0x0c, 0x67, 0x5f, 0x35, 0xdd, 0xa6, 0x8a, 0x5e, 0xf8,
-    0x7d, 0x1c, 0x3a, 0xff, 0xb3, 0x8c, 0x78, 0x1c, 0xe6, 0xe7, 0x52, 0x1e,
-    0xde, 0xc2, 0x0a, 0x92, 0x6c, 0x4a, 0x20, 0x4c, 0xa5, 0xc2, 0x5e, 0xc2,
-    0x22, 0xfe, 0x0e, 0xf1, 0xc4, 0xdc, 0xeb, 0xef, 0x4f, 0x8c, 0x9d, 0x48,
-    0x7a, 0x22, 0x5d, 0x7f, 0xe8, 0x18, 0xef, 0xcf, 0xc7, 0xf6, 0x9d, 0x7b,
-    0xf7, 0xd1, 0xd7, 0xd3, 0x7e, 0xf3, 0x1d, 0x7e, 0x80, 0x3e, 0xfa, 0x3a,
-    0xf0, 0xa0, 0x0e, 0xbd, 0x9e, 0xd1, 0xd5, 0x06, 0xd7, 0x43, 0x54, 0x14,
-    0x7e, 0x4c, 0x81, 0xd1, 0xc0, 0x12, 0x79, 0x72, 0xfc, 0xc6, 0xe2, 0x1d,
-    0xa3, 0xaf, 0xf8, 0x1a, 0xe4, 0x6f, 0x24, 0x59, 0xd7, 0xbc, 0xfb, 0x0e,
-    0xbf, 0x4f, 0xfc, 0xd0, 0xc6, 0x75, 0xf7, 0xf3, 0x43, 0x19, 0xd7, 0x3c,
-    0xff, 0x0f, 0x4e, 0x72, 0xda, 0x84, 0x6d, 0x39, 0xcf, 0xee, 0x17, 0xfc,
-    0x9a, 0x99, 0x07, 0xd0, 0x03, 0xaa, 0x47, 0xcc, 0xb2, 0xfb, 0xfd, 0x0c,
-    0x7a, 0x85, 0xbf, 0x8e, 0xb9, 0xc4, 0xeb, 0xfe, 0x80, 0x7c, 0xec, 0x2d,
-    0xc4, 0xea, 0xdc, 0xf3, 0x36, 0x0a, 0x54, 0x91, 0x4b, 0xc8, 0x40, 0x5f,
-    0xdb, 0xcb, 0x4e, 0x3b, 0x9d, 0x50, 0xaa, 0x27, 0x23, 0x6c, 0x48, 0x63,
-    0xfd, 0x28, 0xbd, 0xc8, 0x59, 0xd7, 0xf4, 0x0c, 0xde, 0x45, 0x0e, 0xbf,
-    0xe9, 0x67, 0x26, 0xc1, 0x85, 0x9d, 0x7e, 0x04, 0x37, 0x16, 0x75, 0x21,
-    0xee, 0xf0, 0xde, 0xe9, 0x61, 0xd7, 0xdc, 0x18, 0x59, 0xd7, 0xa0, 0x1a,
-    0x3a, 0xa0, 0xfc, 0x42, 0x43, 0x82, 0xac, 0x90, 0x5f, 0xbb, 0xfa, 0x98,
-    0x27, 0x5f, 0xf4, 0x77, 0x4f, 0xe8, 0xe6, 0xd1, 0xd7, 0xfe, 0x5b, 0x87,
-    0xec, 0xd2, 0x81, 0xdc, 0xea, 0x09, 0xfd, 0xa1, 0xd5, 0xf7, 0x01, 0xf7,
-    0x61, 0xd7, 0x91, 0x9f, 0x1d, 0x5d, 0x3c, 0x2d, 0x13, 0x50, 0x53, 0x28,
-    0xec, 0x28, 0xfc, 0xc7, 0x7f, 0xc0, 0x4e, 0xe7, 0x1e, 0x6d, 0x1d, 0x7f,
-    0xfe, 0x89, 0x0c, 0x4f, 0xf6, 0x6d, 0x77, 0x36, 0xb8, 0x03, 0xaf, 0xef,
-    0x8b, 0xcf, 0x3f, 0x8e, 0xb3, 0x4e, 0xbb, 0x7d, 0x61, 0xbe, 0x72, 0xeb,
-    0xd0, 0x81, 0x3a, 0xb7, 0x4c, 0x5d, 0x67, 0x0f, 0x09, 0x9d, 0x16, 0x5f,
-    0xec, 0x66, 0x49, 0xaf, 0xd6, 0x75, 0xdb, 0x34, 0x75, 0xfb, 0x27, 0xce,
-    0xe8, 0xea, 0x83, 0x7e, 0x23, 0x17, 0xb3, 0x9a, 0x3a, 0x9a, 0x6e, 0xb6,
-    0x0f, 0xdf, 0xf0, 0x20, 0x1f, 0x76, 0x40, 0xed, 0x1d, 0x50, 0x98, 0x76,
-    0x42, 0xb5, 0x08, 0xef, 0xff, 0xfe, 0xec, 0x73, 0x76, 0xa6, 0xff, 0x14,
-    0x7f, 0x9a, 0xeb, 0xb6, 0x04, 0x27, 0x5f, 0x22, 0x9b, 0x78, 0x75, 0xfd,
-    0xf7, 0xd1, 0x38, 0xee, 0x75, 0xe1, 0x45, 0x9d, 0x5c, 0x3e, 0xe0, 0x12,
-    0x78, 0xc2, 0xff, 0x0c, 0x38, 0xfb, 0x04, 0xeb, 0xfd, 0xd7, 0x99, 0x39,
-    0x13, 0x9d, 0x76, 0x2c, 0xea, 0x0a, 0x71, 0x59, 0x0e, 0x55, 0x97, 0xb9,
-    0x76, 0xc3, 0x3b, 0xf6, 0xd2, 0x2e, 0x34, 0x75, 0xf9, 0xf6, 0x67, 0x34,
-    0x75, 0x04, 0xf4, 0x56, 0x53, 0x7e, 0xeb, 0x8a, 0x2c, 0xeb, 0xe5, 0x26,
-    0xd4, 0x1d, 0x7f, 0x03, 0x70, 0x67, 0x30, 0xeb, 0xf9, 0xc0, 0xb8, 0xcf,
-    0x1d, 0x50, 0x7b, 0x08, 0x5b, 0x7f, 0x9c, 0x1a, 0x8e, 0xc6, 0x8e, 0xa8,
-    0x4c, 0x4f, 0x08, 0x90, 0x97, 0xaf, 0x62, 0x41, 0x70, 0x1a, 0x75, 0xb4,
-    0x75, 0xc8, 0xa6, 0x8d, 0x37, 0xe2, 0xd7, 0x80, 0xed, 0x3a, 0xf9, 0x99,
-    0xb5, 0x07, 0x5f, 0xda, 0x17, 0x9e, 0x3c, 0x75, 0xfa, 0x77, 0xd6, 0x48,
-    0xeb, 0xff, 0xe0, 0xe6, 0xc7, 0xe4, 0xdf, 0x64, 0xfe, 0x75, 0x9d, 0x50,
-    0x7f, 0x48, 0x4f, 0x7f, 0x3e, 0xe0, 0x5a, 0x68, 0xea, 0x84, 0xcc, 0x77,
-    0x1b, 0x98, 0x8f, 0x90, 0xa6, 0xe9, 0x05, 0x95, 0x62, 0xdb, 0x59, 0x58,
-    0x96, 0x83, 0x3b, 0xd4, 0x86, 0x82, 0xcb, 0x91, 0xed, 0x6f, 0x0a, 0x34,
-    0x8c, 0x72, 0x69, 0x5a, 0x9c, 0x49, 0x58, 0xdf, 0x61, 0xf6, 0xf1, 0xb1,
-    0x82, 0x34, 0xd1, 0x8d, 0x47, 0x51, 0xde, 0xfa, 0x3b, 0x4d, 0xb6, 0xdf,
-    0xb1, 0xaf, 0xdf, 0xe5, 0x73, 0x8d, 0x77, 0x69, 0xa2, 0x9c, 0xbf, 0xf2,
-    0x71, 0xf5, 0xdc, 0xc1, 0x69, 0xd7, 0xe5, 0xf3, 0x99, 0xa3, 0xaf, 0xff,
-    0xdd, 0xff, 0xdc, 0x8f, 0x6b, 0x1b, 0xa8, 0xe3, 0x4e, 0xbf, 0xff, 0xbd,
-    0x93, 0x0a, 0x6b, 0xd1, 0xf5, 0x39, 0x34, 0x74, 0xeb, 0xfc, 0x8b, 0x0c,
-    0x6b, 0xf1, 0x3a, 0xfe, 0xcf, 0x6f, 0x28, 0x64, 0xeb, 0xff, 0x26, 0xfa,
-    0x1c, 0x0f, 0x5d, 0x93, 0xaf, 0xff, 0xb2, 0x7c, 0xdf, 0xda, 0x41, 0x80,
-    0x3a, 0xce, 0xa5, 0x11, 0x19, 0xa3, 0xeb, 0xff, 0x67, 0x63, 0x98, 0xab,
-    0x2c, 0xb2, 0x55, 0xc8, 0xc9, 0xd7, 0x4e, 0xa8, 0x55, 0x3d, 0xe1, 0xdb,
-    0x49, 0xd1, 0x5b, 0xab, 0x82, 0x65, 0xe8, 0x5d, 0x6d, 0x92, 0x6d, 0x20,
-    0xdf, 0xb8, 0xd7, 0x76, 0x9a, 0x2b, 0xcb, 0xff, 0xfb, 0x03, 0xd8, 0xfa,
-    0xaf, 0x85, 0xc1, 0xad, 0x40, 0x0a, 0xb2, 0xb8, 0x88, 0xfd, 0xb3, 0x3b,
-    0xff, 0x95, 0x79, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x12, 0x3d, 0xe6, 0xe2,
-    0xce, 0xbc, 0x80, 0x83, 0xaf, 0x37, 0x16, 0x52, 0xa5, 0xd5, 0xfb, 0x8d,
-    0x77, 0x69, 0xa2, 0x48, 0xbf, 0xff, 0xa1, 0x38, 0x9b, 0x50, 0x33, 0xc7,
-    0x93, 0xaf, 0x39, 0xd7, 0xff, 0x87, 0x01, 0xb7, 0x9c, 0x89, 0xdf, 0x8d,
-    0x3a, 0xe9, 0x2b, 0x09, 0x82, 0x61, 0x5f, 0x4c, 0xfc, 0xb7, 0x7e, 0xce,
-    0xab, 0x8b, 0x3a, 0xca, 0xc2, 0x75, 0x2f, 0x19, 0xcf, 0x92, 0x6f, 0xfe,
-    0x55, 0xe4, 0xae, 0x71, 0xae, 0xed, 0x34, 0x49, 0x57, 0xee, 0x35, 0xdd,
-    0xa6, 0x8b, 0xc6, 0xff, 0xa4, 0xae, 0x71, 0xae, 0xed, 0x34, 0x49, 0xb6,
-    0x57, 0x0f, 0xe1, 0xcc, 0xee, 0x67, 0xa7, 0x5f, 0x90, 0x1a, 0xc1, 0x3a,
-    0xff, 0xfb, 0xf7, 0xdf, 0x31, 0x45, 0x1e, 0x59, 0xbf, 0x8e, 0xa9, 0x1f,
-    0xbe, 0x89, 0x6f, 0x7d, 0x19, 0xce, 0xbb, 0x9e, 0x3a, 0xf4, 0xc3, 0x39,
-    0xd6, 0x13, 0xae, 0xfb, 0xf4, 0xea, 0x01, 0xa9, 0xfa, 0x1f, 0x76, 0xda,
-    0xb0, 0x9a, 0x6e, 0x42, 0x3b, 0xa4, 0x4e, 0x3d, 0xa1, 0x6f, 0xa8, 0xd5,
-    0x0e, 0x81, 0xc6, 0x73, 0xf9, 0x56, 0xbd, 0x81, 0x8d, 0x71, 0x25, 0x5d,
-    0x4d, 0x19, 0x2a, 0xcb, 0x3b, 0x1f, 0xd7, 0x8f, 0x3f, 0x86, 0x4f, 0xd8,
-    0xdd, 0x2a, 0x27, 0x1a, 0x07, 0xe7, 0x95, 0x2f, 0x29, 0xe0, 0x40, 0xce,
-    0xe4, 0x66, 0x26, 0xac, 0xd4, 0x9c, 0xce, 0x6d, 0xef, 0x09, 0x6f, 0x5a,
-    0x2b, 0x25, 0x27, 0xd5, 0x8e, 0x51, 0x3c, 0xd6, 0xd3, 0x6b, 0x96, 0x90,
-    0xed, 0x79, 0xc9, 0xf7, 0x76, 0x95, 0x76, 0xf6, 0xd8, 0x94, 0x14, 0x85,
-    0x36, 0x0c, 0x7d, 0xc3, 0x5b, 0x6d, 0xea, 0xb8, 0xd1, 0xf5, 0xee, 0x78,
-    0xff, 0x6d, 0x61, 0x76, 0x53, 0x1e, 0x19, 0x9d, 0xb6, 0xdb, 0x97, 0xcb,
-    0xf6, 0x92, 0xdb, 0xb5, 0x68, 0x48, 0xa8,
+    0x29, 0x7b, 0x65, 0x9f, 0x49, 0x36, 0x92, 0x6f, 0xd2, 0x18, 0xcd, 0x17,
+    0x10, 0xc2, 0xa9, 0xab, 0x5e, 0x48, 0x59, 0x71, 0x0c, 0x5f, 0x23, 0x5f,
+    0x87, 0xc4, 0x32, 0xf2, 0x07, 0x0f, 0x88, 0x65, 0x95, 0xdd, 0x18, 0x7c,
+    0x47, 0xe9, 0x47, 0x8b, 0x6d, 0x1b, 0x19, 0x4f, 0x3f, 0x69, 0x46, 0x97,
+    0xfb, 0xa8, 0xc8, 0x79, 0x13, 0x9d, 0x79, 0x36, 0x30, 0x4e, 0xad, 0xd1,
+    0x1d, 0x31, 0xcf, 0x8d, 0x2f, 0xd9, 0x93, 0x3f, 0xd3, 0xae, 0x04, 0x1d,
+    0x7f, 0x71, 0xc7, 0xec, 0x00, 0xeb, 0x9f, 0x87, 0x59, 0x0e, 0x69, 0x6b,
+    0x66, 0x9d, 0x65, 0x9d, 0x76, 0xda, 0xa8, 0x89, 0x5e, 0x0a, 0xf5, 0x09,
+    0xc7, 0xbe, 0x88, 0x5f, 0xf7, 0x61, 0x79, 0x34, 0x0c, 0xe7, 0x5f, 0xfd,
+    0xf1, 0xda, 0x1e, 0xc0, 0x30, 0x40, 0x75, 0xc0, 0x83, 0xab, 0x0f, 0x64,
+    0x08, 0x95, 0x89, 0x86, 0x01, 0x6b, 0xf8, 0x48, 0xdf, 0xfc, 0x23, 0x13,
+    0x8e, 0x26, 0xc8, 0xdb, 0x3a, 0xf4, 0x6f, 0xa3, 0xa9, 0xcf, 0x87, 0x48,
+    0xb7, 0x9f, 0x90, 0x75, 0xf9, 0x36, 0xdc, 0x40, 0x75, 0x48, 0xf0, 0x96,
+    0x35, 0x7f, 0xdf, 0x5c, 0x3a, 0xc5, 0xc3, 0x19, 0xd7, 0xb3, 0x76, 0x4e,
+    0xbd, 0xb8, 0x33, 0x87, 0xb2, 0x27, 0x97, 0xdb, 0x33, 0x92, 0x3a, 0xf0,
+    0x5c, 0x4e, 0xa4, 0x37, 0xae, 0x47, 0x7f, 0xfd, 0x1f, 0x1f, 0x9c, 0x70,
+    0x42, 0xac, 0xb2, 0xc9, 0xd5, 0x09, 0xaf, 0x3b, 0xde, 0x9c, 0x3f, 0x1f,
+    0xa6, 0x03, 0x73, 0x39, 0x0e, 0x53, 0xb7, 0xca, 0x32, 0x50, 0xc2, 0x7b,
+    0x21, 0x6c, 0xd8, 0xd2, 0x37, 0x57, 0x49, 0x4b, 0xec, 0x68, 0xb3, 0x42,
+    0xeb, 0x86, 0xeb, 0x85, 0x67, 0x61, 0x56, 0xf4, 0xb2, 0x70, 0x19, 0x0c,
+    0x79, 0x3a, 0x84, 0xbf, 0xa3, 0xc1, 0xbc, 0xbd, 0x34, 0xeb, 0xc2, 0xd8,
+    0x3a, 0xbe, 0x1b, 0x64, 0x1c, 0xbf, 0x99, 0x7e, 0x71, 0xf7, 0x3a, 0xff,
+    0xfd, 0xae, 0x71, 0x26, 0xd7, 0x23, 0xc8, 0xd4, 0x09, 0xd4, 0xb4, 0x52,
+    0x89, 0x13, 0x25, 0xd7, 0xcb, 0xf4, 0x68, 0xeb, 0xfd, 0xe8, 0xfd, 0xbd,
+    0x4e, 0x1d, 0x7f, 0x63, 0x7b, 0x1b, 0xc8, 0xeb, 0xf9, 0x7a, 0x45, 0x3c,
+    0xc9, 0xd7, 0xe8, 0xdf, 0xb1, 0x23, 0xa8, 0x51, 0x6d, 0xe3, 0x3f, 0xa5,
+    0xbb, 0x45, 0xf7, 0xfd, 0x9b, 0x8e, 0x7b, 0xd9, 0x39, 0xd7, 0x6f, 0xe3,
+    0xaf, 0xde, 0x71, 0xff, 0x0e, 0xbf, 0xda, 0xc5, 0xa7, 0xba, 0xe7, 0x5a,
+    0x30, 0xfb, 0x84, 0x5f, 0xc4, 0xd7, 0xd2, 0xf8, 0xb4, 0x3a, 0xf6, 0xd7,
+    0x20, 0xeb, 0xfd, 0xc4, 0x98, 0x73, 0x63, 0x9d, 0x76, 0xfa, 0xf8, 0x7e,
+    0x90, 0x47, 0xc1, 0xeb, 0xfe, 0x18, 0x79, 0xfb, 0x1c, 0x01, 0xd7, 0xf9,
+    0x38, 0x3e, 0xf6, 0x4e, 0x75, 0xcf, 0xb0, 0xeb, 0xfa, 0x42, 0x92, 0xee,
+    0x1d, 0x7e, 0x9d, 0x39, 0x12, 0x3a, 0x94, 0x44, 0xdc, 0xc6, 0x5c, 0x17,
+    0x12, 0xbb, 0xec, 0x0a, 0x28, 0x75, 0xff, 0xe7, 0x4f, 0x47, 0xb5, 0xd7,
+    0x4e, 0xfe, 0x75, 0xf0, 0x8f, 0xf2, 0x3a, 0xff, 0xdd, 0x8e, 0x00, 0x71,
+    0x97, 0x01, 0xd7, 0xb3, 0x26, 0x3a, 0xd9, 0xd3, 0xd8, 0x01, 0xed, 0xfd,
+    0xff, 0x3f, 0x5b, 0x89, 0xd7, 0xcb, 0x8c, 0x9c, 0xeb, 0xf6, 0x6c, 0x18,
+    0xdc, 0xea, 0x43, 0xc9, 0xd1, 0x0d, 0xf4, 0x0f, 0x9a, 0x75, 0x05, 0x56,
+    0x8e, 0x43, 0x4b, 0x87, 0xdd, 0x21, 0x74, 0x81, 0x79, 0xd1, 0x3f, 0x9d,
+    0xf6, 0xc8, 0x6f, 0xf0, 0x3e, 0xe0, 0x87, 0xb0, 0x75, 0x42, 0x2e, 0x1e,
+    0x10, 0xb7, 0xf6, 0xb1, 0x69, 0xd8, 0x3a, 0xf6, 0xf2, 0xd1, 0xd5, 0xb9,
+    0xe4, 0x70, 0xae, 0xf6, 0x80, 0xc9, 0xd5, 0x07, 0x81, 0x84, 0x77, 0xdf,
+    0xbf, 0x24, 0x75, 0xf4, 0x7e, 0xc1, 0xd1, 0x57, 0xe9, 0x2a, 0xcb, 0x2c,
+    0x9d, 0x42, 0x7a, 0x5f, 0x93, 0x5f, 0x3f, 0x97, 0xe3, 0xa8, 0x28, 0xb7,
+    0xc7, 0x40, 0x11, 0x5f, 0xef, 0xa2, 0x2e, 0xcb, 0xf4, 0xea, 0x86, 0x42,
+    0x0e, 0x18, 0x24, 0x35, 0xf8, 0x82, 0xb8, 0x53, 0x3c, 0x29, 0x81, 0x2f,
+    0x18, 0x61, 0x5d, 0xfc, 0x35, 0xd9, 0x2f, 0xbc, 0xc4, 0x31, 0x46, 0x01,
+    0xd7, 0xa4, 0x2e, 0x75, 0xb7, 0x62, 0x0f, 0x16, 0x0a, 0xef, 0x79, 0xc0,
+    0x75, 0xfd, 0x1c, 0x9e, 0x39, 0x39, 0xd7, 0xfe, 0x81, 0xf7, 0x7f, 0x79,
+    0x4a, 0x0e, 0xbf, 0x7e, 0x0c, 0x16, 0x9d, 0x7b, 0x91, 0x31, 0xd7, 0xc8,
+    0x2f, 0x31, 0xd7, 0xc9, 0xae, 0x61, 0xd7, 0xfb, 0xd9, 0xf6, 0x26, 0x4d,
+    0x1d, 0x53, 0xa6, 0x7b, 0x21, 0xb0, 0x97, 0x70, 0xf5, 0x64, 0xfd, 0x1c,
+    0xf1, 0x06, 0xc2, 0x0b, 0xfe, 0x84, 0xec, 0x2e, 0x7c, 0x64, 0xeb, 0xfa,
+    0x3a, 0x93, 0xb8, 0x9d, 0x7f, 0xd3, 0x8e, 0x4b, 0xb8, 0x0d, 0x1d, 0x7f,
+    0xec, 0x1d, 0xe5, 0xae, 0x7f, 0x00, 0x3a, 0xfd, 0x9e, 0xd6, 0x28, 0x75,
+    0x21, 0xf3, 0x2c, 0xfe, 0xfe, 0x1f, 0x7c, 0xee, 0x6d, 0x1d, 0x78, 0x31,
+    0xb0, 0xeb, 0xff, 0xec, 0x11, 0x86, 0x42, 0x31, 0xbc, 0x90, 0x4e, 0xbf,
+    0xfc, 0xff, 0x26, 0x94, 0x72, 0x7f, 0x8c, 0xe7, 0x4e, 0xa8, 0x47, 0x50,
+    0x4c, 0x7a, 0x3a, 0x29, 0x97, 0xfc, 0xbe, 0xe7, 0xb3, 0xfe, 0x4e, 0x75,
+    0xff, 0xf2, 0x8f, 0xed, 0x20, 0xcd, 0x0d, 0xe6, 0x6e, 0x75, 0xff, 0x47,
+    0xb3, 0x8d, 0x77, 0x69, 0xa2, 0xf8, 0xbf, 0x67, 0x23, 0x79, 0x1d, 0x7b,
+    0xb0, 0xb6, 0x9f, 0x57, 0x90, 0xef, 0xff, 0xc2, 0xdf, 0x9d, 0x84, 0xe2,
+    0x2d, 0x36, 0xe1, 0x67, 0x5e, 0x7e, 0x4e, 0x68, 0xbf, 0xea, 0x11, 0x67,
+    0x86, 0x6d, 0x57, 0xbf, 0xff, 0xdd, 0x7d, 0x24, 0x6b, 0xe7, 0xbb, 0x8b,
+    0xc6, 0xbf, 0x0e, 0xba, 0x36, 0x8e, 0xbe, 0xd6, 0x9d, 0x67, 0x57, 0x51,
+    0x32, 0x06, 0x0f, 0x0c, 0x5f, 0x6f, 0x2f, 0x39, 0xd7, 0xff, 0xc1, 0x6f,
+    0x50, 0x73, 0x63, 0xcb, 0x48, 0x13, 0xad, 0x2c, 0x3f, 0x17, 0x22, 0xbf,
+    0xe8, 0x5f, 0xc0, 0xe6, 0x03, 0x47, 0x5f, 0xf2, 0x60, 0x85, 0x44, 0xce,
+    0x1d, 0x48, 0x7d, 0xfb, 0x47, 0x37, 0xbd, 0x9b, 0x9d, 0x7f, 0x3f, 0x37,
+    0x96, 0x78, 0xeb, 0xff, 0x7b, 0x49, 0xcf, 0x0f, 0xef, 0x23, 0xaf, 0xff,
+    0x2e, 0x36, 0xf3, 0xf1, 0xcc, 0xd9, 0x1b, 0x9d, 0x7f, 0xe8, 0xce, 0x67,
+    0x00, 0xb4, 0xd1, 0xd7, 0x9f, 0x7d, 0xa3, 0xaf, 0xe7, 0xf6, 0xa3, 0x27,
+    0x3a, 0xa1, 0x33, 0xfc, 0x2d, 0x43, 0xe1, 0x4d, 0xd8, 0x78, 0xc8, 0xfd,
+    0xff, 0x7f, 0x0b, 0xd6, 0x2e, 0x18, 0xce, 0xbf, 0xf7, 0x27, 0xc0, 0xe7,
+    0x7b, 0x8c, 0x67, 0x5f, 0xfb, 0x07, 0xda, 0xfb, 0xb2, 0x33, 0x73, 0xab,
+    0x11, 0x05, 0xa4, 0x1b, 0xff, 0xe9, 0x47, 0x27, 0xf2, 0x29, 0xad, 0x38,
+    0xc8, 0xeb, 0xfa, 0x7d, 0x62, 0xe1, 0x8c, 0xeb, 0x33, 0x32, 0x20, 0x3e,
+    0xa8, 0x5e, 0x4e, 0xa1, 0xd7, 0xd2, 0xe0, 0x64, 0x75, 0xf2, 0xfc, 0x93,
+    0x9d, 0x58, 0x78, 0x88, 0x45, 0x7f, 0xf6, 0xcf, 0x29, 0x03, 0x2c, 0xea,
+    0x2c, 0xeb, 0xa7, 0xf1, 0xd7, 0xfb, 0x67, 0x5e, 0x51, 0x82, 0x75, 0x41,
+    0xe4, 0xe0, 0xbd, 0xff, 0xfa, 0x5d, 0x8e, 0x3f, 0xbf, 0xf2, 0x7b, 0x5d,
+    0x43, 0xaf, 0xec, 0x67, 0xef, 0x5f, 0xc7, 0x5f, 0xff, 0xbd, 0xf6, 0x51,
+    0xb1, 0x04, 0x1c, 0x48, 0x5e, 0x15, 0x7d, 0xdf, 0xbb, 0xf8, 0xeb, 0xf6,
+    0x2f, 0x13, 0x61, 0xd7, 0xa7, 0x99, 0x8c, 0xea, 0x84, 0xd1, 0xe7, 0x55,
+    0xc2, 0xf6, 0xab, 0x21, 0x2f, 0xe4, 0xf7, 0x7b, 0x0e, 0xbf, 0x71, 0x27,
+    0x75, 0x9a, 0x61, 0x3b, 0xef, 0x7f, 0x0e, 0x69, 0x84, 0xee, 0x04, 0x1a,
+    0x81, 0x3b, 0xfc, 0x2e, 0xa7, 0xa3, 0x80, 0x35, 0x02, 0x77, 0xfb, 0x59,
+    0xd4, 0xd7, 0xf3, 0x9a, 0x61, 0x3b, 0xb0, 0x26, 0x98, 0x4e, 0xe6, 0x59,
+    0x3c, 0xc2, 0x75, 0x89, 0xa5, 0xee, 0x68, 0x85, 0xcb, 0x22, 0xd1, 0xfe,
+    0xc4, 0x16, 0x48, 0xad, 0xe2, 0xcc, 0x26, 0x54, 0xf9, 0xec, 0x9b, 0xa7,
+    0xee, 0xcc, 0x78, 0xf5, 0x0b, 0xa3, 0xe8, 0x5b, 0xd5, 0xe7, 0x20, 0x18,
+    0x47, 0x6a, 0x36, 0x7f, 0x4a, 0x4e, 0xbc, 0x20, 0x59, 0xd7, 0xfd, 0x1f,
+    0xf8, 0x53, 0x67, 0xd5, 0x9d, 0x78, 0x73, 0x58, 0x7a, 0xfc, 0x1b, 0xbc,
+    0x10, 0x4c, 0x75, 0x43, 0x3b, 0xda, 0x78, 0x4f, 0x06, 0x30, 0xbc, 0x3b,
+    0x50, 0xe9, 0xb1, 0xb6, 0xa4, 0x31, 0xe6, 0x85, 0x0f, 0x21, 0x2a, 0xb2,
+    0x4e, 0xc6, 0xb6, 0x2a, 0xfa, 0x85, 0xef, 0xa7, 0x70, 0x76, 0x43, 0x33,
+    0xe9, 0x8d, 0xf8, 0x39, 0xc4, 0x50, 0xeb, 0xfb, 0xb1, 0xf4, 0x77, 0x01,
+    0xd7, 0xef, 0x64, 0xc8, 0xb3, 0xaf, 0xd1, 0xb8, 0x01, 0x07, 0x54, 0x1e,
+    0x70, 0x93, 0xdf, 0xa3, 0x64, 0x0f, 0x8e, 0xbf, 0x26, 0xcf, 0x24, 0xe7,
+    0x5f, 0x9e, 0x5e, 0xc6, 0x9d, 0x7e, 0x1c, 0xfb, 0x93, 0x1d, 0x7f, 0xfc,
+    0x2d, 0x45, 0x87, 0xf7, 0xe4, 0xb3, 0x7f, 0x1d, 0x7f, 0xfb, 0x01, 0xae,
+    0xa7, 0xcd, 0xe5, 0x19, 0x39, 0xd7, 0xfd, 0xd7, 0x5f, 0x52, 0x37, 0x91,
+    0xd7, 0xf7, 0xd1, 0x96, 0xdb, 0xce, 0x75, 0x42, 0x60, 0xd2, 0x50, 0x44,
+    0xc0, 0x1c, 0x54, 0xea, 0x80, 0x02, 0x40, 0xd2, 0x7e, 0x14, 0x89, 0x37,
+    0xa3, 0x2e, 0xbf, 0xf6, 0x3f, 0x66, 0x41, 0xee, 0x6e, 0x75, 0xfc, 0x09,
+    0xa5, 0x1e, 0xd1, 0xd7, 0xff, 0xff, 0xec, 0xee, 0x08, 0x30, 0x7d, 0xdc,
+    0xec, 0x64, 0xc9, 0xc9, 0xba, 0x9b, 0xf8, 0xeb, 0xe1, 0x8c, 0x64, 0xeb,
+    0xe8, 0xdf, 0x4e, 0x75, 0x43, 0x6a, 0x2d, 0x3b, 0xa8, 0x4e, 0x32, 0x9e,
+    0x42, 0x91, 0x8c, 0x31, 0x93, 0xbc, 0xa7, 0xd1, 0x5f, 0xf1, 0xef, 0xe5,
+    0xdb, 0x21, 0x03, 0xf4, 0x82, 0xff, 0xf9, 0x07, 0x17, 0x1f, 0x47, 0xf9,
+    0x0e, 0x2c, 0xeb, 0xfe, 0x0a, 0x60, 0xff, 0x2c, 0xd1, 0xd7, 0xfd, 0xd4,
+    0x97, 0x5e, 0x48, 0xb3, 0xaf, 0xfd, 0xa4, 0x1d, 0xe5, 0xe4, 0xd2, 0x1d,
+    0x58, 0x7e, 0x9e, 0x37, 0xbf, 0x69, 0x70, 0x18, 0x3a, 0xa4, 0x9a, 0x06,
+    0x27, 0x2e, 0x15, 0x7e, 0x21, 0xbe, 0x18, 0xe4, 0x8e, 0xbf, 0xee, 0xc4,
+    0x90, 0x47, 0xfd, 0xce, 0xbf, 0xe8, 0xcf, 0x7d, 0x00, 0x23, 0x73, 0xad,
+    0xc8, 0x44, 0x96, 0x10, 0x2c, 0xe2, 0xff, 0xff, 0xf7, 0x5d, 0x3d, 0x2f,
+    0xc7, 0xda, 0xeb, 0xcb, 0xe8, 0xc3, 0x79, 0x12, 0x3a, 0xff, 0xda, 0xfb,
+    0xe4, 0x1f, 0xe5, 0x9a, 0x3a, 0xe0, 0xe8, 0xea, 0x63, 0x46, 0x77, 0x5e,
+    0x05, 0x02, 0xff, 0xfe, 0xcd, 0xf3, 0x4e, 0x3d, 0x48, 0xf7, 0x7f, 0x75,
+    0x9d, 0x50, 0x9c, 0x6b, 0xc6, 0x04, 0x26, 0x57, 0xf0, 0xfe, 0xb4, 0xec,
+    0x1d, 0x7f, 0xfe, 0x71, 0xf3, 0xbf, 0x46, 0x3d, 0xa6, 0x73, 0xa7, 0x5f,
+    0xfa, 0x77, 0x1d, 0x7b, 0xa9, 0x1a, 0x3a, 0xff, 0xa0, 0x1a, 0x0f, 0xef,
+    0xc9, 0x1d, 0x7b, 0x9a, 0xd1, 0xe2, 0x03, 0xbe, 0x6b, 0xbb, 0x4d, 0x10,
+    0x1a, 0xa6, 0xa6, 0xfe, 0xe4, 0x76, 0x3e, 0x64, 0x91, 0x41, 0xc6, 0x2a,
+    0x74, 0xc8, 0xfe, 0xc3, 0x76, 0x80, 0x9c, 0xff, 0xa3, 0x75, 0xbd, 0xb2,
+    0x3a, 0x75, 0x62, 0xa1, 0x24, 0x8f, 0x2f, 0xe9, 0x55, 0xee, 0xbb, 0x19,
+    0xd7, 0xd0, 0x0d, 0xbc, 0x3a, 0x80, 0x78, 0x3e, 0x1e, 0xbe, 0x1f, 0x03,
+    0xf3, 0xaf, 0xcb, 0x62, 0x18, 0x86, 0x21, 0x89, 0x3a, 0xff, 0xfe, 0x96,
+    0x69, 0x39, 0xc4, 0x5f, 0xdf, 0x77, 0x19, 0xf1, 0xd5, 0x88, 0xbb, 0x42,
+    0x27, 0x3c, 0xbf, 0xfc, 0xce, 0x0f, 0xb0, 0x65, 0x9a, 0xfa, 0xb3, 0xaf,
+    0xff, 0x4b, 0x37, 0x97, 0xd8, 0x02, 0xac, 0xb2, 0xc9, 0x57, 0xe5, 0xb3,
+    0x89, 0xb0, 0xeb, 0xd2, 0xc1, 0x98, 0xfe, 0xbe, 0xa8, 0xd4, 0x23, 0xe5,
+    0xe1, 0x89, 0x50, 0xa8, 0xa7, 0xb0, 0xdd, 0x18, 0xc9, 0xaf, 0xf9, 0x06,
+    0x5a, 0x62, 0xac, 0x4b, 0x10, 0xc4, 0x9d, 0x7d, 0x36, 0xb2, 0x63, 0xaf,
+    0xc0, 0x8f, 0x63, 0x19, 0xd7, 0xfa, 0x33, 0x8d, 0x77, 0x69, 0xa2, 0x09,
+    0xbf, 0xe8, 0xf6, 0x71, 0xae, 0xed, 0x34, 0x5f, 0x37, 0xe7, 0x0f, 0x61,
+    0x43, 0xaf, 0x0e, 0x68, 0x28, 0xa7, 0x69, 0xea, 0xd0, 0xe8, 0x53, 0x10,
+    0xd9, 0x0d, 0x0b, 0xff, 0xa3, 0xa8, 0xa6, 0x72, 0x75, 0xff, 0xb9, 0xd5,
+    0x89, 0xd2, 0x24, 0x66, 0x7d, 0x2a, 0xbf, 0xdf, 0xf7, 0x6f, 0xa8, 0xde,
+    0x9d, 0x7f, 0xe9, 0xdf, 0x7d, 0xbc, 0xf0, 0xbe, 0xc3, 0xaf, 0xff, 0xb3,
+    0xd0, 0x3e, 0xd6, 0x62, 0x8a, 0x3c, 0x8e, 0xbf, 0xf6, 0x06, 0x25, 0x1d,
+    0xc0, 0x39, 0xd7, 0xf3, 0xcb, 0xf9, 0x38, 0x4e, 0xbc, 0xcb, 0x2c, 0x95,
+    0x7e, 0xee, 0x35, 0xf8, 0x52, 0xa5, 0xfd, 0xff, 0xfe, 0x9b, 0x91, 0xb3,
+    0xe2, 0x8f, 0xf3, 0xec, 0xda, 0xf9, 0x9b, 0xf8, 0xea, 0xf2, 0x29, 0x7e,
+    0x9b, 0x5f, 0xfe, 0x4e, 0x27, 0xbf, 0xcf, 0x3a, 0xf0, 0x4e, 0xa9, 0xd5,
+    0x14, 0xb5, 0x0d, 0x69, 0xc0, 0x3b, 0x18, 0x78, 0xf8, 0x96, 0xff, 0xcb,
+    0x8d, 0xf4, 0x39, 0x3f, 0xd9, 0x1d, 0x7f, 0xff, 0x93, 0xae, 0x3b, 0xcb,
+    0xec, 0xa0, 0x64, 0xeb, 0xc0, 0x9d, 0x7f, 0xfb, 0x33, 0xa1, 0xec, 0x6b,
+    0x3a, 0x80, 0x3a, 0xff, 0x29, 0xf2, 0x69, 0x47, 0x34, 0x75, 0x4e, 0x98,
+    0xfc, 0x90, 0x42, 0xc0, 0x88, 0xf7, 0xf3, 0x1e, 0x4b, 0xb1, 0xc3, 0xaf,
+    0xf7, 0xa1, 0x3a, 0xa4, 0x6e, 0x75, 0xff, 0xed, 0xc7, 0xe3, 0x7a, 0x80,
+    0x04, 0x72, 0x47, 0x54, 0x22, 0xb9, 0x0b, 0xfe, 0x99, 0xdf, 0x31, 0xea,
+    0x5b, 0x0e, 0xbf, 0xfd, 0x13, 0xfd, 0xec, 0x6f, 0xec, 0x9c, 0x42, 0x75,
+    0x39, 0xfa, 0x09, 0x3d, 0xfe, 0x8c, 0x1f, 0x30, 0x19, 0x69, 0xd7, 0xfb,
+    0xb9, 0xb3, 0xe6, 0xa4, 0xd3, 0xad, 0xfe, 0x8f, 0xb7, 0xc6, 0xd7, 0xf9,
+    0xc7, 0xe7, 0xde, 0x75, 0xce, 0xbf, 0x67, 0x1f, 0x76, 0x4e, 0xbf, 0xff,
+    0xd3, 0xe3, 0x23, 0x81, 0xe2, 0x7f, 0x38, 0x7b, 0x03, 0x39, 0xd5, 0x3a,
+    0x22, 0xf4, 0x51, 0x79, 0x96, 0x59, 0x2a, 0xff, 0x7d, 0x04, 0x0e, 0x6f,
+    0xe2, 0x95, 0x2f, 0xef, 0xff, 0xe6, 0x0f, 0xc6, 0xf5, 0x02, 0x1c, 0x67,
+    0xe7, 0xb5, 0x93, 0x9d, 0x5d, 0x45, 0x4f, 0xe8, 0x94, 0x89, 0x88, 0x3c,
+    0x3b, 0x2a, 0x76, 0x52, 0x04, 0xa3, 0xf1, 0x09, 0xaa, 0x4a, 0x60, 0xe4,
+    0x6f, 0xab, 0x87, 0x67, 0x61, 0x48, 0x30, 0x8d, 0xd1, 0x4f, 0xa3, 0xd0,
+    0xbf, 0xf6, 0x20, 0xce, 0xe3, 0xec, 0x59, 0xd7, 0xfe, 0xea, 0x32, 0x1e,
+    0xe7, 0xb6, 0xf0, 0xeb, 0xd8, 0x20, 0x3a, 0xfb, 0x3d, 0x34, 0x8e, 0xbf,
+    0xfb, 0x68, 0x63, 0x6b, 0x4e, 0x3f, 0x41, 0xa3, 0xab, 0xa7, 0xd8, 0xe4,
+    0x57, 0xfe, 0xcf, 0x47, 0x35, 0xd8, 0x1f, 0x1e, 0x20, 0x8b, 0xfb, 0x38,
+    0xd7, 0x76, 0x9a, 0x20, 0x85, 0x4f, 0x26, 0xf4, 0x05, 0x0e, 0xa8, 0x3e,
+    0x4d, 0x25, 0x5e, 0xd9, 0x0b, 0x3a, 0xfe, 0x7e, 0xf3, 0x88, 0xc9, 0xd7,
+    0xf3, 0x18, 0x59, 0x71, 0x91, 0xd5, 0x87, 0xf4, 0x23, 0xbf, 0x96, 0xdf,
+    0xff, 0xa0, 0x33, 0x49, 0x07, 0xd0, 0x09, 0x85, 0x26, 0x3a, 0x94, 0x54,
+    0xe5, 0xd8, 0x43, 0x02, 0x19, 0xc3, 0x09, 0xbd, 0x85, 0xd7, 0xf7, 0x73,
+    0xde, 0x45, 0x9d, 0x7f, 0x7b, 0xee, 0x75, 0xf7, 0x3a, 0xb7, 0x3d, 0xb1,
+    0x2c, 0xbf, 0xb3, 0x7f, 0x73, 0x90, 0x75, 0xff, 0xda, 0x17, 0xf3, 0xaf,
+    0xec, 0x4f, 0x87, 0x50, 0x4f, 0xc7, 0x45, 0xb5, 0x08, 0xb5, 0xfe, 0x12,
+    0x77, 0xf6, 0x37, 0xee, 0xce, 0xe1, 0xd7, 0x42, 0x87, 0x5c, 0x82, 0x75,
+    0x99, 0x3a, 0x82, 0x69, 0x7e, 0x8a, 0x5e, 0x1f, 0xe7, 0x3a, 0xfd, 0xd7,
+    0x96, 0x09, 0xd7, 0xf2, 0x78, 0x73, 0xa8, 0x75, 0xd9, 0xdf, 0x87, 0x9f,
+    0x04, 0xb7, 0x3b, 0x3f, 0x11, 0xf1, 0x87, 0x7d, 0x23, 0xf3, 0x65, 0x49,
+    0x39, 0xac, 0x28, 0x18, 0xca, 0x2f, 0xed, 0x20, 0x43, 0x82, 0x75, 0xff,
+    0xfd, 0xee, 0xe6, 0xb5, 0x99, 0xff, 0x27, 0xcf, 0xc7, 0xc7, 0x5f, 0xf7,
+    0x63, 0x9e, 0x18, 0xcd, 0xce, 0xbf, 0xff, 0xe4, 0x9e, 0x25, 0xae, 0x71,
+    0x37, 0x9a, 0x4f, 0xc5, 0xe6, 0xe7, 0x5f, 0xe8, 0x79, 0xdf, 0x8f, 0xf4,
+    0xeb, 0xdd, 0xc1, 0x0a, 0x34, 0xfa, 0x6f, 0xe6, 0x9a, 0xc4, 0xe6, 0x90,
+    0xaf, 0xd1, 0x97, 0xdf, 0xf9, 0xbd, 0x8c, 0xe4, 0xb5, 0xfa, 0xce, 0xb9,
+    0x34, 0x75, 0xff, 0x64, 0xef, 0xe0, 0x7d, 0x19, 0x1d, 0x7f, 0x3f, 0xbe,
+    0x44, 0x94, 0x3a, 0xfe, 0xfa, 0xbd, 0x32, 0xfb, 0x9d, 0x50, 0x99, 0x1e,
+    0x1a, 0xa8, 0x7f, 0xc1, 0x57, 0x3a, 0xf1, 0x7d, 0xee, 0x67, 0x4e, 0xbd,
+    0xa4, 0x59, 0xd6, 0x8e, 0x1b, 0x6f, 0x0d, 0xdf, 0x24, 0xc8, 0xc9, 0xd7,
+    0xff, 0x2d, 0xf7, 0xfb, 0xe4, 0xe4, 0x7e, 0xc1, 0x3a, 0xff, 0xfd, 0xfc,
+    0xe3, 0x19, 0xd5, 0x63, 0xd9, 0xdf, 0xf8, 0x75, 0xf7, 0xb5, 0xf7, 0x41,
+    0x46, 0x26, 0x11, 0x7d, 0x4b, 0xbf, 0x69, 0x79, 0xed, 0x1d, 0x7f, 0xf2,
+    0x29, 0x9e, 0x4e, 0xe7, 0xa3, 0x87, 0x5f, 0x9e, 0x42, 0x90, 0x75, 0xfd,
+    0x0e, 0x3e, 0xc1, 0x3a, 0xa4, 0x9f, 0x5e, 0x43, 0xa9, 0x12, 0xf8, 0x4e,
+    0xb4, 0x21, 0x24, 0xbf, 0x9b, 0xd4, 0xdb, 0x45, 0x0e, 0xbf, 0xfc, 0x80,
+    0x8d, 0x2e, 0x13, 0x9c, 0x46, 0x4e, 0xbe, 0x63, 0xee, 0x4e, 0x75, 0xfe,
+    0x80, 0xe7, 0x93, 0xbf, 0x9d, 0x65, 0xc1, 0xeb, 0x84, 0x96, 0xff, 0xff,
+    0xcb, 0x71, 0x04, 0x93, 0x5f, 0xaf, 0xa9, 0x1e, 0xef, 0xee, 0xb3, 0xaf,
+    0xff, 0x87, 0xff, 0x49, 0x01, 0xd7, 0x4f, 0x3a, 0xce, 0xbb, 0xe3, 0x19,
+    0xd7, 0xff, 0xe7, 0x4f, 0x20, 0x70, 0x39, 0xe4, 0x5a, 0x70, 0xeb, 0xdc,
+    0x7d, 0x62, 0x2e, 0xb8, 0x9d, 0xd1, 0xbb, 0x93, 0xce, 0x9b, 0x37, 0xf1,
+    0x93, 0x5d, 0x28, 0x3a, 0xff, 0xf4, 0xe1, 0xec, 0x77, 0x37, 0x06, 0x7b,
+    0x47, 0x53, 0x9f, 0x07, 0xe2, 0xb4, 0x15, 0x62, 0x78, 0x60, 0x90, 0x9f,
+    0x78, 0xe3, 0x46, 0x12, 0xb7, 0xf7, 0x22, 0x74, 0x1f, 0x1d, 0x78, 0x3f,
+    0x56, 0x75, 0xf8, 0x60, 0x39, 0x31, 0xd7, 0xda, 0xff, 0x8a, 0x1d, 0x7e,
+    0x8e, 0xfa, 0x24, 0x75, 0xf0, 0x7f, 0xf6, 0xa0, 0xfc, 0x37, 0x26, 0x01,
+    0x25, 0xf8, 0x18, 0xb8, 0xe9, 0xd7, 0xf7, 0xf1, 0xf3, 0x83, 0x23, 0xaf,
+    0x30, 0x7b, 0x87, 0x50, 0x53, 0x76, 0xc2, 0xc4, 0x84, 0x70, 0xa4, 0x78,
+    0x9b, 0xf2, 0xfb, 0xdc, 0xfb, 0xa3, 0xae, 0x86, 0x1e, 0x75, 0xff, 0x9c,
+    0x5b, 0x9c, 0x6b, 0xbb, 0x4d, 0x10, 0x8d, 0xd2, 0x9c, 0xea, 0x84, 0x4c,
+    0x00, 0x7b, 0xf1, 0xbd, 0x89, 0x17, 0xec, 0x9f, 0x40, 0x73, 0xaf, 0xff,
+    0xff, 0x77, 0x3f, 0xe2, 0x9d, 0x4d, 0xe3, 0xdf, 0xf4, 0x73, 0x7f, 0x7e,
+    0xfa, 0x3a, 0xff, 0xec, 0xdf, 0xef, 0x90, 0x7f, 0x96, 0x68, 0xeb, 0xff,
+    0xff, 0xff, 0xff, 0xff, 0xf6, 0x0c, 0xe2, 0xe1, 0x81, 0x9e, 0x38, 0x1c,
+    0x1c, 0xf6, 0x91, 0xb8, 0x3f, 0x67, 0xce, 0x46, 0x85, 0xd4, 0xd6, 0x20,
+    0x01, 0xf8, 0x05, 0xc3, 0x03, 0x3c, 0x70, 0xea, 0x84, 0xd3, 0xb1, 0x1a,
+    0xff, 0xef, 0x38, 0xcf, 0xbc, 0x86, 0x33, 0x47, 0x5f, 0xfb, 0xee, 0x75,
+    0xd6, 0xab, 0x2c, 0xb2, 0x75, 0xff, 0xfb, 0x1b, 0xd8, 0x10, 0x8a, 0x4f,
+    0x82, 0x8a, 0x1d, 0x73, 0xbc, 0xe8, 0x96, 0x92, 0x25, 0xff, 0xfd, 0x30,
+    0xc0, 0x34, 0xde, 0xa7, 0x26, 0x18, 0x06, 0x8e, 0xbf, 0xfb, 0xdd, 0x4d,
+    0x9d, 0x79, 0x72, 0x14, 0x3a, 0xfe, 0xff, 0xc9, 0xf8, 0xa8, 0x75, 0xfd,
+    0x8c, 0xe0, 0xfe, 0x03, 0xaf, 0xd2, 0xcf, 0x40, 0x0e, 0xba, 0x17, 0x39,
+    0xe9, 0xee, 0x5b, 0x7f, 0xff, 0xf0, 0x16, 0xf2, 0xeb, 0xa7, 0x90, 0x38,
+    0x1c, 0xf2, 0x2d, 0x38, 0x75, 0x69, 0x13, 0xbf, 0x97, 0xdf, 0xff, 0x87,
+    0x35, 0x9d, 0x7d, 0xa6, 0xf5, 0x17, 0x0d, 0x3a, 0xfd, 0x3a, 0xe0, 0x30,
+    0x75, 0x49, 0x75, 0x4c, 0x31, 0xe5, 0x6e, 0x45, 0x34, 0x36, 0x78, 0x5d,
+    0xd5, 0xbd, 0x23, 0x7a, 0x31, 0xfd, 0x84, 0x9f, 0x55, 0x6f, 0xf4, 0x6b,
+    0x51, 0x3e, 0x32, 0x75, 0xfe, 0xee, 0x2f, 0x3b, 0xf8, 0x9d, 0x41, 0x3e,
+    0x5f, 0x19, 0xdf, 0x67, 0x14, 0x43, 0xaa, 0x17, 0xb1, 0xf2, 0x75, 0xe9,
+    0xe3, 0x0a, 0xfc, 0x8a, 0xf3, 0x2c, 0xb2, 0x55, 0xff, 0x60, 0x1f, 0x99,
+    0xb3, 0x02, 0x52, 0xa5, 0xfd, 0xcc, 0xb2, 0x55, 0xe6, 0x59, 0x64, 0xab,
+    0xf9, 0xe7, 0x0f, 0x63, 0x45, 0x2a, 0x5f, 0xd0, 0xa2, 0xf1, 0x94, 0x8d,
+    0xb3, 0x7b, 0xf3, 0x50, 0x3f, 0x56, 0x52, 0xa6, 0xce, 0xf3, 0x2c, 0xb2,
+    0x55, 0xed, 0x47, 0x0a, 0x54, 0xbf, 0xbe, 0x71, 0xdf, 0xc7, 0x58, 0x08,
+    0x8a, 0x5f, 0x2c, 0xb2, 0x57, 0x7f, 0x04, 0x62, 0x4e, 0xd3, 0xaf, 0xda,
+    0xfe, 0x7d, 0xb1, 0x3a, 0xfc, 0x14, 0xd9, 0x01, 0x3a, 0xfb, 0x07, 0x18,
+    0xce, 0xae, 0x1e, 0x52, 0xca, 0x29, 0x11, 0x31, 0xf5, 0xda, 0xff, 0xee,
+    0xbc, 0x85, 0xd4, 0x98, 0x52, 0x63, 0xaf, 0xfe, 0xce, 0x4f, 0x1b, 0xe9,
+    0x07, 0x00, 0x75, 0xfd, 0xdc, 0xd9, 0x9e, 0xd1, 0xd4, 0xd4, 0x5a, 0x81,
+    0x13, 0xc8, 0x75, 0xc4, 0xf3, 0x3b, 0x0c, 0x31, 0x86, 0xcd, 0xd3, 0xf8,
+    0xea, 0x85, 0x4a, 0x79, 0x28, 0x08, 0x4e, 0xaf, 0x6e, 0xc5, 0x58, 0x93,
+    0xaf, 0xff, 0x63, 0x1b, 0x88, 0x31, 0xb1, 0xd8, 0x59, 0xd7, 0xda, 0xea,
+    0x4c, 0x55, 0xff, 0x3e, 0xfe, 0xc9, 0xbf, 0xe2, 0x87, 0x59, 0xa8, 0x7b,
+    0xdf, 0x91, 0x5f, 0xe1, 0xcd, 0xe5, 0xa4, 0x50, 0xeb, 0xe7, 0x7e, 0x28,
+    0x75, 0x7c, 0x3d, 0x49, 0xcc, 0xef, 0xfb, 0x31, 0xa0, 0x8c, 0xde, 0x47,
+    0x5f, 0x43, 0xaf, 0x61, 0x57, 0xff, 0x75, 0x1c, 0x00, 0x80, 0x47, 0x74,
+    0x75, 0xfd, 0xdc, 0x5a, 0xde, 0x47, 0x5e, 0x65, 0x96, 0x4a, 0xbf, 0xc3,
+    0xee, 0xa4, 0x0c, 0xe5, 0x2a, 0x5f, 0xde, 0x80, 0x64, 0x91, 0x19, 0x89,
+    0x75, 0xe4, 0xc0, 0x3e, 0xc3, 0x3a, 0xd8, 0xd4, 0xd3, 0x57, 0x19, 0x15,
+    0xfc, 0x08, 0x04, 0x77, 0x47, 0x5f, 0xe8, 0xfb, 0xce, 0x27, 0xb4, 0x75,
+    0x42, 0xb8, 0x39, 0x14, 0x6f, 0x0a, 0x74, 0x7c, 0x98, 0x97, 0xb1, 0xc2,
+    0x00, 0xbc, 0x4b, 0x2f, 0xc0, 0xc4, 0xea, 0x87, 0x5f, 0xff, 0x63, 0x60,
+    0x5f, 0xda, 0x0f, 0xef, 0xc9, 0x1d, 0x5b, 0x9f, 0xaa, 0xc9, 0xef, 0xff,
+    0xfe, 0x17, 0x5c, 0x71, 0xa1, 0xec, 0x6b, 0xf7, 0x49, 0x6b, 0xaf, 0x23,
+    0xaf, 0x7f, 0xed, 0x1d, 0x79, 0xb1, 0xa3, 0xaf, 0xfe, 0xfb, 0x2c, 0xeb,
+    0xf5, 0x39, 0xc8, 0x3a, 0xb0, 0xf7, 0xc0, 0x37, 0x7e, 0x8f, 0x6b, 0x66,
+    0x1d, 0x7e, 0xff, 0x8a, 0x75, 0x0e, 0xa8, 0x4e, 0x05, 0xc8, 0xc0, 0xe0,
+    0x2f, 0x9e, 0x21, 0xdb, 0x28, 0xbf, 0xc2, 0xec, 0xe0, 0xba, 0x87, 0x5f,
+    0xfd, 0x9e, 0xd7, 0xdd, 0x2c, 0x63, 0x90, 0x75, 0xf2, 0x6c, 0xc1, 0x09,
+    0xfa, 0xac, 0xc6, 0xff, 0xff, 0x83, 0xd4, 0x67, 0x36, 0x91, 0x6f, 0xed,
+    0x7f, 0x2c, 0xdf, 0xc7, 0x56, 0x22, 0x91, 0xce, 0x6f, 0xfa, 0x66, 0xf5,
+    0x17, 0x1c, 0x50, 0xeb, 0xf4, 0xff, 0x3f, 0x89, 0x8e, 0xb4, 0x8e, 0xbd,
+    0xf4, 0x66, 0x3a, 0xa4, 0x6b, 0x80, 0x21, 0x58, 0x8b, 0x57, 0x3a, 0xd2,
+    0xd5, 0x43, 0xb7, 0xff, 0x9e, 0x53, 0x0c, 0xa5, 0x23, 0x06, 0x55, 0x16,
+    0x52, 0x9e, 0xd4, 0x85, 0xb3, 0x4e, 0xd2, 0x55, 0x9c, 0xd2, 0xc1, 0xf9,
+    0x2b, 0xc9, 0x72, 0x9d, 0xfb, 0x2d, 0xb5, 0xe3, 0xce, 0x04, 0x3c, 0xc6,
+    0x7c, 0x1b, 0x53, 0x8a, 0x5e, 0x97, 0x73, 0xfc, 0xa7, 0x36, 0x63, 0x71,
+    0xfb, 0x0d, 0x6b, 0xdb, 0x20, 0x4e, 0xbf, 0xfe, 0xc1, 0x57, 0xca, 0x26,
+    0xfa, 0xee, 0x01, 0xce, 0xa9, 0x1f, 0x60, 0x47, 0x2f, 0xf3, 0x8b, 0x73,
+    0xdd, 0x43, 0xaf, 0xff, 0xfb, 0x3a, 0xff, 0x75, 0x8a, 0x38, 0x82, 0x06,
+    0x26, 0xec, 0x1d, 0x68, 0x3a, 0xff, 0xfd, 0x1c, 0xec, 0x2f, 0x6b, 0xf8,
+    0x18, 0x9b, 0xb0, 0x75, 0xf9, 0x39, 0x34, 0x77, 0x88, 0xcb, 0x03, 0x28,
+    0x87, 0xd6, 0xe9, 0xb4, 0xac, 0x8b, 0xec, 0x3e, 0xec, 0xc3, 0xce, 0xbf,
+    0xf3, 0x88, 0x3e, 0x07, 0xf7, 0xe4, 0x8e, 0xbe, 0x41, 0x9e, 0x0e, 0xbd,
+    0xee, 0x41, 0xd7, 0xfc, 0x30, 0xb4, 0x1c, 0x5c, 0x1d, 0x72, 0x07, 0x0f,
+    0x3e, 0x61, 0xba, 0x63, 0x46, 0xe7, 0x10, 0x05, 0xbe, 0x98, 0xa2, 0x64,
+    0x99, 0x0f, 0x2b, 0xd0, 0x33, 0x9d, 0x7c, 0x9d, 0x45, 0x9d, 0x6e, 0xa1,
+    0xbb, 0x98, 0x6e, 0xfe, 0x86, 0xc6, 0xbc, 0x87, 0x5f, 0xf4, 0x7b, 0xae,
+    0x07, 0xdf, 0x47, 0x50, 0x4f, 0x8c, 0x4a, 0xef, 0xfd, 0xc0, 0x7c, 0xea,
+    0x37, 0xfe, 0x00, 0xeb, 0xd3, 0x7f, 0xc3, 0xaf, 0xfc, 0xe9, 0xcc, 0xdd,
+    0x56, 0x59, 0x64, 0xea, 0x84, 0x51, 0x3a, 0x16, 0x87, 0xaf, 0xff, 0x86,
+    0x25, 0xf3, 0xef, 0x90, 0x7f, 0x96, 0x68, 0xea, 0xc4, 0xf3, 0x5b, 0x08,
+    0xae, 0xc3, 0x0c, 0x05, 0xd7, 0x80, 0xeb, 0x3a, 0xec, 0x01, 0xd7, 0x86,
+    0x43, 0x06, 0xc3, 0x06, 0xef, 0xb4, 0xd6, 0xa1, 0xd5, 0x07, 0xa0, 0xe5,
+    0xf7, 0xee, 0x68, 0x62, 0x73, 0xaf, 0xff, 0x99, 0xc6, 0xeb, 0x3d, 0x36,
+    0x28, 0x38, 0x03, 0xab, 0x0f, 0xdd, 0x09, 0xef, 0xe7, 0xf7, 0x5c, 0x40,
+    0x75, 0xff, 0x9f, 0xd9, 0x33, 0xc0, 0xc4, 0xc7, 0x5f, 0xfb, 0xa9, 0x9f,
+    0x72, 0x66, 0x63, 0x73, 0xac, 0x9c, 0x45, 0x47, 0x4a, 0xf4, 0x79, 0x73,
+    0x5a, 0x68, 0xc1, 0x2a, 0x49, 0x90, 0x36, 0x19, 0x00, 0x35, 0xbb, 0x04,
+    0xeb, 0xff, 0xde, 0x81, 0x6e, 0x7b, 0xa9, 0xc0, 0x34, 0xeb, 0xf0, 0x53,
+    0x5d, 0x43, 0xaf, 0xe4, 0x1c, 0xf7, 0x50, 0xeb, 0x46, 0x1e, 0x86, 0x89,
+    0xa8, 0x28, 0xd2, 0xc1, 0x4f, 0xe1, 0x31, 0x7f, 0xa1, 0x7a, 0xd3, 0x8c,
+    0xe7, 0x5f, 0xf0, 0x35, 0x24, 0xeb, 0xa4, 0xe7, 0x5f, 0x6b, 0x07, 0xc7,
+    0x5e, 0xda, 0x8e, 0x1d, 0x48, 0x7e, 0xce, 0x71, 0xf9, 0x05, 0xef, 0x3b,
+    0x19, 0xd7, 0xfb, 0xdd, 0x45, 0x40, 0xe8, 0x75, 0xdf, 0x70, 0xea, 0x0a,
+    0x6e, 0x5d, 0x35, 0x18, 0x54, 0x78, 0xbb, 0xf1, 0xef, 0xa6, 0x57, 0xdd,
+    0x47, 0x91, 0xd7, 0x82, 0xf2, 0x3a, 0xef, 0xc1, 0x06, 0xef, 0x08, 0x2f,
+    0xf9, 0xb9, 0xe8, 0xd8, 0x82, 0x03, 0xaf, 0xff, 0xef, 0xe3, 0xda, 0xc1,
+    0xf9, 0xc8, 0x40, 0x8b, 0xc8, 0xeb, 0xf3, 0x7b, 0xbb, 0xb1, 0x9d, 0x7f,
+    0xf2, 0x04, 0x7f, 0xf6, 0xa0, 0x63, 0x47, 0x52, 0x23, 0xfc, 0x4e, 0x3f,
+    0x5a, 0xd8, 0x57, 0x7f, 0xf0, 0x1f, 0x99, 0xb3, 0x03, 0xc1, 0x64, 0xeb,
+    0xff, 0xf8, 0x73, 0x5f, 0xfc, 0xce, 0xb8, 0xe4, 0xd2, 0x8d, 0xce, 0xbf,
+    0x71, 0xae, 0xed, 0x34, 0x40, 0xd7, 0xf3, 0xce, 0x07, 0x10, 0x92, 0xb0,
+    0x7d, 0xec, 0xd7, 0xf8, 0x7d, 0xbb, 0x66, 0x77, 0xba, 0xf2, 0xf8, 0x8f,
+    0xf1, 0x86, 0x4d, 0xff, 0x75, 0x30, 0x71, 0xa1, 0xc3, 0xa9, 0x69, 0xd9,
+    0xfa, 0x34, 0x4d, 0x87, 0x57, 0xbd, 0xfc, 0x1d, 0x7f, 0x81, 0xe4, 0x9d,
+    0x70, 0xd3, 0xab, 0x73, 0xcf, 0x11, 0xcb, 0xf0, 0x58, 0xb7, 0x0b, 0x16,
+    0x75, 0x42, 0xac, 0xcc, 0x8f, 0xc5, 0x21, 0x10, 0xe4, 0x57, 0xfb, 0x37,
+    0xf0, 0x73, 0x14, 0x3a, 0xfe, 0xcf, 0x40, 0xa0, 0x0e, 0xbf, 0xe0, 0xf0,
+    0x5d, 0x9f, 0xbb, 0xb2, 0x75, 0xe7, 0xe4, 0xe6, 0x8c, 0x16, 0xff, 0xcf,
+    0xcc, 0x10, 0x6b, 0xda, 0xdc, 0xeb, 0xff, 0xff, 0xfb, 0x3d, 0xd7, 0x15,
+    0x3e, 0x6b, 0x8e, 0xfe, 0xd9, 0x81, 0xf9, 0x8b, 0x71, 0xde, 0x47, 0x88,
+    0x2e, 0xff, 0xce, 0xea, 0x35, 0xc3, 0xf1, 0x46, 0x4f, 0x10, 0x5d, 0xff,
+    0xdd, 0x4e, 0xa4, 0x0f, 0xbe, 0x28, 0xc9, 0xe2, 0x0b, 0xbf, 0xd0, 0x83,
+    0xef, 0x8a, 0x32, 0x78, 0x82, 0xef, 0xe5, 0xe0, 0x7e, 0x28, 0xc9, 0xe2,
+    0x0b, 0xbf, 0xff, 0xe7, 0x11, 0x45, 0xfc, 0xd3, 0x7a, 0x9c, 0x45, 0x27,
+    0xc6, 0x4f, 0x10, 0x5d, 0xdb, 0xfc, 0x0a, 0x72, 0xed, 0x4f, 0xe2, 0x9b,
+    0xa1, 0x09, 0xf5, 0x42, 0xac, 0x7e, 0x9f, 0x0c, 0xa3, 0x1b, 0xfc, 0x90,
+    0xa6, 0xbd, 0xad, 0xce, 0xbe, 0x7e, 0x01, 0xce, 0xbf, 0xfb, 0xa9, 0xd4,
+    0x81, 0xf7, 0xc5, 0x19, 0x3c, 0x41, 0x77, 0xfd, 0x36, 0x9a, 0x93, 0xfc,
+    0x51, 0x93, 0xc4, 0x17, 0x7e, 0xf6, 0xa1, 0x7f, 0x1a, 0x89, 0xff, 0xaa,
+    0x77, 0xff, 0xbe, 0x37, 0xa8, 0xd8, 0xf6, 0xbe, 0x28, 0xc9, 0xe2, 0x0b,
+    0xbf, 0xff, 0xf8, 0x45, 0x17, 0xf3, 0xfc, 0xf9, 0xa6, 0xf5, 0x38, 0x8a,
+    0x4f, 0x8c, 0x9e, 0x20, 0xba, 0xc4, 0xc9, 0x77, 0x44, 0x75, 0xdb, 0xfe,
+    0xea, 0x71, 0x14, 0x9f, 0x19, 0x3c, 0x41, 0x77, 0xff, 0xce, 0xfb, 0xcb,
+    0x5d, 0x40, 0x86, 0x39, 0x05, 0x5f, 0xfb, 0x25, 0x2f, 0xf5, 0xc1, 0x9f,
+    0x6c, 0xf1, 0x05, 0xd3, 0x51, 0xcb, 0xc4, 0x7d, 0x27, 0x5f, 0xf9, 0xa9,
+    0xcf, 0x38, 0x35, 0xf1, 0x93, 0xc4, 0x17, 0x7f, 0x75, 0x3b, 0xd4, 0x01,
+    0xa0, 0x0b, 0xbf, 0x60, 0x3e, 0x28, 0xc9, 0xe2, 0x0b, 0xbb, 0x3c, 0xd3,
+    0xf1, 0xe9, 0xcd, 0x6e, 0x8e, 0xcd, 0x42, 0xfe, 0xfe, 0x5e, 0x07, 0xe2,
+    0x8c, 0x9e, 0x20, 0xbb, 0xff, 0x37, 0xa9, 0xc4, 0x52, 0x7c, 0x64, 0xf1,
+    0x05, 0xdd, 0x9f, 0x1d, 0x11, 0x7a, 0x3e, 0xbf, 0xdf, 0xa2, 0xdc, 0x77,
+    0x91, 0xe2, 0x0b, 0xbf, 0xf6, 0x26, 0xcc, 0x1c, 0x0b, 0xc8, 0xf1, 0x05,
+    0xac, 0xf0, 0x28, 0x2b, 0xbf, 0xbc, 0x37, 0x01, 0xa0, 0xc7, 0xc9, 0xa8,
+    0xc5, 0x7d, 0x18, 0xe7, 0xf0, 0xb4, 0x65, 0xbe, 0xe0, 0x41, 0xa2, 0x0b,
+    0x55, 0x11, 0x97, 0x3b, 0x4e, 0xb6, 0x9a, 0xc9, 0xc3, 0x05, 0x25, 0xe7,
+    0xc6, 0xb7, 0x4b, 0x68, 0xeb, 0xd1, 0x2d, 0xa3, 0xaa, 0x0d, 0xb8, 0x8c,
+    0xd4, 0xec, 0xaf, 0x60, 0x99, 0xee, 0x54, 0x0a, 0x50, 0x00, 0xbd, 0x5f,
+    0xfd, 0x92, 0x1c, 0xf7, 0x53, 0x37, 0xf1, 0xd7, 0xe8, 0xf6, 0xba, 0x87,
+    0x5f, 0xfb, 0x53, 0x4b, 0xf0, 0xcd, 0x2f, 0xc2, 0x75, 0x48, 0xfa, 0xbc,
+    0x4d, 0x7f, 0xf4, 0x6f, 0x2f, 0xab, 0xd7, 0xa3, 0x76, 0x4e, 0xbf, 0x4b,
+    0x6b, 0x6b, 0xf9, 0xce, 0xb7, 0x50, 0xfe, 0x5d, 0x26, 0xfd, 0xc8, 0xde,
+    0x5a, 0x3a, 0xa4, 0x79, 0xdc, 0x26, 0xbf, 0xf8, 0x1f, 0xeb, 0x6f, 0x38,
+    0x05, 0xa6, 0x8e, 0xbf, 0xc0, 0xff, 0xc3, 0x1e, 0xd1, 0xd4, 0x03, 0xfb,
+    0xd2, 0x45, 0x42, 0x75, 0x19, 0x0e, 0x97, 0x84, 0xed, 0xfc, 0xf2, 0x8d,
+    0x8f, 0xd3, 0xaf, 0xff, 0x4f, 0x9b, 0xfb, 0x48, 0x30, 0x07, 0x59, 0xd7,
+    0xdb, 0xea, 0x37, 0x3a, 0xf2, 0xe2, 0x47, 0x5f, 0xb0, 0x3d, 0xfd, 0x93,
+    0xab, 0xe1, 0xf3, 0xb9, 0x18, 0x8d, 0xde, 0x0b, 0xf8, 0xea, 0xe1, 0xe5,
+    0x39, 0x7d, 0xe4, 0xdb, 0xc3, 0xaf, 0x3f, 0x00, 0x75, 0xb7, 0x83, 0x71,
+    0xe1, 0xdb, 0xe6, 0x73, 0xae, 0x75, 0xf2, 0x9c, 0x46, 0x4e, 0xbf, 0x4e,
+    0xfd, 0x86, 0x33, 0xa9, 0x89, 0x3c, 0xdc, 0x23, 0xa8, 0x54, 0x77, 0x85,
+    0xa9, 0x0f, 0xa7, 0x59, 0x01, 0x38, 0xb7, 0x5f, 0xfe, 0x11, 0x89, 0xd7,
+    0xd4, 0xe7, 0x1e, 0x47, 0x5f, 0xe9, 0xe7, 0x81, 0xdf, 0x3c, 0x75, 0x61,
+    0xfe, 0x22, 0x45, 0xff, 0xdc, 0x1f, 0xf7, 0xf0, 0xe4, 0xee, 0x27, 0x5e,
+    0x7e, 0x4e, 0x75, 0xc0, 0x83, 0xaf, 0x92, 0x17, 0x87, 0x51, 0xd7, 0xf3,
+    0xa9, 0xe8, 0xe0, 0x0e, 0xa0, 0x9b, 0x71, 0x0a, 0xbf, 0xff, 0xd0, 0x81,
+    0x18, 0xfd, 0xbe, 0xc6, 0x86, 0x1b, 0xf5, 0x67, 0x5c, 0x08, 0x3a, 0xe8,
+    0x50, 0xeb, 0xfe, 0xcf, 0x6a, 0x17, 0xf7, 0x26, 0x3a, 0xff, 0x6b, 0x3a,
+    0x9a, 0xfe, 0x73, 0xae, 0x65, 0x92, 0xaf, 0xf8, 0x73, 0x63, 0xcb, 0x48,
+    0x13, 0xa9, 0xa9, 0xf8, 0xa0, 0xe7, 0x05, 0x56, 0xad, 0xd2, 0x00, 0x30,
+    0xb0, 0x45, 0x44, 0x5b, 0x47, 0x4c, 0x9a, 0x7d, 0x18, 0xbc, 0xcb, 0x2c,
+    0x95, 0x65, 0x94, 0xa9, 0x7f, 0x7d, 0x33, 0xbf, 0x0a, 0x55, 0x1b, 0xbf,
+    0x61, 0x7b, 0x53, 0xab, 0x5a, 0x79, 0x62, 0x57, 0xf7, 0xa3, 0x3b, 0x93,
+    0x9d, 0x76, 0x2c, 0xea, 0xdc, 0xf0, 0x74, 0x59, 0x50, 0xe8, 0x95, 0xa5,
+    0x1a, 0xee, 0x4a, 0x36, 0x52, 0x18, 0xfb, 0xc7, 0x6e, 0x92, 0x9e, 0xb9,
+    0x09, 0xae, 0xcb, 0xf7, 0x7a, 0x59, 0xe0, 0x16, 0x06, 0x52, 0xa6, 0xa5,
+    0x39, 0xfa, 0x1a, 0xbf, 0xcb, 0x7a, 0xd8, 0xdb, 0x7f, 0x60, 0x00, 0x9c,
+    0x91, 0xd7, 0x37, 0x0e, 0xa0, 0x9e, 0x0b, 0x96, 0x5d, 0x8c, 0x9d, 0x74,
+    0x78, 0xea, 0x9c, 0xd5, 0xb4, 0x5a, 0xcb, 0x3a, 0xb0, 0xd9, 0x78, 0x8a,
+    0xff, 0x49, 0x07, 0x17, 0xff, 0x4e, 0xbf, 0xf6, 0x7b, 0x5d, 0x45, 0xbe,
+    0x70, 0xea, 0x83, 0xee, 0x13, 0x2b, 0xef, 0x9e, 0x8d, 0x87, 0x5f, 0x62,
+    0xf3, 0xc7, 0x5e, 0xf3, 0xa8, 0x75, 0xff, 0xff, 0xcd, 0x79, 0xbf, 0x97,
+    0xed, 0xf9, 0xd4, 0xf7, 0xa3, 0x78, 0x9e, 0x34, 0x75, 0xff, 0xff, 0x31,
+    0x8b, 0xbe, 0xc8, 0x97, 0x63, 0x93, 0xc7, 0xb4, 0xf2, 0x3a, 0xf2, 0x6f,
+    0x31, 0xd7, 0xec, 0xc9, 0xff, 0xd1, 0xd7, 0xdc, 0x14, 0x01, 0xd7, 0xc8,
+    0xd7, 0xe1, 0xd7, 0x40, 0x0e, 0xbe, 0xfe, 0x7f, 0xd5, 0xe9, 0xb5, 0xfa,
+    0x41, 0x48, 0x89, 0x4e, 0xaa, 0xdf, 0xf7, 0x5f, 0x5d, 0x49, 0xdc, 0x4e,
+    0xbe, 0x79, 0xfe, 0xc8, 0xea, 0x61, 0x2b, 0xc4, 0x87, 0xe9, 0x42, 0x3b,
+    0x08, 0x37, 0x25, 0x42, 0x0e, 0x0e, 0x3b, 0xc0, 0x1a, 0x74, 0x3b, 0xe8,
+    0x5e, 0x7d, 0x22, 0xda, 0x37, 0xbf, 0x87, 0xf0, 0xad, 0xe4, 0x75, 0xe4,
+    0x9f, 0xf3, 0xaf, 0xd0, 0x04, 0xdf, 0x0e, 0xb9, 0x7b, 0x0e, 0xb0, 0x60,
+    0xdf, 0x09, 0x35, 0xff, 0xe9, 0x0c, 0x7c, 0x58, 0xc2, 0x9e, 0x49, 0xce,
+    0xbf, 0x3a, 0xf3, 0xab, 0x3a, 0xb7, 0x3f, 0x1f, 0x25, 0xde, 0xf7, 0x20,
+    0xeb, 0xfd, 0xaf, 0x6c, 0xc1, 0xc0, 0x9d, 0x7b, 0xb1, 0xb0, 0xeb, 0xda,
+    0x94, 0xe7, 0x56, 0x1b, 0xaf, 0xa3, 0xb5, 0x09, 0xf5, 0xc8, 0xb7, 0x16,
+    0xd2, 0x12, 0xcb, 0x23, 0x71, 0xbf, 0x36, 0xde, 0x7f, 0x9f, 0x4e, 0xbd,
+    0x32, 0x74, 0xeb, 0xfa, 0x38, 0xf3, 0x27, 0x4e, 0xbf, 0x68, 0x30, 0x33,
+    0xb9, 0xe4, 0x68, 0x72, 0xf2, 0xe1, 0x67, 0x56, 0xe7, 0xb2, 0xb3, 0xeb,
+    0xff, 0xe1, 0x97, 0xcc, 0x0a, 0x6b, 0x7f, 0x7e, 0xfa, 0x3a, 0xfd, 0xdf,
+    0xc6, 0x36, 0x1d, 0x7f, 0x0b, 0xfa, 0x50, 0xa1, 0xd5, 0x07, 0xab, 0xf4,
+    0xa6, 0xfb, 0x33, 0x79, 0x1d, 0x7b, 0x49, 0x31, 0xd6, 0x50, 0x4d, 0xee,
+    0x88, 0x6f, 0xfe, 0x79, 0xc6, 0x37, 0x40, 0x8c, 0x4e, 0x75, 0x70, 0xfa,
+    0x84, 0x9e, 0xfd, 0xf3, 0xb1, 0xc9, 0x1d, 0x5f, 0x15, 0x4f, 0x44, 0x30,
+    0x30, 0x8d, 0xb0, 0xa7, 0x78, 0x65, 0x32, 0x43, 0x79, 0x7a, 0x83, 0xaf,
+    0xe9, 0xe6, 0x93, 0x0b, 0x93, 0x9d, 0x7c, 0xbc, 0x7e, 0x9d, 0x74, 0xa7,
+    0x3a, 0xf7, 0x42, 0x87, 0x5f, 0xbb, 0x89, 0x2d, 0x1d, 0x7f, 0xfd, 0xd8,
+    0xfa, 0xaf, 0x85, 0xc1, 0xad, 0x40, 0x0a, 0xbf, 0x71, 0xae, 0xed, 0x3c,
+    0x40, 0x97, 0xb5, 0x1b, 0x9d, 0x60, 0x61, 0xe7, 0xee, 0x67, 0x7b, 0xc9,
+    0x39, 0xd7, 0xa7, 0x71, 0x3a, 0xa4, 0x99, 0x28, 0x49, 0xb9, 0x0a, 0x05,
+    0x94, 0x78, 0x72, 0xfe, 0x16, 0xba, 0x9d, 0x43, 0xae, 0xda, 0x91, 0xd7,
+    0xde, 0x9d, 0xc4, 0xeb, 0xc2, 0xea, 0x1d, 0x79, 0x44, 0xf1, 0xd7, 0xb4,
+    0xfe, 0x3a, 0x94, 0x36, 0xfb, 0x8e, 0x5d, 0xf3, 0xa7, 0x5f, 0xcb, 0xf2,
+    0x07, 0xf8, 0x3a, 0xf2, 0xfc, 0xd3, 0xad, 0xe8, 0x3c, 0x9c, 0x2d, 0xbf,
+    0xa1, 0x78, 0xa4, 0x68, 0xea, 0x9d, 0x36, 0x2c, 0x19, 0x69, 0x0f, 0x54,
+    0x80, 0x46, 0x2c, 0x3e, 0x26, 0xbb, 0x9f, 0x9d, 0x7f, 0x85, 0xd9, 0xd6,
+    0xa0, 0x07, 0x5e, 0xdb, 0x75, 0x0e, 0xbf, 0xe8, 0x5c, 0xb2, 0x7c, 0xfd,
+    0x82, 0x75, 0xf3, 0xf9, 0x83, 0x39, 0xd5, 0x88, 0x82, 0x41, 0xf7, 0x3d,
+    0xbc, 0xcb, 0x2c, 0x9e, 0xaf, 0xab, 0xce, 0x21, 0x2d, 0x5f, 0x55, 0x4d,
+    0x65, 0xf4, 0xbf, 0x85, 0x0e, 0xb0, 0x0e, 0xac, 0x36, 0x6e, 0x47, 0x50,
+    0x9d, 0x78, 0x45, 0xf9, 0x0b, 0x40, 0x2c, 0xf9, 0xb2, 0xf9, 0x7c, 0xfe,
+    0x73, 0xaf, 0xff, 0x85, 0x14, 0x57, 0x5e, 0xef, 0xef, 0x29, 0x41, 0xd5,
+    0x07, 0xeb, 0x84, 0x95, 0x3a, 0x39, 0x14, 0x86, 0x25, 0xf6, 0x05, 0xe4,
+    0x75, 0xf9, 0xc4, 0x51, 0x67, 0x5f, 0xf7, 0x53, 0x98, 0x8b, 0x86, 0x33,
+    0xaf, 0xc8, 0xb7, 0x1c, 0x3a, 0xbe, 0x2f, 0xb3, 0xb1, 0x03, 0x70, 0x6b,
+    0x22, 0x00, 0x8b, 0xe4, 0x68, 0x0a, 0x28, 0x24, 0x71, 0xcf, 0x2b, 0xdc,
+    0x05, 0x42, 0x41, 0xf9, 0x26, 0xd9, 0xcd, 0xf9, 0x3d, 0x1e, 0xd1, 0x57,
+    0xcd, 0x8f, 0x68, 0xab, 0x99, 0x64, 0xaa, 0x91, 0xef, 0xe1, 0x33, 0x24,
+    0x37, 0x63, 0x25, 0x2a, 0x6b, 0xef, 0xff, 0xbd, 0x0d, 0xcc, 0x1f, 0x75,
+    0x20, 0x67, 0x3a, 0x8e, 0xac, 0x3d, 0x6d, 0x26, 0x50, 0x11, 0x3c, 0xcb,
+    0xed, 0xff, 0xbd, 0xac, 0x6f, 0x5c, 0x7d, 0xa3, 0xaf, 0xd1, 0xb1, 0x04,
+    0x07, 0x7c, 0x37, 0xb7, 0xe9, 0x77, 0xf8, 0xe1, 0xd7, 0xff, 0x3a, 0xf9,
+    0x1b, 0x13, 0x60, 0xff, 0xa3, 0xab, 0x73, 0xef, 0xe9, 0x45, 0xfb, 0x3f,
+    0x5c, 0x68, 0xea, 0x3a, 0xec, 0x9b, 0x86, 0xc7, 0x44, 0xf7, 0xfc, 0x9f,
+    0xb0, 0x7b, 0x1f, 0x46, 0x73, 0xaf, 0xfa, 0x27, 0x8d, 0xfc, 0x39, 0x39,
+    0xd5, 0x88, 0xa5, 0x69, 0x6a, 0x1f, 0xdf, 0x9d, 0x63, 0x1b, 0x9d, 0x53,
+    0x26, 0x9b, 0xc8, 0x7c, 0xf4, 0xba, 0xfb, 0x3b, 0x93, 0x9d, 0x7a, 0x4f,
+    0xc3, 0xaf, 0xd2, 0xcf, 0x60, 0x4a, 0xbe, 0x81, 0x18, 0x3a, 0xa6, 0x3d,
+    0xff, 0x0d, 0xfd, 0x26, 0xbe, 0x06, 0x97, 0xc3, 0xa9, 0x44, 0x6a, 0x24,
+    0x20, 0x3c, 0x65, 0x7f, 0xc3, 0x9d, 0xcf, 0x9d, 0xc9, 0xce, 0xbf, 0xff,
+    0xf8, 0x10, 0x2d, 0x7f, 0x3e, 0xe0, 0xdf, 0xc8, 0xbd, 0x76, 0x3e, 0x89,
+    0xd7, 0xf7, 0xec, 0x14, 0xe7, 0x30, 0xeb, 0xef, 0x29, 0x9d, 0x3a, 0xff,
+    0xc3, 0x9e, 0xf7, 0xf3, 0xfb, 0x1a, 0x75, 0xb4, 0x75, 0xc8, 0x03, 0xae,
+    0xea, 0x1d, 0x77, 0xfa, 0xf8, 0x6a, 0xa6, 0x15, 0xa7, 0x3e, 0xb0, 0x1d,
+    0x5c, 0x08, 0x3a, 0xe0, 0x41, 0xd7, 0xef, 0xe5, 0x82, 0xaa, 0x1a, 0xa0,
+    0x0a, 0xd4, 0x26, 0xaa, 0xa1, 0x10, 0x21, 0x54, 0x29, 0x77, 0xff, 0xd8,
+    0x2f, 0xbe, 0x94, 0x51, 0xfe, 0x35, 0x60, 0x3a, 0xff, 0xef, 0x77, 0x17,
+    0xf6, 0x01, 0x9b, 0xf8, 0xeb, 0xfd, 0xbb, 0x53, 0x9f, 0x60, 0x27, 0x5f,
+    0x01, 0x6f, 0x2f, 0x88, 0xce, 0xd2, 0x9f, 0x91, 0xaf, 0xe0, 0x2f, 0xee,
+    0xbe, 0xce, 0x75, 0xfd, 0xa4, 0x11, 0x8d, 0xce, 0xbb, 0x37, 0x3a, 0xb7,
+    0x3f, 0x4f, 0x19, 0xed, 0x95, 0xdf, 0x03, 0x89, 0xc3, 0xaa, 0x13, 0x11,
+    0x78, 0x5e, 0xb2, 0x67, 0x7d, 0xaf, 0xf7, 0xf1, 0xd7, 0x63, 0x27, 0x5f,
+    0xf4, 0x6f, 0x80, 0x8d, 0x99, 0x39, 0xd7, 0xf0, 0xe7, 0xb4, 0xe0, 0x3a,
+    0xb8, 0x7f, 0x60, 0x16, 0xd1, 0xd5, 0xff, 0xa6, 0x89, 0xf5, 0xcc, 0x6c,
+    0x4e, 0x75, 0xfd, 0x8b, 0xc0, 0xa3, 0x27, 0x5c, 0xb8, 0x3a, 0x96, 0x78,
+    0x2e, 0x59, 0x7f, 0x0e, 0x4d, 0xd4, 0xf1, 0xd7, 0xd9, 0x9d, 0xd1, 0xd5,
+    0x88, 0xee, 0x78, 0x40, 0xf8, 0x87, 0x68, 0xb2, 0xf3, 0x2c, 0xb2, 0x55,
+    0xfb, 0x14, 0x1f, 0xf4, 0x52, 0xa5, 0xfd, 0xf2, 0xac, 0xb2, 0xc9, 0xd7,
+    0x60, 0x0e, 0xac, 0x37, 0x7e, 0x26, 0xa8, 0x44, 0x9f, 0x9c, 0xef, 0x93,
+    0x80, 0xd1, 0xd7, 0xfd, 0xae, 0x47, 0xfe, 0x14, 0xd8, 0x75, 0xff, 0x87,
+    0x34, 0xde, 0xa3, 0x60, 0x4e, 0xbf, 0xff, 0xca, 0x32, 0xfc, 0x51, 0x5d,
+    0x64, 0x87, 0xf7, 0xd6, 0x09, 0xd5, 0x08, 0xd8, 0xc3, 0xa4, 0x3b, 0xbe,
+    0x65, 0xc6, 0x47, 0x5f, 0xf7, 0xa3, 0x70, 0x3f, 0x7a, 0x87, 0x5b, 0xa7,
+    0x56, 0x1e, 0x43, 0x4e, 0x2f, 0x32, 0xcb, 0x25, 0x5f, 0xc8, 0xea, 0x75,
+    0x3c, 0x52, 0xa5, 0xfd, 0xef, 0x23, 0x27, 0x5e, 0xd3, 0xf0, 0xea, 0xdc,
+    0xdb, 0xf8, 0x72, 0xf7, 0x60, 0x27, 0x52, 0x1b, 0xd7, 0x22, 0xbf, 0x60,
+    0x33, 0x26, 0x3a, 0xda, 0xf8, 0x99, 0xaf, 0x10, 0x3b, 0x0b, 0x01, 0x1f,
+    0xbb, 0xf9, 0x05, 0x3e, 0x8c, 0x8e, 0x7a, 0xfc, 0xc1, 0xec, 0x4f, 0xf9,
+    0xd5, 0x32, 0xb7, 0x1e, 0xc3, 0xe4, 0x65, 0x0a, 0xfe, 0x6d, 0x7a, 0x36,
+    0x41, 0xd4, 0x87, 0xd0, 0x29, 0x97, 0x86, 0x36, 0x1d, 0x73, 0x05, 0x0e,
+    0xb9, 0x3a, 0x75, 0x9e, 0x73, 0x5d, 0xc1, 0x9b, 0xef, 0x6b, 0xf6, 0x33,
+    0xaf, 0xf4, 0x0c, 0x85, 0x23, 0x73, 0xaa, 0x19, 0xf6, 0x32, 0x61, 0xc8,
+    0xfd, 0x54, 0x8c, 0x2d, 0xa6, 0xbb, 0x9c, 0xa3, 0x9f, 0x23, 0x86, 0xec,
+    0xa2, 0x17, 0x35, 0x04, 0x27, 0xc6, 0x31, 0xdd, 0x43, 0xd7, 0xd2, 0xfe,
+    0xf6, 0x10, 0x6d, 0xa5, 0x7d, 0x27, 0xda, 0x26, 0xbf, 0x24, 0xd2, 0x41,
+    0x3a, 0xe6, 0x25, 0x0e, 0xbf, 0xe9, 0xbd, 0xb5, 0xa8, 0x9b, 0xfe, 0x1d,
+    0x7f, 0x83, 0x02, 0xb8, 0x0c, 0x1d, 0x50, 0x7d, 0xee, 0x7f, 0x7f, 0xf6,
+    0x27, 0x60, 0x3d, 0xfe, 0x37, 0xd1, 0xd7, 0x82, 0xa0, 0x0e, 0xbf, 0x2f,
+    0x9c, 0x7f, 0x1d, 0x5f, 0x0f, 0x12, 0x07, 0x6f, 0xff, 0x36, 0x67, 0x6f,
+    0x62, 0x5e, 0x1c, 0x59, 0xd7, 0xff, 0xc8, 0xbd, 0xe5, 0xaf, 0x98, 0x23,
+    0x88, 0x03, 0xaf, 0x27, 0x7f, 0x3a, 0xbe, 0x2a, 0x2e, 0x62, 0x09, 0xa5,
+    0x08, 0x9e, 0x10, 0x76, 0x11, 0x0e, 0x47, 0xe4, 0x9d, 0x89, 0xf6, 0x55,
+    0x89, 0x8e, 0x29, 0x55, 0x81, 0x0c, 0xf6, 0x2e, 0x35, 0x56, 0x13, 0x6b,
+    0x0f, 0x8c, 0x69, 0x8a, 0x46, 0x28, 0xc5, 0x4e, 0x98, 0x65, 0x68, 0xa6,
+    0xe3, 0x4f, 0x3a, 0x2d, 0x2a, 0x4f, 0xc8, 0x69, 0x59, 0xd9, 0x6e, 0x78,
+    0x54, 0x96, 0xba, 0xda, 0x5c, 0xae, 0xf4, 0x87, 0x64, 0xa4, 0xf6, 0xb1,
+    0xc6, 0xc5, 0x35, 0x35, 0xcb, 0x94, 0xe1, 0xa5, 0xd2, 0x3f, 0x7b, 0x5b,
+    0xde, 0xbd, 0x75, 0x64, 0x0a, 0x53, 0x63, 0x06, 0x1e, 0x23, 0x5b, 0x40,
+    0x6a, 0xdd, 0x04, 0x7a, 0xd2, 0xdd, 0x7f, 0x3a, 0x4b, 0xb2, 0x55, 0x7b,
+    0x32, 0xc1, 0x36, 0xe7, 0xf3, 0xfe, 0xd6, 0x35, 0x9b, 0x52, 0xd7, 0x29,
+    0x58, 0xe3, 0x6b, 0x25, 0x9c, 0x55, 0x2d, 0xf9, 0x50, 0x2f, 0x3c, 0x75,
+    0xfe, 0x57, 0x38, 0xd7, 0x76, 0x9a, 0x2e, 0x3b, 0xfc, 0xae, 0x71, 0xae,
+    0xed, 0x34, 0x5d, 0x77, 0xff, 0x2a, 0xf2, 0x57, 0x38, 0xd7, 0x76, 0x9a,
+    0x25, 0x1a, 0x88, 0xe4, 0xb9, 0x25, 0x0b, 0xc0, 0x94, 0xa9, 0x08, 0xf6,
+    0x94, 0x24, 0x74, 0x4c, 0x6e, 0x2f, 0x9c, 0x70, 0x18, 0x0e, 0xf4, 0x51,
+    0xe3, 0xfd, 0xa3, 0xfb, 0xff, 0xca, 0xad, 0xe4, 0xae, 0x71, 0xae, 0xed,
+    0x34, 0x4b, 0x57, 0xfc, 0xc3, 0xba, 0x8c, 0x6f, 0x1b, 0xed, 0x1d, 0x7e,
+    0xe3, 0x5d, 0xda, 0x68, 0x8d, 0xef, 0xfc, 0xf2, 0x57, 0x38, 0xd7, 0x76,
+    0x9a, 0x25, 0xfb, 0xfa, 0x3d, 0xf7, 0xaf, 0xe3, 0xaf, 0xf6, 0x7d, 0xe2,
+    0x9d, 0xff, 0x47, 0x5e, 0x9b, 0x5c, 0x3a, 0xca, 0xb1, 0x54, 0xd0, 0xf1,
+    0x11, 0x66, 0x7d, 0x4a, 0x12, 0xef, 0xa6, 0xf7, 0xf9, 0x5c, 0xe3, 0x5d,
+    0xda, 0x68, 0xaa, 0xee, 0x4d, 0xa3, 0xaf, 0x91, 0x6f, 0xb0, 0xea, 0x50,
+    0xdd, 0x78, 0x62, 0xf0, 0xed, 0x32, 0x75, 0xfc, 0xfd, 0x98, 0x60, 0x27,
+    0x5f, 0xfd, 0xee, 0xc6, 0x85, 0xff, 0x60, 0xa7, 0x0e, 0xbd, 0x12, 0xc3,
+    0xa8, 0x28, 0x8d, 0xdc, 0xb2, 0x64, 0x7b, 0xfe, 0x53, 0x07, 0x37, 0xf3,
+    0xac, 0xeb, 0x82, 0x87, 0x5f, 0xd9, 0xc6, 0xbb, 0xb4, 0xd1, 0x20, 0x57,
+    0xc3, 0xcd, 0x54, 0x56, 0xfd, 0xa7, 0x17, 0xdc, 0xeb, 0xbf, 0x83, 0xaa,
+    0x47, 0xc3, 0xb9, 0x2f, 0x09, 0xaf, 0xf4, 0xa3, 0x93, 0xc7, 0x27, 0x3a,
+    0xff, 0x72, 0x75, 0xc0, 0xcb, 0x47, 0x54, 0x1f, 0x3e, 0x1a, 0x5f, 0x64,
+    0xee, 0x13, 0xaf, 0xff, 0x64, 0xdd, 0x75, 0xfb, 0xb1, 0xef, 0xd6, 0x75,
+    0x4e, 0xac, 0x24, 0x24, 0x59, 0x0a, 0xc5, 0x0c, 0x9e, 0x1c, 0xc3, 0x09,
+    0x7f, 0x10, 0x7d, 0x21, 0xbf, 0xf8, 0x72, 0x75, 0x76, 0xe0, 0x47, 0x3c,
+    0x75, 0x2a, 0x8c, 0x8e, 0x42, 0x0e, 0xff, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d,
+    0x16, 0x45, 0xfe, 0x57, 0x38, 0xd7, 0x76, 0x9a, 0x2d, 0x7b, 0xff, 0xd9,
+    0xf6, 0x27, 0x57, 0x26, 0xf0, 0x60, 0x4e, 0xbf, 0xca, 0xe7, 0x1a, 0xee,
+    0xd3, 0x45, 0xc9, 0x7e, 0xe3, 0x5d, 0xda, 0x68, 0xbb, 0x2f, 0xfc, 0xf2,
+    0x57, 0x38, 0xd7, 0x76, 0x9a, 0x28, 0xeb, 0x2b, 0x87, 0xfa, 0xb3, 0x3b,
+    0xe1, 0x89, 0x2c, 0xeb, 0x48, 0xeb, 0xf7, 0x1a, 0xee, 0xd3, 0x45, 0x2b,
+    0x7f, 0xcd, 0xea, 0x4d, 0xd8, 0x9f, 0x0e, 0xbf, 0xfd, 0xd8, 0x9e, 0x3a,
+    0x9b, 0x1c, 0x3d, 0x43, 0x95, 0x37, 0x37, 0x49, 0x5c, 0x46, 0x3c, 0xcd,
+    0x95, 0xba, 0x60, 0xef, 0x0d, 0x7b, 0xff, 0x3a, 0x7a, 0x5f, 0x85, 0xc4,
+    0x07, 0x59, 0x50, 0xa7, 0x1a, 0xb8, 0xc9, 0xfa, 0x53, 0x53, 0xb2, 0x7a,
+    0xe5, 0x1c, 0xd6, 0xec, 0xa9, 0x38, 0x94, 0xb2, 0x90, 0x1f, 0x89, 0xfe,
+    0x93, 0x3d, 0x0b, 0xcd, 0x91, 0xda, 0xdf, 0xf4, 0x95, 0xce, 0x35, 0xdd,
+    0xa6, 0x88, 0xe2, 0xff, 0x91, 0x5c, 0xe3, 0x5d, 0xda, 0x68, 0xad, 0x6c,
+    0xab, 0xa2, 0x27, 0xc8, 0xb7, 0xff, 0x95, 0x5b, 0xc9, 0x5c, 0xe3, 0x5d,
+    0xda, 0x68, 0x96, 0xef, 0x7f, 0xc0, 0x1d, 0x76, 0x6e, 0x75, 0xfe, 0x0e,
+    0x2d, 0x70, 0x9a, 0x3a, 0xf6, 0xcf, 0xe4, 0x75, 0x35, 0x10, 0x7b, 0x8e,
+    0xa0, 0xb6, 0xc3, 0x1b, 0xdd, 0x0c, 0x8e, 0xbf, 0xec, 0xdc, 0x70, 0x00,
+    0x79, 0x1d, 0x72, 0xda, 0x75, 0x41, 0xe6, 0xc8, 0xde, 0xf8, 0x63, 0x79,
+    0x1d, 0x7f, 0xfe, 0x7d, 0xc0, 0x1e, 0xbc, 0xb3, 0x43, 0xfb, 0xfd, 0x3a,
+    0x9a, 0x7f, 0x1d, 0x21, 0xb2, 0x87, 0x5f, 0xc9, 0xc1, 0x4f, 0x68, 0xeb,
+    0xf7, 0x1c, 0x72, 0x0e, 0xa3, 0x44, 0x36, 0x87, 0xc1, 0xd1, 0x17, 0x2b,
+    0xba, 0x04, 0xeb, 0xf9, 0x04, 0x38, 0x81, 0x3a, 0xa0, 0xdf, 0x48, 0x52,
+    0xfb, 0x26, 0x96, 0x1d, 0x7f, 0xe7, 0x92, 0xb9, 0xc6, 0xbb, 0xb4, 0xd1,
+    0x30, 0x5f, 0x81, 0xa7, 0x10, 0x1d, 0x7f, 0xbf, 0xdf, 0x89, 0x0b, 0xc3,
+    0xaf, 0xfa, 0x27, 0xf0, 0xc7, 0xfe, 0xd1, 0xd6, 0xf7, 0x4f, 0xb3, 0x6c,
+    0xce, 0xfb, 0x76, 0xa2, 0x87, 0x56, 0x1e, 0x77, 0x8a, 0xef, 0xf6, 0x93,
+    0xa8, 0xbc, 0x50, 0xeb, 0xff, 0xcf, 0x3f, 0x52, 0x07, 0x26, 0x4e, 0x21,
+    0xd5, 0xe3, 0xf9, 0x64, 0xca, 0xe6, 0xe1, 0xd7, 0x7e, 0x02, 0xa9, 0x0d,
+    0x67, 0x05, 0x6f, 0xf6, 0x04, 0x73, 0xdd, 0xc3, 0xae, 0x61, 0x34, 0xf1,
+    0x85, 0x5f, 0xd3, 0xfd, 0xdb, 0x71, 0x01, 0xd7, 0xf6, 0x7b, 0xd1, 0xcd,
+    0x1d, 0x7f, 0x38, 0x82, 0x70, 0x78, 0xea, 0x84, 0x45, 0x89, 0x96, 0xd9,
+    0x65, 0x95, 0x85, 0xdc, 0x89, 0xcf, 0xc2, 0xd3, 0x90, 0x99, 0x6c, 0x20,
+    0xb7, 0x7e, 0xe1, 0x02, 0xc8, 0x5d, 0x28, 0x61, 0xc1, 0xa8, 0x4d, 0x79,
+    0x3f, 0x61, 0x03, 0x26, 0x1f, 0x61, 0x65, 0x79, 0x7f, 0xf0, 0xab, 0xff,
+    0x3c, 0x95, 0xce, 0x35, 0xdd, 0xa6, 0x89, 0x8e, 0xfa, 0x39, 0x1b, 0x47,
+    0x59, 0x54, 0x44, 0x52, 0xc7, 0x7a, 0x95, 0x7d, 0x13, 0xc7, 0x0e, 0xbf,
+    0x64, 0x4c, 0x8b, 0x3a, 0x90, 0xf1, 0xf8, 0x43, 0x7f, 0x05, 0x71, 0x9e,
+    0xd1, 0xd7, 0xfb, 0xb1, 0xc9, 0xfe, 0xfe, 0x03, 0xae, 0x7d, 0x1d, 0x7d,
+    0xf3, 0xd9, 0xd3, 0xad, 0x1d, 0x37, 0x1a, 0x15, 0xbd, 0x03, 0x39, 0xd7,
+    0xff, 0xff, 0xd2, 0xd7, 0x73, 0xf6, 0x75, 0xdc, 0x6e, 0x6b, 0xe6, 0x6f,
+    0x2d, 0x20, 0xa1, 0xd7, 0x9d, 0xda, 0x68, 0xac, 0x6f, 0x9f, 0xec, 0x28,
+    0x75, 0x34, 0xf2, 0xb8, 0x4f, 0x7f, 0xed, 0xbc, 0xf0, 0xe7, 0xf0, 0x3e,
+    0x3a, 0x94, 0x4d, 0xb1, 0xa4, 0xdb, 0x8d, 0xf2, 0x19, 0x5e, 0x22, 0xbf,
+    0xf8, 0x7c, 0xa7, 0xf0, 0x38, 0xd8, 0xe1, 0xd7, 0xfb, 0x93, 0xfb, 0x4f,
+    0xbb, 0x4e, 0xa8, 0x3f, 0x87, 0x43, 0xbf, 0xa3, 0x6b, 0xd9, 0xbc, 0xc7,
+    0x5f, 0xdf, 0xed, 0xb7, 0xa8, 0xc1, 0x3a, 0xfe, 0xcd, 0x6f, 0x28, 0xe9,
+    0xd7, 0x46, 0xc3, 0xac, 0x1e, 0x9e, 0x20, 0x96, 0xdf, 0xf4, 0x6f, 0x29,
+    0xa4, 0xfc, 0x9c, 0xea, 0x84, 0x6d, 0xe3, 0xca, 0x13, 0xde, 0x89, 0x78,
+    0xeb, 0xff, 0x60, 0x78, 0x9f, 0xce, 0x0d, 0x48, 0xeb, 0xe5, 0xbe, 0xfe,
+    0x3a, 0xff, 0xe9, 0xe3, 0xdf, 0x3e, 0xb7, 0xee, 0xd7, 0xdd, 0x1d, 0x7f,
+    0xdc, 0x8d, 0x3f, 0x06, 0x24, 0x75, 0x71, 0x10, 0xfb, 0x14, 0x6f, 0x49,
+    0xe7, 0x3a, 0xf7, 0xc9, 0xd6, 0x75, 0xc1, 0xf1, 0xd4, 0xc2, 0x4c, 0x7f,
+    0x21, 0x53, 0xb9, 0x2a, 0x0e, 0x08, 0xfd, 0xff, 0x85, 0xc3, 0xd8, 0xd9,
+    0xd7, 0x13, 0xaf, 0xff, 0xfd, 0xfc, 0xf8, 0xdf, 0x83, 0xfe, 0xd7, 0xcc,
+    0xde, 0x59, 0xf8, 0x83, 0x47, 0x5f, 0xfe, 0x9f, 0x37, 0xf6, 0x90, 0x60,
+    0x0e, 0xb3, 0xaf, 0xf6, 0xe3, 0x81, 0xeb, 0xb2, 0x75, 0x61, 0xfe, 0x3a,
+    0x4d, 0x05, 0x35, 0x01, 0x3d, 0xd4, 0x3c, 0xef, 0xe9, 0xe6, 0x93, 0x0b,
+    0x93, 0x9d, 0x7c, 0x23, 0x9e, 0x3a, 0xfc, 0x8c, 0x7c, 0xe2, 0x1d, 0x4c,
+    0x41, 0xfe, 0xc1, 0xaf, 0x47, 0xef, 0xe9, 0xfe, 0xed, 0xb8, 0x80, 0xeb,
+    0xe6, 0x38, 0xd0, 0x9d, 0x7f, 0xee, 0xba, 0xfd, 0xd8, 0xf7, 0xeb, 0x3a,
+    0xb0, 0xf8, 0xa6, 0x23, 0xbf, 0xe4, 0x92, 0x77, 0xf5, 0xad, 0x0e, 0xa8,
+    0x47, 0x76, 0x42, 0x53, 0xc4, 0x57, 0xba, 0x8a, 0xc3, 0x25, 0xb6, 0x72,
+    0x19, 0x16, 0x64, 0x7b, 0x6d, 0x86, 0x57, 0x08, 0x3b, 0x18, 0x63, 0x96,
+    0x88, 0xde, 0xa3, 0x5f, 0xf4, 0x74, 0x5b, 0x70, 0xb2, 0xfb, 0x19, 0x0d,
+    0xd2, 0x13, 0xaf, 0xee, 0x72, 0x03, 0x8b, 0x3a, 0xfa, 0x7e, 0x44, 0xe7,
+    0x5d, 0xf4, 0x07, 0x5e, 0xea, 0x2c, 0xeb, 0x4c, 0x75, 0x39, 0xac, 0xfc,
+    0x6e, 0xfc, 0xe3, 0x3f, 0xfa, 0x3a, 0xff, 0xa0, 0x3d, 0xc0, 0xf1, 0xda,
+    0x75, 0x22, 0x62, 0x6e, 0x58, 0x02, 0x31, 0x44, 0xd1, 0x0f, 0x8a, 0x2d,
+    0xd3, 0xaf, 0x6b, 0xee, 0x8e, 0xbe, 0xde, 0x78, 0x50, 0xea, 0x9c, 0xf4,
+    0x82, 0x21, 0xf8, 0xf5, 0xde, 0x83, 0xaf, 0xf6, 0xfc, 0x84, 0x93, 0xe8,
+    0xeb, 0xec, 0x18, 0x91, 0xd5, 0x87, 0xa2, 0xb3, 0x2b, 0xfd, 0x80, 0xd6,
+    0x79, 0x38, 0x75, 0xf7, 0xfe, 0xcd, 0x1d, 0x7d, 0x1c, 0x71, 0x3a, 0xff,
+    0x3f, 0x24, 0x04, 0xdf, 0x47, 0x5f, 0x6b, 0x50, 0x03, 0xaa, 0x11, 0xcf,
+    0x84, 0x28, 0x63, 0xd2, 0x2f, 0xc7, 0xd9, 0x33, 0xbe, 0x90, 0x3f, 0x91,
+    0xd7, 0xdc, 0xfb, 0x00, 0x3a, 0xa0, 0xf1, 0x90, 0x8e, 0xff, 0x24, 0xee,
+    0xb0, 0x02, 0x0e, 0xbf, 0xe4, 0x6f, 0x72, 0x61, 0x80, 0x9d, 0x7d, 0x2f,
+    0x67, 0xd3, 0xaf, 0x36, 0x00, 0x75, 0xee, 0x42, 0xce, 0xa7, 0x3d, 0x9f,
+    0xc8, 0xd9, 0x1b, 0xbf, 0x44, 0xff, 0x72, 0x63, 0xaf, 0x40, 0xc8, 0xea,
+    0x99, 0x35, 0x6e, 0x10, 0x74, 0xc8, 0x61, 0x21, 0xa3, 0x0f, 0x15, 0x5f,
+    0xfa, 0x33, 0x5f, 0x21, 0x03, 0xf6, 0x47, 0x5f, 0xc8, 0xce, 0xa7, 0xc6,
+    0x4e, 0xa1, 0x3e, 0xff, 0x20, 0x5f, 0xa0, 0x3e, 0xc6, 0x9d, 0x7d, 0xd8,
+    0x16, 0x9d, 0x52, 0x3e, 0x7d, 0x10, 0xf8, 0x9a, 0xf9, 0xc5, 0xe6, 0x3a,
+    0xfc, 0x9e, 0x1c, 0x91, 0xd7, 0xd0, 0xcc, 0x4c, 0x75, 0xdf, 0x56, 0x75,
+    0xfd, 0xe1, 0x70, 0x60, 0x9d, 0x7e, 0x17, 0x06, 0x09, 0xd6, 0xff, 0xe1,
+    0xe7, 0x78, 0xaa, 0xa7, 0x47, 0xc2, 0x84, 0x08, 0x4b, 0xd2, 0x21, 0x66,
+    0xbf, 0xd0, 0xc8, 0x7f, 0x7e, 0x48, 0xeb, 0xf9, 0x39, 0xbe, 0xa2, 0x47,
+    0x5b, 0x61, 0xd5, 0xc3, 0xf3, 0xe9, 0xa6, 0xd1, 0x6d, 0xe1, 0x45, 0x0e,
+    0xbe, 0xc0, 0xa6, 0xc3, 0xae, 0x85, 0xe1, 0xbd, 0x71, 0xbb, 0xfe, 0xc6,
+    0x5f, 0x7e, 0xc7, 0xd1, 0x3a, 0xda, 0x3a, 0x90, 0xfd, 0x38, 0x54, 0xe7,
+    0x57, 0x02, 0x0a, 0xb9, 0x96, 0x4a, 0xa4, 0x35, 0xac, 0x8a, 0xdf, 0xe7,
+    0x90, 0xe7, 0xba, 0x85, 0x2a, 0x68, 0x6f, 0x3e, 0xfa, 0x3a, 0xfb, 0xef,
+    0x5f, 0xc7, 0x50, 0x4d, 0xff, 0x87, 0x2f, 0x40, 0xcc, 0x75, 0xc3, 0x07,
+    0x5a, 0x63, 0xaa, 0x63, 0xc0, 0xe0, 0xdb, 0x8a, 0x5f, 0xfc, 0xa2, 0x0b,
+    0x75, 0x0b, 0x7d, 0xfc, 0x75, 0xe0, 0x66, 0xd1, 0xd4, 0xa1, 0xf1, 0x71,
+    0x12, 0xf9, 0x7a, 0xfd, 0x67, 0x59, 0x43, 0xad, 0xb6, 0x75, 0xdc, 0x50,
+    0xea, 0x83, 0xde, 0x42, 0x3f, 0xc4, 0x7e, 0x89, 0xdf, 0xff, 0x77, 0x25,
+    0xa8, 0xf4, 0xb1, 0x8d, 0xc4, 0x07, 0x5f, 0xfa, 0x49, 0xee, 0xe6, 0xfe,
+    0xfe, 0x0e, 0xbb, 0x34, 0x75, 0x41, 0xea, 0x48, 0xfe, 0xb4, 0x8c, 0x5f,
+    0x42, 0x92, 0xfc, 0x90, 0xb8, 0x59, 0xd6, 0xc3, 0xa9, 0x0f, 0x73, 0x45,
+    0x1b, 0x64, 0xb5, 0x0a, 0xc0, 0xb1, 0x85, 0x21, 0x23, 0xd8, 0x40, 0xbc,
+    0x6b, 0xd7, 0xb5, 0x13, 0x1d, 0x47, 0x59, 0x67, 0x57, 0x8b, 0xad, 0x81,
+    0x57, 0xe0, 0x27, 0x11, 0x43, 0xae, 0x75, 0x0e, 0xa9, 0x91, 0x2b, 0xd3,
+    0x60, 0x11, 0x09, 0x3d, 0xde, 0x83, 0xaf, 0xd1, 0xdc, 0xd8, 0xe7, 0x53,
+    0x9b, 0xc0, 0x0a, 0xdf, 0xc9, 0xec, 0xeb, 0xa8, 0x75, 0xfd, 0xdf, 0xde,
+    0x7e, 0xa1, 0xd7, 0x99, 0x65, 0x92, 0xaf, 0xf8, 0x31, 0x3f, 0xdc, 0xeb,
+    0xee, 0x52, 0xa5, 0xfd, 0xd9, 0x39, 0xd4, 0x14, 0x57, 0x35, 0x35, 0x12,
+    0xef, 0x42, 0xd0, 0xea, 0xc3, 0xc9, 0x69, 0x7d, 0xf2, 0x73, 0x68, 0x27,
+    0x5f, 0xbb, 0x1b, 0xbb, 0x19, 0xd7, 0xff, 0xd1, 0xed, 0x07, 0x3c, 0x9d,
+    0xff, 0x37, 0xf1, 0xd5, 0xd3, 0xfa, 0xf1, 0x55, 0xb8, 0x75, 0xfe, 0xcc,
+    0x6f, 0xdd, 0x9d, 0xc3, 0xae, 0xff, 0x47, 0x5f, 0xff, 0xb0, 0x31, 0x9b,
+    0xfd, 0xf2, 0x0f, 0xf2, 0xcd, 0x1d, 0x72, 0xc0, 0x75, 0xce, 0x27, 0x57,
+    0x4d, 0x53, 0x8b, 0x5f, 0x96, 0x9e, 0x03, 0x9d, 0x53, 0xa7, 0xc5, 0x90,
+    0x9e, 0x63, 0x22, 0x98, 0x41, 0xcd, 0x44, 0x5f, 0xd0, 0x80, 0xfc, 0x82,
+    0xfb, 0xbe, 0x49, 0xce, 0xbf, 0xcd, 0x4d, 0x0e, 0x6c, 0x73, 0xaf, 0xa2,
+    0x77, 0x91, 0xd7, 0x67, 0x8e, 0xbf, 0x64, 0xe3, 0x9b, 0x9d, 0x58, 0x8b,
+    0x1d, 0xc8, 0xb8, 0x65, 0xd2, 0x11, 0x15, 0xbe, 0x81, 0x46, 0x33, 0xaf,
+    0x76, 0x02, 0x75, 0xdc, 0xd1, 0xd4, 0x72, 0x16, 0xd7, 0xfa, 0x06, 0x4e,
+    0xbc, 0x09, 0xd7, 0xde, 0x5a, 0xf8, 0x75, 0xff, 0xc0, 0x81, 0x6b, 0xf8,
+    0x1f, 0x46, 0x47, 0x5e, 0x92, 0x74, 0xeb, 0xef, 0x0e, 0x48, 0xeb, 0xf6,
+    0x7e, 0xc1, 0xd3, 0x9d, 0x7f, 0xf9, 0x35, 0xdc, 0x08, 0xe6, 0xc1, 0xcd,
+    0x1d, 0x52, 0x4d, 0x11, 0x43, 0x0d, 0xc8, 0xa6, 0x44, 0xe0, 0xd8, 0x90,
+    0x78, 0xae, 0x98, 0x4d, 0xab, 0x8c, 0x46, 0x51, 0x3c, 0x29, 0xe4, 0x62,
+    0x18, 0xd3, 0x72, 0x3f, 0x2d, 0xe3, 0x33, 0x48, 0xc9, 0xe6, 0x85, 0xef,
+    0x21, 0xc6, 0xb7, 0xbe, 0xcb, 0x82, 0x78, 0x76, 0x81, 0xe5, 0x82, 0x40,
+    0x31, 0x91, 0xea, 0x50, 0x1f, 0xa3, 0x30, 0xd8, 0x92, 0xc9, 0x16, 0xd9,
+    0x8f, 0xd8, 0xd7, 0x2f, 0xf9, 0x5f, 0x26, 0x6d, 0x6b, 0xf8, 0x3a, 0xff,
+    0xff, 0xbf, 0x85, 0x7d, 0xa4, 0xeb, 0xa7, 0xb3, 0x80, 0x5b, 0xc8, 0xea,
+    0x55, 0x51, 0x74, 0xf1, 0xc6, 0x04, 0xf2, 0xfd, 0xc6, 0xbb, 0xb4, 0xd1,
+    0x5b, 0xdf, 0xf9, 0xe4, 0xae, 0x71, 0xae, 0xed, 0x34, 0x4e, 0x16, 0x57,
+    0x0f, 0xf5, 0x66, 0x77, 0x30, 0x82, 0x75, 0xba, 0x75, 0xb4, 0x75, 0x7e,
+    0x68, 0x36, 0xc4, 0x2f, 0x9a, 0xee, 0xd3, 0x45, 0xa3, 0x7f, 0xfb, 0x03,
+    0xd7, 0x52, 0x69, 0x93, 0x5f, 0xac, 0xea, 0xe1, 0xfd, 0x74, 0xb6, 0xf9,
+    0xae, 0x20, 0x3a, 0xff, 0xa6, 0xc6, 0x3d, 0x73, 0x8f, 0xe3, 0xaf, 0xe8,
+    0x71, 0xfc, 0x38, 0x75, 0xc8, 0xa1, 0xd7, 0xff, 0xe9, 0xe3, 0xd0, 0x1e,
+    0x47, 0x5f, 0x43, 0x80, 0x3a, 0xff, 0xd1, 0xbb, 0xb1, 0xf4, 0x5d, 0x8e,
+    0x73, 0xaf, 0xfd, 0x1c, 0x06, 0x26, 0x73, 0xdf, 0x9d, 0x50, 0x8d, 0x4e,
+    0xa9, 0xe9, 0x12, 0xd9, 0x32, 0x63, 0x3a, 0x87, 0x55, 0xfe, 0xef, 0x7f,
+    0x51, 0x71, 0xa3, 0xaf, 0xff, 0xc9, 0xa1, 0xcd, 0x8f, 0xe1, 0xcd, 0x75,
+    0xe6, 0x3a, 0xb1, 0x11, 0x33, 0x1a, 0xdf, 0x60, 0x1f, 0xa7, 0x5d, 0xdd,
+    0x1d, 0x65, 0x58, 0x0a, 0xeb, 0x18, 0xb3, 0xac, 0x84, 0xfb, 0x48, 0xa6,
+    0x20, 0x59, 0xe7, 0x63, 0x44, 0xf4, 0x2e, 0x36, 0xc8, 0xfe, 0x90, 0x5f,
+    0x35, 0xdd, 0xa6, 0x8b, 0x6a, 0xff, 0xfe, 0x87, 0xf4, 0x76, 0x34, 0x89,
+    0x24, 0xe6, 0x04, 0xeb, 0xfb, 0xb0, 0xb8, 0x40, 0x9d, 0x5c, 0x45, 0x76,
+    0x8b, 0x7c, 0xad, 0x7f, 0xee, 0xa0, 0x5e, 0x41, 0xea, 0x2c, 0xeb, 0xfe,
+    0xcc, 0x6e, 0xdf, 0xfd, 0x4e, 0x1d, 0x7d, 0x1b, 0x31, 0x0e, 0xbf, 0xe8,
+    0x94, 0x72, 0x78, 0xe4, 0xe7, 0x5f, 0xf4, 0x73, 0xe6, 0xa3, 0xae, 0x87,
+    0x5f, 0xee, 0xa3, 0xcb, 0xc9, 0x39, 0xd5, 0x89, 0xb6, 0x34, 0xc2, 0x63,
+    0xde, 0x1d, 0x89, 0x0b, 0x27, 0x3b, 0x67, 0x17, 0xf2, 0x8f, 0xc0, 0xfe,
+    0x27, 0x5f, 0xc3, 0xb6, 0x9c, 0xc5, 0x0e, 0xbf, 0x24, 0xeb, 0x86, 0x9d,
+    0x7e, 0x7d, 0xe5, 0xf7, 0x47, 0x5f, 0xf9, 0x26, 0xd6, 0xc7, 0x19, 0xff,
+    0x09, 0xd6, 0x55, 0x44, 0x78, 0x09, 0x77, 0x8b, 0xf6, 0x13, 0xfd, 0x2a,
+    0xa5, 0x53, 0xad, 0x04, 0x6b, 0x17, 0x2f, 0xa7, 0x5f, 0xb8, 0xd7, 0x76,
+    0x9a, 0x2e, 0x5b, 0x2a, 0x13, 0xc9, 0xc1, 0x6b, 0xf7, 0x1a, 0xee, 0xd3,
+    0x45, 0xdb, 0x7f, 0xc9, 0x29, 0x20, 0x82, 0x24, 0x75, 0x95, 0xc3, 0xe9,
+    0x73, 0x3a, 0x87, 0x69, 0xe5, 0x39, 0x4c, 0xa7, 0xa8, 0x83, 0x1b, 0xe2,
+    0x94, 0x9e, 0xa4, 0xae, 0x24, 0x58, 0xe1, 0x6f, 0xd9, 0x7a, 0x83, 0x38,
+    0xf3, 0xa7, 0x4f, 0x42, 0x46, 0xff, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x15,
+    0x3d, 0xf8, 0x55, 0xe6, 0xb4, 0x75, 0xd3, 0xac, 0xeb, 0xf6, 0xeb, 0x77,
+    0x13, 0xa8, 0x26, 0xf7, 0xf1, 0x7b, 0x78, 0xeb, 0xfe, 0x87, 0x9f, 0xe6,
+    0xfa, 0x80, 0x9d, 0x48, 0x79, 0x62, 0x21, 0x7c, 0xd7, 0x76, 0x9a, 0x2b,
+    0x9b, 0xfc, 0xae, 0x71, 0xae, 0xed, 0x34, 0x59, 0xd7, 0x9d, 0xe4, 0x75,
+    0xfc, 0x9a, 0xc1, 0x76, 0x4e, 0xae, 0x22, 0xc7, 0xa5, 0xa2, 0x7f, 0xe1,
+    0xab, 0xff, 0xde, 0x8d, 0x7c, 0xff, 0x5e, 0x89, 0xa6, 0x43, 0xaf, 0xe4,
+    0x5c, 0xff, 0xf2, 0x47, 0x5f, 0xe8, 0xef, 0xc5, 0xb1, 0x6c, 0x0f, 0x1d,
+    0x58, 0x8b, 0xbe, 0xa7, 0x6c, 0x2f, 0xbf, 0x73, 0x3c, 0x8b, 0x3a, 0xf9,
+    0xc6, 0x02, 0x75, 0xfa, 0x68, 0x5c, 0x7d, 0x3a, 0xe9, 0x2c, 0xea, 0xc3,
+    0x7e, 0x25, 0x37, 0xee, 0x35, 0xdd, 0xa6, 0x89, 0x0a, 0xff, 0xd8, 0xbc,
+    0x7e, 0x4f, 0xf3, 0x75, 0x9d, 0x7f, 0xc9, 0xbe, 0xbc, 0x30, 0xbd, 0x1d,
+    0x74, 0x95, 0xc4, 0x56, 0x74, 0xcc, 0x08, 0x37, 0xff, 0x75, 0x17, 0x9a,
+    0xf9, 0xbc, 0xb3, 0xc7, 0x5f, 0x4b, 0xbf, 0x74, 0x75, 0x41, 0xf5, 0x62,
+    0x35, 0xf3, 0x17, 0xd8, 0x59, 0xd7, 0xf7, 0x75, 0xac, 0xe4, 0xe7, 0x5d,
+    0x0c, 0x9d, 0x58, 0x78, 0x88, 0x5d, 0x79, 0x7b, 0x24, 0x75, 0xff, 0xee,
+    0xc0, 0x16, 0xf2, 0xd7, 0xb3, 0x16, 0x75, 0x95, 0x9d, 0x75, 0xac, 0x2d,
+    0xb9, 0x0d, 0x14, 0x87, 0xbf, 0x0c, 0x56, 0x4d, 0xd5, 0xe7, 0x86, 0x58,
+    0xc2, 0x9b, 0x44, 0x1e, 0x6a, 0xfc, 0x83, 0xe8, 0xf5, 0xff, 0xca, 0xf5,
+    0xf4, 0x39, 0xef, 0x40, 0x0e, 0xbf, 0xfc, 0xaa, 0xde, 0x4a, 0xe7, 0x1a,
+    0xee, 0xd3, 0x44, 0xf9, 0x4d, 0x5f, 0x79, 0x43, 0xf6, 0x39, 0xdd, 0x05,
+    0xc3, 0x43, 0xa8, 0x77, 0x26, 0xe7, 0x5f, 0xff, 0x4a, 0x76, 0x1a, 0x18,
+    0xb9, 0xdb, 0xcf, 0x9f, 0x3b, 0xb6, 0x75, 0x48, 0xfe, 0x80, 0x2d, 0x7e,
+    0xce, 0x66, 0x4c, 0x75, 0x95, 0xe9, 0xe4, 0x7d, 0x22, 0xbf, 0x71, 0xae,
+    0xed, 0x34, 0x56, 0x57, 0xfe, 0x79, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x13,
+    0x75, 0x95, 0xc3, 0xfd, 0x59, 0x9d, 0x35, 0x1a, 0x09, 0x0a, 0x8b, 0xf7,
+    0x1a, 0xee, 0xd3, 0x44, 0xad, 0x7e, 0x18, 0x0b, 0xf4, 0xeb, 0xf2, 0xab,
+    0x79, 0x2b, 0x87, 0xb0, 0x86, 0x77, 0xfe, 0xf6, 0x2b, 0x9c, 0x49, 0xdd,
+    0x67, 0x5f, 0xfe, 0x62, 0x58, 0x86, 0x06, 0xb1, 0xe4, 0x99, 0xcc, 0x3a,
+    0xff, 0xc9, 0xaf, 0xd6, 0x29, 0xb3, 0xf7, 0x3a, 0xfe, 0x81, 0x76, 0xbb,
+    0x19, 0xd5, 0x23, 0xed, 0x5a, 0x05, 0xc1, 0xe1, 0xd7, 0xee, 0x35, 0xdd,
+    0xa6, 0x89, 0x72, 0xff, 0x91, 0xe5, 0xe1, 0x85, 0xe8, 0xeb, 0xf4, 0xb6,
+    0xd3, 0xae, 0x75, 0xe8, 0xdb, 0x83, 0xaf, 0x20, 0xc1, 0xd5, 0x23, 0xdf,
+    0x09, 0x4e, 0xc1, 0xdb, 0xff, 0xf3, 0xf9, 0x3f, 0x90, 0xa4, 0xa3, 0xc3,
+    0xfc, 0x8e, 0xbf, 0xa5, 0xdc, 0x1c, 0x69, 0xd7, 0xa5, 0xdf, 0x1d, 0x77,
+    0x61, 0x0f, 0x1f, 0xa5, 0x77, 0xff, 0x0a, 0x03, 0x5c, 0x84, 0x93, 0xe8,
+    0xea, 0xc3, 0xed, 0x42, 0xcb, 0xcf, 0x25, 0x58, 0xa2, 0xb1, 0xb8, 0x86,
+    0x14, 0x88, 0xb0, 0x5b, 0xa6, 0x6f, 0x09, 0x5d, 0x18, 0xfa, 0x30, 0x8b,
+    0x2a, 0x8a, 0xfc, 0x57, 0x2d, 0x66, 0xff, 0xe5, 0x5e, 0x4a, 0xe7, 0x1a,
+    0xee, 0xd3, 0x44, 0x77, 0x7f, 0xde, 0xee, 0x49, 0x57, 0x1d, 0x1d, 0x7f,
+    0x30, 0x86, 0x1b, 0x82, 0x75, 0xdf, 0xf4, 0xeb, 0xf9, 0x80, 0x39, 0xd7,
+    0xf1, 0xd7, 0xff, 0xf7, 0xa4, 0x81, 0xea, 0x6c, 0xf9, 0x81, 0xe2, 0x7e,
+    0xd3, 0xaf, 0xf6, 0x33, 0xa8, 0x1f, 0x68, 0xeb, 0xf8, 0x03, 0x9b, 0xfb,
+    0x0e, 0xbf, 0x3a, 0x9d, 0xc0, 0x1d, 0x7f, 0x08, 0x1f, 0x8f, 0xf4, 0xea,
+    0x84, 0x40, 0x70, 0xb1, 0xc9, 0xef, 0xfc, 0x9c, 0xf9, 0xa1, 0xc5, 0xc3,
+    0x4e, 0xbf, 0xf4, 0x0f, 0xfe, 0x47, 0xd8, 0xf2, 0x3a, 0xff, 0xc3, 0xfc,
+    0xbe, 0x62, 0x0c, 0x2c, 0xeb, 0xe6, 0xbb, 0xb4, 0xd1, 0x50, 0xdf, 0xf6,
+    0x77, 0x05, 0xf9, 0xc4, 0x3a, 0x94, 0x4c, 0x71, 0xa7, 0xc8, 0x7d, 0xc3,
+    0xed, 0x16, 0xde, 0x63, 0x78, 0x3a, 0xe9, 0x61, 0xd7, 0xfd, 0x2f, 0x27,
+    0x1d, 0xa8, 0x27, 0x5f, 0x48, 0x1a, 0xc3, 0xaf, 0xff, 0x3a, 0xf3, 0x83,
+    0x89, 0xb1, 0x38, 0xe7, 0x5f, 0xfd, 0xd1, 0xc9, 0xbd, 0xdc, 0xe2, 0x68,
+    0xeb, 0xf6, 0xe2, 0x8b, 0x43, 0xaa, 0x11, 0x61, 0x88, 0xe8, 0x87, 0x7f,
+    0xa3, 0xcf, 0xdf, 0x81, 0x83, 0xaf, 0xfd, 0x9e, 0xd7, 0x32, 0x6e, 0xa2,
+    0x87, 0x5f, 0xf7, 0xc7, 0x1c, 0xda, 0xf9, 0xdf, 0xce, 0xa4, 0x3f, 0xef,
+    0xcf, 0xef, 0xf4, 0xa3, 0x93, 0xc7, 0x27, 0x3a, 0xff, 0xda, 0xc1, 0xf6,
+    0xb2, 0x49, 0xd3, 0xaf, 0xed, 0x66, 0xc1, 0x8d, 0xce, 0xad, 0x1f, 0x57,
+    0x8f, 0x2f, 0xff, 0xa0, 0x18, 0x3f, 0x1f, 0xdf, 0x3b, 0x80, 0x73, 0xae,
+    0x19, 0xce, 0xa8, 0x4c, 0x9b, 0x21, 0x3c, 0x84, 0x42, 0xa1, 0x7f, 0x6c,
+    0x75, 0xf5, 0x97, 0x3a, 0xff, 0xff, 0x24, 0x79, 0xfa, 0xae, 0xbb, 0x83,
+    0xef, 0x80, 0x96, 0x8e, 0xb6, 0x22, 0x24, 0x44, 0xbe, 0xfb, 0xbe, 0xc9,
+    0xce, 0xbf, 0x64, 0xee, 0x3b, 0x0e, 0xbf, 0xff, 0xff, 0xd1, 0x2f, 0x9e,
+    0xea, 0x46, 0xbe, 0x67, 0xed, 0x8d, 0x9f, 0x33, 0x9c, 0xcd, 0x9f, 0xbf,
+    0x4e, 0xbe, 0xe8, 0xbe, 0xd1, 0xd5, 0x89, 0x82, 0x89, 0x16, 0x8a, 0x3d,
+    0x09, 0x8b, 0xff, 0xfe, 0xfd, 0xd8, 0xd2, 0x7e, 0xba, 0x7a, 0x3a, 0x9e,
+    0xd6, 0x04, 0xeb, 0x2a, 0xc0, 0x64, 0x8e, 0xb1, 0x65, 0xcc, 0x21, 0x78,
+    0x2f, 0x9d, 0x7c, 0x30, 0xb2, 0xc8, 0xd2, 0x94, 0x4b, 0x68, 0xee, 0xe2,
+    0xa8, 0x6d, 0xc8, 0x68, 0xac, 0xb7, 0xb0, 0xb1, 0x18, 0xd2, 0x35, 0x0d,
+    0x0f, 0x46, 0x57, 0xb6, 0x83, 0x7c, 0xd7, 0x76, 0x9a, 0x2a, 0x8b, 0xfd,
+    0xc8, 0xd9, 0xbc, 0xb3, 0xc7, 0x57, 0x0f, 0x8b, 0xf2, 0xdb, 0xff, 0x3c,
+    0x95, 0xce, 0x35, 0xdd, 0xa6, 0x89, 0xae, 0xf2, 0xdf, 0xc7, 0x59, 0x5c,
+    0x44, 0x42, 0xc8, 0xdd, 0x2a, 0xfd, 0xc6, 0xbb, 0xb4, 0xd1, 0x56, 0x5f,
+    0xf4, 0x4a, 0x39, 0x3c, 0x72, 0x73, 0xac, 0xae, 0x1f, 0x60, 0x99, 0xdf,
+    0xf7, 0x63, 0x7f, 0x47, 0x5d, 0x8c, 0xeb, 0xff, 0x81, 0x82, 0xac, 0x81,
+    0xa9, 0xdc, 0x4e, 0xa5, 0x4f, 0xfe, 0x0e, 0xef, 0xfe, 0x55, 0xe4, 0xae,
+    0x71, 0xae, 0xed, 0x34, 0x48, 0x97, 0xee, 0x35, 0xdd, 0xa6, 0x8b, 0x4a,
+    0xff, 0xcf, 0x25, 0x73, 0x8d, 0x77, 0x69, 0xa2, 0x7d, 0xb2, 0xb8, 0x7f,
+    0xab, 0x33, 0xbf, 0xfc, 0xaa, 0xde, 0x4a, 0xe7, 0x1a, 0xee, 0xd3, 0x45,
+    0x09, 0x7f, 0xf6, 0x32, 0xaf, 0x94, 0x7d, 0x27, 0xa0, 0xeb, 0xf7, 0xbf,
+    0x6b, 0xe8, 0xeb, 0xe4, 0x9e, 0x38, 0x75, 0x2c, 0xf2, 0x7a, 0x51, 0x7e,
+    0xe3, 0x5d, 0xda, 0x68, 0xa3, 0xef, 0xfa, 0x25, 0x1c, 0x9e, 0x39, 0x39,
+    0xd7, 0xff, 0xff, 0xfb, 0xea, 0x72, 0x68, 0xef, 0x33, 0xaf, 0xf7, 0x58,
+    0xa3, 0x88, 0x20, 0x62, 0x6e, 0xc1, 0xd7, 0xe7, 0xd2, 0x7a, 0x0e, 0xbf,
+    0xe8, 0x9a, 0x06, 0x26, 0xec, 0x1d, 0x50, 0x8e, 0xc5, 0x21, 0x20, 0x24,
+    0xb7, 0xff, 0xf6, 0x07, 0xb1, 0xf5, 0x5f, 0x0b, 0x83, 0x5a, 0x80, 0x15,
+    0x79, 0xe4, 0xac, 0x2a, 0x0a, 0xc2, 0x21, 0x33, 0xf4, 0x64, 0xbb, 0x66,
+    0x97, 0xff, 0x67, 0x55, 0xf2, 0x8f, 0xa4, 0xf4, 0x1d, 0x65, 0x67, 0x56,
+    0x80, 0xb9, 0x53, 0x1e, 0x64, 0xa8, 0x6d, 0x97, 0x27, 0x9c, 0x30, 0x91,
+    0x96, 0x28, 0xa9, 0x49, 0x55, 0x6c, 0xa1, 0xdd, 0xe1, 0x42, 0x90, 0xa6,
+    0x98, 0x8b, 0xb0, 0xce, 0x01, 0x47, 0xa5, 0xcb, 0xdf, 0xe5, 0x73, 0x8d,
+    0x77, 0x69, 0xa2, 0x22, 0xbf, 0xb3, 0x8d, 0x77, 0x69, 0xa2, 0x2b, 0xbf,
+    0xe6, 0x35, 0x73, 0x8d, 0x77, 0x69, 0xa2, 0xb8, 0xa5, 0x51, 0x00, 0xe7,
+    0x17, 0xff, 0x81, 0x02, 0xd5, 0x5f, 0xc0, 0xfa, 0x32, 0x3a, 0xf9, 0x59,
+    0xe6, 0x63, 0x3a, 0xc9, 0xb9, 0xf9, 0x81, 0x2e, 0xfb, 0x3a, 0xfe, 0x3a,
+    0xff, 0x62, 0x70, 0x00, 0xff, 0x47, 0x59, 0x80, 0x27, 0xa7, 0xa2, 0x0b,
+    0xff, 0xfb, 0xda, 0x4e, 0xba, 0x49, 0x07, 0xdf, 0xf7, 0x98, 0x75, 0xfb,
+    0x8d, 0x77, 0x69, 0xa2, 0x9e, 0xbf, 0xcb, 0x40, 0xfe, 0xfc, 0x91, 0xd7,
+    0x2d, 0x0e, 0xa8, 0x3c, 0x86, 0x99, 0xdf, 0xff, 0xe9, 0x47, 0xb5, 0xfa,
+    0xda, 0x80, 0x8c, 0xea, 0x7e, 0xd3, 0xaf, 0xff, 0xee, 0x73, 0xfe, 0x72,
+    0x07, 0x14, 0x4e, 0xf7, 0x3e, 0x9d, 0x7f, 0xf2, 0x4b, 0x04, 0x10, 0xb4,
+    0xe4, 0x8e, 0xbf, 0xd2, 0x8e, 0x4f, 0x1c, 0x9c, 0xeb, 0xef, 0x82, 0xf2,
+    0x3a, 0xfc, 0xf9, 0xd4, 0x59, 0xd5, 0xa3, 0xc7, 0xd8, 0x45, 0x50, 0x89,
+    0xfc, 0x7b, 0xbf, 0xe8, 0x16, 0xe6, 0xcc, 0xf6, 0x8e, 0xbf, 0x3c, 0xf1,
+    0xcf, 0xce, 0xa6, 0x12, 0xb3, 0xf8, 0x2b, 0xc5, 0x96, 0xbd, 0xee, 0x42,
+    0x8c, 0x2e, 0xba, 0x30, 0xe0, 0xd8, 0x43, 0xb6, 0x71, 0x7f, 0xf9, 0xe4,
+    0xa8, 0x45, 0xd9, 0xd6, 0xa0, 0x07, 0x5f, 0xfe, 0x00, 0x3f, 0xd2, 0xbf,
+    0x45, 0xd6, 0x30, 0x75, 0xff, 0xc3, 0x80, 0x71, 0x02, 0xab, 0x45, 0x9d,
+    0x5c, 0x44, 0x77, 0x93, 0x29, 0x54, 0xe4, 0x83, 0x09, 0x74, 0x86, 0xc5,
+    0xb0, 0xeb, 0xf0, 0xc7, 0xec, 0x1d, 0x1d, 0x7f, 0x29, 0xc7, 0x0b, 0x89,
+    0xd4, 0x13, 0xe6, 0xc0, 0xf7, 0x2b, 0xbf, 0xf9, 0x03, 0xc7, 0xdd, 0x5e,
+    0x72, 0x27, 0x3a, 0x95, 0x3f, 0x3e, 0x96, 0xdc, 0x18, 0x3a, 0xff, 0xfd,
+    0xd8, 0xe6, 0x49, 0x1f, 0xd8, 0x14, 0xfd, 0xa5, 0x5f, 0xa2, 0x40, 0xfe,
+    0x47, 0x5f, 0x35, 0xdd, 0xa6, 0x8a, 0xce, 0xa6, 0x3d, 0x5e, 0x14, 0x5f,
+    0x79, 0x17, 0xa3, 0xaf, 0xe9, 0xd7, 0x03, 0x2d, 0x1d, 0x7e, 0xcf, 0x6b,
+    0xee, 0x8e, 0xbd, 0x13, 0xa1, 0xd7, 0xef, 0x03, 0xe8, 0xc8, 0xeb, 0xdf,
+    0xbe, 0x8e, 0xbf, 0xec, 0x92, 0x7e, 0xc6, 0xc5, 0x81, 0x67, 0x5f, 0xb2,
+    0x69, 0xff, 0x01, 0xd6, 0x56, 0x15, 0x11, 0x04, 0x57, 0x21, 0x51, 0xb9,
+    0x1f, 0x08, 0x56, 0x5b, 0xd2, 0x97, 0x1b, 0x12, 0x9d, 0x0e, 0x7d, 0x41,
+    0xbf, 0xf7, 0x53, 0xcf, 0xc9, 0xe1, 0x02, 0x75, 0xfb, 0xc8, 0x38, 0xb3,
+    0xaf, 0xa4, 0xe2, 0xae, 0x1f, 0x16, 0xd1, 0xed, 0xff, 0x9e, 0x4a, 0xe7,
+    0x1a, 0xee, 0xd3, 0x44, 0x8b, 0x7f, 0xfe, 0xf7, 0x70, 0x55, 0xf3, 0xbe,
+    0xfa, 0x51, 0x47, 0x3a, 0xff, 0xcf, 0xe5, 0x61, 0x38, 0x9e, 0xfc, 0xea,
+    0x55, 0x1b, 0xf0, 0x94, 0xea, 0xf7, 0xf6, 0x71, 0xae, 0xed, 0x34, 0x59,
+    0x37, 0xff, 0xbd, 0xaf, 0xba, 0x57, 0x27, 0x41, 0x96, 0x8e, 0xa5, 0x51,
+    0x0b, 0x87, 0x17, 0xff, 0xf9, 0xd3, 0xdf, 0xf1, 0xf4, 0xab, 0x7a, 0x9c,
+    0x89, 0x68, 0xeb, 0xfb, 0x38, 0xd7, 0x76, 0x9a, 0x2d, 0x8b, 0xff, 0xf9,
+    0x81, 0xdf, 0x83, 0x9c, 0xf6, 0xbb, 0x37, 0xcf, 0x9d, 0xdb, 0x3a, 0xf7,
+    0x3f, 0xe9, 0xd7, 0x79, 0x58, 0x44, 0x3f, 0x1a, 0xa9, 0x54, 0x77, 0x24,
+    0x2f, 0xef, 0x66, 0xb0, 0xeb, 0xe6, 0xbb, 0xb4, 0xd1, 0x6d, 0xdf, 0x6a,
+    0x77, 0xe1, 0xd5, 0xc3, 0xcf, 0xf1, 0x6d, 0xfc, 0x9d, 0xf2, 0x03, 0xf3,
+    0xaf, 0xfa, 0x25, 0x1c, 0x9e, 0x39, 0x39, 0xd6, 0x56, 0x48, 0xf1, 0xc6,
+    0x99, 0x88, 0x84, 0xb6, 0xff, 0xf6, 0x08, 0x15, 0x5b, 0x87, 0x30, 0x54,
+    0x3a, 0xf3, 0x0b, 0xa1, 0x3a, 0xf4, 0xfd, 0x43, 0xaf, 0xfc, 0xc2, 0x61,
+    0x30, 0xff, 0x77, 0x06, 0x00, 0x75, 0xfd, 0x03, 0x20, 0xfe, 0xb3, 0xaf,
+    0x9a, 0xee, 0xd3, 0x45, 0xe1, 0x7f, 0xe7, 0xf4, 0x6c, 0xe7, 0x33, 0x7d,
+    0x1d, 0x5c, 0x3e, 0xd1, 0x2d, 0xbe, 0xf6, 0xde, 0x74, 0xeb, 0xf2, 0xe0,
+    0x64, 0xe7, 0x5f, 0xe9, 0x40, 0xfb, 0x63, 0xb4, 0xeb, 0xfd, 0x1e, 0x7e,
+    0xfc, 0x0c, 0x1d, 0x7f, 0xef, 0xab, 0xde, 0x5e, 0xc1, 0xf6, 0x8e, 0xbb,
+    0x14, 0x3a, 0xa0, 0xf5, 0xf1, 0x06, 0xf9, 0x27, 0xc5, 0x9d, 0x7e, 0xc1,
+    0x06, 0xd4, 0x1d, 0x7e, 0x8f, 0xbf, 0xbe, 0x8e, 0xbf, 0xf9, 0x70, 0xdf,
+    0x98, 0x3f, 0xcb, 0x34, 0x75, 0xff, 0xff, 0x9d, 0x3c, 0xeb, 0x71, 0x03,
+    0x7a, 0x9c, 0x97, 0xd9, 0x60, 0x9d, 0x58, 0x8a, 0xfe, 0xa2, 0xdf, 0xfd,
+    0x9d, 0xeb, 0xc9, 0x69, 0x1c, 0x91, 0xd7, 0x40, 0x0e, 0xa9, 0x1e, 0xbf,
+    0x90, 0xa9, 0x80, 0xb8, 0x48, 0xc2, 0x20, 0x62, 0x83, 0x93, 0xa5, 0xe4,
+    0x26, 0xb7, 0x21, 0x42, 0x49, 0x89, 0x56, 0x67, 0xd8, 0x45, 0x39, 0x00,
+    0x08, 0x44, 0xa3, 0x50, 0xd8, 0xf3, 0xcd, 0xfe, 0xdd, 0x5c, 0x03, 0xf3,
+    0x47, 0x5f, 0xe0, 0x2b, 0x34, 0xa0, 0x7c, 0x75, 0x2a, 0x9a, 0x9c, 0x43,
+    0xaf, 0x86, 0x97, 0x93, 0x37, 0x3a, 0xf9, 0xae, 0xed, 0x34, 0x5e, 0x97,
+    0xfe, 0x4f, 0x74, 0x5e, 0x40, 0x70, 0x1d, 0x5c, 0x3e, 0x95, 0x96, 0xde,
+    0x5a, 0x78, 0xeb, 0xfe, 0x7f, 0x4a, 0x14, 0xf2, 0x4e, 0x75, 0x2c, 0xf5,
+    0x04, 0x6e, 0xfd, 0x8b, 0xeb, 0x84, 0xea, 0x0a, 0x68, 0x39, 0x08, 0x4f,
+    0xae, 0xdb, 0x44, 0x37, 0xff, 0xfb, 0x66, 0x0a, 0xa1, 0xc0, 0xf7, 0x16,
+    0xb7, 0x96, 0x09, 0xd7, 0xf9, 0x5f, 0x64, 0xd2, 0x70, 0x9d, 0x48, 0x89,
+    0x4e, 0xb0, 0x52, 0xa8, 0xfd, 0xc8, 0x6d, 0xd4, 0x36, 0xff, 0x13, 0xc2,
+    0xfe, 0x50, 0x96, 0xc9, 0xd4, 0xc6, 0xc6, 0x28, 0x92, 0x91, 0x66, 0x8c,
+    0x1f, 0x91, 0x8d, 0x2e, 0x16, 0x9d, 0x23, 0x04, 0x69, 0xe3, 0x18, 0xce,
+    0x90, 0xff, 0x9d, 0xbf, 0x66, 0x53, 0xa5, 0xdf, 0xf4, 0xeb, 0xff, 0xbf,
+    0x89, 0x87, 0x36, 0x3a, 0xd6, 0x87, 0x5f, 0x67, 0x5f, 0xc7, 0x5f, 0xec,
+    0x4e, 0x00, 0x1f, 0xe8, 0xeb, 0x30, 0x14, 0x44, 0xc0, 0xa2, 0xe8, 0x82,
+    0xfb, 0xd1, 0xbc, 0xe7, 0x5f, 0xf7, 0xb5, 0x9b, 0xcb, 0xbf, 0xa8, 0x75,
+    0x21, 0xef, 0x89, 0x1d, 0xf4, 0x6c, 0x89, 0x1d, 0x7e, 0xe3, 0x5d, 0xda,
+    0x68, 0x88, 0xef, 0xff, 0xbb, 0xfe, 0xb5, 0x8b, 0x1c, 0xd9, 0xf2, 0x18,
+    0x93, 0xaf, 0xfa, 0x27, 0xe6, 0x7b, 0xc9, 0xe3, 0xaf, 0x0c, 0x6e, 0x75,
+    0x48, 0xf4, 0xc2, 0x71, 0x7f, 0xd9, 0xcc, 0xd6, 0x38, 0xce, 0x75, 0xec,
+    0x0a, 0xce, 0xbf, 0xff, 0xdd, 0x74, 0xf4, 0x74, 0x73, 0xdd, 0x4e, 0xe2,
+    0x32, 0x75, 0xff, 0xff, 0xef, 0x79, 0x17, 0xc4, 0xcd, 0xc7, 0xff, 0x47,
+    0x7e, 0x6c, 0x4f, 0x4d, 0x07, 0x54, 0x23, 0x67, 0x17, 0x6f, 0xf3, 0xaf,
+    0x39, 0x28, 0x59, 0xd7, 0x4e, 0xb2, 0xae, 0x65, 0x92, 0xaf, 0xfc, 0xab,
+    0x7a, 0x93, 0x76, 0x27, 0x54, 0x06, 0xbd, 0x91, 0x7b, 0xed, 0x91, 0xe8,
+    0x3a, 0xa4, 0x7f, 0x88, 0xb5, 0x7f, 0x63, 0xaf, 0x37, 0xf1, 0xd7, 0xf9,
+    0xd5, 0xd2, 0x71, 0xc0, 0x75, 0x98, 0xce, 0xbf, 0xe8, 0xcd, 0xe1, 0xe4,
+    0xf2, 0x3a, 0x98, 0x83, 0xc9, 0x08, 0x9d, 0xfc, 0xc6, 0x39, 0xd7, 0xf1,
+    0xd7, 0xf4, 0x29, 0x82, 0x8a, 0x1d, 0x7f, 0x67, 0xb6, 0xbd, 0x9d, 0x3a,
+    0xb1, 0x11, 0x22, 0x5d, 0xa2, 0xcb, 0xff, 0xf9, 0xaa, 0xf1, 0xc5, 0x3c,
+    0xaf, 0x23, 0xc2, 0xe0, 0x3a, 0x98, 0xb5, 0xeb, 0x16, 0x14, 0x2b, 0xe2,
+    0x13, 0x32, 0x20, 0xc2, 0x26, 0x99, 0xef, 0x0a, 0xb4, 0x22, 0x98, 0xdb,
+    0x90, 0xf4, 0xe9, 0x0b, 0xc3, 0x70, 0x04, 0x22, 0x59, 0xa7, 0xbf, 0x42,
+    0xc3, 0x61, 0x75, 0xdb, 0x5d, 0x3a, 0xfd, 0xc6, 0xbb, 0xb4, 0xd1, 0x17,
+    0x5f, 0xbc, 0x0f, 0xa3, 0x22, 0xaf, 0xda, 0xf7, 0x60, 0x07, 0x5f, 0x9e,
+    0x78, 0xe7, 0xe7, 0x59, 0x59, 0xd1, 0x89, 0x83, 0x2e, 0x67, 0xf9, 0x4e,
+    0xd9, 0x3d, 0x2a, 0xa8, 0x9e, 0x51, 0xe9, 0xdf, 0xfc, 0xb7, 0x92, 0xb9,
+    0xc6, 0xbb, 0xb4, 0xd1, 0x33, 0x5f, 0xcc, 0x33, 0x0f, 0x60, 0x6a, 0x3c,
+    0x75, 0xed, 0xe3, 0x47, 0x5e, 0x6a, 0x2c, 0xeb, 0xe6, 0x17, 0x9c, 0x4e,
+    0xbb, 0x6d, 0x88, 0x3a, 0xec, 0xfc, 0xeb, 0xff, 0xdd, 0x85, 0xbf, 0xb3,
+    0x70, 0x2f, 0xef, 0x4e, 0xbe, 0x49, 0xff, 0x13, 0xaf, 0xd9, 0x3e, 0x02,
+    0x63, 0xab, 0xe1, 0xe5, 0x78, 0x8a, 0xff, 0x7c, 0xc1, 0x7e, 0x03, 0x6c,
+    0xeb, 0xff, 0xf2, 0xdf, 0xb9, 0xb8, 0x3a, 0xcb, 0xf6, 0x6e, 0xfe, 0x75,
+    0xfd, 0x9a, 0x8f, 0xa3, 0x07, 0x50, 0x51, 0x77, 0x86, 0xdd, 0x59, 0xbb,
+    0x58, 0x75, 0xdb, 0x5e, 0x3a, 0xcc, 0x13, 0xac, 0x08, 0x35, 0xbf, 0x8c,
+    0xdf, 0xff, 0xf9, 0x06, 0x1a, 0x30, 0xbf, 0x91, 0xce, 0x26, 0xce, 0x3b,
+    0x80, 0xea, 0x62, 0x15, 0x56, 0x34, 0x79, 0x05, 0xa6, 0x84, 0xb7, 0x61,
+    0xbe, 0xe5, 0xe0, 0x42, 0xf1, 0x3d, 0xfc, 0xcc, 0x08, 0xe7, 0x8e, 0xbe,
+    0x7e, 0xa4, 0xc7, 0x5f, 0x76, 0x68, 0x09, 0xd5, 0x87, 0xdc, 0xd2, 0xb7,
+    0x21, 0xbf, 0xcd, 0x4c, 0x10, 0xf6, 0x0e, 0xa3, 0xaf, 0xdd, 0x7f, 0x48,
+    0x07, 0x5f, 0xfe, 0xf9, 0xd7, 0x4f, 0x03, 0xf1, 0x17, 0x91, 0xd5, 0x88,
+    0xab, 0x69, 0x82, 0x05, 0x2c, 0x9e, 0xff, 0xff, 0xff, 0xff, 0xf3, 0x14,
+    0x60, 0x63, 0x14, 0x61, 0x30, 0xf6, 0x1e, 0xd6, 0x0c, 0x30, 0xe6, 0x17,
+    0x27, 0xda, 0xcf, 0xc2, 0xc5, 0x63, 0x6f, 0x7f, 0xbd, 0x61, 0x44, 0x30,
+    0x98, 0xd8, 0x6f, 0x7c, 0xf9, 0xdd, 0xb3, 0xaf, 0xff, 0xc0, 0xde, 0x5d,
+    0xfe, 0x38, 0xaf, 0x51, 0xaf, 0xc3, 0xaf, 0xfe, 0xdd, 0x98, 0xf0, 0x51,
+    0x8f, 0x50, 0xb3, 0xaf, 0xff, 0xfc, 0x8b, 0x4e, 0x77, 0xfd, 0x4a, 0x36,
+    0x72, 0x07, 0xdd, 0xc9, 0x1d, 0x7f, 0xe4, 0xf2, 0x35, 0x03, 0xec, 0x69,
+    0xd5, 0x88, 0xf1, 0xf2, 0x46, 0xd3, 0x6d, 0xf7, 0xb6, 0xf3, 0xa7, 0x5f,
+    0xff, 0xe7, 0x16, 0x8e, 0x07, 0xbf, 0xfc, 0xec, 0x4b, 0x91, 0x39, 0xd5,
+    0x88, 0x86, 0xfc, 0x92, 0xff, 0xff, 0x3a, 0x83, 0x80, 0xff, 0x5f, 0x24,
+    0x9d, 0x86, 0x8b, 0x9d, 0x7d, 0xe4, 0xea, 0x1d, 0x7f, 0xcf, 0xc9, 0x7c,
+    0xc6, 0x87, 0x0e, 0xa6, 0x12, 0xe0, 0x54, 0x46, 0x59, 0x91, 0xa4, 0xf6,
+    0x17, 0x0e, 0x46, 0x2c, 0x3f, 0x90, 0x5b, 0x87, 0x5f, 0xde, 0xc5, 0xef,
+    0x8b, 0x3a, 0xdd, 0xc3, 0x7a, 0x82, 0x17, 0xfb, 0xf0, 0xbc, 0xb4, 0x92,
+    0x3a, 0xff, 0xfc, 0x14, 0x19, 0xf3, 0x48, 0xfd, 0x55, 0x96, 0x59, 0x2a,
+    0xfe, 0xf7, 0x62, 0x7e, 0xfe, 0x75, 0xfd, 0xbc, 0xb4, 0x0f, 0xe6, 0x3a,
+    0xff, 0xa7, 0xc0, 0x07, 0xf7, 0xe4, 0x8e, 0xbf, 0x9d, 0xc3, 0xb3, 0x02,
+    0x75, 0xe7, 0x76, 0x9a, 0x2c, 0xfb, 0xf8, 0x0e, 0x32, 0x45, 0x9d, 0x53,
+    0xa2, 0xe4, 0x27, 0x4d, 0x2d, 0x01, 0x3d, 0xff, 0x93, 0xb1, 0x24, 0xf4,
+    0x7b, 0x47, 0x5f, 0xfe, 0xe7, 0x5f, 0xe6, 0x6c, 0x1c, 0xd6, 0x09, 0xd7,
+    0xfd, 0x08, 0x1c, 0x5b, 0x39, 0xd3, 0xaf, 0xfe, 0xd7, 0x92, 0x66, 0x5c,
+    0x31, 0xbe, 0x8e, 0xa4, 0x46, 0x3b, 0xa5, 0x7e, 0x6f, 0x79, 0x96, 0x59,
+    0x2a, 0xff, 0xcf, 0x2d, 0x0e, 0x34, 0x39, 0xc2, 0x95, 0x2f, 0xef, 0xdb,
+    0x5f, 0xaf, 0x02, 0x75, 0xfe, 0xf7, 0x73, 0x67, 0xc9, 0x2c, 0xea, 0xc3,
+    0xe2, 0xfc, 0xae, 0xff, 0xdb, 0xc8, 0x7f, 0x07, 0xc6, 0xac, 0x07, 0x5d,
+    0x0a, 0x1d, 0x7f, 0xc1, 0x81, 0x80, 0x4b, 0xa8, 0x75, 0x42, 0x23, 0xe7,
+    0x43, 0x41, 0x6b, 0xfd, 0xd4, 0x08, 0xbb, 0xcc, 0x75, 0xfe, 0x0f, 0x7f,
+    0x70, 0x6d, 0xe1, 0xd5, 0x07, 0xce, 0x86, 0x37, 0xfc, 0x82, 0x1f, 0xa1,
+    0xff, 0xda, 0x3a, 0xf4, 0x0a, 0x87, 0x54, 0x97, 0x70, 0xc2, 0x4a, 0xd3,
+    0x3d, 0xd6, 0x26, 0x2f, 0xe4, 0x3a, 0x96, 0x7d, 0xd8, 0xc0, 0xc0, 0x9c,
+    0x30, 0xae, 0xd4, 0x2c, 0x7d, 0x09, 0x6d, 0x84, 0x1f, 0x4e, 0xef, 0xfb,
+    0xff, 0x68, 0x72, 0x68, 0x59, 0xd7, 0xf9, 0xd9, 0xea, 0x47, 0x20, 0xea,
+    0x50, 0xfa, 0xb8, 0x73, 0x7f, 0xee, 0x26, 0xa5, 0xf7, 0xb0, 0x30, 0x75,
+    0xf7, 0x12, 0x16, 0x75, 0xff, 0xfb, 0xca, 0x7f, 0x18, 0x1e, 0xe6, 0xb7,
+    0x94, 0x74, 0xea, 0xe2, 0x2d, 0x56, 0x7c, 0x24, 0x17, 0x3c, 0x8e, 0xbf,
+    0xff, 0xff, 0x85, 0xd9, 0xf6, 0x74, 0x73, 0xdf, 0x81, 0x6f, 0x27, 0x0c,
+    0x0b, 0xf1, 0xe4, 0x75, 0xfe, 0xce, 0xf7, 0xff, 0x38, 0x9d, 0x7f, 0xcd,
+    0xce, 0xb5, 0xf8, 0xf2, 0x3a, 0xf2, 0x4d, 0xa3, 0xaa, 0x0f, 0x4d, 0x66,
+    0xf6, 0x40, 0xa6, 0x81, 0x30, 0xaf, 0x21, 0x0a, 0xb8, 0x42, 0xdf, 0xdf,
+    0x13, 0xae, 0xb4, 0x3a, 0xf6, 0xcc, 0x09, 0xd6, 0xe4, 0xe7, 0x95, 0x31,
+    0x6d, 0xff, 0xb1, 0x9d, 0xae, 0x66, 0xd0, 0xfe, 0xc9, 0xd5, 0x0a, 0x9d,
+    0xfb, 0x1b, 0x7b, 0xc2, 0x60, 0x4a, 0xaf, 0xff, 0xff, 0x81, 0xac, 0xc1,
+    0x53, 0xef, 0x06, 0x33, 0xaa, 0xe8, 0x72, 0x75, 0xe2, 0xce, 0xbf, 0x7d,
+    0x81, 0xfa, 0xb3, 0xab, 0x11, 0x51, 0xe7, 0xeb, 0xf6, 0xc7, 0xec, 0x7d,
+    0x3a, 0xff, 0xfb, 0xfd, 0xe5, 0xa0, 0xf6, 0x38, 0x17, 0x76, 0x4e, 0xac,
+    0x44, 0xf2, 0x11, 0x09, 0x55, 0xed, 0x44, 0xe7, 0x5f, 0xf4, 0x63, 0x7a,
+    0x9b, 0x1f, 0x87, 0x5d, 0x9d, 0x3a, 0x84, 0xf3, 0x76, 0xce, 0x2a, 0x48,
+    0xba, 0xd1, 0x6f, 0x9a, 0x6f, 0x77, 0xf6, 0x4e, 0xbc, 0x0f, 0xda, 0x75,
+    0xef, 0x67, 0xd3, 0xaf, 0xe8, 0xdf, 0x5f, 0x39, 0x07, 0x5e, 0x0f, 0xed,
+    0x3a, 0xf8, 0x23, 0x12, 0x3a, 0x90, 0xde, 0xb8, 0xed, 0x05, 0x1c, 0x7b,
+    0x8f, 0x20, 0xea, 0xc7, 0x7a, 0xd9, 0x76, 0x34, 0xeb, 0xfb, 0x89, 0xb3,
+    0x07, 0x47, 0x5f, 0xdb, 0xfb, 0x3b, 0xfb, 0x19, 0xd7, 0xf7, 0x33, 0xbd,
+    0xff, 0xc7, 0x5f, 0xba, 0x31, 0x9c, 0x32, 0xfe, 0xce, 0x4f, 0xfb, 0x84,
+    0xd1, 0x06, 0xaa, 0x69, 0x6d, 0xc9, 0xd1, 0x3f, 0x25, 0x3a, 0x84, 0x7d,
+    0xa4, 0x34, 0x6f, 0xce, 0xd4, 0x5c, 0x1d, 0x7f, 0x4b, 0xa2, 0xfb, 0xf8,
+    0xea, 0x69, 0xe9, 0x09, 0x2d, 0xf7, 0xd1, 0x79, 0xce, 0xac, 0x3c, 0x4d,
+    0x10, 0xdf, 0xa3, 0xdf, 0x16, 0xc9, 0xd7, 0xfa, 0x48, 0xb8, 0xef, 0xd0,
+    0x9d, 0x7f, 0xfa, 0x30, 0x77, 0xf6, 0x71, 0x27, 0x75, 0x9d, 0x7e, 0x76,
+    0x7d, 0x9d, 0xd1, 0xfe, 0x78, 0xd2, 0x98, 0xb5, 0x5f, 0xf0, 0x2b, 0x28,
+    0xca, 0x32, 0x17, 0x9c, 0x21, 0x18, 0x53, 0x5e, 0xd6, 0x48, 0xeb, 0xf2,
+    0x6f, 0x24, 0x13, 0xaf, 0x27, 0x70, 0xeb, 0xa1, 0x78, 0x78, 0x0d, 0x26,
+    0xbf, 0x99, 0xc5, 0xc7, 0x14, 0x3a, 0xf8, 0x3a, 0xec, 0x1d, 0x7e, 0x1e,
+    0x32, 0xf3, 0x9d, 0x50, 0x7e, 0xf8, 0x5c, 0xe4, 0x37, 0x7e, 0x27, 0x54,
+    0x26, 0x80, 0x8b, 0x7c, 0x85, 0x1e, 0x8b, 0x2f, 0x77, 0x04, 0xeb, 0xfd,
+    0x34, 0x4e, 0xb7, 0x9a, 0x0e, 0xbf, 0xfe, 0x75, 0x3d, 0x1c, 0x07, 0x23,
+    0xc2, 0xe0, 0x3a, 0xfe, 0x1c, 0x06, 0x0c, 0x8e, 0xbf, 0xfe, 0x53, 0xe7,
+    0xd1, 0x7f, 0x69, 0x37, 0xea, 0x32, 0x75, 0x87, 0x0f, 0xfd, 0xca, 0xab,
+    0x13, 0x40, 0x71, 0xa1, 0x34, 0xfe, 0x19, 0xb7, 0x6b, 0x61, 0xd7, 0xc8,
+    0x2e, 0x13, 0xaf, 0xfc, 0xbc, 0xf6, 0xbe, 0xe9, 0xe5, 0x87, 0x5f, 0xb5,
+    0x1c, 0xf4, 0x1c, 0xa9, 0xbf, 0xa0, 0xa2, 0x57, 0x4b, 0xd7, 0xef, 0xb3,
+    0x3b, 0xf0, 0xeb, 0xee, 0xe2, 0x6c, 0x3a, 0xfe, 0xd2, 0x73, 0x3f, 0xe1,
+    0xd7, 0xff, 0xfa, 0x26, 0xf8, 0x8d, 0xff, 0x9a, 0xff, 0xe2, 0xd3, 0xdd,
+    0x43, 0xab, 0x13, 0xaf, 0x48, 0x56, 0xac, 0x8f, 0xa5, 0x3e, 0x22, 0xda,
+    0x2d, 0xb9, 0x6c, 0x03, 0x45, 0xf9, 0x7d, 0xae, 0x66, 0x1d, 0x7f, 0xf4,
+    0xbd, 0xfc, 0xa4, 0xbf, 0x7a, 0x16, 0x75, 0xfe, 0xf6, 0xa2, 0x7c, 0xd0,
+    0x4e, 0xbb, 0xb8, 0x75, 0xff, 0xf7, 0x60, 0x38, 0xdf, 0x98, 0x38, 0x1e,
+    0xc1, 0xd7, 0xff, 0x26, 0x0e, 0x66, 0xbe, 0x4b, 0x4b, 0x3a, 0xff, 0xcf,
+    0x1b, 0xcb, 0xe6, 0xb7, 0x0c, 0x1d, 0x41, 0x4e, 0x03, 0x72, 0x04, 0x46,
+    0x63, 0x33, 0x98, 0x57, 0x49, 0xde, 0x43, 0xbc, 0xa4, 0x70, 0xeb, 0xf8,
+    0x30, 0x0e, 0x66, 0xe7, 0x52, 0xa7, 0x92, 0xb1, 0xcb, 0xfd, 0x0b, 0xc4,
+    0xe4, 0xd2, 0x3a, 0xe4, 0x98, 0xeb, 0xff, 0xde, 0x8e, 0x8b, 0xcf, 0x1c,
+    0xe3, 0xc8, 0xeb, 0xde, 0x49, 0xce, 0xbf, 0x01, 0xf7, 0x89, 0x8e, 0xbc,
+    0x30, 0xd3, 0xaf, 0xfe, 0x0a, 0x4d, 0xd8, 0xe6, 0xf2, 0x8e, 0x1d, 0x7f,
+    0xf9, 0x05, 0xf7, 0xd6, 0xb3, 0x81, 0xee, 0x1d, 0x5f, 0x13, 0x49, 0x41,
+    0x65, 0xa4, 0x38, 0xe0, 0x94, 0x68, 0x6b, 0x69, 0x16, 0xd0, 0x75, 0xee,
+    0xa7, 0x8e, 0xb6, 0xcc, 0x35, 0x5f, 0x43, 0xea, 0x17, 0x44, 0x02, 0xbd,
+    0x91, 0xd3, 0xa4, 0x2c, 0xba, 0x46, 0xf1, 0xbd, 0x82, 0x12, 0x37, 0xfd,
+    0x83, 0x21, 0xc5, 0xc3, 0x4e, 0xbf, 0x75, 0x36, 0x60, 0x4e, 0xbf, 0xf0,
+    0x60, 0x70, 0x7f, 0x96, 0x68, 0xeb, 0xf3, 0xad, 0x36, 0xb0, 0xeb, 0xde,
+    0x8d, 0xce, 0xac, 0x3c, 0x47, 0x28, 0xbd, 0x09, 0x31, 0xd7, 0x85, 0x88,
+    0xda, 0x3a, 0xfd, 0x93, 0xae, 0x34, 0x75, 0xff, 0xff, 0xa3, 0xa8, 0xb5,
+    0x66, 0x93, 0xf3, 0xef, 0x53, 0x7d, 0x35, 0x27, 0x3a, 0x82, 0x9e, 0x9a,
+    0x86, 0xa8, 0x51, 0x34, 0x20, 0x3a, 0x40, 0x23, 0x7a, 0x23, 0xda, 0x27,
+    0xbe, 0xf8, 0xf2, 0x62, 0x4e, 0xbf, 0xfb, 0x36, 0x60, 0x70, 0x7f, 0x96,
+    0x68, 0xeb, 0xf7, 0x23, 0xbf, 0x42, 0x75, 0x70, 0xfb, 0x5d, 0x12, 0xfa,
+    0x12, 0x78, 0x3a, 0xf9, 0x97, 0xcd, 0x1d, 0x7f, 0xd2, 0x5b, 0xcb, 0xda,
+    0x85, 0x0e, 0xa8, 0x3d, 0xa7, 0x21, 0xbd, 0xa4, 0x13, 0xaf, 0xc2, 0xdf,
+    0x9a, 0xdc, 0xea, 0xc3, 0xc4, 0x71, 0xaa, 0x63, 0x4e, 0xd1, 0xe1, 0x2a,
+    0x02, 0x11, 0x7a, 0xfd, 0x92, 0xe9, 0xe4, 0x75, 0xe4, 0xea, 0x1d, 0x5b,
+    0x9b, 0x1f, 0x0b, 0xdf, 0x7d, 0xfd, 0xf4, 0x75, 0xfd, 0xfe, 0xa2, 0x6f,
+    0xf8, 0x75, 0xef, 0xf3, 0x73, 0xab, 0xa7, 0x9b, 0xe3, 0x0b, 0xfd, 0x2f,
+    0xc6, 0x7d, 0x26, 0xe7, 0x5f, 0x00, 0x19, 0xb9, 0xd7, 0xf6, 0xd7, 0xb1,
+    0xc5, 0xa7, 0x5f, 0xf7, 0xef, 0x20, 0xe6, 0x03, 0x47, 0x5f, 0xe0, 0x26,
+    0xfb, 0xcb, 0x3c, 0x75, 0x74, 0xfb, 0x34, 0x71, 0x7e, 0xdf, 0x4b, 0x46,
+    0x33, 0xaf, 0xff, 0xd9, 0xaf, 0x9d, 0x74, 0xf0, 0x3f, 0x11, 0x79, 0x1d,
+    0x50, 0x88, 0x01, 0x2b, 0xbf, 0x9e, 0x70, 0x38, 0x84, 0xea, 0x6a, 0xa0,
+    0x29, 0x88, 0xb8, 0x6b, 0xd2, 0x2f, 0x42, 0x6b, 0x64, 0x28, 0xb6, 0xc8,
+    0x6f, 0xf7, 0xd8, 0x6e, 0xde, 0x72, 0x0e, 0xbf, 0xa3, 0xa9, 0xc8, 0x59,
+    0xd5, 0xd3, 0xe1, 0xf1, 0xb5, 0x42, 0xb6, 0xcc, 0x94, 0xe6, 0xf0, 0xd7,
+    0xba, 0x6f, 0xce, 0xb2, 0xce, 0xad, 0xcd, 0x43, 0x04, 0x62, 0xff, 0xe8,
+    0xe6, 0x6c, 0x79, 0x03, 0x30, 0x27, 0x5f, 0xcf, 0xbc, 0x86, 0x02, 0x75,
+    0xff, 0x46, 0xf2, 0x41, 0x5b, 0xf8, 0xea, 0x73, 0xe3, 0x12, 0xcb, 0xf3,
+    0xcb, 0x27, 0x83, 0xaf, 0xfe, 0x8d, 0x6b, 0x17, 0xe1, 0x85, 0xe8, 0xeb,
+    0xff, 0x92, 0x34, 0x2f, 0x2f, 0x9a, 0xce, 0x1d, 0x7f, 0xff, 0x93, 0x53,
+    0xe3, 0x38, 0x3f, 0xed, 0x42, 0xb8, 0x2f, 0xc3, 0xaf, 0xf6, 0xf2, 0xd4,
+    0xd2, 0x89, 0xce, 0xa0, 0xa6, 0x88, 0xd2, 0x61, 0x42, 0xf2, 0x1f, 0xec,
+    0x77, 0xff, 0xfe, 0xea, 0x6f, 0xec, 0xdf, 0xdc, 0xe4, 0x78, 0x1f, 0x46,
+    0x5d, 0xc3, 0xaf, 0x05, 0xc4, 0xeb, 0xdc, 0x8d, 0x87, 0x50, 0x4d, 0xbf,
+    0x06, 0xaf, 0xfd, 0x28, 0x1f, 0x71, 0x36, 0x60, 0x4e, 0xbf, 0xf3, 0xf5,
+    0xa8, 0xff, 0x34, 0xfd, 0x3a, 0xfe, 0xeb, 0x8e, 0xf2, 0x43, 0xaf, 0xff,
+    0xda, 0x1f, 0x9d, 0x74, 0xf0, 0x3f, 0x11, 0x79, 0x1d, 0x7f, 0xba, 0x8a,
+    0x6d, 0xff, 0xc5, 0x0e, 0xbf, 0xe8, 0x65, 0x7d, 0x84, 0x19, 0xce, 0xbf,
+    0xfe, 0x1c, 0xd6, 0x2e, 0x1b, 0x9e, 0x4e, 0x61, 0xd6, 0xc6, 0xa2, 0xf3,
+    0xc7, 0x3b, 0x0e, 0x2f, 0xe9, 0xf3, 0x88, 0xd8, 0x3a, 0xf8, 0x43, 0x0b,
+    0x3a, 0xff, 0xfb, 0xf1, 0xf6, 0xba, 0x93, 0x0c, 0x2d, 0xe4, 0x75, 0xf6,
+    0x0f, 0xee, 0x75, 0x2c, 0xfb, 0xf6, 0x27, 0xdf, 0xce, 0x0c, 0x0b, 0xc8,
+    0xea, 0x84, 0x6f, 0x64, 0x23, 0xd0, 0x92, 0x91, 0x33, 0xce, 0xc6, 0x15,
+    0x50, 0xbd, 0x2f, 0x39, 0x30, 0x61, 0x4d, 0x91, 0xb2, 0x35, 0x2d, 0x21,
+    0x4d, 0x31, 0x0f, 0x4f, 0x9c, 0xf8, 0x05, 0x83, 0x18, 0x8f, 0xa3, 0x73,
+    0xbf, 0xfb, 0x04, 0x19, 0x9c, 0xd7, 0xa3, 0x0e, 0xbf, 0xed, 0xfd, 0x9c,
+    0x49, 0xdd, 0x67, 0x5b, 0x00, 0x7f, 0x22, 0x81, 0x79, 0x83, 0x24, 0x3a,
+    0xfa, 0x05, 0xe4, 0x75, 0xfb, 0x18, 0xdc, 0x41, 0xf0, 0xdf, 0x70, 0x7e,
+    0xfe, 0xd9, 0xd4, 0x8e, 0x68, 0xeb, 0xff, 0x75, 0x16, 0x1c, 0x9a, 0x33,
+    0x87, 0x5f, 0x40, 0x1d, 0x67, 0x5c, 0x32, 0xc3, 0xdd, 0x13, 0xdb, 0xed,
+    0x27, 0xa0, 0xea, 0x83, 0xcb, 0x72, 0xbb, 0xe6, 0xf5, 0x26, 0x3a, 0xff,
+    0xfc, 0x38, 0xa2, 0x88, 0x1e, 0xa4, 0xdd, 0x4d, 0xfc, 0x75, 0x41, 0xfc,
+    0xe1, 0x15, 0xe6, 0xbf, 0x0e, 0xbf, 0x69, 0xb1, 0xc5, 0x0e, 0xae, 0x9e,
+    0x18, 0x06, 0xef, 0xf6, 0x4b, 0x10, 0x3d, 0x43, 0xaf, 0xfe, 0xcd, 0xfd,
+    0xa4, 0x18, 0x03, 0xac, 0xeb, 0xd2, 0x5f, 0x4e, 0xa9, 0xcf, 0x7b, 0xc8,
+    0x57, 0xc8, 0xa2, 0x32, 0x75, 0x61, 0xe2, 0x89, 0x1d, 0xdf, 0x30, 0xeb,
+    0xed, 0x0c, 0x2c, 0xea, 0x83, 0x6f, 0xb8, 0xbd, 0xee, 0xc9, 0x67, 0x5d,
+    0xd4, 0x3a, 0xb0, 0xd8, 0xf8, 0x72, 0xa1, 0x70, 0xd6, 0x4c, 0x98, 0x82,
+    0xa4, 0x35, 0xbb, 0x09, 0x97, 0x63, 0x12, 0x2d, 0x43, 0x4f, 0xf5, 0x7d,
+    0xb5, 0x2b, 0xc1, 0x5b, 0x4e, 0xb7, 0x4e, 0xb0, 0x0e, 0xbb, 0x52, 0x3a,
+    0x80, 0x6d, 0xb4, 0x21, 0xf8, 0x85, 0xfd, 0x3c, 0xd2, 0x61, 0x72, 0x73,
+    0xaf, 0x3e, 0x70, 0xeb, 0xc3, 0x9e, 0x3a, 0xba, 0x6d, 0x04, 0x6a, 0xef,
+    0x09, 0xd7, 0xa3, 0x7d, 0x1d, 0x7c, 0x83, 0x2c, 0x3a, 0xf4, 0xee, 0x27,
+    0x50, 0x4f, 0x59, 0x63, 0x9e, 0x1f, 0xbf, 0x67, 0xba, 0x9e, 0x3a, 0xfc,
+    0xfb, 0xe6, 0xfe, 0x3a, 0xca, 0x74, 0xf3, 0xbc, 0x4d, 0x72, 0x70, 0xeb,
+    0xfa, 0x7f, 0x93, 0xbb, 0xf4, 0xea, 0x62, 0x13, 0xdf, 0x86, 0x99, 0x10,
+    0x63, 0x5a, 0x3e, 0xf4, 0xa5, 0xc5, 0x6f, 0xfb, 0x02, 0x14, 0xdf, 0x37,
+    0xf1, 0xd7, 0xcd, 0x18, 0x91, 0xd5, 0xd3, 0xd9, 0x73, 0x9b, 0xfd, 0x19,
+    0xe8, 0xeb, 0x84, 0xea, 0x9c, 0xf4, 0x42, 0x43, 0x7f, 0xf0, 0x60, 0x3c,
+    0x8f, 0x23, 0x50, 0x27, 0x5f, 0x4d, 0x1b, 0x52, 0x3a, 0xfe, 0xf3, 0x42,
+    0x15, 0xf0, 0xeb, 0xfe, 0x9b, 0x5b, 0x1c, 0x67, 0xfc, 0x27, 0x5f, 0x67,
+    0xb1, 0x67, 0x5c, 0x2a, 0x1d, 0x6d, 0x39, 0xb6, 0xfc, 0x82, 0xfe, 0xef,
+    0xf3, 0xcd, 0xd4, 0x3a, 0xf8, 0x47, 0x3c, 0x75, 0x42, 0x74, 0x21, 0x23,
+    0xc4, 0x25, 0x09, 0x50, 0xba, 0x67, 0x3e, 0x93, 0xf8, 0xc2, 0xfe, 0xf9,
+    0x34, 0x78, 0x76, 0x1d, 0x7f, 0xf8, 0x63, 0x67, 0x23, 0x98, 0x9d, 0x80,
+    0x9d, 0x78, 0x5d, 0x67, 0x54, 0x91, 0x27, 0x86, 0x28, 0x91, 0x65, 0x58,
+    0x87, 0xc1, 0x06, 0x62, 0xcf, 0x18, 0x78, 0xe3, 0x15, 0x1b, 0x89, 0x5a,
+    0x13, 0xc3, 0xbe, 0x50, 0xd8, 0x0c, 0xe2, 0x2e, 0x4f, 0x3c, 0xa9, 0x1a,
+    0x5b, 0x65, 0xa7, 0xef, 0x29, 0x1d, 0x23, 0x13, 0x9a, 0x5a, 0x4f, 0x23,
+    0xab, 0x5c, 0x70, 0x3d, 0x9f, 0x00, 0x79, 0x49, 0x80, 0x94, 0x5c, 0xc1,
+    0x84, 0x18, 0xcb, 0x8e, 0xd4, 0xf7, 0xd7, 0xa7, 0x5b, 0xff, 0x84, 0xf3,
+    0x2a, 0x5b, 0x72, 0x83, 0xbe, 0xca, 0xb1, 0xda, 0x8c, 0x12, 0x95, 0x7c,
+    0x39, 0x5e, 0xde, 0x0a, 0xb5, 0xff, 0xe5, 0x56, 0xf2, 0x57, 0x38, 0xd7,
+    0x76, 0x9a, 0x26, 0xcb, 0xfc, 0xae, 0x71, 0xae, 0xed, 0x34, 0x55, 0xb7,
+    0xfa, 0x52, 0xff, 0xc3, 0x12, 0x3a, 0xfb, 0x3a, 0xfe, 0x3a, 0xcc, 0x0c,
+    0x3d, 0x31, 0x33, 0xbf, 0xec, 0x1c, 0x5c, 0x4b, 0xfe, 0x1d, 0x7f, 0xb9,
+    0x8d, 0x80, 0x7d, 0x59, 0xd7, 0xfd, 0x1d, 0x89, 0xf9, 0x18, 0x13, 0xa9,
+    0xa8, 0xa2, 0xe1, 0xbf, 0x4d, 0x2f, 0xd1, 0xc5, 0xf4, 0x27, 0x5e, 0x0e,
+    0x09, 0xd7, 0x9d, 0xda, 0x68, 0xad, 0x2f, 0xca, 0x6f, 0xaf, 0xf7, 0x3a,
+    0x9a, 0x7a, 0x68, 0x4f, 0x7f, 0xf9, 0x3d, 0x28, 0x6f, 0x53, 0xda, 0x7d,
+    0xce, 0xae, 0x1f, 0x56, 0xc2, 0x1b, 0xff, 0xdd, 0x45, 0xc3, 0x71, 0x78,
+    0x3e, 0xdb, 0x3a, 0xff, 0xf9, 0xb1, 0xcc, 0x03, 0xad, 0xe5, 0x08, 0xd3,
+    0xaf, 0xff, 0xa5, 0xac, 0x18, 0x5b, 0xe7, 0xbd, 0x0b, 0x3a, 0xef, 0x7a,
+    0x11, 0x30, 0xe9, 0x97, 0xff, 0xff, 0xa3, 0x62, 0x7b, 0x58, 0xa3, 0x7a,
+    0x9e, 0xc9, 0x86, 0x17, 0x3e, 0x32, 0x75, 0xfe, 0x8f, 0x3f, 0x7e, 0x06,
+    0x0e, 0xbe, 0x97, 0x92, 0x73, 0xaf, 0xdf, 0x7c, 0x30, 0x03, 0xab, 0x73,
+    0xca, 0xd8, 0x45, 0x7f, 0x9e, 0x5e, 0x49, 0xfa, 0x87, 0x54, 0x1e, 0xba,
+    0x12, 0xdf, 0xb3, 0xa9, 0x8b, 0x3a, 0xff, 0xe1, 0x74, 0x6f, 0x5f, 0xf9,
+    0xf8, 0x87, 0x54, 0xe7, 0xd1, 0xd2, 0x5b, 0xfd, 0x28, 0xe4, 0xf1, 0xc9,
+    0xce, 0xbd, 0x9c, 0x01, 0xd7, 0xe9, 0xb0, 0x2b, 0x63, 0x3a, 0xfe, 0x18,
+    0x67, 0x79, 0x68, 0xea, 0x43, 0xf4, 0x98, 0x6f, 0x68, 0xae, 0xa1, 0x1b,
+    0x59, 0x0a, 0x8b, 0xff, 0xff, 0xfb, 0x11, 0xb9, 0xe8, 0x1f, 0x6b, 0xe4,
+    0x20, 0x71, 0x7f, 0x39, 0x09, 0x27, 0xd1, 0xd7, 0xf6, 0x79, 0xc4, 0x1f,
+    0x9d, 0x7f, 0x77, 0xe2, 0x4e, 0xe2, 0x75, 0xfe, 0x85, 0xe8, 0x22, 0xec,
+    0x9d, 0x52, 0x44, 0x66, 0x16, 0x09, 0x75, 0x95, 0x61, 0x2f, 0xb3, 0xc4,
+    0x33, 0x27, 0x30, 0x09, 0x3e, 0x43, 0x5d, 0xa4, 0x89, 0x0e, 0x2e, 0x16,
+    0xad, 0xeb, 0xb0, 0xd4, 0x78, 0x44, 0x0c, 0x3f, 0x74, 0x4d, 0xe8, 0xc4,
+    0xef, 0xdc, 0x6b, 0xbb, 0x4d, 0x16, 0x05, 0xf9, 0xdb, 0xf7, 0xb3, 0x1d,
+    0x65, 0x70, 0xf7, 0x74, 0x67, 0x7e, 0xe3, 0x5d, 0xda, 0x68, 0x9d, 0x6f,
+    0xff, 0xf7, 0x62, 0x70, 0xe2, 0xd5, 0xd6, 0xb3, 0xa9, 0xaf, 0xe7, 0x3a,
+    0xfc, 0xaa, 0xde, 0x4a, 0xe2, 0x25, 0xe6, 0x33, 0xbc, 0xa4, 0x2c, 0xeb,
+    0xe7, 0x6f, 0xd5, 0x9d, 0x7a, 0x5a, 0x55, 0x43, 0x7f, 0xb0, 0x72, 0xfd,
+    0xc6, 0xbb, 0xb4, 0xd1, 0x6c, 0xdf, 0xde, 0x7e, 0xfc, 0x0c, 0x1d, 0x7f,
+    0xff, 0x49, 0x5d, 0x42, 0x60, 0x53, 0x35, 0x9e, 0x18, 0x3a, 0xa1, 0x10,
+    0xae, 0x5d, 0x7f, 0xe0, 0x46, 0x95, 0xea, 0x35, 0xf8, 0x75, 0xff, 0x44,
+    0xa3, 0x93, 0xc7, 0x27, 0x3a, 0xca, 0xe2, 0x6a, 0x0b, 0x85, 0xc3, 0x90,
+    0x89, 0xf5, 0xff, 0x85, 0x55, 0xfe, 0x9e, 0x17, 0xda, 0x3a, 0xff, 0xef,
+    0xf4, 0xae, 0x71, 0xf5, 0xd7, 0x91, 0xd7, 0x38, 0x31, 0x10, 0xc0, 0x41,
+    0xbe, 0x6b, 0xbb, 0x4d, 0x17, 0x35, 0x96, 0x75, 0x70, 0xde, 0xb2, 0x5b,
+    0x7f, 0xb8, 0x39, 0xb8, 0x12, 0x47, 0x5d, 0x32, 0xce, 0xa3, 0xac, 0xae,
+    0x1f, 0xaa, 0x11, 0x32, 0x65, 0xb6, 0x2f, 0x7e, 0xe3, 0x5d, 0xda, 0x68,
+    0xbb, 0xef, 0xf4, 0x95, 0xd7, 0x38, 0x8c, 0x9d, 0x65, 0x70, 0xfa, 0x1c,
+    0xce, 0xf9, 0x55, 0x02, 0x03, 0xaa, 0x1f, 0x4b, 0xf7, 0x2f, 0x0f, 0x05,
+    0xa6, 0xfb, 0xab, 0xa4, 0xff, 0xcf, 0x23, 0x4a, 0x5c, 0x2f, 0xde, 0x10,
+    0x20, 0x8e, 0x1c, 0x61, 0x9b, 0xa8, 0x6f, 0xfa, 0x15, 0xbf, 0x49, 0xef,
+    0xfc, 0xcb, 0x8c, 0xfa, 0x41, 0xde, 0x47, 0x5f, 0xfd, 0x93, 0xe3, 0x3d,
+    0xcd, 0x62, 0x09, 0xd7, 0x22, 0xbd, 0x44, 0x08, 0x9f, 0xdf, 0xb5, 0xa5,
+    0xbc, 0x8e, 0xbf, 0xff, 0xff, 0xf7, 0x53, 0xa9, 0x03, 0xe1, 0x75, 0x33,
+    0xdf, 0xf9, 0x3d, 0xae, 0xa7, 0x22, 0x77, 0xe3, 0x4e, 0xbb, 0x50, 0x75,
+    0xff, 0xdb, 0xb7, 0xf7, 0xdf, 0xd9, 0x82, 0xa1, 0xd7, 0x85, 0xd5, 0x84,
+    0xc6, 0x9a, 0x4f, 0xa8, 0x4c, 0x78, 0x56, 0xf7, 0xee, 0xb3, 0xaf, 0xd9,
+    0xb5, 0xe8, 0x50, 0xeb, 0x6d, 0x1d, 0x53, 0x9b, 0xdc, 0x2a, 0xae, 0x1f,
+    0xd0, 0xac, 0xdf, 0xfb, 0x4e, 0xa7, 0x52, 0x07, 0xf8, 0x3a, 0xff, 0xdd,
+    0x7f, 0x3f, 0x77, 0x96, 0x78, 0xea, 0xc3, 0xfb, 0x43, 0xdb, 0x9c, 0x07,
+    0x5f, 0xff, 0xfe, 0x17, 0x64, 0x73, 0xde, 0xc9, 0xe0, 0x5d, 0x4d, 0x2e,
+    0x30, 0x42, 0x75, 0xec, 0xfb, 0xa3, 0xab, 0x11, 0x4d, 0xc1, 0x5d, 0xa7,
+    0x4b, 0xfd, 0xdc, 0x0a, 0x6c, 0xe6, 0x1d, 0x79, 0xdd, 0xa6, 0x89, 0x5e,
+    0xff, 0x28, 0xe2, 0x0f, 0x67, 0x4e, 0xa6, 0x9e, 0xca, 0x13, 0xdf, 0xfe,
+    0xf7, 0x72, 0x4d, 0xea, 0x06, 0x07, 0xc7, 0x54, 0x91, 0xeb, 0xc8, 0x46,
+    0x09, 0x0d, 0xd2, 0x9c, 0xeb, 0xff, 0xfc, 0xfb, 0xeb, 0x39, 0xef, 0x3c,
+    0xff, 0x56, 0x1e, 0xa2, 0x87, 0x5f, 0xdf, 0xef, 0xee, 0xc0, 0x0e, 0xbf,
+    0xf0, 0xbb, 0x21, 0xec, 0x4f, 0x8c, 0x9d, 0x7f, 0xfe, 0xc4, 0x06, 0x2d,
+    0x3d, 0xa8, 0x5b, 0xef, 0xe3, 0xaf, 0xfa, 0x17, 0xec, 0x9a, 0x49, 0xe3,
+    0xaa, 0x48, 0x8b, 0xf2, 0x9d, 0xf7, 0xef, 0xc9, 0x1d, 0x7f, 0xd0, 0xd1,
+    0x89, 0xc0, 0xfe, 0x3a, 0xff, 0xff, 0x27, 0x9d, 0x6e, 0x20, 0xeb, 0x2e,
+    0x33, 0xb5, 0x27, 0x3a, 0x82, 0x8b, 0x94, 0x22, 0x73, 0x7b, 0xfe, 0xfc,
+    0x0b, 0x79, 0x6b, 0x81, 0x3a, 0xff, 0xff, 0x62, 0x0f, 0xb0, 0x7e, 0x0b,
+    0x86, 0x06, 0x78, 0xe1, 0xd6, 0xcf, 0x22, 0x5f, 0x61, 0xd5, 0xff, 0x6e,
+    0x0c, 0xe6, 0x67, 0xb4, 0x75, 0x05, 0x56, 0x6e, 0x43, 0x2b, 0xb0, 0xdc,
+    0x18, 0x62, 0xfd, 0x2a, 0xbf, 0xec, 0xdf, 0x41, 0x87, 0x19, 0xce, 0xbf,
+    0xe7, 0x96, 0xbb, 0x1c, 0xfa, 0x13, 0xab, 0x0f, 0xcb, 0xc7, 0x17, 0xff,
+    0x79, 0x36, 0x27, 0xa6, 0x94, 0x0f, 0x8e, 0xbf, 0xfc, 0xf9, 0x2e, 0xe2,
+    0x0e, 0x03, 0x6f, 0x0e, 0xbc, 0xf2, 0x56, 0x17, 0xec, 0x25, 0x09, 0xc0,
+    0xc3, 0x1b, 0x23, 0x27, 0x59, 0xa0, 0x05, 0xc5, 0x97, 0x52, 0xbf, 0x3d,
+    0x0c, 0xdf, 0xa4, 0x3b, 0x48, 0xb7, 0xff, 0xb3, 0xaa, 0x8e, 0x05, 0x07,
+    0xd9, 0xd3, 0xaf, 0x7a, 0x02, 0x55, 0xff, 0xee, 0xba, 0x7a, 0x24, 0x9c,
+    0x9f, 0xf0, 0x15, 0x7f, 0x9d, 0xaa, 0x87, 0x8c, 0x15, 0x60, 0xf9, 0x74,
+    0x37, 0x65, 0x42, 0xcb, 0x8c, 0x6c, 0x69, 0x0b, 0xa4, 0x3e, 0xfa, 0x19,
+    0x7b, 0x21, 0x59, 0x7f, 0xf9, 0x55, 0xbc, 0x95, 0xce, 0x35, 0xdd, 0xa6,
+    0x89, 0x86, 0xff, 0xfe, 0xcd, 0x8e, 0x1e, 0xc2, 0xbe, 0xee, 0x07, 0xff,
+    0x68, 0xeb, 0xff, 0xdc, 0x70, 0x2a, 0xa7, 0xa4, 0xcc, 0x6a, 0x47, 0x5d,
+    0x8a, 0x8a, 0x2a, 0xfe, 0xaf, 0x5f, 0xfc, 0xc0, 0xcd, 0xe5, 0xfb, 0xf8,
+    0x62, 0x47, 0x5f, 0xb1, 0x7f, 0x37, 0x63, 0x3a, 0xfe, 0x85, 0xe0, 0x23,
+    0x61, 0xd4, 0x13, 0xda, 0xe9, 0x6d, 0xfe, 0xe6, 0x36, 0x01, 0xf5, 0x67,
+    0x5f, 0xbb, 0x01, 0x45, 0x0e, 0xa4, 0x3f, 0xde, 0x11, 0x6d, 0x1a, 0x5f,
+    0xe8, 0x79, 0xfc, 0xa3, 0xf0, 0xeb, 0xf3, 0xf2, 0x4e, 0xb3, 0xa8, 0x4f,
+    0x67, 0xf3, 0x3b, 0xfd, 0xa8, 0xc1, 0x0f, 0x60, 0xeb, 0xfa, 0x30, 0x43,
+    0xd8, 0x3a, 0xf7, 0xfc, 0x9b, 0xe1, 0xed, 0x68, 0xc2, 0xff, 0xf7, 0x13,
+    0xfc, 0x53, 0x3d, 0xfc, 0x6e, 0x13, 0xaf, 0xff, 0xc9, 0xce, 0xbf, 0xc0,
+    0xe4, 0xbb, 0x1b, 0x03, 0x07, 0x5f, 0xf3, 0x3f, 0x7b, 0x0d, 0xea, 0x4c,
+    0x75, 0xf7, 0xeb, 0xc0, 0x9d, 0x6c, 0xdc, 0xf7, 0xb6, 0x8f, 0x2f, 0xe8,
+    0xe4, 0x4b, 0x58, 0x75, 0x35, 0x38, 0xfe, 0x1c, 0x75, 0x30, 0x61, 0x6b,
+    0xe2, 0xbb, 0xf9, 0x71, 0x83, 0xed, 0xb3, 0xad, 0xa3, 0xaf, 0xd1, 0x83,
+    0xed, 0xb3, 0xaf, 0xee, 0xa7, 0xb4, 0xfb, 0xfc, 0x3e, 0x69, 0x8b, 0x96,
+    0x21, 0x7f, 0xa5, 0xe8, 0x5e, 0xc0, 0x48, 0xeb, 0xff, 0xfc, 0xce, 0xd7,
+    0xb3, 0xbf, 0x07, 0x27, 0x4c, 0x1d, 0xe5, 0xa3, 0xaf, 0xcc, 0xfb, 0x3a,
+    0xd3, 0xac, 0x38, 0x88, 0xe7, 0x66, 0xbf, 0xfd, 0xe1, 0x70, 0x77, 0x10,
+    0x3f, 0xfb, 0x47, 0x5f, 0xf4, 0x4f, 0xf6, 0x5d, 0xfd, 0xe7, 0x3a, 0xa1,
+    0x10, 0xdc, 0x49, 0xbf, 0xfb, 0x37, 0x97, 0xce, 0xbb, 0x60, 0x42, 0x75,
+    0xfd, 0xb3, 0xef, 0x86, 0x00, 0x75, 0xff, 0xe8, 0xf0, 0x22, 0x59, 0xbf,
+    0xa7, 0xfd, 0x93, 0xaf, 0x69, 0xc0, 0x75, 0x42, 0x26, 0x10, 0xc3, 0xc9,
+    0xb7, 0xf3, 0x83, 0x9c, 0x4e, 0x1d, 0x7b, 0xdf, 0x30, 0xea, 0x01, 0xe4,
+    0xfd, 0x2c, 0xbf, 0xb4, 0x8a, 0x2d, 0xfc, 0x75, 0xff, 0xff, 0xb9, 0x9b,
+    0x20, 0x7d, 0xf3, 0xe8, 0xc7, 0x5d, 0x3d, 0x1e, 0xd1, 0xd7, 0xf0, 0xe6,
+    0xbe, 0x35, 0x84, 0x75, 0x6e, 0x8c, 0xde, 0x16, 0xec, 0x6e, 0xbe, 0xf9,
+    0xb3, 0x6a, 0x73, 0xab, 0x0f, 0x75, 0x43, 0x3b, 0x31, 0x9d, 0x77, 0xb0,
+    0xeb, 0xff, 0xcc, 0x11, 0x85, 0xba, 0x75, 0xfd, 0xd8, 0x3a, 0xa0, 0xf7,
+    0xff, 0x15, 0xbf, 0xdd, 0x49, 0x9d, 0xba, 0x91, 0xd7, 0xf0, 0xf9, 0xd6,
+    0x9e, 0x3a, 0xff, 0xc9, 0xef, 0xf8, 0xfa, 0xf8, 0xbf, 0x1d, 0x50, 0x7d,
+    0x8e, 0x57, 0x7f, 0xd8, 0x98, 0xb1, 0xc9, 0xdc, 0xeb, 0xf4, 0x7b, 0x40,
+    0xfc, 0xea, 0x62, 0x13, 0xb0, 0xc7, 0x26, 0x91, 0x76, 0x13, 0xe2, 0x41,
+    0xe3, 0x5b, 0xff, 0xf7, 0x47, 0x3d, 0xd4, 0xcd, 0xfd, 0x9b, 0x23, 0x47,
+    0x5f, 0xfc, 0xe3, 0xd8, 0x40, 0xa6, 0xb2, 0x47, 0x5e, 0x80, 0x7d, 0x3a,
+    0xfe, 0xcd, 0x9d, 0x40, 0x4c, 0x75, 0x62, 0x38, 0x5d, 0x54, 0x50, 0x34,
+    0x3b, 0x7b, 0xe8, 0x70, 0xeb, 0xcc, 0x1d, 0x30, 0x8e, 0xa7, 0x3c, 0x1d,
+    0x0e, 0xdf, 0x7c, 0x5f, 0xc6, 0x9d, 0x7f, 0x85, 0xd9, 0x8f, 0x64, 0xe7,
+    0x5f, 0xb7, 0x66, 0x6d, 0x41, 0xd6, 0x55, 0x84, 0xcd, 0x22, 0x88, 0xc7,
+    0xc3, 0x08, 0xac, 0x94, 0x16, 0xd8, 0x5a, 0xee, 0xab, 0x34, 0x30, 0xf9,
+    0x0a, 0xc5, 0x91, 0x76, 0x1b, 0xa0, 0x77, 0x18, 0xd3, 0xb5, 0x1e, 0x97,
+    0xa3, 0x41, 0xfd, 0xed, 0x92, 0x1d, 0xb2, 0x6f, 0xa6, 0x57, 0xff, 0xdc,
+    0x4d, 0xe5, 0xa4, 0xf7, 0x63, 0x9e, 0x83, 0xaf, 0xdc, 0x6b, 0xbb, 0x4d,
+    0x15, 0x75, 0xee, 0x42, 0xce, 0xbf, 0xe9, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d,
+    0x11, 0xe5, 0xff, 0x44, 0xa3, 0x93, 0xc7, 0x27, 0x3a, 0xff, 0xd1, 0xe4,
+    0xfd, 0x83, 0x92, 0x9e, 0x63, 0xac, 0xa8, 0x53, 0x5f, 0xc4, 0xfe, 0x19,
+    0xb8, 0xd8, 0xa2, 0xe8, 0xe6, 0xfd, 0xc6, 0xbb, 0xb4, 0xd1, 0x60, 0xde,
+    0x52, 0x27, 0x3a, 0xff, 0xfe, 0x1f, 0xde, 0x75, 0xe6, 0xdf, 0xfc, 0xce,
+    0x4b, 0xec, 0x8e, 0xbf, 0x60, 0xe7, 0xb4, 0x75, 0xfe, 0xe3, 0xaf, 0xef,
+    0x1f, 0x73, 0xac, 0xae, 0x26, 0x18, 0xa1, 0x9b, 0x47, 0x5d, 0x8b, 0xe9,
+    0x2d, 0xfe, 0x57, 0x38, 0xd7, 0x76, 0x9a, 0x2c, 0xab, 0xf7, 0x1a, 0xee,
+    0xd3, 0x45, 0xa7, 0x7f, 0xce, 0x1e, 0xbc, 0xdd, 0x45, 0x9d, 0x65, 0x70,
+    0xfa, 0xd6, 0x67, 0x7e, 0x61, 0xec, 0x51, 0x88, 0x62, 0x18, 0xb3, 0xaf,
+    0xf9, 0x85, 0xd4, 0x64, 0x2e, 0xed, 0x3a, 0xfc, 0xc3, 0xd8, 0x1a, 0xc8,
+    0x3a, 0xff, 0x7d, 0x5e, 0x7b, 0x49, 0xa3, 0xac, 0x87, 0x53, 0x08, 0xf0,
+    0xf6, 0xcd, 0x2f, 0xff, 0xe4, 0xeb, 0x8f, 0xa5, 0x9c, 0xc8, 0x11, 0xcf,
+    0x1d, 0x7e, 0xd8, 0xe1, 0xc5, 0x9d, 0x7c, 0xb8, 0xdf, 0x47, 0x5f, 0xfc,
+    0x98, 0xe0, 0x89, 0x72, 0x30, 0x4e, 0xa9, 0x23, 0x7b, 0x15, 0x66, 0x28,
+    0x12, 0x2b, 0xf7, 0xce, 0x73, 0xfe, 0x9d, 0x7e, 0x45, 0x20, 0x5a, 0x75,
+    0xb3, 0x47, 0xa3, 0xe2, 0xbb, 0xff, 0xe1, 0x6f, 0x53, 0xa9, 0xc8, 0x99,
+    0x9c, 0xe9, 0xd7, 0xfe, 0x5a, 0xde, 0x5b, 0x7f, 0xf5, 0x38, 0x75, 0xf9,
+    0xf5, 0xe8, 0x09, 0xd5, 0x07, 0xd1, 0xfa, 0x15, 0x42, 0x36, 0x7b, 0x0b,
+    0x7b, 0xe8, 0xfb, 0x1d, 0x3a, 0xf9, 0xae, 0xed, 0x34, 0x5b, 0x97, 0xd3,
+    0x40, 0x70, 0xeb, 0xff, 0x67, 0x30, 0x7e, 0x77, 0x37, 0x64, 0xeb, 0xf0,
+    0x81, 0xf7, 0xd1, 0xd5, 0x07, 0xce, 0xe8, 0x15, 0xba, 0x3d, 0xf8, 0x44,
+    0xe5, 0xba, 0x84, 0x45, 0xfe, 0x71, 0x04, 0xc3, 0x0b, 0x3a, 0xf2, 0xc5,
+    0x0e, 0xb0, 0x9d, 0x7f, 0xdd, 0xfd, 0xf5, 0x98, 0x2a, 0x1d, 0x7e, 0xd3,
+    0xee, 0xe1, 0x3a, 0xc8, 0x13, 0xdf, 0xf1, 0xc5, 0x42, 0x2b, 0xf0, 0x6b,
+    0xad, 0xd7, 0xfd, 0x0e, 0x3d, 0xcc, 0x16, 0x9d, 0x7f, 0xbd, 0xe4, 0x9d,
+    0x70, 0x27, 0x54, 0x8f, 0x9b, 0x0d, 0x2f, 0xfa, 0x07, 0xf5, 0xc6, 0xbc,
+    0x87, 0x5e, 0x8c, 0xe1, 0xd7, 0xfb, 0xb1, 0x24, 0xdb, 0xc5, 0x9d, 0x41,
+    0x3c, 0xed, 0x0d, 0x5f, 0xbe, 0x6f, 0xa4, 0x50, 0xeb, 0x3c, 0xe7, 0x9b,
+    0xb9, 0x15, 0xff, 0xd2, 0xce, 0xa7, 0x03, 0xd8, 0x16, 0x9d, 0x7f, 0xb7,
+    0x94, 0x0f, 0xb0, 0x07, 0x5f, 0x68, 0x09, 0xe3, 0xa9, 0xd1, 0x7d, 0xa2,
+    0x9f, 0xd0, 0xbe, 0x99, 0x5f, 0xfd, 0xe4, 0x04, 0x48, 0x3d, 0x81, 0x69,
+    0xd7, 0xf7, 0xa5, 0x9c, 0xcd, 0x1d, 0x47, 0x5e, 0xfd, 0xfc, 0x75, 0xdf,
+    0xc1, 0xd5, 0x23, 0x65, 0xe1, 0xca, 0x3a, 0xfb, 0x76, 0xa7, 0x0e, 0xbd,
+    0x0b, 0x57, 0x11, 0x13, 0xb9, 0xe2, 0xc8, 0x7c, 0x15, 0x50, 0x9a, 0x36,
+    0x21, 0x24, 0x2d, 0x6f, 0x0f, 0xb6, 0xce, 0xbd, 0xf1, 0x8b, 0x62, 0xce,
+    0xbf, 0xe9, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x14, 0x3d, 0x22, 0x22, 0xe6,
+    0x1e, 0x72, 0x8b, 0xf0, 0x21, 0xb8, 0xb3, 0xaf, 0xa2, 0x6c, 0x09, 0xd5,
+    0xc3, 0xc7, 0xd1, 0x35, 0xff, 0x64, 0x07, 0xb1, 0xb5, 0x13, 0x1d, 0x7f,
+    0x80, 0x9d, 0xee, 0x01, 0xce, 0xa5, 0x9f, 0x58, 0x0e, 0xaa, 0x11, 0x5e,
+    0xf0, 0x8d, 0xbf, 0xf3, 0x86, 0x03, 0xd4, 0x14, 0x59, 0xd7, 0xfe, 0xd8,
+    0xfc, 0xd3, 0xf7, 0x51, 0x39, 0xd7, 0xfb, 0x5f, 0xb7, 0x3c, 0x30, 0x75,
+    0x2d, 0x15, 0xbd, 0x3b, 0xf2, 0x05, 0xff, 0xdf, 0xcb, 0xaf, 0xcd, 0xfd,
+    0x09, 0x39, 0xd7, 0xfa, 0x51, 0xc9, 0xe3, 0x93, 0x9d, 0x7e, 0x7d, 0x6c,
+    0xcd, 0x1d, 0x50, 0x7b, 0x80, 0x34, 0xbf, 0x27, 0xb4, 0xe8, 0x75, 0xff,
+    0x70, 0x1c, 0x71, 0xf6, 0x00, 0xea, 0x01, 0xee, 0x7e, 0x4b, 0x7b, 0xef,
+    0x24, 0x75, 0xfd, 0xf7, 0xdf, 0xc6, 0x4e, 0x75, 0x48, 0xf3, 0xa6, 0x1e,
+    0xbf, 0xf9, 0xa3, 0x1e, 0x1c, 0xd9, 0x9c, 0x91, 0xd7, 0xfd, 0xf8, 0xa9,
+    0xf7, 0xbd, 0xff, 0x47, 0x5f, 0xe1, 0x17, 0xf7, 0xd8, 0x69, 0xd7, 0xc2,
+    0x09, 0xc0, 0x75, 0x61, 0xea, 0x21, 0x95, 0xfe, 0xd7, 0xcf, 0x7c, 0x0e,
+    0x09, 0xd6, 0x01, 0xd6, 0x4d, 0xcf, 0x1b, 0x86, 0xd7, 0xe7, 0xdf, 0x5e,
+    0x43, 0xaa, 0x13, 0xad, 0xc2, 0x34, 0x43, 0xec, 0x24, 0x85, 0x9b, 0x45,
+    0x17, 0xe7, 0xfd, 0x48, 0xfa, 0x75, 0xf9, 0x85, 0x9c, 0x8d, 0x1d, 0x53,
+    0x1e, 0xa0, 0x95, 0x5f, 0xf3, 0xea, 0x26, 0xde, 0x59, 0xb0, 0xeb, 0xff,
+    0xf0, 0x7b, 0x1f, 0x55, 0xf0, 0xb8, 0x35, 0xa8, 0x01, 0x57, 0x07, 0x0e,
+    0xbf, 0x4f, 0x13, 0xbe, 0x8e, 0xac, 0x44, 0xa2, 0x2b, 0xb8, 0xad, 0xc0,
+    0xfc, 0xeb, 0xf9, 0xc1, 0x30, 0xc0, 0x4e, 0xbf, 0xe1, 0xc9, 0xc3, 0xdc,
+    0x1f, 0x1d, 0x50, 0x7f, 0x5d, 0x17, 0x12, 0xcb, 0x2a, 0xc4, 0xb6, 0x44,
+    0xac, 0x5a, 0x1b, 0x14, 0x3c, 0x61, 0x9c, 0xe2, 0x30, 0x79, 0x42, 0x34,
+    0x31, 0x80, 0x64, 0x63, 0xca, 0x21, 0x36, 0x1c, 0x1b, 0xc2, 0x51, 0x08,
+    0x66, 0x8e, 0x43, 0x91, 0xc2, 0xae, 0x17, 0xdd, 0x8c, 0x95, 0xe1, 0xa6,
+    0x03, 0x01, 0x85, 0x16, 0x9f, 0x7d, 0x28, 0x7b, 0xf8, 0x56, 0xec, 0x22,
+    0xdb, 0x86, 0x7f, 0xd8, 0x53, 0xdf, 0x47, 0x24, 0xb3, 0xaf, 0x3f, 0x14,
+    0x3a, 0xca, 0xce, 0x6f, 0x59, 0x21, 0xbf, 0xca, 0xe7, 0x1a, 0xee, 0xd3,
+    0x45, 0xe7, 0x50, 0xea, 0x22, 0x24, 0xe0, 0x18, 0xc0, 0xb2, 0x9a, 0xa5,
+    0xbc, 0xa9, 0xfe, 0x46, 0xd0, 0xb5, 0x3e, 0xc2, 0xa8, 0x6b, 0x24, 0xdd,
+    0x4a, 0x0a, 0xd8, 0x55, 0x7f, 0x95, 0xce, 0x35, 0xdd, 0xa6, 0x8a, 0x5a,
+    0xfd, 0xc6, 0xbb, 0xb4, 0xd1, 0x61, 0x5f, 0xff, 0xa3, 0x04, 0x31, 0xd8,
+    0xdf, 0xd8, 0x2e, 0xb3, 0xaf, 0xef, 0xf8, 0x93, 0xba, 0xce, 0xb2, 0xb8,
+    0x8b, 0x25, 0x99, 0xed, 0xa8, 0xdf, 0xe5, 0x73, 0x8d, 0x77, 0x69, 0xa2,
+    0xcb, 0xbb, 0x8a, 0x1d, 0x7c, 0xaa, 0x8c, 0x33, 0x12, 0x75, 0x15, 0x79,
+    0x5f, 0xab, 0x3a, 0x9a, 0x7a, 0xfa, 0x2e, 0xfc, 0x2a, 0x85, 0x13, 0xda,
+    0x6e, 0xba, 0x3a, 0x75, 0x80, 0x75, 0xca, 0x4e, 0x75, 0xb9, 0x23, 0x51,
+    0x82, 0x14, 0xd3, 0xe3, 0x73, 0xdb, 0xfe, 0x7d, 0xc7, 0x37, 0xf4, 0x28,
+    0x75, 0xfe, 0x9f, 0x7d, 0x40, 0x7c, 0x87, 0x5f, 0xa3, 0x36, 0x46, 0x8e,
+    0xb4, 0x39, 0xed, 0xb2, 0x69, 0x4e, 0x8b, 0xb1, 0x84, 0xa5, 0xf3, 0xca,
+    0x41, 0x3a, 0xfe, 0x7e, 0x47, 0x9f, 0xa7, 0x5e, 0x65, 0x96, 0x4a, 0xbf,
+    0xe8, 0x96, 0xfe, 0xe4, 0x66, 0xe5, 0x2a, 0x5f, 0xdf, 0xf7, 0xef, 0xbe,
+    0x79, 0x37, 0x64, 0xeb, 0xa3, 0x47, 0x50, 0x53, 0x04, 0xe9, 0x08, 0xa5,
+    0x69, 0x27, 0x61, 0xdd, 0xcc, 0x33, 0x12, 0x75, 0xfc, 0x8f, 0xa0, 0x6b,
+    0xf3, 0xaf, 0xfe, 0x49, 0x3e, 0x9c, 0x7f, 0x6e, 0x68, 0xab, 0xff, 0xfb,
+    0xa9, 0xee, 0xe6, 0x87, 0x17, 0xfe, 0xba, 0xf2, 0x3a, 0xff, 0x44, 0xbc,
+    0xfd, 0x70, 0x9d, 0x50, 0x8c, 0xdc, 0x42, 0xe2, 0xd5, 0xa4, 0x75, 0xa4,
+    0x75, 0xa4, 0x75, 0x41, 0xb0, 0x50, 0x41, 0x04, 0x2f, 0xef, 0xf5, 0xd7,
+    0x96, 0x1d, 0x7f, 0xfd, 0xa4, 0x6e, 0x0f, 0x20, 0x70, 0x38, 0xa1, 0xd4,
+    0xb3, 0xf9, 0xf1, 0x6d, 0xb7, 0x3a, 0xca, 0x1d, 0x6f, 0xce, 0xa1, 0x34,
+    0x5a, 0x11, 0xac, 0x3f, 0x5d, 0x11, 0x78, 0xce, 0xe4, 0x83, 0xaf, 0xe1,
+    0x85, 0x8c, 0x61, 0xd7, 0x4a, 0x0e, 0xa0, 0x9e, 0x94, 0xc2, 0x9f, 0x94,
+    0xdf, 0xff, 0xff, 0x76, 0x3d, 0xa4, 0xd6, 0xa3, 0xdd, 0x48, 0xe0, 0x16,
+    0xf2, 0x97, 0x94, 0x3a, 0xe4, 0xdc, 0xeb, 0xa1, 0x67, 0x5f, 0xff, 0xa0,
+    0x7f, 0x94, 0xa3, 0xdd, 0xc5, 0xfd, 0x80, 0x1d, 0x7f, 0xfc, 0x83, 0xfc,
+    0xb3, 0x5c, 0x84, 0x93, 0xe8, 0xaa, 0x92, 0x28, 0xfc, 0xad, 0x73, 0x55,
+    0x85, 0xf8, 0x99, 0xe1, 0x0a, 0x18, 0x6e, 0x64, 0x65, 0x4a, 0x26, 0x34,
+    0x83, 0x90, 0xfa, 0x75, 0xe1, 0x8c, 0x6f, 0x50, 0x80, 0xf1, 0x8e, 0xc7,
+    0xdd, 0xb1, 0x6f, 0xb0, 0xb8, 0xbf, 0xfc, 0xaa, 0xde, 0x4a, 0xe7, 0x1a,
+    0xee, 0xd3, 0x45, 0x19, 0x7e, 0xd9, 0x1c, 0x80, 0x1d, 0x7e, 0x17, 0x04,
+    0x7d, 0x3a, 0xff, 0xed, 0xda, 0x9c, 0xee, 0x60, 0xcb, 0x47, 0x59, 0x58,
+    0x44, 0x97, 0x4a, 0x3c, 0x4f, 0x52, 0x65, 0xd4, 0x72, 0x1e, 0x2b, 0x39,
+    0x7a, 0x43, 0x36, 0xa1, 0xf3, 0xe8, 0x74, 0xdf, 0xfc, 0xab, 0xc9, 0x5c,
+    0xe3, 0x5d, 0xda, 0x68, 0x8e, 0x6f, 0xff, 0x2a, 0xb7, 0x92, 0xb9, 0xc6,
+    0xbb, 0xb4, 0xd1, 0x39, 0x5f, 0xe5, 0x73, 0x8d, 0x77, 0x69, 0xa2, 0xcc,
+    0xbf, 0xe9, 0x69, 0xd6, 0xaf, 0x7c, 0x03, 0xaf, 0xf9, 0x87, 0x07, 0x17,
+    0x1b, 0xc2, 0xce, 0xbf, 0xdc, 0x8f, 0x75, 0xf7, 0x91, 0xd7, 0xff, 0xff,
+    0xd1, 0x37, 0x63, 0xd1, 0xf5, 0x39, 0x34, 0x77, 0x36, 0x67, 0x70, 0x3b,
+    0x30, 0xea, 0x02, 0x2d, 0x04, 0xce, 0xff, 0x66, 0xb9, 0xcc, 0xdf, 0x47,
+    0x5f, 0xb3, 0xdc, 0xc5, 0x9d, 0x7f, 0xe4, 0x18, 0xd4, 0x7a, 0x7c, 0x64,
+    0xeb, 0xfb, 0x8d, 0xeb, 0xa3, 0x04, 0xeb, 0xb7, 0x59, 0xd6, 0x55, 0x89,
+    0x4f, 0xc6, 0x21, 0xe5, 0x22, 0x20, 0x99, 0xac, 0x9b, 0xf3, 0xdd, 0xb3,
+    0x0b, 0xfc, 0xae, 0x71, 0xae, 0xed, 0x34, 0x5b, 0xb7, 0xf0, 0xba, 0xbc,
+    0x9f, 0xa7, 0x5e, 0x4d, 0xc0, 0x75, 0xfb, 0x8d, 0x77, 0x69, 0xa2, 0x90,
+    0xbf, 0xf6, 0x75, 0x36, 0x77, 0x30, 0x5a, 0x75, 0xe7, 0x92, 0xb8, 0x7e,
+    0x1a, 0x33, 0xb2, 0xad, 0x47, 0x6f, 0x0b, 0x97, 0x08, 0xcb, 0xff, 0x95,
+    0x79, 0x2b, 0x9c, 0x6b, 0xbb, 0x4d, 0x12, 0x95, 0x4e, 0xba, 0x89, 0x32,
+    0x8a, 0xd5, 0xdc, 0xfc, 0x12, 0x8a, 0xc5, 0xe7, 0xd1, 0x96, 0x6d, 0x1e,
+    0x5f, 0xe9, 0x20, 0xfb, 0x10, 0x27, 0x5e, 0xd7, 0xeb, 0x3a, 0xca, 0xee,
+    0x79, 0xa8, 0x61, 0x78, 0x5e, 0x47, 0x5f, 0xf9, 0xe4, 0xae, 0x71, 0xae,
+    0xed, 0x34, 0x4e, 0xd7, 0x4e, 0xc6, 0x75, 0xff, 0xf9, 0x03, 0xfa, 0xe3,
+    0x69, 0xc2, 0x30, 0x38, 0xd3, 0xaf, 0xf4, 0xa3, 0x93, 0xc7, 0x27, 0x3a,
+    0xff, 0xdd, 0x17, 0x97, 0xe0, 0x5b, 0xc8, 0xea, 0x83, 0xf2, 0xc3, 0x4b,
+    0x2b, 0x89, 0xb2, 0xac, 0x6b, 0xa9, 0x4e, 0x34, 0x30, 0xc7, 0xbf, 0xfe,
+    0x57, 0xee, 0xdb, 0x88, 0x33, 0xd0, 0x28, 0x03, 0xaf, 0xfe, 0x75, 0xf7,
+    0x1a, 0xfd, 0x8f, 0xb2, 0x3a, 0xf2, 0x05, 0xce, 0xbf, 0xf8, 0x73, 0xaf,
+    0x3e, 0x68, 0x5f, 0x73, 0xae, 0xdb, 0x54, 0x28, 0xa0, 0xea, 0x26, 0x86,
+    0xaa, 0x4a, 0xc5, 0x17, 0x1c, 0x76, 0x95, 0x36, 0xe1, 0xe5, 0x7f, 0xff,
+    0x05, 0xfc, 0xae, 0x6a, 0x07, 0x70, 0x6b, 0x50, 0x03, 0xaf, 0xdc, 0x6b,
+    0xbb, 0x4d, 0x11, 0x65, 0xff, 0x9e, 0x4a, 0xe7, 0x1a, 0xee, 0xd3, 0x44,
+    0xbb, 0x7f, 0xff, 0x60, 0x7b, 0x1f, 0x55, 0xf0, 0xb8, 0x35, 0xa8, 0x01,
+    0x56, 0x57, 0x11, 0xb2, 0xb3, 0x3d, 0xb4, 0xab, 0xff, 0x96, 0xf2, 0x57,
+    0x38, 0xd7, 0x76, 0x9a, 0x26, 0x2b, 0xff, 0xec, 0x6c, 0x2b, 0xd7, 0x4d,
+    0xb4, 0x06, 0x04, 0xea, 0x55, 0x14, 0x1d, 0x50, 0xbf, 0x71, 0xae, 0xed,
+    0x34, 0x55, 0x36, 0xc3, 0xab, 0x0f, 0x09, 0x43, 0x3b, 0xff, 0x7e, 0xfc,
+    0x90, 0xe3, 0x2e, 0x03, 0xaf, 0xfe, 0x7d, 0x71, 0x19, 0xf7, 0x53, 0x92,
+    0x3a, 0xff, 0xb8, 0xfd, 0xde, 0x59, 0xe5, 0x42, 0x88, 0x2e, 0x9f, 0x52,
+    0xa8, 0xf7, 0x78, 0x52, 0x5f, 0xfe, 0x55, 0x6f, 0x25, 0x73, 0x8d, 0x77,
+    0x69, 0xa2, 0x74, 0xbf, 0xc8, 0xfc, 0x89, 0x3e, 0xc3, 0xaf, 0xd3, 0x44,
+    0xd1, 0xa3, 0xaf, 0xe6, 0x71, 0x36, 0x60, 0x9d, 0x48, 0x7a, 0xba, 0x28,
+    0xbc, 0x9d, 0x83, 0x95, 0x34, 0x37, 0xff, 0x7f, 0xaf, 0x46, 0xea, 0xff,
+    0x32, 0x2c, 0xea, 0x59, 0xfa, 0x74, 0xae, 0xff, 0xcf, 0x25, 0x73, 0x8d,
+    0x77, 0x69, 0xa2, 0x77, 0xbf, 0x7b, 0xf7, 0x5a, 0x15, 0x7f, 0xe1, 0x8f,
+    0x66, 0xb3, 0x37, 0x91, 0xd4, 0x14, 0xfa, 0xf2, 0x31, 0xc5, 0x91, 0x3a,
+    0x57, 0x89, 0xef, 0xf8, 0x31, 0x28, 0x55, 0x9d, 0x00, 0xeb, 0xfa, 0x15,
+    0x00, 0xe0, 0x4e, 0xa5, 0x51, 0x6b, 0x89, 0xe2, 0x75, 0x7f, 0xf9, 0x55,
+    0xbc, 0x95, 0xce, 0x35, 0xdd, 0xa6, 0x8a, 0x16, 0xff, 0xff, 0xf7, 0x7f,
+    0x5a, 0xde, 0x4a, 0xb7, 0xbf, 0xfa, 0x07, 0x27, 0x53, 0xf8, 0x98, 0xeb,
+    0xf7, 0xfb, 0xf9, 0x1a, 0x75, 0xfb, 0x01, 0x8e, 0x27, 0x5f, 0x69, 0x19,
+    0xf1, 0xd7, 0xa0, 0x0a, 0xce, 0x7d, 0xe2, 0x53, 0xe2, 0x4a, 0x44, 0xcb,
+    0x86, 0x1d, 0xb7, 0xff, 0x95, 0x5b, 0xc9, 0x5c, 0xe3, 0x5d, 0xda, 0x68,
+    0xa4, 0xaf, 0xff, 0xf6, 0x69, 0x5f, 0xb9, 0x37, 0x5d, 0x7e, 0xec, 0x7b,
+    0xf5, 0x9d, 0x50, 0xc9, 0x20, 0x9e, 0x33, 0x49, 0x43, 0x65, 0xb1, 0xae,
+    0xf0, 0xa1, 0x72, 0xbd, 0xc0, 0x5f, 0xe8, 0xe1, 0x7f, 0x27, 0xdb, 0x57,
+    0xbf, 0xca, 0xe7, 0x1a, 0xee, 0xd3, 0x44, 0x49, 0x7f, 0xf9, 0x55, 0xbc,
+    0x95, 0xce, 0x35, 0xdd, 0xa6, 0x89, 0x7a, 0xf3, 0x12, 0xb0, 0x1d, 0x7d,
+    0xcf, 0xfd, 0xa3, 0xaf, 0xdc, 0x02, 0xd3, 0x47, 0x5e, 0x81, 0xdc, 0xeb,
+    0xf7, 0xbe, 0xac, 0x60, 0xeb, 0x27, 0x4f, 0x0c, 0x46, 0xef, 0xff, 0x77,
+    0x64, 0x08, 0x18, 0xf0, 0x39, 0xcd, 0xce, 0xba, 0x3c, 0x75, 0xff, 0xef,
+    0xc2, 0x9c, 0xfb, 0x36, 0xd7, 0xee, 0x33, 0x1d, 0x52, 0x46, 0xda, 0x13,
+    0x01, 0x3b, 0x42, 0xb7, 0xf0, 0x3b, 0x1c, 0x45, 0x9d, 0x7f, 0xe9, 0xb5,
+    0x1b, 0x1f, 0xb1, 0xbc, 0xc7, 0x54, 0x1f, 0x73, 0x96, 0x5f, 0xb2, 0x7c,
+    0xd2, 0xce, 0xbf, 0xfa, 0x6f, 0x9f, 0x46, 0x36, 0x3e, 0xc8, 0x98, 0xea,
+    0x3a, 0xfe, 0x9a, 0x4f, 0xe7, 0xd8, 0x75, 0x42, 0x21, 0x71, 0x31, 0xc2,
+    0xae, 0xe4, 0x1d, 0x41, 0x56, 0x40, 0x84, 0x73, 0x46, 0x8b, 0xc8, 0x55,
+    0x09, 0x06, 0xc8, 0x56, 0x6d, 0x16, 0xde, 0x0e, 0x09, 0xd7, 0x07, 0x73,
+    0xaf, 0xe1, 0xff, 0xd3, 0x42, 0x87, 0x5e, 0x60, 0xa7, 0x0e, 0xb2, 0x39,
+    0xe7, 0x7e, 0x5f, 0x7e, 0x1c, 0x9f, 0xee, 0xc3, 0xaf, 0xb2, 0x7f, 0xbb,
+    0x0e, 0xbf, 0x06, 0x37, 0x0b, 0xfc, 0x3d, 0x11, 0x2b, 0xbf, 0xfe, 0x4e,
+    0x7c, 0xec, 0x27, 0xb5, 0xfb, 0x7f, 0x83, 0xaf, 0x92, 0x70, 0x31, 0x9d,
+    0x7c, 0xd7, 0x76, 0x9a, 0x29, 0x7b, 0xe1, 0xf4, 0x70, 0xeb, 0xfe, 0xce,
+    0x31, 0xe0, 0x73, 0x9b, 0x9d, 0x48, 0x7b, 0x7b, 0x08, 0x2a, 0x49, 0xb1,
+    0x28, 0x81, 0x32, 0x97, 0x09, 0x7b, 0x08, 0x8b, 0xf8, 0x3b, 0xc7, 0x13,
+    0x73, 0xaf, 0xbd, 0x3e, 0x32, 0x75, 0x21, 0xe8, 0x89, 0x75, 0xff, 0xa0,
+    0x63, 0xbf, 0x3f, 0x1f, 0xda, 0x75, 0xef, 0xdf, 0x47, 0x5f, 0x4d, 0xfb,
+    0xcc, 0x75, 0xfa, 0x00, 0xfb, 0xe8, 0xeb, 0xc2, 0x80, 0x3a, 0xf6, 0x7b,
+    0x47, 0x54, 0x1b, 0x5d, 0x0d, 0x50, 0x51, 0xf9, 0x32, 0x07, 0x47, 0x00,
+    0x49, 0xe5, 0xcb, 0xf3, 0x1b, 0x88, 0x76, 0x8e, 0xbf, 0xe0, 0x6b, 0x91,
+    0xbc, 0x91, 0x67, 0x5e, 0xf3, 0xec, 0x3a, 0xfd, 0x3f, 0xf3, 0x43, 0x19,
+    0xd7, 0xdf, 0xcd, 0x0c, 0x67, 0x5c, 0xf3, 0xfc, 0x3d, 0x39, 0xcb, 0x6a,
+    0x11, 0xb4, 0xe7, 0x3f, 0xb8, 0x5f, 0xf2, 0x6a, 0x64, 0x1f, 0x40, 0x0e,
+    0xa9, 0x1f, 0x32, 0xcb, 0xef, 0xf4, 0x31, 0xea, 0x16, 0xfe, 0x3a, 0xe7,
+    0x13, 0xaf, 0xfa, 0x01, 0xf3, 0xb0, 0xb7, 0x13, 0xab, 0x73, 0xcc, 0xd8,
+    0x29, 0x52, 0x45, 0x2f, 0x21, 0x01, 0x7f, 0x6f, 0x2d, 0x38, 0xee, 0x75,
+    0x42, 0xa8, 0x9c, 0x8d, 0xb1, 0x21, 0x8f, 0xf4, 0xa2, 0xf7, 0x21, 0x67,
+    0x5f, 0xd0, 0x33, 0x79, 0x14, 0x3a, 0xff, 0xa5, 0x9c, 0x9b, 0x06, 0x16,
+    0x75, 0xf8, 0x10, 0xdc, 0x59, 0xd4, 0x87, 0xbb, 0xc3, 0x7b, 0xa5, 0x87,
+    0x5f, 0x70, 0x61, 0x67, 0x5e, 0x80, 0x68, 0xea, 0x83, 0xf1, 0x09, 0x0e,
+    0x0a, 0xb2, 0x41, 0x7e, 0xef, 0xea, 0x60, 0x9d, 0x7f, 0xd1, 0xdd, 0x3f,
+    0xa3, 0x9b, 0x47, 0x5f, 0xf9, 0x6e, 0x1f, 0xb3, 0x4a, 0x07, 0x73, 0xa8,
+    0x27, 0xf6, 0x87, 0x57, 0xdc, 0x07, 0xdd, 0x87, 0x5e, 0x46, 0x7c, 0x75,
+    0x74, 0xf0, 0xb4, 0x4d, 0x41, 0x4c, 0xa3, 0xb0, 0xa3, 0xf3, 0x1d, 0xff,
+    0x01, 0x3b, 0x9c, 0x79, 0xb4, 0x75, 0xff, 0xfa, 0x24, 0x31, 0x3f, 0xd9,
+    0xb5, 0xdc, 0xda, 0xe0, 0x0e, 0xbf, 0xbe, 0x2f, 0x3c, 0xfe, 0x3a, 0xcd,
+    0x3a, 0xed, 0xf5, 0x86, 0xf9, 0xcb, 0xaf, 0x42, 0x04, 0xea, 0xdd, 0x31,
+    0x75, 0x9c, 0x3c, 0x26, 0x74, 0x59, 0x7f, 0xb1, 0x99, 0x26, 0xbf, 0x59,
+    0xd7, 0x6c, 0xd1, 0xd7, 0xec, 0x9f, 0x3b, 0xa3, 0xaa, 0x0d, 0xf8, 0x8c,
+    0x5e, 0xce, 0x68, 0xea, 0x69, 0xba, 0xd8, 0x3f, 0x7f, 0xc0, 0x80, 0x7d,
+    0xd9, 0x03, 0xb4, 0x75, 0x42, 0x61, 0xd9, 0x0a, 0xd4, 0x23, 0xbf, 0xff,
+    0xfb, 0xb1, 0xcd, 0xda, 0x9b, 0xfc, 0x51, 0xfe, 0x6b, 0xae, 0xd8, 0x10,
+    0x9d, 0x7c, 0x8a, 0x6d, 0xe1, 0xd7, 0xf7, 0xdf, 0x44, 0xe3, 0xb9, 0xd7,
+    0x85, 0x16, 0x75, 0x70, 0xfb, 0x80, 0x49, 0xe3, 0x0b, 0xfc, 0x30, 0xe3,
+    0xec, 0x13, 0xaf, 0xf7, 0x5e, 0x64, 0xe4, 0x4e, 0x75, 0xd8, 0xb3, 0xa8,
+    0x29, 0xc5, 0x64, 0x39, 0x56, 0x5e, 0xe5, 0xdb, 0x0c, 0xef, 0xdb, 0x48,
+    0xb8, 0xd1, 0xd7, 0xe7, 0xd9, 0x9c, 0xd1, 0xd4, 0x13, 0xd1, 0x59, 0x4d,
+    0xfb, 0xae, 0x28, 0xb3, 0xaf, 0x94, 0x9b, 0x50, 0x75, 0xfc, 0x0d, 0xc1,
+    0x9c, 0xc3, 0xaf, 0xe7, 0x02, 0xe3, 0x3c, 0x75, 0x41, 0xec, 0x21, 0x6d,
+    0xfe, 0x70, 0x6a, 0x3b, 0x1a, 0x3a, 0xa1, 0x31, 0x3c, 0x22, 0x42, 0x5e,
+    0xbd, 0x89, 0x05, 0xc0, 0x69, 0xd6, 0xd1, 0xd7, 0x22, 0x9a, 0x34, 0xdf,
+    0x8b, 0x5e, 0x03, 0xb4, 0xeb, 0xe6, 0x66, 0xd4, 0x1d, 0x7f, 0x68, 0x5e,
+    0x78, 0xf1, 0xd7, 0xe9, 0xdf, 0x59, 0x23, 0xaf, 0xff, 0x83, 0x9b, 0x1f,
+    0x93, 0x7d, 0x93, 0xf9, 0xd6, 0x75, 0x41, 0xfd, 0x21, 0x3d, 0xfc, 0xfb,
+    0x81, 0x69, 0xa3, 0xaa, 0x13, 0x31, 0xdc, 0x6e, 0x62, 0x3e, 0x42, 0x9b,
+    0xa4, 0x16, 0x55, 0x8b, 0x6d, 0x65, 0x62, 0x5a, 0x0c, 0xef, 0x52, 0x1a,
+    0x0b, 0x2e, 0x47, 0xb5, 0xbc, 0x28, 0xd2, 0x31, 0xc9, 0xa5, 0x6a, 0x71,
+    0x25, 0x63, 0x7d, 0x87, 0xdb, 0xc6, 0xc6, 0x08, 0xd3, 0x46, 0x35, 0x1d,
+    0x47, 0x7b, 0xe8, 0xed, 0x36, 0xdb, 0x7e, 0xc6, 0xbf, 0x7f, 0x95, 0xce,
+    0x35, 0xdd, 0xa6, 0x8a, 0x72, 0xff, 0xc9, 0xc7, 0xd7, 0x73, 0x05, 0xa7,
+    0x5f, 0x97, 0xce, 0x66, 0x8e, 0xbf, 0xff, 0x77, 0xff, 0x72, 0x3d, 0xac,
+    0x6e, 0xa3, 0x8d, 0x3a, 0xff, 0xfe, 0xf6, 0x4c, 0x29, 0xaf, 0x47, 0xd4,
+    0xe4, 0xd1, 0xd3, 0xaf, 0xf2, 0x2c, 0x31, 0xaf, 0xc4, 0xeb, 0xfb, 0x3d,
+    0xbc, 0xa1, 0x93, 0xaf, 0xfc, 0x9b, 0xe8, 0x70, 0x3d, 0x76, 0x4e, 0xbf,
+    0xfe, 0xc9, 0xf3, 0x7f, 0x69, 0x06, 0x00, 0xeb, 0x3a, 0x94, 0x44, 0x66,
+    0x8f, 0xaf, 0xfd, 0x9d, 0x8e, 0x62, 0xac, 0xb2, 0xc9, 0x57, 0x23, 0x27,
+    0x5d, 0x3a, 0xa1, 0x54, 0xf7, 0x87, 0x6d, 0x27, 0x45, 0x6e, 0xae, 0x09,
+    0x97, 0xa1, 0x75, 0xb6, 0x49, 0xb4, 0x83, 0x7e, 0xe3, 0x5d, 0xda, 0x68,
+    0xaf, 0x2f, 0xff, 0xec, 0x0f, 0x63, 0xea, 0xbe, 0x17, 0x06, 0xb5, 0x00,
+    0x2a, 0xca, 0xe2, 0x23, 0xf6, 0xcc, 0xef, 0xfe, 0x55, 0xe4, 0xae, 0x71,
+    0xae, 0xed, 0x34, 0x48, 0xf7, 0x9b, 0x8b, 0x3a, 0xf2, 0x02, 0x0e, 0xbc,
+    0xdc, 0x59, 0x4a, 0x97, 0x57, 0xee, 0x35, 0xdd, 0xa6, 0x89, 0x22, 0xff,
+    0xfe, 0x84, 0xe2, 0x6d, 0x40, 0xcf, 0x1e, 0x4e, 0xbc, 0xe7, 0x5f, 0xfe,
+    0x1c, 0x06, 0xde, 0x72, 0x27, 0x7e, 0x34, 0xeb, 0xa4, 0xac, 0x26, 0x09,
+    0x85, 0x7d, 0x33, 0xf2, 0xdd, 0xfb, 0x3a, 0xae, 0x2c, 0xeb, 0x2b, 0x09,
+    0xd4, 0xbc, 0x67, 0x3e, 0x49, 0xbf, 0xf9, 0x57, 0x92, 0xb9, 0xc6, 0xbb,
+    0xb4, 0xd1, 0x25, 0x5f, 0xb8, 0xd7, 0x76, 0x9a, 0x2f, 0x1b, 0xfe, 0x92,
+    0xb9, 0xc6, 0xbb, 0xb4, 0xd1, 0x26, 0xd9, 0x5c, 0x3f, 0x87, 0x33, 0xb9,
+    0x9e, 0x9d, 0x7e, 0x40, 0x6b, 0x04, 0xeb, 0xff, 0xef, 0xdf, 0x7c, 0xc5,
+    0x14, 0x79, 0x66, 0xfe, 0x3a, 0xa4, 0x7e, 0xfa, 0x25, 0xbd, 0xf4, 0x67,
+    0x3a, 0xee, 0x78, 0xeb, 0xd3, 0x0c, 0xe7, 0x58, 0x4e, 0xbb, 0xef, 0xd3,
+    0xa8, 0x06, 0xa7, 0xe8, 0x7d, 0xdb, 0x6a, 0xc2, 0x69, 0xb9, 0x08, 0xee,
+    0x91, 0x38, 0xf6, 0x85, 0xbe, 0xa3, 0x54, 0x3a, 0x07, 0x19, 0xcf, 0xe5,
+    0x5a, 0xf6, 0x06, 0x35, 0xc4, 0x95, 0x75, 0x34, 0x64, 0xab, 0x2c, 0xec,
+    0x7f, 0x5e, 0x3c, 0xfe, 0x19, 0x3f, 0x63, 0x74, 0xa8, 0x9c, 0x68, 0x55,
+    0x9e, 0x54, 0xbc, 0xa7, 0x81, 0x03, 0x3b, 0x91, 0x98, 0x9a, 0xb3, 0x52,
+    0x73, 0x39, 0xb7, 0xbc, 0x25, 0xbd, 0x68, 0xac, 0x94, 0x9f, 0x56, 0x39,
+    0x44, 0xf3, 0x5b, 0x4d, 0xae, 0x5a, 0x43, 0xb5, 0xe7, 0x28, 0x49, 0xda,
+    0x55, 0xdb, 0xdb, 0x62, 0x50, 0x52, 0x14, 0xd8, 0x31, 0xf7, 0x0d, 0x6d,
+    0xb7, 0xaa, 0xe3, 0x47, 0xd7, 0xb9, 0xe3, 0xfd, 0xb5, 0x85, 0xd9, 0x4c,
+    0x78, 0x66, 0x76, 0xdb, 0x6e, 0x5f, 0x2f, 0xda, 0x4b, 0x6e, 0xd5, 0xa1,
+    0x22, 0xa0,
 };
 
-static const unsigned kPreloadedHSTSBits = 293909;
+static const unsigned kPreloadedHSTSBits = 293963;
 
-static const unsigned kHSTSRootPosition = 293293;
+static const unsigned kHSTSRootPosition = 293347;
 
 #endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index d89f008..91edc1f 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -176,6 +176,26 @@
         "SpiderOak2",
         "SpiderOak3"
       ]
+    },
+    {
+      "name": "yahoo",
+      "static_spki_hashes": [
+         "VeriSignClass2_G2",
+         "VeriSignClass2_G3",
+         "VeriSignClass3_G3",
+         "VeriSignClass3_G4",
+         "VeriSignClass3_G5",
+         "VeriSignUniversal",
+         "GeoTrustGlobal",
+         "GeoTrustPrimary",
+         "GeoTrustPrimary_G2",
+         "GeoTrustPrimary_G3",
+         "GeoTrustUniversal",
+         "DigiCertGlobalRoot",
+         "DigiCertEVRoot",
+         "YahooBackup1",
+         "YahooBackup2"
+      ]
     }
   ],
 
@@ -1348,7 +1368,7 @@
     { "name": "tw.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
     { "name": "ua.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
     { "name": "uk.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
-    { "name": "search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
+    { "name": "search.yahoo.com", "include_subdomains": false, "mode": "force-https", "pins": "yahoo" },
     { "name": "uy.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
     { "name": "uz.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
     { "name": "ve.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
@@ -1356,9 +1376,9 @@
     { "name": "xa.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
     { "name": "za.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
     { "name": "zh.search.yahoo.com", "include_subdomains": false, "mode": "force-https" },
-    { "name": "login.yahoo.com", "include_subdomains": true, "mode": "force-https" },
-    { "name": "mail.yahoo.com", "include_subdomains": false, "mode": "force-https" },
-    { "name": "edit.yahoo.com", "include_subdomains": true, "mode": "force-https" },
+    { "name": "login.yahoo.com", "include_subdomains": true, "mode": "force-https", "pins": "yahoo" },
+    { "name": "mail.yahoo.com", "include_subdomains": false, "mode": "force-https", "pins": "yahoo" },
+    { "name": "edit.yahoo.com", "include_subdomains": true, "mode": "force-https", "pins": "yahoo" },
     { "name": "ahoyconference.com", "include_subdomains": true, "mode": "force-https" },
     { "name": "balcan-underground.net", "include_subdomains": true, "mode": "force-https" },
     { "name": "baldwinkoo.com", "include_subdomains": true, "mode": "force-https" },
@@ -4528,6 +4548,7 @@
     "WITHYOUTUBE_COM",
     "WITHGOOGLE_COM",
     "G4W_CO",
-    "BADSSL_COM"
+    "BADSSL_COM",
+    "YAHOO_COM"
   ]
 }
diff --git a/net/net.gyp b/net/net.gyp
index 61b2c75..1749a46 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -62,11 +62,11 @@
             '<(SHARED_INTERMEDIATE_DIR)/net/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)-inc.cc',
           ],
           'inputs': [
-            'tools/tld_cleanup/make_dafsa.py',
+            'tools/dafsa/make_dafsa.py',
           ],
           'action': [
             'python',
-            'tools/tld_cleanup/make_dafsa.py',
+            'tools/dafsa/make_dafsa.py',
             '<(RULE_INPUT_PATH)',
             '<(SHARED_INTERMEDIATE_DIR)/net/<(RULE_INPUT_DIRNAME)/<(RULE_INPUT_ROOT)-inc.cc',
           ],
diff --git a/net/net.gypi b/net/net.gypi
index 070cf4f..cd5e3cc 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -34,6 +34,8 @@
       'base/ip_endpoint.h',
       'base/load_timing_info.cc',
       'base/load_timing_info.h',
+      'base/lookup_string_in_fixed_set.cc',
+      'base/lookup_string_in_fixed_set.h',
       'base/net_error_list.h',
       'base/net_errors.cc',
       'base/net_errors.h',
@@ -1284,6 +1286,7 @@
       'base/ip_pattern_unittest.cc',
       'base/keygen_handler_unittest.cc',
       'base/layered_network_delegate_unittest.cc',
+      'base/lookup_string_in_fixed_set_unittest.cc',
       'base/mime_sniffer_unittest.cc',
       'base/mime_util_unittest.cc',
       'base/net_util_icu_unittest.cc',
diff --git a/net/quic/quic_crypto_client_stream.cc b/net/quic/quic_crypto_client_stream.cc
index 7783a257..2c2a98c 100644
--- a/net/quic/quic_crypto_client_stream.cc
+++ b/net/quic/quic_crypto_client_stream.cc
@@ -427,10 +427,15 @@
 void QuicCryptoClientStream::DoVerifyProofComplete(
     QuicCryptoClientConfig::CachedState* cached) {
   if (!verify_ok_) {
-    next_state_ = STATE_NONE;
     if (verify_details_.get()) {
       client_session()->OnProofVerifyDetailsAvailable(*verify_details_);
     }
+    if (num_client_hellos_ == 0) {
+      cached->Clear();
+      next_state_ = STATE_INITIALIZE;
+      return;
+    }
+    next_state_ = STATE_NONE;
     UMA_HISTOGRAM_BOOLEAN("Net.QuicVerifyProofFailed.HandshakeConfirmed",
                           handshake_confirmed());
     CloseConnectionWithDetails(
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc
index 8c88880..d4b41d5 100644
--- a/net/quic/quic_crypto_client_stream_test.cc
+++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -19,6 +19,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 using std::string;
+using std::vector;
 
 namespace net {
 namespace test {
@@ -135,6 +136,26 @@
   ASSERT_EQ(1u, connection_->encrypted_packets_.size());
 }
 
+TEST_F(QuicCryptoClientStreamTest, InvalidCachedServerConfig) {
+  // Seed the config with a cached server config.
+  CompleteCryptoHandshake();
+
+  // Recreate connection with the new config.
+  CreateConnection();
+
+  QuicCryptoClientConfig::CachedState* state =
+      crypto_config_.LookupOrCreate(server_id_);
+
+  vector<string> certs = state->certs();
+  string cert_sct = state->cert_sct();
+  string signature = state->signature();
+  state->SetProof(certs, cert_sct, signature + signature);
+
+  stream()->CryptoConnect();
+  // Check that a client hello was sent.
+  ASSERT_EQ(1u, connection_->encrypted_packets_.size());
+}
+
 TEST_F(QuicCryptoClientStreamTest, ServerConfigUpdate) {
   // Test that the crypto client stream can receive server config updates after
   // the connection has been established.
diff --git a/net/tools/tld_cleanup/PRESUBMIT.py b/net/tools/dafsa/PRESUBMIT.py
similarity index 84%
rename from net/tools/tld_cleanup/PRESUBMIT.py
rename to net/tools/dafsa/PRESUBMIT.py
index 8391e0e..253fcbb 100644
--- a/net/tools/tld_cleanup/PRESUBMIT.py
+++ b/net/tools/dafsa/PRESUBMIT.py
@@ -3,13 +3,13 @@
 # found in the LICENSE file.
 
 
-"""Chromium presubmit script for src/net/tools/tld_cleanup."""
+"""Chromium presubmit script for src/net/tools/dafsa."""
 
 
 def _RunMakeDafsaTests(input_api, output_api):
   """Runs unittest for make_dafsa if any related file has been modified."""
-  files = ('net/tools/tld_cleanup/make_dafsa.py',
-           'net/tools/tld_cleanup/make_dafsa_unittest.py')
+  files = ('net/tools/dafsa/make_dafsa.py',
+           'net/tools/dafsa/make_dafsa_unittest.py')
   if not any(f in input_api.LocalPaths() for f in files):
     return []
   test_path = input_api.os_path.join(input_api.PresubmitLocalPath(),
diff --git a/net/tools/tld_cleanup/make_dafsa.py b/net/tools/dafsa/make_dafsa.py
similarity index 100%
rename from net/tools/tld_cleanup/make_dafsa.py
rename to net/tools/dafsa/make_dafsa.py
diff --git a/net/tools/tld_cleanup/make_dafsa_unittest.py b/net/tools/dafsa/make_dafsa_unittest.py
similarity index 100%
rename from net/tools/tld_cleanup/make_dafsa_unittest.py
rename to net/tools/dafsa/make_dafsa_unittest.py
diff --git a/ppapi/BUILD.gn b/ppapi/BUILD.gn
index 1d42bd2..f45a224 100644
--- a/ppapi/BUILD.gn
+++ b/ppapi/BUILD.gn
@@ -29,6 +29,7 @@
 
 import("//build/config/features.gni")
 import("//build/config/nacl/config.gni")
+import("//build/config/nacl/rules.gni")
 import("//ppapi/ppapi_sources.gni")
 import("//testing/test.gni")
 
@@ -312,7 +313,7 @@
       }
     }
 
-    action("generate_nmf") {
+    generate_nmf("ppapi_nacl_tests_nmf") {
       if (is_nacl_glibc) {
         nmf = "${root_build_dir}/ppapi_nacl_tests_glibc.nmf"
       } else if (current_cpu == "pnacl") {
@@ -320,85 +321,15 @@
       } else {
         nmf = "${root_build_dir}/ppapi_nacl_tests_newlib.nmf"
       }
-      nexe = "${root_out_dir}/ppapi_nacl_tests.nexe"
-
-      objdump = rebase_path("${nacl_toolprefix}objdump")
-
-      script = "//native_client_sdk/src/tools/create_nmf.py"
-      sources = [
-        nexe,
+      executables = get_target_outputs(":nacl_tests_copy")
+      deps = [
+        ":nacl_tests_copy",
       ]
-      outputs = [
-        nmf,
-      ]
-      data = [
-        nexe,
-      ]
-      nmf_flags = []
-      if (is_nacl_glibc) {
-        nmf_flags += [ "--library-path=" + rebase_path(root_out_dir) ]
-        if (current_cpu == "x86") {
-          nmf_flags += [ "--library-path=" +
-                         rebase_path("${nacl_toolchain_tooldir}/lib32") ]
-          data += [ "$root_build_dir/lib32/" ]
-        }
-        if (target_cpu == "x64" || (target_cpu == "x86" && is_win)) {
-          nmf_flags += [ "--library-path=" +
-                         rebase_path("${nacl_toolchain_tooldir}/lib") ]
-          data += [ "$root_build_dir/lib64/" ]
-        }
-        if (current_cpu == "arm") {
-          nmf_flags += [ "--library-path=" +
-                         rebase_path("${nacl_toolchain_tooldir}/lib") ]
-          data += [ "$root_build_dir/lib/" ]
-        }
-      }
-      args = [
-               "--no-default-libpath",
-               "--objdump=" + objdump,
-               "--output=" + rebase_path(nmf, root_build_dir),
-               "--stage-dependencies=" + rebase_path(root_build_dir),
-             ] + nmf_flags + rebase_path(sources, root_build_dir)
-      if (current_cpu == "pnacl") {
-        deps = [
-          ":translate_pexe_to_nexe",
-        ]
-      } else {
-        deps = [
-          ":ppapi_nacl_tests",
-        ]
-        if (is_nacl_glibc && current_cpu == "arm") {
-          deps += [ "//native_client/src/untrusted/elf_loader:elf_loader" ]
-        }
-      }
     }
 
-    action("generate_nonsfi_nmf") {
+    generate_nonsfi_test_nmf("ppapi_nacl_tests_pnacl_nonsfi_nmf") {
       nmf = "${root_build_dir}/ppapi_nacl_tests_pnacl_nonsfi.nmf"
-      nexe = "${root_out_dir}/ppapi_nacl_tests.nexe"
-
-      script = "//ppapi/tests/create_nonsfi_test_nmf.py"
-      sources = [
-        nexe,
-      ]
-      outputs = [
-        nmf,
-      ]
-      data = [
-        nexe,
-      ]
-      if (target_cpu == "x86") {
-        arch = "x86-32"
-      } else if (target_cpu == "x64") {
-        arch = "x86-64"
-      } else if (target_cpu == "arm") {
-        arch = "arm"
-      }
-      args = [
-        "--program=" + rebase_path(sources[0], root_build_dir),
-        "--arch=${arch}",
-        "--output=" + rebase_path(nmf, root_build_dir),
-      ]
+      executable = "${root_out_dir}/ppapi_nacl_tests.nexe"
       deps = [
         ":translate_pexe_to_nexe",
       ]
@@ -409,12 +340,12 @@
     data_deps = [
       ":copy_test_files",
       ":nacl_tests_copy(//build/toolchain/nacl:clang_newlib_${target_cpu})",
-      ":generate_nmf(//build/toolchain/nacl:glibc_${target_cpu})",
+      ":ppapi_nacl_tests_nmf(//build/toolchain/nacl:glibc_${target_cpu})",
     ]
     if (enable_pnacl) {
       data_deps += [
-        ":generate_nmf(//build/toolchain/nacl:newlib_pnacl)",
-        ":generate_nonsfi_nmf(//build/toolchain/nacl:newlib_pnacl_nonsfi)",
+        ":ppapi_nacl_tests_nmf(//build/toolchain/nacl:newlib_pnacl)",
+        ":ppapi_nacl_tests_pnacl_nonsfi_nmf(//build/toolchain/nacl:newlib_pnacl_nonsfi)",
       ]
     }
   }
diff --git a/remoting/android/java/AndroidManifest.xml.jinja2 b/remoting/android/java/AndroidManifest.xml.jinja2
index d7406793..46e28c735 100644
--- a/remoting/android/java/AndroidManifest.xml.jinja2
+++ b/remoting/android/java/AndroidManifest.xml.jinja2
@@ -62,9 +62,6 @@
         <activity android:name="org.chromium.chromoting.HelpActivity"
                 android:configChanges="orientation|screenSize"
                 android:uiOptions="splitActionBarWhenNarrow">
-                <meta-data
-                    android:name="android.support.PARENT_ACTIVITY"
-                    android:value="org.chromium.chromoting.Chromoting"/>
         </activity>
     </application>
 </manifest>
diff --git a/remoting/android/java/res/drawable-hdpi/empty_host_list.png b/remoting/android/java/res/drawable-hdpi/empty_host_list.png
new file mode 100644
index 0000000..ecab7e45
--- /dev/null
+++ b/remoting/android/java/res/drawable-hdpi/empty_host_list.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-ldpi/empty_host_list.png b/remoting/android/java/res/drawable-ldpi/empty_host_list.png
new file mode 100644
index 0000000..16d2822
--- /dev/null
+++ b/remoting/android/java/res/drawable-ldpi/empty_host_list.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-mdpi/empty_host_list.png b/remoting/android/java/res/drawable-mdpi/empty_host_list.png
new file mode 100644
index 0000000..ebc4e4a
--- /dev/null
+++ b/remoting/android/java/res/drawable-mdpi/empty_host_list.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-xhdpi/empty_host_list.png b/remoting/android/java/res/drawable-xhdpi/empty_host_list.png
new file mode 100644
index 0000000..8fa44f0
--- /dev/null
+++ b/remoting/android/java/res/drawable-xhdpi/empty_host_list.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-xxhdpi/empty_host_list.png b/remoting/android/java/res/drawable-xxhdpi/empty_host_list.png
new file mode 100644
index 0000000..ba58c88
--- /dev/null
+++ b/remoting/android/java/res/drawable-xxhdpi/empty_host_list.png
Binary files differ
diff --git a/remoting/android/java/res/drawable-xxxhdpi/empty_host_list.png b/remoting/android/java/res/drawable-xxxhdpi/empty_host_list.png
new file mode 100644
index 0000000..4c0c92c
--- /dev/null
+++ b/remoting/android/java/res/drawable-xxxhdpi/empty_host_list.png
Binary files differ
diff --git a/remoting/android/java/res/drawable/empty_host_list.png b/remoting/android/java/res/drawable/empty_host_list.png
deleted file mode 100644
index 7d2e19b..0000000
--- a/remoting/android/java/res/drawable/empty_host_list.png
+++ /dev/null
Binary files differ
diff --git a/remoting/android/java/res/layout/main.xml b/remoting/android/java/res/layout/main.xml
index c113e06..317bdaa 100644
--- a/remoting/android/java/res/layout/main.xml
+++ b/remoting/android/java/res/layout/main.xml
@@ -39,6 +39,7 @@
                     android:layout_height="wrap_content"
                     android:layout_width="wrap_content"
                     android:src="@drawable/empty_host_list"
+                    android:padding="16dp"
                     android:contentDescription="@null"/>
                 <TextView
                     android:gravity="center"
@@ -47,10 +48,16 @@
                     android:text="@string/host_list_empty_android"
                     style="@style/EmptyStateText"/>
                 <TextView
-                    android:id="@+id/host_setup_link_android"
                     android:gravity="center"
                     android:layout_height="wrap_content"
                     android:layout_width="match_parent"
+                    android:text="@string/host_list_empty_instructions_android"
+                    style="@style/EmptyStateText.Detail"/>
+                <Button
+                    android:id="@+id/host_setup_link_android"
+                    android:gravity="center"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
                     android:text="@string/host_setup_link_android"
                     style="@style/EmptyStateText.Hyperlink"/>
             </LinearLayout>
diff --git a/remoting/android/java/res/values-v17/styles.xml b/remoting/android/java/res/values-v17/styles.xml
index 1765609..0ce1112f 100644
--- a/remoting/android/java/res/values-v17/styles.xml
+++ b/remoting/android/java/res/values-v17/styles.xml
@@ -24,13 +24,18 @@
         <item name="android:statusBarColor">@android:color/transparent</item>
     </style>
 
-    <style name="EmptyStateText" parent="@android:style/TextAppearance.Large">
-        <item name="android:textColor">#888</item>
+    <style name="EmptyStateText" parent="@android:style/TextAppearance">
+        <item name="android:textColor">#616161</item>
+        <item name="android:textSize">22sp</item>
     </style>
-    <style name="EmptyStateText.Hyperlink" parent="@style/EmptyStateText">
-        <item name="android:textColor">@android:color/holo_blue_light</item>
-        <item name="android:textStyle">italic</item>
+    <style name="EmptyStateText.Detail" parent="EmptyStateText">
+        <item name="android:textSize">18sp</item>
     </style>
+    <style name="EmptyStateText.Hyperlink" parent="@style/Widget.AppCompat.Button.Borderless">
+        <item name="android:textColor">#4285F4</item>
+        <item name="android:textSize">18sp</item>
+    </style>
+
     <style name="NavigationTextStyle">
         <item name="android:textColor">#212121</item>
         <item name="android:fontFamily">sans-serif-medium</item>
diff --git a/remoting/android/java/src/org/chromium/chromoting/HelpActivity.java b/remoting/android/java/src/org/chromium/chromoting/HelpActivity.java
index 1d3d0d5..28e0696 100644
--- a/remoting/android/java/src/org/chromium/chromoting/HelpActivity.java
+++ b/remoting/android/java/src/org/chromium/chromoting/HelpActivity.java
@@ -17,7 +17,6 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.RemoteException;
-import android.support.v4.app.NavUtils;
 import android.support.v7.app.AppCompatActivity;
 import android.support.v7.widget.Toolbar;
 import android.text.TextUtils;
@@ -171,7 +170,7 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         int id = item.getItemId();
         if (id == android.R.id.home) {
-            NavUtils.navigateUpFromSameTask(this);
+            finish();
             return true;
         }
         if (id == R.id.actionbar_feedback) {
diff --git a/remoting/resources/remoting_strings.grd b/remoting/resources/remoting_strings.grd
index e7328298..8bef0622 100644
--- a/remoting/resources/remoting_strings.grd
+++ b/remoting/resources/remoting_strings.grd
@@ -576,11 +576,14 @@
         <message desc="Menu item to select the Trackpad input mode. In this mode, the mouse cursor is visible and the screen acts as a laptop's trackpad." name="IDS_SELECT_TRACKPAD_MODE" formatter_data="android_java">
           Trackpad mode
         </message>
-        <message desc="Message displayed to the user if there are no hosts registered to their account" name="IDS_HOST_LIST_EMPTY_ANDROID" formatter_data="android_java">
-          You have no computers registered.
+        <message desc="Message displayed in the Android application if the user has not setup any computers for remote access." name="IDS_HOST_LIST_EMPTY_ANDROID" formatter_data="android_java">
+          There's nothing to connect to.
         </message>
-        <message desc="Message displayed to the user if there are no hosts registered to their account. This is styled to look like a hyperlink. When a user activates the link, they are taken to a web page that explains how to set up a Chromoting host." name="IDS_HOST_SETUP_LINK_ANDROID" formatter_data="android_java">
-          Learn how to set up a computer for remote access.
+        <message desc="Instruction displayed in the Android application if the user has not setup any computers for remote access. It appears after some larger text which states that the user has no computers to connect to." name="IDS_HOST_LIST_EMPTY_INSTRUCTIONS_ANDROID" formatter_data="android_java">
+          You need to first setup your computer for remote access.
+        </message>
+        <message desc="This button appears below some text which explains that the user needs to setup a computer for remote access. When a user activates the button, they are taken to a web page that explains how to set up a Chromoting host." name="IDS_HOST_SETUP_LINK_ANDROID" formatter_data="android_java">
+          Learn how
         </message>
         <message desc="Title of the authentication dialog" name="IDS_TITLE_AUTHENTICATE" formatter_data="android_java">
           Authenticate to host
@@ -648,8 +651,9 @@
 For information about privacy, please see the Google Privacy Policy (http://goo.gl/SyrVzj) and the Chrome Privacy Policy (http://goo.gl/0uXE5d).
         </message>
         <message name="IDS_PLAY_STORE_CHANGES" desc="List of what's changed in this release of Chrome Remote Desktop for Android. [CHAR-LIMIT=500] [NAME=play_store_changes]">
-• Added Credits screen.
-• Fixed a problem when going full-screen with the keyboard visible.
+• Material Design UI updates.
+• Third-party licensing credits.
+• Information shown for remote computers that are offline.
         </message>
       </if>  <!-- is_android or is_ios -->
 
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index e6fc643..e7d41ca 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -554,7 +554,7 @@
   }
   source_set("skia_opts_avx") {
     sources = gypi_skia_opts.avx_sources
-    if (!is_win || is_clang) {
+    if (!is_win) {
       cflags = [ "-mavx" ]
     }
     if (is_win) {
@@ -570,7 +570,7 @@
   }
   source_set("skia_opts_avx2") {
     sources = gypi_skia_opts.avx2_sources
-    if (!is_win || is_clang) {
+    if (!is_win) {
       cflags = [ "-mavx2" ]
     }
     if (is_win) {
diff --git a/sync/syncable/directory_backing_store.cc b/sync/syncable/directory_backing_store.cc
index eb2e20c4..cbe943b 100644
--- a/sync/syncable/directory_backing_store.cc
+++ b/sync/syncable/directory_backing_store.cc
@@ -84,7 +84,8 @@
 void UnpackProtoFields(sql::Statement* statement,
                        EntryKernel* kernel,
                        int* index,
-                       int end_index) {
+                       int end_index,
+                       int* total_entry_copies) {
   const void* prev_blob = nullptr;
   int prev_length = -1;
   int prev_index = -1;
@@ -110,6 +111,7 @@
       prev_blob = blob;
       prev_length = length;
       prev_index = *index;
+      ++(*total_entry_copies);
     }
   }
 }
@@ -117,7 +119,8 @@
 // The caller owns the returned EntryKernel*.  Assumes the statement currently
 // points to a valid row in the metas table. Returns NULL to indicate that
 // it detected a corruption in the data on unpacking.
-scoped_ptr<EntryKernel> UnpackEntry(sql::Statement* statement) {
+scoped_ptr<EntryKernel> UnpackEntry(sql::Statement* statement,
+                                    int* total_specifics_copies) {
   scoped_ptr<EntryKernel> kernel(new EntryKernel());
   DCHECK_EQ(statement->ColumnCount(), static_cast<int>(FIELD_COUNT));
   int i = 0;
@@ -140,7 +143,7 @@
                 statement->ColumnString(i));
   }
   UnpackProtoFields<sync_pb::EntitySpecifics, ProtoField>(
-      statement, kernel.get(), &i, PROTO_FIELDS_END);
+      statement, kernel.get(), &i, PROTO_FIELDS_END, total_specifics_copies);
   for ( ; i < UNIQUE_POSITION_FIELDS_END; ++i) {
     std::string temp;
     statement->ColumnBlobAsString(i, &temp);
@@ -154,8 +157,10 @@
     kernel->mutable_ref(static_cast<UniquePositionField>(i)) =
         UniquePosition::FromProto(proto);
   }
+  int attachemnt_specifics_counts = 0;
   UnpackProtoFields<sync_pb::AttachmentMetadata, AttachmentMetadataField>(
-      statement, kernel.get(), &i, ATTACHMENT_METADATA_FIELDS_END);
+      statement, kernel.get(), &i, ATTACHMENT_METADATA_FIELDS_END,
+      &attachemnt_specifics_counts);
 
   // Sanity check on positions.  We risk strange and rare crashes if our
   // assumptions about unique position values are broken.
@@ -221,7 +226,12 @@
   return save_statement->Run();
 }
 
-void UploadModelTypeEntryCount(const int(&entries_counts)[MODEL_TYPE_COUNT]) {
+// total_specifics_copies : Total copies of entries in memory, include extra
+// copy for some entries which create by copy-on-write mechanism.
+// entries_counts : entry counts for each model type.
+void UploadModelTypeEntryCount(const int total_specifics_copies,
+                               const int(&entries_counts)[MODEL_TYPE_COUNT]) {
+  int total_entry_counts = 0;
   for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
     std::string model_type;
     if (RealModelTypeToNotificationType((ModelType)i, &model_type)) {
@@ -231,8 +241,12 @@
           base::HistogramBase::kUmaTargetedHistogramFlag);
       if (histogram)
         histogram->Add(entries_counts[i]);
+      total_entry_counts += entries_counts[i];
     }
   }
+  UMA_HISTOGRAM_COUNTS("Sync.ModelTypeCount", total_entry_counts);
+  UMA_HISTOGRAM_COUNTS("Sync.ExtraSyncDataCount",
+                       total_specifics_copies - total_entry_counts);
 }
 
 }  // namespace
@@ -634,6 +648,7 @@
   select.append("SELECT ");
   AppendColumnList(&select);
   select.append(" FROM metas");
+  int total_specifics_copies = 0;
   int model_type_entry_count[MODEL_TYPE_COUNT];
   for (int i = FIRST_REAL_MODEL_TYPE; i < MODEL_TYPE_COUNT; ++i) {
     model_type_entry_count[i] = 0;
@@ -642,7 +657,7 @@
   sql::Statement s(db_->GetUniqueStatement(select.c_str()));
 
   while (s.Step()) {
-    scoped_ptr<EntryKernel> kernel = UnpackEntry(&s);
+    scoped_ptr<EntryKernel> kernel = UnpackEntry(&s, &total_specifics_copies);
     // A null kernel is evidence of external data corruption.
     if (!kernel)
       return false;
@@ -656,7 +671,7 @@
     }
   }
 
-  UploadModelTypeEntryCount(model_type_entry_count);
+  UploadModelTypeEntryCount(total_specifics_copies, model_type_entry_count);
 
   return s.Succeeded();
 }
@@ -683,7 +698,8 @@
   sql::Statement s(db_->GetUniqueStatement(select.c_str()));
 
   while (s.Step()) {
-    scoped_ptr<EntryKernel> kernel = UnpackEntry(&s);
+    int total_entry_copies;
+    scoped_ptr<EntryKernel> kernel = UnpackEntry(&s, &total_entry_copies);
     // A null kernel is evidence of external data corruption.
     if (!kernel)
       return false;
diff --git a/sync/syncable/syncable_id.h b/sync/syncable/syncable_id.h
index 932d2e6..e9f937a 100644
--- a/sync/syncable/syncable_id.h
+++ b/sync/syncable/syncable_id.h
@@ -106,7 +106,8 @@
   static Id GetRoot();
 
  private:
-  friend scoped_ptr<EntryKernel> UnpackEntry(sql::Statement* statement);
+  friend scoped_ptr<EntryKernel> UnpackEntry(sql::Statement* statement,
+                                             int* total_created_entries);
   friend void BindFields(const EntryKernel& entry,
                          sql::Statement* statement);
   SYNC_EXPORT_PRIVATE friend std::ostream& operator<<(std::ostream& out,
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index bf23ba8f..f4e68fa4 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -1493,19 +1493,16 @@
         "swarming": {
           "can_use_on_swarming_builders": true
         }
-      },
-      {
-        "isolate_name": "telemetry_perf_unittests",
-        "name": "telemetry_perf_unittests",
-        "swarming": {
-          "can_use_on_swarming_builders": true
-        }
       }
     ],
     "scripts": [
       {
         "name": "telemetry_unittests",
         "script": "telemetry_unittests.py"
+      },
+      {
+        "name": "telemetry_perf_unittests",
+        "script": "telemetry_perf_unittests.py"
       }
     ]
   },
diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json
index f1c97439..408892b 100644
--- a/testing/variations/fieldtrial_testing_config_android.json
+++ b/testing/variations/fieldtrial_testing_config_android.json
@@ -307,7 +307,7 @@
             "params": {
                 "Enabled": "true",
                 "Optimize": "true",
-                "Sample_Probability": "100"
+                "Sample_Probability": "50"
             }
         }
     ],
@@ -319,6 +319,11 @@
             }
         }
     ],
+    "WebRTC-LocalIPPermissionCheck": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "WebRTC-PeerConnectionDTLS1.2": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_chromeos.json b/testing/variations/fieldtrial_testing_config_chromeos.json
index 53e9eaf..48e0590 100644
--- a/testing/variations/fieldtrial_testing_config_chromeos.json
+++ b/testing/variations/fieldtrial_testing_config_chromeos.json
@@ -110,6 +110,11 @@
             }
         }
     ],
+    "WebRTC-LocalIPPermissionCheck": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "WebRTC-PeerConnectionDTLS1.2": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_linux.json b/testing/variations/fieldtrial_testing_config_linux.json
index 981bab5..d7a866c7 100644
--- a/testing/variations/fieldtrial_testing_config_linux.json
+++ b/testing/variations/fieldtrial_testing_config_linux.json
@@ -136,6 +136,11 @@
             }
         }
     ],
+    "WebRTC-LocalIPPermissionCheck": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "WebRTC-PeerConnectionDTLS1.2": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_mac.json b/testing/variations/fieldtrial_testing_config_mac.json
index 1d752b6..68652e5 100644
--- a/testing/variations/fieldtrial_testing_config_mac.json
+++ b/testing/variations/fieldtrial_testing_config_mac.json
@@ -151,6 +151,11 @@
             }
         }
     ],
+    "WebRTC-LocalIPPermissionCheck": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "WebRTC-PeerConnectionDTLS1.2": [
         {
             "group_name": "Enabled"
diff --git a/testing/variations/fieldtrial_testing_config_win.json b/testing/variations/fieldtrial_testing_config_win.json
index 1976398..98eaeb3 100644
--- a/testing/variations/fieldtrial_testing_config_win.json
+++ b/testing/variations/fieldtrial_testing_config_win.json
@@ -230,6 +230,11 @@
             }
         }
     ],
+    "WebRTC-LocalIPPermissionCheck": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "WebRTC-PeerConnectionDTLS1.2": [
         {
             "group_name": "Enabled"
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 950b1a5..1d17b10 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -430,7 +430,6 @@
 crbug.com/525872 imported/web-platform-tests/html/rendering/non-replaced-elements/tables/table-border-2.html [ Failure ]
 crbug.com/490511 imported/web-platform-tests/html/semantics/document-metadata/styling/LinkStyle.html [ Failure Pass ]
 crbug.com/525896 imported/web-platform-tests/html/semantics/embedded-content/the-embed-element/embed-represent-nothing-01.html [ Failure ]
-crbug.com/508725 imported/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText.html [ Failure Timeout ]
 crbug.com/490511 imported/web-platform-tests/html/semantics/embedded-content/media-elements/interfaces/HTMLElement/HTMLTrackElement/src.html [ Failure ]
 crbug.com/526920 imported/web-platform-tests/html/semantics/embedded-content/media-elements/location-of-the-media-resource/currentSrc.html [ Failure ]
 crbug.com/525889 imported/web-platform-tests/html/webappapis/scripting/processing-model-2/compile-error-in-setInterval.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html b/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html
index 703ab815..55df78e 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/advertising-data.html
@@ -5,7 +5,7 @@
 <script>
 'use strict';
 
-test(function(t) { assert_true(window.testRunner instanceof Object); t.done(); },
+test(t => { assert_true(window.testRunner instanceof Object); t.done(); },
      'window.testRunner is required for the following tests.');
 // Tests that we are handling values returned from the underlying platform
 // correctly. Only meant to be used by chromium.
diff --git a/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html b/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html
index 03c4442d..1c3f52a 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html
@@ -9,15 +9,15 @@
      'window.testRunner is required for the following tests.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => {
       testRunner.setBluetoothMockDataSet('EmptyAdapter');
       return assert_promise_rejects_with_message(
-        device.connectGATT(),{
-          name: 'NetworkError',
-          message: 'Bluetooth Device is no longer in range.'
-        }, 'Device went out of range.');
+        device.connectGATT(),
+        new DOMException('Bluetooth Device is no longer in range.',
+                         'NetworkError'),
+        'Device went out of range.');
     });
 }, 'Device goes out of range. Reject with NetworkError.');
 
@@ -32,59 +32,43 @@
 [{
   testName: 'Unknown error when connnecting.',
   uuid: errorUUID(0x0),
-  error: {
-    name: 'NetworkError',
-    message: 'Unknown error when connecting to the device.'
-  }
+  error: new DOMException('Unknown error when connecting to the device.',
+                          'NetworkError')
 }, {
   testName: 'Connection was already in progress.',
   uuid: errorUUID(0x1),
-  error: {
-    name: 'NetworkError',
-    message: 'Connection already in progress.'
-  }
+  error: new DOMException('Connection already in progress.',
+                          'NetworkError')
 }, {
   testName: 'Connection failed.',
   uuid: errorUUID(0x2),
-  error: {
-    name: 'NetworkError',
-    message: 'Connection failed for unknown reason.'
-  }
+  error: new DOMException('Connection failed for unknown reason.',
+                          'NetworkError')
 }, {
   testName: 'Authentication failed when connecting.',
   uuid: errorUUID(0x3),
-  error: {
-    name: 'NetworkError',
-    message: 'Authentication failed.'
-  }
+  error: new DOMException('Authentication failed.',
+                          'NetworkError')
 }, {
   testName: 'Authentication canceled when connecting.',
   uuid: errorUUID(0x4),
-  error: {
-    name: 'NetworkError',
-    message: 'Authentication canceled.'
-  }
+  error: new DOMException('Authentication canceled.',
+                          'NetworkError')
 }, {
   testName: 'Authentication rejected when connecting.',
   uuid: errorUUID(0x5),
-  error: {
-    name: 'NetworkError',
-    message: 'Authentication rejected.'
-  }
+  error: new DOMException('Authentication rejected.',
+                          'NetworkError')
 }, {
   testName: 'Authentication timed out when connecting.',
   uuid: errorUUID(0x6),
-  error: {
-    name: 'NetworkError',
-    message: 'Authentication timeout.'
-  }
+  error: new DOMException('Authentication timeout.',
+                          'NetworkError')
 }, {
   testName: 'Tried to connect to an unsupported device.',
   uuid: errorUUID(0x7),
-  error: {
-    name: 'NetworkError',
-    message: 'Unsupported device.'
-  }
+  error: new DOMException('Unsupported device.',
+                          'NetworkError')
 }].forEach(testSpec => {
   promise_test(() => {
     testRunner.setBluetoothMockDataSet('FailingConnectionsAdapter');
@@ -99,8 +83,8 @@
 });
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => assert_true(gattServer.connected));
 }, 'Device will connect');
diff --git a/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic.html b/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic.html
index bb239f21..8ec992e 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/getCharacteristic.html
@@ -9,43 +9,41 @@
      'window.testRunner is required for the following tests.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => {
       testRunner.setBluetoothMockDataSet('EmptyAdapter');
       return assert_promise_rejects_with_message(
-        service.getCharacteristic('gap.device_name'), {
-          name: 'NetworkError',
-          message: 'Bluetooth Device is no longer in range.'
-        }, 'Device went out of range.');
+        service.getCharacteristic('gap.device_name'),
+        new DOMException('Bluetooth Device is no longer in range.',
+                         'NetworkError'),
+        'Device went out of range.');
     });
 }, 'Device goes out of range. Reject with NetworkError.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattService => gattService.getPrimaryService('generic_access'))
     .then(service => {
-      testRunner.setBluetoothMockDataSet('MissingServiceGenericAccessAdapter');
+      testRunner.setBluetoothMockDataSet('MissingServiceHeartRateAdapter');
       return assert_promise_rejects_with_message(
-        service.getCharacteristic('gap.device_name'), {
-          name: 'InvalidStateError',
-          message: 'GATT Service no longer exists.'
-        }, 'Service got removed.');
+        service.getCharacteristic('gap.device_name'),
+        new DOMException('GATT Service no longer exists.',
+                         'InvalidStateError'),
+        'Service got removed.');
     });
 }, 'Service is removed. Reject with InvalidStateError.');
 
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  let expected = {
-    name: 'NotFoundError',
-    message: 'Characteristic not found in device.'
-  };
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  let expected = new DOMException('Characteristic not found in device.',
+                                  'NotFoundError');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => Promise.all(
@@ -58,8 +56,8 @@
 }, 'Request for wrong characteristic. Reject with NotFoundError.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => Promise.all(
@@ -76,8 +74,8 @@
 }, 'Request for characteristic. Should return right characteristic');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(services => Promise.all(
@@ -100,24 +98,25 @@
 }, 'Calls to get the same characteristic should return the same object.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => {
       return assert_promise_rejects_with_message(
-        service.getCharacteristic('wrong_name'), {
-          name: 'SyntaxError',
-          message: 'Failed to execute \'getCharacteristic\' on ' +
-                   '\'BluetoothGATTService\': \Invalid Characteristic name: ' +
-                   '\'wrong_name\'. ' +
-                   'It must be a valid UUID alias (e.g. 0x1234), ' +
-                   'UUID (lowercase hex characters e.g. ' +
-                   '\'00001234-0000-1000-8000-00805f9b34fb\'), ' +
-                   'or recognized standard name from ' +
-                   'https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicsHome.aspx' +
-                   ' e.g. \'aerobic_heart_rate_lower_limit\'.'
-        }, 'Wrong Characteristic name passed.');
+        service.getCharacteristic('wrong_name'), new DOMException(
+          'Failed to execute \'getCharacteristic\' on ' +
+          '\'BluetoothGATTService\': Invalid Characteristic name: ' +
+          '\'wrong_name\'. ' +
+          'It must be a valid UUID alias (e.g. 0x1234), ' +
+          'UUID (lowercase hex characters e.g. ' +
+          '\'00001234-0000-1000-8000-00805f9b34fb\'), ' +
+          'or recognized standard name from ' +
+          'https://developer.bluetooth.org/gatt/characteristics/' +
+          'Pages/CharacteristicsHome.aspx' +
+          ' e.g. \'aerobic_heart_rate_lower_limit\'.',
+          'SyntaxError'),
+        'Wrong Characteristic name passed.');
     });
 }, 'Wrong Characteristic name. Reject with SyntaxError.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService.html b/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService.html
index 6bd46c6b..389a12e 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService.html
@@ -9,37 +9,43 @@
      'window.testRunner is required for the following tests.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => {
       testRunner.setBluetoothMockDataSet('EmptyAdapter');
       return assert_promise_rejects_with_message(
-        gattServer.getPrimaryService('generic_access'), {
-          name: 'NetworkError',
-          message: 'Bluetooth Device is no longer in range.'
-        }, 'Device went out of range.');
+        gattServer.getPrimaryService('generic_access'),
+        new DOMException('Bluetooth Device is no longer in range.',
+                         'NetworkError'),
+        'Device went out of range.');
     });
 }, 'Device goes out of range. Reject with NetworkError.');
 
-promise_test(function() {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  let expected = {
-    name: 'NotFoundError',
-    message: 'Service not found in device.'
-  };
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+promise_test(() => {
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  let expected = new DOMException('Service not found in device.',
+                                  'NotFoundError');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => Promise.all(
       [assert_promise_rejects_with_message(
-        gattServer.getPrimaryService(heart_rate.alias), expected),
+        gattServer.getPrimaryService(glucose.alias), expected),
        assert_promise_rejects_with_message(
-         gattServer.getPrimaryService(heart_rate.name), expected),
+         gattServer.getPrimaryService(glucose.name), expected),
        assert_promise_rejects_with_message(
-         gattServer.getPrimaryService(heart_rate.uuid), expected)]));
+         gattServer.getPrimaryService(glucose.uuid), expected)]));
 }, 'Request for wrong service. Reject with NotFoundError.');
 
 promise_test(() => {
+  // Because state doesn't get cleaned after each test in a file, we need to
+  // clean it ourselves. In this case, the services for a HeartRateDevice had
+  // been discovered in the previous test, since the state doesn't get cleaned
+  // it appears as if the services had been discovered for the device in this
+  // test.
+  // TODO(ortuno): split tests into different files.
+  // http://crbug.com/554240
+  testRunner.setBluetoothMockDataSet('');
   testRunner.setBluetoothMockDataSet('DelayedServicesDiscoveryAdapter');
   return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
@@ -50,20 +56,28 @@
 }, 'Request for service. Must return even when the services are not immediately discovered');
 
 promise_test(() => {
+  // Because state doesn't get cleaned after each test in a file, we need to
+  // clean it ourselves. In this case, the services for a HeartRateDevice had
+  // been discovered in the previous test, since the state doesn't get cleaned
+  // it appears as if the services had been discovered for the device in this
+  // test.
+  // TODO(ortuno): split tests into different files.
+  // http://crbug.com/554240
+  testRunner.setBluetoothMockDataSet('');
   testRunner.setBluetoothMockDataSet('DelayedServicesDiscoveryAdapter');
   return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => {
       return assert_promise_rejects_with_message(
         gattServer.getPrimaryService('battery_service'),
-        {name: 'NotFoundError', message: 'Service not found in device.'});
+        new DOMException('Service not found in device.', 'NotFoundError'));
     });
 }, 'Request for wrong service. Must reject with NotFoundError even when the services' +
    ' are not immediately discovered');
 
 promise_test(function() {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => Promise.all(
       [gattServer.getPrimaryService(generic_access.alias),
@@ -79,9 +93,9 @@
     });
 }, 'Request for service. Should return right service');
 
-promise_test(function() {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+promise_test(() => {
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => Promise.all(
       [gattServer.getPrimaryService(generic_access.alias),
@@ -102,23 +116,23 @@
 }, 'Calls to get the same service should return the same object.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => {
       return assert_promise_rejects_with_message(
-        gattServer.getPrimaryService('wrong_name'), {
-          name: 'SyntaxError',
-          message: 'Failed to execute \'getPrimaryService\' on ' +
-                   '\'BluetoothGATTRemoteServer\': Invalid Service name: ' +
-                   '\'wrong_name\'. ' +
-                   'It must be a valid UUID alias (e.g. 0x1234), ' +
-                   'UUID (lowercase hex characters e.g. ' +
-                   '\'00001234-0000-1000-8000-00805f9b34fb\'), ' +
-                   'or recognized standard name from ' +
-                   'https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx' +
-                   ' e.g. \'alert_notification\'.'
-        }, 'Wrong Service name passed.');
+        gattServer.getPrimaryService('wrong_name'), new DOMException(
+          'Failed to execute \'getPrimaryService\' on ' +
+          '\'BluetoothGATTRemoteServer\': Invalid Service name: ' +
+          '\'wrong_name\'. ' +
+          'It must be a valid UUID alias (e.g. 0x1234), ' +
+          'UUID (lowercase hex characters e.g. ' +
+          '\'00001234-0000-1000-8000-00805f9b34fb\'), ' +
+          'or recognized standard name from ' +
+          'https://developer.bluetooth.org/gatt/services/Pages/ServicesHome.aspx' +
+          ' e.g. \'alert_notification\'.',
+          'SyntaxError'),
+        'Wrong Service name passed.');
     });
 }, 'Wrong Service name. Reject with SyntaxError.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothDevice.html b/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothDevice.html
index a2280ad..58d9a77e 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothDevice.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothDevice.html
@@ -16,7 +16,7 @@
 promise_test(() => {
   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter');
   return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
-    .then(function(device) {
+    .then(device => {
       assert_equals(device.constructor.name, 'BluetoothDevice');
 
       // Attempt (and fail) to overwrite all members, verifying they are
@@ -30,7 +30,7 @@
       device.productVersion = 'overwritten';
       device.paired = 'overwritten';
       device.uuids = 'overwritten';
-      assert_equals(device.id, '00:00:00:00:00:03');
+      assert_equals(device.id, '00:00:00:00:00:00');
       assert_equals(device.name, 'Heart Rate Device');
       assert_equals(device.deviceClass, 0x1F00);
       assert_equals(device.vendorIDSource, 'bluetooth');
@@ -38,8 +38,8 @@
       assert_equals(device.productID, 1);
       assert_equals(device.productVersion, 2);
       assert_equals(device.paired, true);
-      assert_equals(device.uuids[0], generic_access.uuid);
-      assert_equals(device.uuids[1], heart_rate.uuid);
+      assert_equals(device.uuids.length, 1);
+      assert_equals(device.uuids[0], heart_rate.uuid);
     });
 }, 'BluetoothDevice attributes.');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/iframeRequestDevice.html b/third_party/WebKit/LayoutTests/bluetooth/iframeRequestDevice.html
index 161a164..5449b2f 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/iframeRequestDevice.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/iframeRequestDevice.html
@@ -36,7 +36,7 @@
       });
     });
 
-    testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
+    testRunner.setBluetoothMockDataSet('HeartRateAdapter');
     for (let i = 0; i < numIframes; i++) {
       let iframe = document.createElement('iframe');
       iframe.src = 'resources/requestDevice-in-iframe.html';
diff --git a/third_party/WebKit/LayoutTests/bluetooth/notifications.html b/third_party/WebKit/LayoutTests/bluetooth/notifications.html
index 06950dc..ceee14d 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/notifications.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/notifications.html
@@ -156,4 +156,20 @@
    .then(characteristic => characteristic.stopNotifications())
    .then(() => runGarbageCollection());
 }, "Stop without starting.");
+
+gatt_errors_tests.forEach(testSpec => {
+  promise_test(() => {
+    testRunner.setBluetoothMockDataSet('FailingGATTOperationsAdapter');
+    return requestDeviceWithKeyDown({filters: [{services: [errorUUID(0xA0)]}]})
+      .then(device => device.connectGATT())
+      .then(gattServer => gattServer.getPrimaryService(errorUUID(0xA0)))
+      .then(service => service.getCharacteristic(testSpec.uuid))
+      .then(characteristic => {
+        return assert_promise_rejects_with_message(
+          characteristic.startNotifications(),
+          testSpec.error,
+          'Trying to write to a characteristic failed.');
+      });
+  }, testSpec.testName);
+});
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/readValue.html b/third_party/WebKit/LayoutTests/bluetooth/readValue.html
index 683e68c..343f9786 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/readValue.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/readValue.html
@@ -9,122 +9,55 @@
      'window.testRunner is required for the following tests.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
     .then(characteristic => {
       testRunner.setBluetoothMockDataSet('EmptyAdapter');
       return assert_promise_rejects_with_message(
-        characteristic.readValue(), {
-          name: 'NetworkError',
-          message: 'Bluetooth Device is no longer in range.'
-        }, 'Device went out of range');
+        characteristic.readValue(), new DOMException(
+          'Bluetooth Device is no longer in range.',
+          'NetworkError'),
+        'Device went out of range');
     });
 }, 'Device goes out of range. Reject with NetworkError.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
     .then(characteristic => {
-      testRunner.setBluetoothMockDataSet('MissingServiceGenericAccessAdapter');
+      testRunner.setBluetoothMockDataSet('MissingServiceHeartRateAdapter');
       return assert_promise_rejects_with_message(
-        characteristic.readValue(), {
-          name: 'InvalidStateError',
-          message: 'GATT Service no longer exists.'
-        }, 'Service got removed.');
+        characteristic.readValue(), new DOMException(
+          'GATT Service no longer exists.',
+          'InvalidStateError'),
+        'Service got removed.');
     });
 }, 'Service gets removed. Reject with InvalidStateError.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattService => gattService.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
     .then(characteristic => {
       testRunner.setBluetoothMockDataSet(
-        'MissingCharacteristicGenericAccessAdapter');
+        'MissingCharacteristicHeartRateAdapter');
       return assert_promise_rejects_with_message(
-        characteristic.readValue(), {
-          name: 'InvalidStateError',
-          message: 'GATT Characteristic no longer exists.'
-        }, 'Characteristic got removed.');
+        characteristic.readValue(), new DOMException(
+          'GATT Characteristic no longer exists.',
+          'InvalidStateError'),
+        'Characteristic got removed.');
     });
 }, 'Characteristic gets removed. Reject with InvalidStateError.');
 
-// The following tests make sure the Web Bluetooth implementation
-// responds correctly to the different types of errors the
-// underlying platform might return for GATT operations.
-
-// Each implementation maps these characteristics to specific code paths
-// that result in different errors thus increasing code coverage
-// when testing. Therefore some of these characteristics might not be useful
-// for all implementations.
-[{
-  testName: 'GATT Error: Unknown.',
-  uuid: errorUUID(0xA1),
-  error: {
-    name: 'NotSupportedError',
-    message: 'GATT Error Unknown.'
-  }
-}, {
-  testName: 'GATT Error: Failed.',
-  uuid: errorUUID(0xA2),
-  error: {
-    name: 'NotSupportedError',
-    message: 'GATT operation failed for unknown reason.'
-  }
-}, {
-  testName: 'GATT Error: In Progress.',
-  uuid: errorUUID(0xA3),
-  error: {
-    name: 'NetworkError',
-    message: 'GATT operation already in progress.'
-  }
-}, {
-  testName: 'GATT Error: Invalid Length.',
-  uuid: errorUUID(0xA4),
-  error: {
-    name: 'InvalidModificationError',
-    message: 'GATT Error: invalid attribute length.'
-  }
-}, {
-  testName: 'GATT Error: Not Permitted.',
-  uuid: errorUUID(0xA5),
-  error: {
-    name: 'NotSupportedError',
-    message: 'GATT operation not permitted.'
-  }
-}, {
-  testName: 'GATT Error: Not Authorized.',
-  uuid: errorUUID(0xA6),
-  error: {
-    name: 'SecurityError',
-    message: 'GATT operation not authorized.'
-  }
-}, {
-  testName: 'GATT Error: Not Paired.',
-  uuid: errorUUID(0xA7),
-  // TODO(ortuno): Change to InsufficientAuthenticationError or similiar
-  // once https://github.com/WebBluetoothCG/web-bluetooth/issues/137 is
-  // resolved.
-  error: {
-    name: 'NetworkError',
-    message: 'GATT Error: Not paired.'
-  }
-}, {
-  testName: 'GATT Error: Not Supported.',
-  uuid: errorUUID(0xA8),
-  error: {
-    name: 'NotSupportedError',
-    message: 'GATT Error: Not supported.'
-  }
-}].forEach(testSpec => {
+gatt_errors_tests.forEach(testSpec => {
   promise_test(() => {
     testRunner.setBluetoothMockDataSet('FailingGATTOperationsAdapter');
     return requestDeviceWithKeyDown({filters: [{services: [errorUUID(0xA0)]}]})
@@ -141,8 +74,8 @@
 });
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
@@ -150,7 +83,7 @@
     .then(value => {
       let decoder = new TextDecoder('utf-8');
       let value_str = decoder.decode(value);
-      assert_equals(value_str, 'Generic Access Device');
+      assert_equals(value_str, 'Heart Rate Device');
     });
 }, 'Request for characteristic. Should return right characteristic');
 </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice-canonicalize-filter.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice-canonicalize-filter.html
index 6adf832..3904c8de 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice-canonicalize-filter.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice-canonicalize-filter.html
@@ -6,7 +6,7 @@
 <script>
 'use strict';
 
-test(function(t) { assert_true(window.testRunner instanceof Object); t.done(); },
+test(t => { assert_true(window.testRunner instanceof Object); t.done(); },
      'window.testRunner is required for the following tests.');
 
 promise_test(() => {
@@ -42,11 +42,10 @@
 
 promise_test(() => {
   testRunner.setBluetoothMockDataSet('EmptyAdapter');
-  let expected = {
-    name: 'TypeError',
-    message: 'Failed to execute \'requestDevice\' on \'Bluetooth\': A device '
-           + 'name can\'t be longer than 248 bytes.'
-  };
+  let expected = new DOMException(
+    'Failed to execute \'requestDevice\' on \'Bluetooth\': A device ' +
+    'name can\'t be longer than 248 bytes.',
+    'TypeError');
   let name_too_long = generate_string(249, 'a');
   return assert_promise_rejects_with_message(
     requestDeviceWithKeyDown({filters: [{name: name_too_long}]}),
@@ -55,13 +54,12 @@
 
 promise_test(() => {
   testRunner.setBluetoothMockDataSet('EmptyAdapter');
-  let expected = {
-    name: 'NotFoundError',
-    message: 'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
-             'A \'name\' or \'namePrefix\' longer than 29 bytes ' +
-             'results in no devices being found, because a device can\'t ' +
-             'advertise a name longer than 29 bytes.'
-  };
+  let expected = new DOMException(
+    'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
+    'A \'name\' or \'namePrefix\' longer than 29 bytes ' +
+    'results in no devices being found, because a device can\'t ' +
+    'advertise a name longer than 29 bytes.',
+    'NotFoundError');
   let name_too_long = generate_string(30, 'a');
   return assert_promise_rejects_with_message(
     requestDeviceWithKeyDown({filters: [{name: name_too_long}]}),
@@ -97,23 +95,21 @@
         'NotFoundError.',
   chars: 10, // \u2764's UTF-8 respresentation is 3 bytes long.
              // 10 chars * 3 bytes/char = 30 bytes
-  expected: {
-    name: 'NotFoundError',
-    message: 'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
-             'A \'name\' or \'namePrefix\' longer than 29 bytes ' +
-             'results in no devices being found, because a device can\'t ' +
-             'advertise a name longer than 29 bytes.'
-  }
+  expected: new DOMException(
+    'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
+    'A \'name\' or \'namePrefix\' longer than 29 bytes ' +
+    'results in no devices being found, because a device can\'t ' +
+    'advertise a name longer than 29 bytes.',
+    'NotFoundError')
 }, {
   test_name: 'Unicode string with utf8 representation greater than 248 must throw ' +
         'TypeError.',
   chars: 83, // \u2764's UTF-8 respresentation is 3 bytes long.
              // 83 chars * 3 bytes/char = 249 bytes
-  expected: {
-    name: 'TypeError',
-    message: 'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
-             'A device name can\'t be longer than 248 bytes.'
-  }
+  expected: new DOMException(
+    'Failed to execute \'requestDevice\' on \'Bluetooth\': ' +
+    'A device name can\'t be longer than 248 bytes.',
+    'TypeError')
 }].forEach(t => {
   let unicode_name = generate_string(t.chars, '\u2764');
   promise_test(() => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice-matches-a-filter.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice-matches-a-filter.html
index 21fa8e74..ad4ae7a 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice-matches-a-filter.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice-matches-a-filter.html
@@ -6,7 +6,7 @@
 <script>
 'use strict';
 
-test(function(t) { assert_true(window.testRunner instanceof Object); t.done(); },
+test(t => { assert_true(window.testRunner instanceof Object); t.done(); },
      'window.testRunner is required for the following tests.');
 
 let matching_services = [heart_rate.uuid];
@@ -63,7 +63,7 @@
   promise_test(() => {
     testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter');
     return assert_promise_rejects(requestDeviceWithKeyDown(args),
-                                  'NotFoundError');
+                                  new DOMException('', 'NotFoundError'));
   }, 'If at least one filter doesn\'t match the promise must reject.');
 });
 
@@ -98,7 +98,7 @@
   promise_test(() => {
     testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter');
     return assert_promise_rejects(requestDeviceWithKeyDown(args),
-                                  'NotFoundError');
+                                  new DOMException('', 'NotFoundError'));
   }, 'If a present filter\'s member doesn\'t match the device, ' +
      'the device doesn\'t match the filter.');
 });
diff --git a/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html b/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
index b1ce848b..de7ffc36 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/requestDevice.html
@@ -6,7 +6,7 @@
 <script>
 'use strict';
 
-test(function(t) { assert_true(window.testRunner instanceof Object); t.done(); },
+test(t => { assert_true(window.testRunner instanceof Object); t.done(); },
      'window.testRunner is required for the following tests.');
 
 promise_test(() => {
@@ -24,7 +24,8 @@
       testRunner.sendBluetoothManualChooserEvent('cancelled', '');
       return assert_promise_rejects_with_message(
         requestDevicePromise,
-        {name: 'NotFoundError', message: 'User cancelled the requestDevice() chooser.'},
+        new DOMException('User cancelled the requestDevice() chooser.',
+                         'NotFoundError'),
         'The adapter failed to start a discovery session.');
     });
 }, 'Discovery session fails to start.');
@@ -33,7 +34,7 @@
   testRunner.setBluetoothMockDataSet('NotPresentAdapter');
   return assert_promise_rejects_with_message(
     requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]}),
-    {name: 'NotFoundError', message: 'Bluetooth adapter not available.'},
+    new DOMException('Bluetooth adapter not available.', 'NotFoundError'),
     'Bluetooth adapter is not present.');
 }, 'Reject with NotFoundError if the adapter is not present.');
 
@@ -51,7 +52,8 @@
       testRunner.sendBluetoothManualChooserEvent('cancelled', '');
       return assert_promise_rejects_with_message(
         requestDevicePromise,
-        {name: 'NotFoundError', message: 'User cancelled the requestDevice() chooser.'},
+        new DOMException('User cancelled the requestDevice() chooser.',
+                         'NotFoundError'),
         'Bluetooth adapter is not powered.');
     });
 }, 'Reject with NotFoundError if the adapter is off.');
@@ -60,16 +62,17 @@
   testRunner.setBluetoothMockDataSet('EmptyAdapter');
   return assert_promise_rejects_with_message(
     requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]}),
-    {name: 'NotFoundError', message: 'User cancelled the requestDevice() chooser.'},
+    new DOMException('User cancelled the requestDevice() chooser.',
+                     'NotFoundError'),
     'No Bluetooth devices in range.');
 }, 'Reject with NotFoundError if there are no devices around.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
   return Promise.all([
-    requestDeviceWithKeyDown({filters: [{services: [generic_access.alias]}]}),
-    requestDeviceWithKeyDown({filters: [{services: [generic_access.name]}]}),
-    requestDeviceWithKeyDown({filters: [{services: [generic_access.uuid]}]})
+    requestDeviceWithKeyDown({filters: [{services: [heart_rate.alias]}]}),
+    requestDeviceWithKeyDown({filters: [{services: [heart_rate.name]}]}),
+    requestDeviceWithKeyDown({filters: [{services: [heart_rate.uuid]}]})
   ]).then(devices => {
     devices.forEach(device => {
       assert_equals(device.constructor.name, 'BluetoothDevice');
@@ -78,30 +81,30 @@
 }, 'Mock will resolve.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
   return assert_promise_rejects(
-    navigator.bluetooth.requestDevice({filters: [{services: ['generic_access']}]}),
-    'SecurityError');
+    navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]}),
+    new DOMException('', 'SecurityError'));
 }, 'Requires a user gesture.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
   return callWithKeyDown(() => {
-    var first = navigator.bluetooth.requestDevice({filters: [{services: ['generic_access']}]});
-    var second = navigator.bluetooth.requestDevice({filters: [{services: ['generic_access']}]});
+    var first = navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]});
+    var second = navigator.bluetooth.requestDevice({filters: [{services: ['heart_rate']}]});
     return Promise.all([
       first.then(device => assert_equals(device.constructor.name, 'BluetoothDevice')),
-      assert_promise_rejects(second, 'SecurityError'),
+      assert_promise_rejects(second, new DOMException('', 'SecurityError')),
     ]);
   });
 }, 'Consumes a user gesture.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
   return Promise.all([
-    requestDeviceWithKeyDown({filters: [{services: [generic_access.alias]}]}),
-    requestDeviceWithKeyDown({filters: [{services: [generic_access.name]}]}),
-    requestDeviceWithKeyDown({filters: [{services: [generic_access.uuid]}]})
+    requestDeviceWithKeyDown({filters: [{services: [heart_rate.alias]}]}),
+    requestDeviceWithKeyDown({filters: [{services: [heart_rate.name]}]}),
+    requestDeviceWithKeyDown({filters: [{services: [heart_rate.uuid]}]})
   ]).then(devices => {
     // requestDevice should return the same object if it was created
     // earlier. https://crbug.com/495270
@@ -122,7 +125,7 @@
       {services: ['glucose', 'heart_rate']}
     ],
     // The optionalServices shouldn't affect the platform's scan.
-    optionalServices: [generic_access.name]
+    optionalServices: ['generic_access']
   });
 }, 'Filters restrict the platform\'s Bluetooth scan.');
 
@@ -160,8 +163,8 @@
 promise_test(() => {
   testRunner.setBluetoothMockDataSet('GlucoseHeartRateAdapter');
   return requestDeviceWithKeyDown({
-    filters: [{services: ['generic_access', 'heart_rate']}]
-  }).then(device => assert_equals(device.name, 'Heart Rate Device'));
+    filters: [{services: ['glucose', 'tx_power']}]
+  }).then(device => assert_equals(device.name, 'Glucose Device'));
 }, 'Filter with 2 services returns a matching device.');
 
 promise_test(() => {
@@ -178,8 +181,8 @@
   // support both services to pass the filter, and neither has a Battery
   // service.
   return assert_promise_rejects(requestDeviceWithKeyDown({
-    filters: [{services: ['generic_access', 'battery_service']}]
-  }), 'NotFoundError');
+    filters: [{services: ['heart_rate', 'battery_service']}]
+  }), new DOMException('', 'NotFoundError'));
 }, 'Too-strict filters do prevent matching.');
 
 promise_test(() => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/resources/bluetooth-helpers.js b/third_party/WebKit/LayoutTests/bluetooth/resources/bluetooth-helpers.js
index 4bcd6cab..6b636bb7 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/resources/bluetooth-helpers.js
+++ b/third_party/WebKit/LayoutTests/bluetooth/resources/bluetooth-helpers.js
@@ -38,6 +38,70 @@
   uuid: '00002a19-0000-1000-8000-00805f9b34fb'
 };
 
+// The following tests make sure the Web Bluetooth implementation
+// responds correctly to the different types of errors the
+// underlying platform might return for GATT operations.
+
+// Each browser should map these characteristics to specific code paths
+// that result in different errors thus increasing code coverage
+// when testing. Therefore some of these characteristics might not be useful
+// for all browsers.
+//
+// TODO(ortuno): According to the testing spec errorUUID(0x101) to
+// errorUUID(0x1ff) should be use for the uuids of the characteristics.
+var gatt_errors_tests = [{
+  testName: 'GATT Error: Unknown.',
+  uuid: errorUUID(0xA1),
+  error: new DOMException(
+      'GATT Error Unknown.',
+      'NotSupportedError')
+}, {
+  testName: 'GATT Error: Failed.',
+  uuid: errorUUID(0xA2),
+  error: new DOMException(
+      'GATT operation failed for unknown reason.',
+      'NotSupportedError')
+}, {
+  testName: 'GATT Error: In Progress.',
+  uuid: errorUUID(0xA3),
+  error: new DOMException(
+      'GATT operation already in progress.',
+      'NetworkError')
+}, {
+  testName: 'GATT Error: Invalid Length.',
+  uuid: errorUUID(0xA4),
+  error: new DOMException(
+      'GATT Error: invalid attribute length.',
+      'InvalidModificationError')
+}, {
+  testName: 'GATT Error: Not Permitted.',
+  uuid: errorUUID(0xA5),
+  error: new DOMException(
+      'GATT operation not permitted.',
+      'NotSupportedError')
+}, {
+  testName: 'GATT Error: Not Authorized.',
+  uuid: errorUUID(0xA6),
+  error: new DOMException(
+      'GATT operation not authorized.',
+      'SecurityError')
+}, {
+  testName: 'GATT Error: Not Paired.',
+  uuid: errorUUID(0xA7),
+  // TODO(ortuno): Change to InsufficientAuthenticationError or similiar
+  // once https://github.com/WebBluetoothCG/web-bluetooth/issues/137 is
+  // resolved.
+  error: new DOMException(
+      'GATT Error: Not paired.',
+      'NetworkError')
+}, {
+  testName: 'GATT Error: Not Supported.',
+  uuid: errorUUID(0xA8),
+  error: new DOMException(
+      'GATT Error: Not supported.',
+      'NotSupportedError')
+}];
+
 // TODO(jyasskin): Upstream this to testharness.js: https://crbug.com/509058.
 function callWithKeyDown(functionCalledOnKeyPress) {
   return new Promise(resolve => {
diff --git a/third_party/WebKit/LayoutTests/bluetooth/writeValue.html b/third_party/WebKit/LayoutTests/bluetooth/writeValue.html
index ed63f1d..881cf22 100644
--- a/third_party/WebKit/LayoutTests/bluetooth/writeValue.html
+++ b/third_party/WebKit/LayoutTests/bluetooth/writeValue.html
@@ -5,125 +5,58 @@
 <script>
 'use strict';
 
-test(function(t) { assert_exists(window, 'testRunner'); t.done(); },
+test(t => { assert_exists(window, 'testRunner'); t.done(); },
      'window.testRunner is required for the following tests.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
     .then(characteristic => {
       testRunner.setBluetoothMockDataSet('EmptyAdapter');
       return assert_promise_rejects_with_message(
-        characteristic.writeValue(new ArrayBuffer(1 /* length */)), {
-          name: 'NetworkError',
-          message: 'Bluetooth Device is no longer in range.'
-        }, 'Device went out of range.');
+        characteristic.writeValue(new ArrayBuffer(1 /* length */)),
+        new DOMException(
+          'Bluetooth Device is no longer in range.', 'NetworkError'),
+        'Device went out of range.');
     });
 }, 'Device goes out of range. Reject with NetworkError.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
     .then(characteristic => {
-      testRunner.setBluetoothMockDataSet('MissingServiceGenericAccessAdapter');
+      testRunner.setBluetoothMockDataSet('MissingServiceHeartRateAdapter');
       return assert_promise_rejects_with_message(
-        characteristic.writeValue(new ArrayBuffer(1 /* length */)), {
-          name: 'InvalidStateError',
-          message: 'GATT Service no longer exists.'
-        }, 'Service got removed.');
+        characteristic.writeValue(new ArrayBuffer(1 /* length */)),
+        new DOMException('GATT Service no longer exists.',
+                         'InvalidStateError'),
+        'Service got removed.');
     });
 }, 'Service gets removed. Reject with InvalidStateError.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
     .then(characteristic => {
-      testRunner.setBluetoothMockDataSet('MissingCharacteristicGenericAccessAdapter');
+      testRunner.setBluetoothMockDataSet('MissingCharacteristicHeartRateAdapter');
       return assert_promise_rejects_with_message(
-        characteristic.writeValue(new ArrayBuffer(1 /* length */)), {
-          name: 'InvalidStateError',
-          message: 'GATT Characteristic no longer exists.'
-        }, 'Characteristic got removed.');
+        characteristic.writeValue(new ArrayBuffer(1 /* length */)),
+        new DOMException(
+          'GATT Characteristic no longer exists.', 'InvalidStateError'),
+        'Characteristic got removed.');
     });
 }, 'Characteristic gets removed. Reject with InvalidStateError.');
 
-// The following tests make sure the Web Bluetooth implementation
-// responds correctly to the different types of errors the
-// underlying platform might return for GATT operations.
-
-// Each implementation maps these characteristics to specific code paths
-// that result in different errors thus increasing code coverage
-// when testing. Therefore some of these characteristics might not be useful
-// for all implementations.
-[{
-  testName: 'GATT Error: Unknown.',
-  uuid: errorUUID(0xA1),
-  error: {
-    name: 'NotSupportedError',
-    message: 'GATT Error Unknown.'
-  }
-}, {
-  testName: 'GATT Error: Failed.',
-  uuid: errorUUID(0xA2),
-  error: {
-    name: 'NotSupportedError',
-    message: 'GATT operation failed for unknown reason.'
-  }
-}, {
-  testName: 'GATT Error: In Progress.',
-  uuid: errorUUID(0xA3),
-  error: {
-    name: 'NetworkError',
-    message: 'GATT operation already in progress.'
-  }
-}, {
-  testName: 'GATT Error: Invalid Length.',
-  uuid: errorUUID(0xA4),
-  error: {
-    name: 'InvalidModificationError',
-    message: 'GATT Error: invalid attribute length.'
-  }
-}, {
-  testName: 'GATT Error: Not Permitted.',
-  uuid: errorUUID(0xA5),
-  error: {
-    name: 'NotSupportedError',
-    message: 'GATT operation not permitted.'
-  }
-}, {
-  testName: 'GATT Error: Not Authorized.',
-  uuid: errorUUID(0xA6),
-  error: {
-    name: 'SecurityError',
-    message: 'GATT operation not authorized.'
-  }
-}, {
-  testName: 'GATT Error: Not Paired.',
-  uuid: errorUUID(0xA7),
-  // TODO(ortuno): Change to InsufficientAuthenticationError or similiar
-  // once https://github.com/WebBluetoothCG/web-bluetooth/issues/137 is
-  // resolved.
-  error: {
-    name: 'NetworkError',
-    message: 'GATT Error: Not paired.'
-  }
-}, {
-  testName: 'GATT Error: Not Supported.',
-  uuid: errorUUID(0xA8),
-  error: {
-    name: 'NotSupportedError',
-    message: 'GATT Error: Not supported.'
-  }
-}].forEach(testSpec => {
+gatt_errors_tests.forEach(testSpec => {
   promise_test(() => {
     testRunner.setBluetoothMockDataSet('FailingGATTOperationsAdapter');
     return requestDeviceWithKeyDown({filters: [{services: [errorUUID(0xA0)]}]})
@@ -140,23 +73,23 @@
 });
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
     .then(characteristic => {
       return assert_promise_rejects_with_message(
-        characteristic.writeValue(new Uint8Array(513 /* length */)), {
-          name: 'InvalidModificationError',
-          message: 'Value can\'t exceed 512 bytes.'
-        }, 'Value passed was too long.');
+        characteristic.writeValue(new Uint8Array(513 /* length */)),
+        new DOMException(
+          'Value can\'t exceed 512 bytes.', 'InvalidModificationError'),
+        'Value passed was too long.');
     });
 }, 'Trying to write more than 512 bytes should return an error.');
 
 promise_test(() => {
-  testRunner.setBluetoothMockDataSet('GenericAccessAdapter');
-  return requestDeviceWithKeyDown({filters: [{services: ['generic_access']}]})
+  testRunner.setBluetoothMockDataSet('HeartRateAdapter');
+  return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
     .then(device => device.connectGATT())
     .then(gattServer => gattServer.getPrimaryService('generic_access'))
     .then(service => service.getCharacteristic('gap.device_name'))
diff --git a/third_party/WebKit/LayoutTests/fast/forms/setrangetext-expected.txt b/third_party/WebKit/LayoutTests/fast/forms/setrangetext-expected.txt
index 593d328..3c9cc21 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/setrangetext-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/forms/setrangetext-expected.txt
@@ -624,11 +624,6 @@
 element.value = '0123456789'
 PASS element.setRangeText('A', 7, 3) threw exception IndexSizeError: Failed to execute 'setRangeText' on 'HTMLInputElement': The provided start value (7) is larger than the provided end value (3)..
 
-Check that setRangeText() on disconnected elements doesn't crash and has proper values.
-element.value = '0123456789'
-element.setRangeText('ABC', 0, 0, 'select')
-FAIL element.value should be ABC0123456789. Was 0123456789.
-
 Running tests on input with attributes: {"type":"button"}
 
 element.value = '0123456789XYZ'
diff --git a/third_party/WebKit/LayoutTests/fast/forms/setrangetext.html b/third_party/WebKit/LayoutTests/fast/forms/setrangetext.html
index 8d91de3..874d215 100644
--- a/third_party/WebKit/LayoutTests/fast/forms/setrangetext.html
+++ b/third_party/WebKit/LayoutTests/fast/forms/setrangetext.html
@@ -7,6 +7,8 @@
 </head>
 <body>
 <script>
+// TODO(tkent): This should be merged to imported/web-platform-tests/html/
+// semantics/forms/textfieldselection/textfieldselection-setRangeText.html
 description("Test setRangeText() method on common input types.");
 
 runTestsShouldPass("input", { type: "password" });
@@ -15,13 +17,6 @@
 runTestsShouldPass("input", { type: "text", dir: "rtl" });
 runTestsShouldPass("input", { type: "url" });
 
-debug("<hr>");
-debug("Check that setRangeText() on disconnected elements doesn't crash and has proper values.");
-element = document.createElement("input");
-evalAndLog("element.value = '0123456789'");
-evalAndLog("element.setRangeText('ABC', 0, 0, 'select')");
-shouldBeEqualToString("element.value", "ABC0123456789");
-
 runTestsShouldFail("input", { type: "button" });
 runTestsShouldFail("input", { type: "checkbox" });
 runTestsShouldFail("input", { type: "email" });
diff --git a/third_party/WebKit/LayoutTests/fast/images/resources/bug106024.jpg b/third_party/WebKit/LayoutTests/fast/images/resources/bug106024.jpg
new file mode 100644
index 0000000..92fe5dba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/images/resources/bug106024.jpg
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/images/resources/small-square-with-colorspin-profile.jpg b/third_party/WebKit/LayoutTests/fast/images/resources/small-square-with-colorspin-profile.jpg
new file mode 100644
index 0000000..a9186968
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/images/resources/small-square-with-colorspin-profile.jpg
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/lists/list-marker-set-overflow-line-box-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/lists/list-marker-set-overflow-line-box-crash-expected.txt
new file mode 100644
index 0000000..240c3b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/lists/list-marker-set-overflow-line-box-crash-expected.txt
@@ -0,0 +1,3 @@
+This test checks that list item don't make non-overflowable box overflowing
+This test has passed if it doesn't crash.
+
diff --git a/third_party/WebKit/LayoutTests/fast/lists/list-marker-set-overflow-line-box-crash.html b/third_party/WebKit/LayoutTests/fast/lists/list-marker-set-overflow-line-box-crash.html
new file mode 100644
index 0000000..1e41043
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/lists/list-marker-set-overflow-line-box-crash.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<style>
+.container {
+  display: inline-block;
+  width: 1280px;
+  position: relative
+}
+.outerspan {
+  position: absolute;
+  left: 0;
+  right: 0;
+}
+</style>
+<div class="container">
+  <span class="outerspan">
+    <span>This test checks that list item don't make non-overflowable box overflowing</span>
+  </span>
+</div>
+This test has passed if it doesn't crash.
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+    document.designMode = 'on';
+    document.execCommand('SelectAll');
+    document.execCommand('Strikethrough');
+    document.execCommand('InsertOrderedList');
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-unknown-resource-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-unknown-resource-expected.txt
new file mode 100644
index 0000000..3baddd2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-unknown-resource-expected.txt
@@ -0,0 +1,11 @@
+Tests that requests to unresolved origins result in unknown security state and show up in the sidebar origin list.
+
+Group: Main Origin
+<SPAN class=title >
+Reload to view details
+</SPAN>
+Group: Unknown / Canceled
+<SPAN class=title >
+http://unknown
+</SPAN>
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-unknown-resource.html b/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-unknown-resource.html
new file mode 100644
index 0000000..237a4ff4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/security/security-unknown-resource.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+<script src="../inspector-test.js"></script>
+<script src="../security-test.js"></script>
+<script>
+function test()
+{
+    var request = new WebInspector.NetworkRequest(InspectorTest.mainTarget, 0, "http://unknown", "https://foo.test", 0, 0, null);
+    InspectorTest.dispatchRequestFinished(request);
+
+    InspectorTest.dumpSecurityPanelSidebarOrigins();
+
+    InspectorTest.completeTest();
+}
+</script>
+</head>
+<body onload="runTest()">
+<p>Tests that requests to unresolved origins result in unknown security state and show up in the sidebar origin list.</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
index 87ce97e28..23b28613 100644
--- a/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
+++ b/third_party/WebKit/LayoutTests/http/tests/inspector/timeline-test.js
@@ -222,13 +222,10 @@
 // Dump just the record name, indenting output on separate lines for subrecords
 InspectorTest.dumpTimelineRecord = function(record, detailsCallback, level, filterTypes)
 {
-    if (typeof level !== "number")
-        level = 0;
-    var message = "";
-    for (var i = 0; i < level ; ++i)
-        message = "----" + message;
+    level = level || 0;
+    var message = "----".repeat(level);
     if (level > 0)
-        message = message + "> ";
+        message += "> ";
     if (record.type() === WebInspector.TimelineModel.RecordType.TimeStamp
         || record.type() === WebInspector.TimelineModel.RecordType.ConsoleTime) {
         message += WebInspector.TimelineUIUtils.eventTitle(record.traceEvent());
@@ -250,13 +247,10 @@
 
 InspectorTest.dumpTimelineModelRecord = function(record, level)
 {
-    if (typeof level !== "number")
-        level = 0;
-    var prefix = "";
-    for (var i = 0; i < level ; ++i)
-        prefix = "----" + prefix;
+    level = level || 0;
+    var prefix = "----".repeat(level);
     if (level > 0)
-        prefix = prefix + "> ";
+        prefix += "> ";
     InspectorTest.addResult(prefix + record.type() + ": " + (WebInspector.TimelineUIUtils.buildDetailsTextForTraceEvent(record.traceEvent(), null) || ""));
 
     var numChildren = record.children() ? record.children().length : 0;
@@ -268,13 +262,10 @@
 InspectorTest.dumpPresentationRecord = function(presentationRecord, detailsCallback, level, filterTypes)
 {
     var record = !presentationRecord.presentationParent() ? null : presentationRecord.record();
-    if (typeof level !== "number")
-        level = 0;
-    var message = "";
-    for (var i = 0; i < level ; ++i)
-        message = "----" + message;
+    level = level || 0;
+    var message = "----".repeat(level);
     if (level > 0)
-        message = message + "> ";
+        message += "> ";
     if (!record) {
         message += "Root";
     } else if (presentationRecord.coalesced()) {
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/textfieldselection/selection-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/textfieldselection/selection-expected.txt
deleted file mode 100644
index 7f6aee8..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/textfieldselection/selection-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-PASS test if selection text is correct for input 
-PASS test if selection text is correct for textarea 
-PASS test if non-ascii selection text is correct for input 
-PASS test if non-ascii selection text is correct for textarea 
-PASS test SelectionStart offset for input 
-FAIL test SelectionStart offset for textarea assert_equals: SelectionStart offset without selection expected 10 but got 0
-PASS test SelectionEnd offset for input 
-FAIL test SelectionEnd offset for textarea assert_equals: SelectionEnd offset without selection expected 10 but got 0
-PASS test SelectionDirection for input 
-PASS test SelectionDirection for textarea 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText-expected.txt
index 1a37e97..0e27218 100644
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText-expected.txt
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/html/semantics/forms/textfieldselection/textfieldselection-setRangeText-expected.txt
@@ -1,5 +1,75 @@
-    
 This is a testharness.js-based test.
-Harness Error. harness_status.status = 2 , harness_status.message = null
+PASS text setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments 
+PASS text selectionMode missing 
+PASS text selectionMode 'select' 
+PASS text selectionMode 'start' 
+PASS text selectionMode 'end' 
+PASS text selectionMode 'preserve' 
+PASS text setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception 
+PASS text setRangeText without argument throws a type error 
+FAIL text setRangeText fires a select event assert_false: event bubbles expected false got true
+PASS search setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments 
+PASS search selectionMode missing 
+PASS search selectionMode 'select' 
+PASS search selectionMode 'start' 
+PASS search selectionMode 'end' 
+PASS search selectionMode 'preserve' 
+PASS search setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception 
+PASS search setRangeText without argument throws a type error 
+FAIL search setRangeText fires a select event assert_false: event bubbles expected false got true
+PASS tel setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments 
+PASS tel selectionMode missing 
+PASS tel selectionMode 'select' 
+PASS tel selectionMode 'start' 
+PASS tel selectionMode 'end' 
+PASS tel selectionMode 'preserve' 
+PASS tel setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception 
+PASS tel setRangeText without argument throws a type error 
+FAIL tel setRangeText fires a select event assert_false: event bubbles expected false got true
+PASS url setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments 
+PASS url selectionMode missing 
+PASS url selectionMode 'select' 
+PASS url selectionMode 'start' 
+PASS url selectionMode 'end' 
+PASS url selectionMode 'preserve' 
+PASS url setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception 
+PASS url setRangeText without argument throws a type error 
+FAIL url setRangeText fires a select event assert_false: event bubbles expected false got true
+PASS password setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments 
+PASS password selectionMode missing 
+PASS password selectionMode 'select' 
+PASS password selectionMode 'start' 
+PASS password selectionMode 'end' 
+PASS password selectionMode 'preserve' 
+PASS password setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception 
+PASS password setRangeText without argument throws a type error 
+FAIL password setRangeText fires a select event assert_false: event bubbles expected false got true
+PASS display_none setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments 
+PASS display_none selectionMode missing 
+PASS display_none selectionMode 'select' 
+PASS display_none selectionMode 'start' 
+PASS display_none selectionMode 'end' 
+PASS display_none selectionMode 'preserve' 
+PASS display_none setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception 
+PASS display_none setRangeText without argument throws a type error 
+FAIL display_none setRangeText fires a select event assert_false: event bubbles expected false got true
+PASS textarea setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments 
+PASS textarea selectionMode missing 
+PASS textarea selectionMode 'select' 
+PASS textarea selectionMode 'start' 
+PASS textarea selectionMode 'end' 
+PASS textarea selectionMode 'preserve' 
+PASS textarea setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception 
+PASS textarea setRangeText without argument throws a type error 
+FAIL textarea setRangeText fires a select event assert_false: event bubbles expected false got true
+PASS input_not_in_doc setRangeText with only one argument replaces the value between selectionStart and selectionEnd, otherwise replaces the value between 2nd and 3rd arguments 
+PASS input_not_in_doc selectionMode missing 
+PASS input_not_in_doc selectionMode 'select' 
+PASS input_not_in_doc selectionMode 'start' 
+PASS input_not_in_doc selectionMode 'end' 
+PASS input_not_in_doc selectionMode 'preserve' 
+PASS input_not_in_doc setRangeText with 3rd argument greater than 2nd argument throws an IndexSizeError exception 
+PASS input_not_in_doc setRangeText without argument throws a type error 
+FAIL input_not_in_doc setRangeText fires a select event assert_false: event bubbles expected false got true
 Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html b/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html
index 2855323b..3d66797 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/category-filter.html
@@ -32,11 +32,11 @@
             "ts": 100,
         },
         {"name": "foooooo", "ts": 1000000, "ph": "B", "tid": mainThread, "pid": pid, "cat":"toplevel", "args": {}},
-        {"name": "FunctionCall", "ts": 1000001, "ph": "B", "tid": mainThread, "pid": pid, "cat":"disabled-by-default-devtools.timeline", "args":{"data":{"frame":"0x2","scriptId":"3","scriptLine":5,"scriptName":"http://example.com"}}},
+        {"name": "FunctionCall", "ts": 1000010, "ph": "B", "tid": mainThread, "pid": pid, "cat":"disabled-by-default-devtools.timeline", "args":{"data":{"frame":"0x2","scriptId":"3","scriptLine":5,"scriptName":"http://example.com"}}},
 
-        {"name":"ResourceSendRequest","ts":1000002,"tid":mainThread,"pid":pid,"cat":"disabled-by-default-devtools.timeline","ph":"I","s":"g","args":{"data":{"frame":"0x2","requestId":"44.1","requestMethod":"GET","url":"http://example.com/foo.js"}}},
+        {"name":"ResourceSendRequest","ts":1000015,"tid":mainThread,"pid":pid,"cat":"disabled-by-default-devtools.timeline","ph":"X","dur":10,"s":"g","args":{"data":{"frame":"0x2","requestId":"44.1","requestMethod":"GET","url":"http://example.com/foo.js"}}},
 
-        {"name": "RecalculateStyles", "ts": 1000003, "ph": "B", "tid": mainThread, "pid": pid, "cat":"disabled-by-default-devtools.timeline", "args":{"beginData":{"frame":"0x2"}}},
+        {"name": "RecalculateStyles", "ts": 1000030, "ph": "B", "tid": mainThread, "pid": pid, "cat":"disabled-by-default-devtools.timeline", "args":{"beginData":{"frame":"0x2"}}},
         {"name": "RecalculateStyles", "ts": 1009999, "ph": "E", "tid": mainThread, "pid": pid, "cat":"disabled-by-default-devtools.timeline", "args":{"elementCount":3}},
 
         {"name": "Layout", "ts": 1010000, "ph": "B", "tid": mainThread, "pid": pid, "cat":"disabled-by-default-devtools.timeline", "args":{"beginData":{"dirtyObjects":1,"frame":"0x2","partialLayout":false,"totalObjects":1}} },
@@ -52,19 +52,19 @@
     for (var i = 0; i < rootRecord.presentationChildren().length; ++i)
         rootRecord.presentationChildren()[i].setCollapsed(false);
 
-    var categoryFilter = WebInspector.panels.timeline._filters._categoryFilter;
+    var filtersControl = WebInspector.panels.timeline._filtersControl;
     InspectorTest.addResult("Original records");
-    categoryFilter.notifyFilterChanged();
+    filtersControl._notifyFiltersChanged();
     InspectorTest.dumpVisibleRecords();
 
     InspectorTest.addResult("Visible records when 'loading' is disabled");
     WebInspector.TimelineUIUtils.categories().loading.hidden = true;
-    categoryFilter.notifyFilterChanged();
+    filtersControl._notifyFiltersChanged();
     InspectorTest.dumpVisibleRecords();
 
     InspectorTest.addResult("Visible records when 'scripting' is disabled");
     WebInspector.TimelineUIUtils.categories().scripting.hidden = true;
-    categoryFilter.notifyFilterChanged();
+    filtersControl._notifyFiltersChanged();
     InspectorTest.dumpVisibleRecords();
 
     InspectorTest.completeTest();
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-filtering.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-filtering.html
index 2d1ca2c..aa28af5 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-filtering.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-filtering.html
@@ -79,7 +79,7 @@
     dumpRecords();
 
     InspectorTest.addResult("Filtered by 'bar':");
-    var textFilterUI = panel._filters._textFilterUI;
+    var textFilterUI = panel._filtersControl._textFilterUI;
     textFilterUI.setValue("bar");
     dumpRecords();
 
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-model.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-model.html
index fe99a39e..ec543bcf 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-model.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-model.html
@@ -33,16 +33,16 @@
 
     var traceEvents = [
         {"name": "Program", "ts": 1000000, "dur": 9999, "ph": "X", args: {},  "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
-        {"name": "FunctionCall", "ts": 1000001, "dur": 9998, "ph": "X", args: {"data":{}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
-        {"name": "ResourceSendRequest", "ts": 1000002, "ph": "I", args: {"data":{"requestId": 1, "url": "http://example.com", "requestMethod": "GET"}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
+        {"name": "FunctionCall", "ts": 1000010, "dur": 9998, "ph": "X", args: {"data":{}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
+        {"name": "ResourceSendRequest", "ts": 1000015, "ph": "X", dur: 10, args: {"data":{"requestId": 1, "url": "http://example.com", "requestMethod": "GET"}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
         {"name": "RecalculateStyles", "ts": 1001003, "dur": 997, "ph": "X", args: {data: {}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline"},
         {"name": "Layout", "ts": 1002001, "ph": "B", args: {beginData: {}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline"},
         {"name": "Layout", "ts": 1003000, "ph": "E", args: {endData: {}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline"},
 
         {"name": "Program", "ts": 2000000, "ph": "B", args: {},  "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
-        {"name": "FunctionCall", "ts": 2000001, "ph": "B", args: {"data":{}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
-        {"name": "ResourceSendRequest", "ts": 2000002, "ph": "I", args: {"data":{"requestId": 1, "url": "http://example.com", "requestMethod": "GET"}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
-        {"name": "RecalculateStyles", "ts": 2001003, "ph": "B", args: {beginData: {}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline"},
+        {"name": "FunctionCall", "ts": 2000010, "ph": "B", args: {"data":{}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
+        {"name": "ResourceSendRequest", "ts": 2000015, "ph": "X", dur: 10, args: {"data":{"requestId": 1, "url": "http://example.com", "requestMethod": "GET"}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline" },
+        {"name": "RecalculateStyles", "ts": 2001030, "ph": "B", args: {beginData: {}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline"},
         {"name": "RecalculateStyles", "ts": 2002000, "ph": "E", args: {}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline"},
         {"name": "Layout", "ts": 2002101, "ph": "B", args: {beginData: {}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline"},
         {"name": "Layout", "ts": 2003001, "ph": "E", args: {endData: {}}, "tid": mainThread, "pid": 100, "cat":"disabled-by-default.devtools.timeline"},
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-received-data.html b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-received-data.html
index a7372e6..bebcfff 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-received-data.html
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-received-data.html
@@ -40,7 +40,7 @@
         var record = InspectorTest.findFirstTimelineRecord("ResourceReceivedData");
         if (record) {
             var data = record.traceEvent().args["data"];
-            if (data && typeof data.encodedDataLength === "number")
+            if (data && typeof data["encodedDataLength"] === "number")
                 InspectorTest.addResult("Resource received data has length, test passed.");
         }
         InspectorTest.completeTest();
diff --git a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-expected.txt b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-expected.txt
index e71cfc0..5485eb66 100644
--- a/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-expected.txt
+++ b/third_party/WebKit/LayoutTests/inspector/tracing/timeline-network-resource-expected.txt
@@ -5,14 +5,12 @@
 ResourceSendRequest Properties:
 {
     data : {
-        frame : <string>
         requestId : <string>
         requestMethod : "GET"
         stackTrace : <object>
         url : .../inspector/tracing/timeline-network-resource.js
     }
     endTime : <number>
-    frameId : <string>
     stackTrace : <object>
     startTime : <number>
     thread : <string>
@@ -23,13 +21,11 @@
 ResourceReceiveResponse Properties:
 {
     data : {
-        frame : <string>
         mimeType : <string>
         requestId : <string>
         statusCode : 0
     }
     endTime : <number>
-    frameId : <string>
     startTime : <number>
     thread : <string>
     type : "ResourceReceiveResponse"
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index e26f5d4..ba13e8c 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -3273,9 +3273,9 @@
     getter onmessage
     getter onstatechange
     getter state
-    method close
     method constructor
     method send
+    method terminate
     setter binaryType
     setter onmessage
     setter onstatechange
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 8b925fe..f468c4a4 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3786,9 +3786,9 @@
     getter onmessage
     getter onstatechange
     getter state
-    method close
     method constructor
     method send
+    method terminate
     setter binaryType
     setter onmessage
     setter onstatechange
diff --git a/third_party/WebKit/PerformanceTests/DOM/select-multiple-add.html b/third_party/WebKit/PerformanceTests/DOM/select-multiple-add.html
new file mode 100644
index 0000000..88d3786
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/DOM/select-multiple-add.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<body>
+<script src="../resources/runner.js"></script>
+<select id="container" multiple></select>
+<script>
+var container = document.getElementById('container');
+var nodes = [];
+var childCount = 500;
+for (var i = 0; i < childCount; ++i) {
+    nodes.push(document.createElement('option'));
+    nodes[i].selected = !!(i % 2);
+}
+
+PerfTestRunner.measureRunsPerSecond({
+    description: 'Measures performance of adding option elements to a multi-selection select element.',
+    run: function() {
+        for (var i = 0; i < childCount; ++i)
+            container.appendChild(nodes[i]);
+        container.innerHTML = '';
+    }
+});
+</script>
+</body>
diff --git a/third_party/WebKit/PerformanceTests/DOM/select-single-add.html b/third_party/WebKit/PerformanceTests/DOM/select-single-add.html
new file mode 100644
index 0000000..5d921d4e
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/DOM/select-single-add.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<body>
+<script src="../resources/runner.js"></script>
+<select id="container"></select>
+<script>
+var container = document.getElementById('container');
+var nodes = [];
+var childCount = 500;
+for (var i = 0; i < childCount; ++i) {
+    nodes.push(document.createElement('option'));
+    nodes[i].selected = !!(i % 2);
+}
+
+PerfTestRunner.measureRunsPerSecond({
+    description: 'Measures performance of adding option elements to a single-selection select element.',
+    run: function() {
+        for (var i = 0; i < childCount; ++i)
+            container.appendChild(nodes[i]);
+        container.innerHTML = '';
+    }
+});
+</script>
+</body>
diff --git a/third_party/WebKit/Source/bindings/core/v8/RetainedDOMInfo.h b/third_party/WebKit/Source/bindings/core/v8/RetainedDOMInfo.h
index 41f289e..0e84230 100644
--- a/third_party/WebKit/Source/bindings/core/v8/RetainedDOMInfo.h
+++ b/third_party/WebKit/Source/bindings/core/v8/RetainedDOMInfo.h
@@ -32,6 +32,7 @@
 #define RetainedDOMInfo_h
 
 #include "bindings/core/v8/RetainedObjectInfo.h"
+#include "platform/heap/Handle.h"
 #include <v8-profiler.h>
 
 namespace blink {
@@ -56,6 +57,7 @@
 private:
     // V8 guarantees to keep RetainedObjectInfos alive only during a GC or heap snapshotting round, when renderer
     // doesn't get control. This allows us to use raw pointers.
+    GC_PLUGIN_IGNORE("553613")
     Node* m_root;
 };
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.cpp b/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.cpp
index 4f6ae86..798a8ff 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.cpp
@@ -6,6 +6,7 @@
 #include "bindings/core/v8/V8BindingForTesting.h"
 
 #include "bindings/core/v8/DOMWrapperWorld.h"
+#include "core/dom/ExecutionContext.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.h b/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.h
index bd80192..6b7c973 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8BindingForTesting.h
@@ -21,7 +21,7 @@
     void setExecutionContext(ExecutionContext*) override;
 private:
     ScriptStateForTesting(v8::Local<v8::Context>, PassRefPtr<DOMWrapperWorld>);
-    ExecutionContext* m_executionContext;
+    RawPtrWillBePersistent<ExecutionContext> m_executionContext;
 };
 
 class V8TestingScope {
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 781c6447..65788117 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -1487,6 +1487,8 @@
             'fetch/FontResource.h',
             'fetch/ImageResource.cpp',
             'fetch/ImageResource.h',
+            'fetch/InspectorFetchTraceEvents.cpp',
+            'fetch/InspectorFetchTraceEvents.h',
             'fetch/IntegrityMetadata.cpp',
             'fetch/IntegrityMetadata.h',
             'fetch/LinkFetchResource.cpp',
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index cc66d59..564a3471 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -1606,6 +1606,153 @@
     return consumeLineWidth(range, cssParserMode);
 }
 
+static bool consumeTranslate3d(CSSParserTokenRange& args, CSSParserMode cssParserMode, RefPtrWillBeRawPtr<CSSFunctionValue>& transformValue)
+{
+    unsigned numberOfArguments = 2;
+    RefPtrWillBeRawPtr<CSSValue> parsedValue;
+    do {
+        parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+        if (!parsedValue)
+            return false;
+        transformValue->append(parsedValue);
+        if (!consumeCommaIncludingWhitespace(args))
+            return false;
+    } while (--numberOfArguments);
+    parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
+    if (!parsedValue)
+        return false;
+    transformValue->append(parsedValue);
+    return true;
+}
+
+static bool consumeNumbers(CSSParserTokenRange& args, RefPtrWillBeRawPtr<CSSFunctionValue>& transformValue, unsigned numberOfArguments)
+{
+    do {
+        RefPtrWillBeRawPtr<CSSValue> parsedValue = consumeNumber(args, ValueRangeAll);
+        if (!parsedValue)
+            return false;
+        transformValue->append(parsedValue);
+        if (--numberOfArguments && !consumeCommaIncludingWhitespace(args))
+            return false;
+    } while (numberOfArguments);
+    return true;
+}
+
+static bool consumePerspective(CSSParserTokenRange& args, CSSParserMode cssParserMode, RefPtrWillBeRawPtr<CSSFunctionValue>& transformValue, bool useLegacyParsing)
+{
+    RefPtrWillBeRawPtr<CSSPrimitiveValue> parsedValue = consumeLength(args, cssParserMode, ValueRangeNonNegative);
+    if (!parsedValue && useLegacyParsing) {
+        double perspective;
+        if (!consumeNumberRaw(args, perspective) || perspective < 0)
+            return false;
+        parsedValue = cssValuePool().createValue(perspective, CSSPrimitiveValue::UnitType::Pixels);
+    }
+    if (!parsedValue)
+        return false;
+    transformValue->append(parsedValue);
+    return true;
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeTransformValue(CSSParserTokenRange& range, CSSParserMode cssParserMode, bool useLegacyParsing)
+{
+    CSSValueID functionId = range.peek().functionId();
+    if (functionId == CSSValueInvalid)
+        return nullptr;
+    CSSParserTokenRange args = consumeFunction(range);
+    if (args.atEnd())
+        return nullptr;
+    RefPtrWillBeRawPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(functionId);
+    RefPtrWillBeRawPtr<CSSValue> parsedValue = nullptr;
+    switch (functionId) {
+    case CSSValueRotate:
+    case CSSValueRotateX:
+    case CSSValueRotateY:
+    case CSSValueRotateZ:
+    case CSSValueSkewX:
+    case CSSValueSkewY:
+    case CSSValueSkew:
+        parsedValue = consumeAngle(args, cssParserMode);
+        if (!parsedValue)
+            return nullptr;
+        if (functionId == CSSValueSkew && consumeCommaIncludingWhitespace(args)) {
+            transformValue->append(parsedValue);
+            parsedValue = consumeAngle(args, cssParserMode);
+        }
+        break;
+    case CSSValueScaleX:
+    case CSSValueScaleY:
+    case CSSValueScaleZ:
+    case CSSValueScale:
+        parsedValue = consumeNumber(args, ValueRangeAll);
+        if (!parsedValue)
+            return nullptr;
+        if (functionId == CSSValueScale && consumeCommaIncludingWhitespace(args)) {
+            transformValue->append(parsedValue);
+            parsedValue = consumeNumber(args, ValueRangeAll);
+        }
+        break;
+    case CSSValuePerspective:
+        if (!consumePerspective(args, cssParserMode, transformValue, useLegacyParsing))
+            return nullptr;
+        break;
+    case CSSValueTranslateX:
+    case CSSValueTranslateY:
+    case CSSValueTranslate:
+        parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+        if (!parsedValue)
+            return nullptr;
+        if (functionId == CSSValueTranslate && consumeCommaIncludingWhitespace(args)) {
+            transformValue->append(parsedValue);
+            parsedValue = consumeLengthOrPercent(args, cssParserMode, ValueRangeAll);
+        }
+        break;
+    case CSSValueTranslateZ:
+        parsedValue = consumeLength(args, cssParserMode, ValueRangeAll);
+        break;
+    case CSSValueMatrix:
+    case CSSValueMatrix3d:
+        if (!consumeNumbers(args, transformValue, (functionId == CSSValueMatrix3d) ? 16 : 6))
+            return nullptr;
+        break;
+    case CSSValueScale3d:
+        if (!consumeNumbers(args, transformValue, 3))
+            return nullptr;
+        break;
+    case CSSValueRotate3d:
+        if (!consumeNumbers(args, transformValue, 3) || !consumeCommaIncludingWhitespace(args))
+            return nullptr;
+        parsedValue = consumeAngle(args, cssParserMode);
+        break;
+    case CSSValueTranslate3d:
+        if (!consumeTranslate3d(args, cssParserMode, transformValue))
+            return nullptr;
+        break;
+    default:
+        return nullptr;
+    }
+    if (parsedValue)
+        transformValue->append(parsedValue);
+    if (!args.atEnd())
+        return nullptr;
+    return transformValue.release();
+}
+
+static PassRefPtrWillBeRawPtr<CSSValue> consumeTransform(CSSParserTokenRange& range, CSSParserMode cssParserMode, bool useLegacyParsing)
+{
+    if (range.peek().id() == CSSValueNone)
+        return consumeIdent(range);
+
+    RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
+    do {
+        RefPtrWillBeRawPtr<CSSValue> parsedTransformValue = consumeTransformValue(range, cssParserMode, useLegacyParsing);
+        if (!parsedTransformValue)
+            return nullptr;
+        list->append(parsedTransformValue.release());
+    } while (!range.atEnd());
+
+    return list.release();
+}
+
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty)
 {
     CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
@@ -1752,6 +1899,8 @@
         return consumeLength(m_range, m_context.mode(), ValueRangeAll);
     case CSSPropertyOutlineWidth:
         return consumeLineWidth(m_range, m_context.mode());
+    case CSSPropertyTransform:
+        return consumeTransform(m_range, m_context.mode(), unresolvedProperty == CSSPropertyAliasWebkitTransform);
     default:
         return nullptr;
     }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index 99f4731..3afdcd3 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -233,8 +233,6 @@
     PassRefPtrWillBeRawPtr<CSSFunctionValue> parseBuiltinFilterArguments(CSSParserValueList*, CSSValueID);
 
     PassRefPtrWillBeRawPtr<CSSValueList> parseTransformOrigin();
-    PassRefPtrWillBeRawPtr<CSSValueList> parseTransform(bool useLegacyParsing);
-    PassRefPtrWillBeRawPtr<CSSValue> parseTransformValue(bool useLegacyParsing, CSSParserValue*);
 
     bool parseCalculation(CSSParserValue*, ValueRange);
 
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index d586c193..de2b40b6 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -773,12 +773,6 @@
     case CSSPropertyOrder:
         validPrimitive = validUnit(value, FInteger);
         break;
-    case CSSPropertyTransform:
-        if (id == CSSValueNone)
-            validPrimitive = true;
-        else
-            parsedValue = parseTransform(unresolvedProperty == CSSPropertyAliasWebkitTransform);
-        break;
     case CSSPropertyTransformOrigin: {
         RefPtrWillBeRawPtr<CSSValueList> list = parseTransformOrigin();
         if (!list)
@@ -1172,6 +1166,7 @@
     case CSSPropertyWebkitTextStroke:
     case CSSPropertyWebkitTextStrokeColor:
     case CSSPropertyWebkitTextStrokeWidth:
+    case CSSPropertyTransform:
         validPrimitive = false;
         break;
 
@@ -5692,195 +5687,4 @@
     return paintOrderList.release();
 }
 
-class TransformOperationInfo {
-public:
-    TransformOperationInfo(CSSValueID id)
-        : m_validID(true)
-        , m_allowSingleArgument(false)
-        , m_argCount(1)
-        , m_unit(CSSPropertyParser::FUnknown)
-    {
-        switch (id) {
-        case CSSValueSkew:
-            m_unit = CSSPropertyParser::FAngle;
-            m_allowSingleArgument = true;
-            m_argCount = 3;
-            break;
-        case CSSValueScale:
-            m_unit = CSSPropertyParser::FNumber;
-            m_allowSingleArgument = true;
-            m_argCount = 3;
-            break;
-        case CSSValueSkewX:
-            m_unit = CSSPropertyParser::FAngle;
-            break;
-        case CSSValueSkewY:
-            m_unit = CSSPropertyParser::FAngle;
-            break;
-        case CSSValueMatrix:
-            m_unit = CSSPropertyParser::FNumber;
-            m_argCount = 11;
-            break;
-        case CSSValueRotate:
-            m_unit = CSSPropertyParser::FAngle;
-            break;
-        case CSSValueScaleX:
-            m_unit = CSSPropertyParser::FNumber;
-            break;
-        case CSSValueScaleY:
-            m_unit = CSSPropertyParser::FNumber;
-            break;
-        case CSSValueScaleZ:
-            m_unit = CSSPropertyParser::FNumber;
-            break;
-        case CSSValueScale3d:
-            m_unit = CSSPropertyParser::FNumber;
-            m_argCount = 5;
-            break;
-        case CSSValueRotateX:
-            m_unit = CSSPropertyParser::FAngle;
-            break;
-        case CSSValueRotateY:
-            m_unit = CSSPropertyParser::FAngle;
-            break;
-        case CSSValueRotateZ:
-            m_unit = CSSPropertyParser::FAngle;
-            break;
-        case CSSValueMatrix3d:
-            m_unit = CSSPropertyParser::FNumber;
-            m_argCount = 31;
-            break;
-        case CSSValueRotate3d:
-            m_unit = CSSPropertyParser::FNumber;
-            m_argCount = 7;
-            break;
-        case CSSValueTranslate:
-            m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
-            m_allowSingleArgument = true;
-            m_argCount = 3;
-            break;
-        case CSSValueTranslateX:
-            m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
-            break;
-        case CSSValueTranslateY:
-            m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
-            break;
-        case CSSValueTranslateZ:
-            m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
-            break;
-        case CSSValuePerspective:
-            m_unit = CSSPropertyParser::FNumber;
-            break;
-        case CSSValueTranslate3d:
-            m_unit = CSSPropertyParser::FLength | CSSPropertyParser::FPercent;
-            m_argCount = 5;
-            break;
-        default:
-            m_validID = false;
-            break;
-        }
-    }
-
-    bool validID() const { return m_validID; }
-    unsigned argCount() const { return m_argCount; }
-    CSSPropertyParser::Units unit() const { return m_unit; }
-
-    bool hasCorrectArgCount(unsigned argCount) { return m_argCount == argCount || (m_allowSingleArgument && argCount == 1); }
-
-private:
-    bool m_validID;
-    bool m_allowSingleArgument;
-    unsigned m_argCount;
-    CSSPropertyParser::Units m_unit;
-};
-
-PassRefPtrWillBeRawPtr<CSSValueList> CSSPropertyParser::parseTransform(bool useLegacyParsing)
-{
-    if (!m_valueList)
-        return nullptr;
-
-    RefPtrWillBeRawPtr<CSSValueList> list = CSSValueList::createSpaceSeparated();
-    for (CSSParserValue* value = m_valueList->current(); value; value = m_valueList->next()) {
-        RefPtrWillBeRawPtr<CSSValue> parsedTransformValue = parseTransformValue(useLegacyParsing, value);
-        if (!parsedTransformValue)
-            return nullptr;
-
-        list->append(parsedTransformValue.release());
-    }
-
-    return list.release();
-}
-
-PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseTransformValue(bool useLegacyParsing, CSSParserValue *value)
-{
-    if (value->m_unit != CSSParserValue::Function || !value->function)
-        return nullptr;
-
-    // Every primitive requires at least one argument.
-    CSSParserValueList* args = value->function->args.get();
-    if (!args)
-        return nullptr;
-
-    // See if the specified primitive is one we understand.
-    CSSValueID type = value->function->id;
-    TransformOperationInfo info(type);
-    if (!info.validID())
-        return nullptr;
-
-    if (!info.hasCorrectArgCount(args->size()))
-        return nullptr;
-
-    // The transform is a list of functional primitives that specify transform operations.
-    // We collect a list of CSSFunctionValues, where each value specifies a single operation.
-
-    // Create the new CSSFunctionValue for this operation and add it to our list.
-    RefPtrWillBeRawPtr<CSSFunctionValue> transformValue = CSSFunctionValue::create(type);
-
-    // Snag our values.
-    CSSParserValue* a = args->current();
-    unsigned argNumber = 0;
-    while (a) {
-        CSSPropertyParser::Units unit = info.unit();
-
-        if (type == CSSValueRotate3d && argNumber == 3) {
-            // 4th param of rotate3d() is an angle rather than a bare number, validate it as such
-            if (!validUnit(a, FAngle, HTMLStandardMode))
-                return nullptr;
-        } else if (type == CSSValueTranslate3d && argNumber == 2) {
-            // 3rd param of translate3d() cannot be a percentage
-            if (!validUnit(a, FLength, HTMLStandardMode))
-                return nullptr;
-        } else if (type == CSSValueTranslateZ && !argNumber) {
-            // 1st param of translateZ() cannot be a percentage
-            if (!validUnit(a, FLength, HTMLStandardMode))
-                return nullptr;
-        } else if (type == CSSValuePerspective && !argNumber) {
-            // 1st param of perspective() must be a non-negative number (deprecated) or length.
-            if (!validUnit(a, FLength | FNonNeg, HTMLStandardMode)) {
-                if (useLegacyParsing && validUnit(a, FNumber | FNonNeg, HTMLStandardMode)) {
-                    a->setUnit(CSSPrimitiveValue::UnitType::Pixels);
-                } else {
-                    return nullptr;
-                }
-            }
-        } else if (!validUnit(a, unit, HTMLStandardMode)) {
-            return nullptr;
-        }
-
-        // Add the value to the current transform operation.
-        transformValue->append(createPrimitiveNumericValue(a));
-
-        a = args->next();
-        if (!a)
-            break;
-        if (!isComma(a))
-            return nullptr;
-        a = args->next();
-
-        argNumber++;
-    }
-
-    return transformValue.release();
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.cpp b/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.cpp
index f918c4f..c4a35e0 100644
--- a/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.cpp
@@ -33,6 +33,7 @@
 #include "core/css/CSSPrimitiveValueMappings.h"
 #include "core/css/CSSShadowValue.h"
 #include "core/css/resolver/StyleResolverState.h"
+#include "core/frame/UseCounter.h"
 #include "core/layout/svg/ReferenceFilterBuilder.h"
 #include "core/svg/SVGElement.h"
 #include "core/svg/SVGURIReference.h"
@@ -71,6 +72,52 @@
     }
 }
 
+static void countFilterUse(FilterOperation::OperationType operationType, const Document& document)
+{
+    // This variable is always reassigned, but MSVC thinks it might be left
+    // uninitialized.
+    UseCounter::Feature feature = UseCounter::NumberOfFeatures;
+    switch (operationType) {
+    case FilterOperation::NONE:
+        ASSERT_NOT_REACHED();
+        return;
+    case FilterOperation::REFERENCE:
+        feature = UseCounter::CSSFilterReference;
+        break;
+    case FilterOperation::GRAYSCALE:
+        feature = UseCounter::CSSFilterGrayscale;
+        break;
+    case FilterOperation::SEPIA:
+        feature = UseCounter::CSSFilterSepia;
+        break;
+    case FilterOperation::SATURATE:
+        feature = UseCounter::CSSFilterSaturate;
+        break;
+    case FilterOperation::HUE_ROTATE:
+        feature = UseCounter::CSSFilterHueRotate;
+        break;
+    case FilterOperation::INVERT:
+        feature = UseCounter::CSSFilterInvert;
+        break;
+    case FilterOperation::OPACITY:
+        feature = UseCounter::CSSFilterOpacity;
+        break;
+    case FilterOperation::BRIGHTNESS:
+        feature = UseCounter::CSSFilterBrightness;
+        break;
+    case FilterOperation::CONTRAST:
+        feature = UseCounter::CSSFilterContrast;
+        break;
+    case FilterOperation::BLUR:
+        feature = UseCounter::CSSFilterBlur;
+        break;
+    case FilterOperation::DROP_SHADOW:
+        feature = UseCounter::CSSFilterDropShadow;
+        break;
+    };
+    UseCounter::count(document, feature);
+}
+
 FilterOperations FilterOperationResolver::createFilterOperations(StyleResolverState& state, const CSSValue& inValue)
 {
     FilterOperations operations;
@@ -84,6 +131,7 @@
     for (auto& currValue : toCSSValueList(inValue)) {
         CSSFunctionValue* filterValue = toCSSFunctionValue(currValue.get());
         FilterOperation::OperationType operationType = filterOperationForType(filterValue->functionType());
+        countFilterUse(operationType, state.document());
         ASSERT(filterValue->length() <= 1);
 
         if (operationType == FilterOperation::REFERENCE) {
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index c24eb41..fa6942c 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -5571,17 +5571,7 @@
 
 bool Document::hasFocus() const
 {
-    Page* page = this->page();
-    if (!page)
-        return false;
-    if (!page->focusController().isActive() || !page->focusController().isFocused())
-        return false;
-    Frame* focusedFrame = page->focusController().focusedFrame();
-    if (focusedFrame && focusedFrame->isLocalFrame()) {
-        if (toLocalFrame(focusedFrame)->tree().isDescendantOf(frame()))
-            return true;
-    }
-    return false;
+    return page() && page()->focusController().isDocumentFocused(*this);
 }
 
 #if ENABLE(OILPAN)
diff --git a/third_party/WebKit/Source/core/fetch/InspectorFetchTraceEvents.cpp b/third_party/WebKit/Source/core/fetch/InspectorFetchTraceEvents.cpp
new file mode 100644
index 0000000..2a6dd39
--- /dev/null
+++ b/third_party/WebKit/Source/core/fetch/InspectorFetchTraceEvents.cpp
@@ -0,0 +1,70 @@
+// Copyright 2015 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 "config.h"
+#include "core/fetch/InspectorFetchTraceEvents.h"
+
+#include "bindings/core/v8/ScriptCallStackFactory.h"
+#include "platform/TraceEvent.h"
+#include "platform/TracedValue.h"
+#include "platform/network/ResourceRequest.h"
+#include "platform/network/ResourceResponse.h"
+
+namespace blink {
+
+namespace {
+
+void setCallStack(TracedValue* value)
+{
+    static const unsigned char* traceCategoryEnabled = 0;
+    WTF_ANNOTATE_BENIGN_RACE(&traceCategoryEnabled, "trace_event category");
+    if (!traceCategoryEnabled)
+        traceCategoryEnabled = TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack"));
+    if (!*traceCategoryEnabled)
+        return;
+    RefPtrWillBeRawPtr<ScriptCallStack> scriptCallStack = currentScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture);
+    if (scriptCallStack)
+        scriptCallStack->toTracedValue(value, "stackTrace");
+}
+
+} // namespace
+
+PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorSendRequestEvent::data(unsigned long identifier, const ResourceRequest& request)
+{
+    RefPtr<TracedValue> value = TracedValue::create();
+    value->setString("requestId", String::number(identifier));
+    value->setString("url", request.url().string());
+    value->setString("requestMethod", request.httpMethod());
+    setCallStack(value.get());
+    return value.release();
+}
+
+PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveResponseEvent::data(unsigned long identifier, const ResourceResponse& response)
+{
+    RefPtr<TracedValue> value = TracedValue::create();
+    value->setString("requestId", String::number(identifier));
+    value->setInteger("statusCode", response.httpStatusCode());
+    value->setString("mimeType", response.mimeType().string().isolatedCopy());
+    return value.release();
+}
+
+PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveDataEvent::data(unsigned long identifier, int encodedDataLength)
+{
+    RefPtr<TracedValue> value = TracedValue::create();
+    value->setString("requestId", String::number(identifier));
+    value->setInteger("encodedDataLength", encodedDataLength);
+    return value.release();
+}
+
+PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorResourceFinishEvent::data(unsigned long identifier, double finishTime, bool didFail)
+{
+    RefPtr<TracedValue> value = TracedValue::create();
+    value->setString("requestId", String::number(identifier));
+    value->setBoolean("didFail", didFail);
+    if (finishTime)
+        value->setDouble("networkTime", finishTime);
+    return value.release();
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/fetch/InspectorFetchTraceEvents.h b/third_party/WebKit/Source/core/fetch/InspectorFetchTraceEvents.h
new file mode 100644
index 0000000..3f181f9
--- /dev/null
+++ b/third_party/WebKit/Source/core/fetch/InspectorFetchTraceEvents.h
@@ -0,0 +1,37 @@
+// Copyright 2015 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.
+
+#ifndef InspectorFetchTraceEvents_h
+#define InspectorFetchTraceEvents_h
+
+#include "wtf/PassRefPtr.h"
+
+namespace blink {
+
+class ResourceRequest;
+class ResourceResponse;
+
+namespace TraceEvent {
+class ConvertableToTraceFormat;
+}
+
+namespace InspectorSendRequestEvent {
+PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(unsigned long identifier, const ResourceRequest&);
+}
+
+namespace InspectorReceiveResponseEvent {
+PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(unsigned long identifier, const ResourceResponse&);
+}
+
+namespace InspectorReceiveDataEvent {
+PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(unsigned long identifier, int encodedDataLength);
+}
+
+namespace InspectorResourceFinishEvent {
+PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(unsigned long identifier, double finishTime, bool didFail);
+}
+
+} // namespace blink
+
+#endif // InspectorFetchTraceEvents_h
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
index 9066f81..558b0f7 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
+++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
@@ -31,6 +31,7 @@
 #include "core/fetch/CrossOriginAccessControl.h"
 #include "core/fetch/FetchContext.h"
 #include "core/fetch/FetchInitiatorTypeNames.h"
+#include "core/fetch/InspectorFetchTraceEvents.h"
 #include "core/fetch/MemoryCache.h"
 #include "core/fetch/ResourceLoader.h"
 #include "core/fetch/ResourceLoaderSet.h"
@@ -67,7 +68,7 @@
     SriResourceIntegrityMismatchEventCount
 };
 
-}
+} // namespace
 
 static void RecordSriResourceIntegrityMismatchEvent(SriResourceIntegrityMismatchEvent event)
 {
@@ -338,6 +339,9 @@
 ResourcePtr<Resource> ResourceFetcher::requestResource(FetchRequest& request, const ResourceFactory& factory, const SubstituteData& substituteData)
 {
     ASSERT(request.options().synchronousPolicy == RequestAsynchronously || factory.type() == Resource::Raw || factory.type() == Resource::XSLStyleSheet);
+    unsigned long identifier = createUniqueIdentifier();
+    TRACE_EVENT1("devtools.timeline", "ResourceSendRequest",
+        "data", InspectorSendRequestEvent::data(identifier, request.resourceRequest()));
 
     context().upgradeInsecureRequest(request);
     context().addClientHintsIfNecessary(request);
@@ -407,7 +411,7 @@
         m_deadStatsRecorder.update(policy);
 
     if (policy != Use)
-        resource->setIdentifier(createUniqueIdentifier());
+        resource->setIdentifier(identifier);
 
     if (!request.forPreload() || policy != Use) {
         ResourceLoadPriority priority = loadPriority(factory.type(), request, ResourcePriority::NotVisible);
diff --git a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
index a549bf6..a49167eb 100644
--- a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
+++ b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
@@ -31,12 +31,14 @@
 #include "core/fetch/ResourceLoader.h"
 
 #include "core/fetch/CSSStyleSheetResource.h"
+#include "core/fetch/InspectorFetchTraceEvents.h"
 #include "core/fetch/Resource.h"
 #include "core/fetch/ResourceFetcher.h"
 #include "core/fetch/ResourcePtr.h"
 #include "platform/Logging.h"
 #include "platform/SharedBuffer.h"
 #include "platform/ThreadedDataReceiver.h"
+#include "platform/TraceEvent.h"
 #include "platform/exported/WrappedResourceRequest.h"
 #include "platform/exported/WrappedResourceResponse.h"
 #include "platform/network/ResourceError.h"
@@ -314,6 +316,7 @@
     m_connectionState = ConnectionStateReceivedResponse;
 
     const ResourceResponse& resourceResponse = response.toResourceResponse();
+    TRACE_EVENT1("devtools.timeline", "ResourceReceiveResponse", "data", InspectorReceiveResponseEvent::data(m_resource->identifier(), resourceResponse));
 
     if (responseNeedsAccessControlCheck()) {
         if (response.wasFetchedViaServiceWorker()) {
@@ -392,6 +395,7 @@
 {
     ASSERT(m_state != Terminated);
     RELEASE_ASSERT(m_connectionState == ConnectionStateReceivedResponse || m_connectionState == ConnectionStateReceivingData);
+    TRACE_EVENT1("devtools.timeline", "ResourceReceivedData", "data", InspectorReceiveDataEvent::data(m_resource->identifier(), encodedDataLength));
     m_connectionState = ConnectionStateReceivingData;
 
     // It is possible to receive data on uninitialized resources if it had an error status code, and we are running a nested message
@@ -413,6 +417,7 @@
 void ResourceLoader::didFinishLoading(WebURLLoader*, double finishTime, int64_t encodedDataLength)
 {
     RELEASE_ASSERT(m_connectionState == ConnectionStateReceivedResponse || m_connectionState == ConnectionStateReceivingData);
+    TRACE_EVENT1("devtools.timeline", "ResourceFinish", "data", InspectorResourceFinishEvent::data(m_resource->identifier(), finishTime, false));
     m_connectionState = ConnectionStateFinishedLoading;
     if (m_state != Initialized)
         return;
@@ -436,6 +441,7 @@
 
 void ResourceLoader::didFail(WebURLLoader*, const WebURLError& error)
 {
+    TRACE_EVENT1("devtools.timeline", "ResourceFinish", "data", InspectorResourceFinishEvent::data(m_resource->identifier(), 0, true));
     m_connectionState = ConnectionStateFailed;
     ASSERT(m_state != Terminated);
     WTF_LOG(ResourceLoading, "Failed to load '%s'.\n", m_resource->url().string().latin1().data());
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index d240ffb..afc2599 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -788,7 +788,7 @@
         PresentationRequestReconnect = 930,
         PresentationRequestGetAvailability = 931,
         PresentationRequestConnectionAvailableEventListener = 932,
-        PresentationConnectionClose = 933,
+        PresentationConnectionTerminate = 933,
         PresentationConnectionSend = 934,
         PresentationConnectionStateChangeEventListener = 935,
         PresentationConnectionMessageEventListener = 936,
@@ -873,6 +873,17 @@
         SelectionDeleteDromDocument = 1011,
         SelectionDOMString = 1012,
         InputTypeRangeVerticalAppearance = 1013,
+        CSSFilterReference = 1014,
+        CSSFilterGrayscale = 1015,
+        CSSFilterSepia = 1016,
+        CSSFilterSaturate = 1017,
+        CSSFilterHueRotate = 1018,
+        CSSFilterInvert = 1019,
+        CSSFilterOpacity = 1020,
+        CSSFilterBrightness = 1021,
+        CSSFilterContrast = 1022,
+        CSSFilterBlur = 1023,
+        CSSFilterDropShadow = 1024,
 
         // Add new features immediately above this line. Don't change assigned
         // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
index a552cb1..6cd1c1e 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
@@ -836,12 +836,14 @@
     getNamedElements(name, elements);
     ASSERT(!elements.isEmpty());
 
+    bool onlyMatchImg = !elements.isEmpty() && isHTMLImageElement(*elements.first());
+    if (onlyMatchImg)
+        UseCounter::count(document(), UseCounter::FormNameAccessForImageElement);
     if (elements.size() == 1) {
         returnValue.setElement(elements.at(0));
         return;
     }
 
-    bool onlyMatchImg = !elements.isEmpty() && isHTMLImageElement(*elements.first());
     returnValue.setRadioNodeList(radioNodeList(name, onlyMatchImg));
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
index 0b7711bc..817c18f 100644
--- a/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSelectElement.cpp
@@ -66,6 +66,7 @@
 #include "core/page/SpatialNavigation.h"
 #include "platform/PlatformMouseEvent.h"
 #include "platform/PopupMenu.h"
+#include "platform/TraceEvent.h"
 #include "platform/text/PlatformLocale.h"
 
 using namespace WTF::Unicode;
@@ -797,6 +798,7 @@
 
 void HTMLSelectElement::recalcListItems(bool updateSelectedStates) const
 {
+    TRACE_EVENT0("blink", "HTMLSelectElement::recalcListItems");
     m_listItems.clear();
 
     m_shouldRecalcListItems = false;
@@ -962,6 +964,7 @@
 // operations.
 void HTMLSelectElement::selectOption(int optionIndex, SelectOptionFlags flags)
 {
+    TRACE_EVENT0("blink", "HTMLSelectElement::selectOption");
     bool shouldDeselect = !m_multiple || (flags & DeselectOtherOptions);
 
     const WillBeHeapVector<RawPtrWillBeMember<HTMLElement>>& items = listItems();
diff --git a/third_party/WebKit/Source/core/html/HTMLTextFormControlElement.cpp b/third_party/WebKit/Source/core/html/HTMLTextFormControlElement.cpp
index 9f9c354c..bdeecb0 100644
--- a/third_party/WebKit/Source/core/html/HTMLTextFormControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTextFormControlElement.cpp
@@ -237,11 +237,6 @@
         text.insert(replacement, start);
 
     setInnerEditorValue(text);
-
-    // FIXME: What should happen to the value (as in value()) if there's no layoutObject?
-    if (!layoutObject())
-        return;
-
     subtreeHasChanged();
 
     if (selectionMode == "select") {
@@ -351,16 +346,15 @@
 
 void HTMLTextFormControlElement::setSelectionRange(int start, int end, TextFieldSelectionDirection direction, NeedToDispatchSelectEvent eventBehaviour, SelectionOption selectionOption)
 {
-    if (openShadowRoot() || !isTextFormControl() || !inDocument())
+    if (openShadowRoot() || !isTextFormControl())
         return;
-
     const int editorValueLength = static_cast<int>(innerEditorValue().length());
     ASSERT(editorValueLength >= 0);
     end = std::max(std::min(end, editorValueLength), 0);
     start = std::min(std::max(start, 0), end);
     cacheSelection(start, end, direction);
 
-    if (selectionOption == NotChangeSelection || (selectionOption == ChangeSelectionIfFocused && document().focusedElement() != this)) {
+    if (selectionOption == NotChangeSelection || (selectionOption == ChangeSelectionIfFocused && document().focusedElement() != this) || !inDocument()) {
         if (eventBehaviour == DispatchSelectEvent)
             scheduleSelectEvent();
         return;
diff --git a/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp b/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
index 849905f..f32305b 100644
--- a/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
@@ -486,8 +486,6 @@
 
 void TextFieldInputType::subtreeHasChanged()
 {
-    ASSERT(element().layoutObject());
-
     bool wasChanged = element().wasChangedSinceLastFormControlChangeEvent();
     element().setChangedSinceLastFormControlChangeEvent(true);
 
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
index 5ae1bf1..c508491 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControls.cpp
@@ -260,13 +260,6 @@
     m_fullScreenButton->setIsWanted(shouldShowFullscreenButton(mediaElement()));
 
     refreshCastButtonVisibilityWithoutUpdate();
-
-    // Set the panel width here, and force a layout, before the controls update.
-    // This would be harmless for the !useNewUi case too, but it causes
-    // compositing/geometry/video-fixed-scrolling.html to fail with two extra
-    // 0 height nodes in the render tree.
-    if (useNewUi)
-        m_panelWidth = m_panel->clientWidth();
 }
 
 LayoutObject* MediaControls::layoutObjectForTextTrackLayout()
@@ -652,9 +645,6 @@
     if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled())
         return;
 
-    if (!m_panelWidth)
-        return;
-
     // Controls that we'll hide / show, in order of decreasing priority.
     MediaControlElement* elements[] = {
         m_playButton.get(),
@@ -668,6 +658,18 @@
         m_durationDisplay.get(),
     };
 
+    if (!m_panelWidth) {
+        // No layout yet -- hide everything, then make them show up later.
+        // This prevents the wrong controls from being shown briefly
+        // immediately after the first layout and paint, but before we have
+        // a chance to revise them.
+        for (MediaControlElement* element : elements) {
+            if (element)
+                element->setDoesFit(false);
+        }
+        return;
+    }
+
     int usedWidth = 0;
     bool droppedCastButton = false;
     // Assume that all controls require 48px.  Ideally, we could get this
diff --git a/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp b/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
index 31a29ae..fb0c417 100644
--- a/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/MediaControlsTest.cpp
@@ -11,6 +11,7 @@
 #include "core/dom/ElementTraversal.h"
 #include "core/html/HTMLVideoElement.h"
 #include "core/testing/DummyPageHolder.h"
+#include "platform/heap/Handle.h"
 #include <gtest/gtest.h>
 
 namespace blink {
@@ -56,17 +57,18 @@
     virtual void SetUp()
     {
         m_pageHolder = DummyPageHolder::create(IntSize(800, 600));
-        Document& document = m_pageHolder->document();
+        Document& document = this->document();
         document.write("<video controls>");
         HTMLVideoElement& video = toHTMLVideoElement(*document.querySelector("video", ASSERT_NO_EXCEPTION));
         m_mediaControls = video.mediaControls();
     }
 
     MediaControls& mediaControls() { return *m_mediaControls; }
+    Document& document() { return m_pageHolder->document(); }
 
 private:
     OwnPtr<DummyPageHolder> m_pageHolder;
-    MediaControls* m_mediaControls;
+    RawPtrWillBePersistent<MediaControls> m_mediaControls;
 };
 
 TEST_F(MediaControlsTest, HideAndShow)
@@ -103,4 +105,15 @@
     ASSERT_FALSE(isElementVisible(*panel));
 }
 
+TEST_F(MediaControlsTest, ResetDoesNotTriggerInitialLayout)
+{
+    Document& document = this->document();
+    int oldResolverCount = document.styleEngine().resolverAccessCount();
+    // Also assert that there are no layouts yet.
+    ASSERT_EQ(0, oldResolverCount);
+    mediaControls().reset();
+    int newResolverCount = document.styleEngine().resolverAccessCount();
+    ASSERT_EQ(oldResolverCount, newResolverCount);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
index 26fff39f..62ff7b5 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorAnimationAgent.cpp
@@ -304,6 +304,8 @@
     if (!animation)
         return;
 
+    animation = animationClone(animation);
+
     AnimationType type = m_idToAnimationType.get(animationId);
     if (type == AnimationType::CSSTransition) {
         KeyframeEffect* effect = toKeyframeEffect(animation->effect());
@@ -323,7 +325,7 @@
         UnrestrictedDoubleOrString unrestrictedDuration;
         unrestrictedDuration.setUnrestrictedDouble(duration + delay);
         timing->setDuration(unrestrictedDuration);
-    } else if (type == AnimationType::WebAnimation) {
+    } else {
         AnimationEffectTiming* timing = animation->effect()->timing();
         UnrestrictedDoubleOrString unrestrictedDuration;
         unrestrictedDuration.setUnrestrictedDouble(duration);
@@ -398,12 +400,12 @@
     }
 
     Element* element = effect->target();
-    RefPtrWillBeRawPtr<CSSRuleList> ruleList = m_cssAgent->matchedRulesList(element);
+    WillBeHeapVector<RefPtrWillBeMember<CSSStyleDeclaration>> styles = m_cssAgent->matchingStyles(element);
     OwnPtr<WebCryptoDigestor> digestor = createDigestor(HashAlgorithmSha1);
     addStringToDigestor(digestor.get(), String::number(type));
     addStringToDigestor(digestor.get(), effect->name());
     for (CSSPropertyID property : cssProperties) {
-        RefPtrWillBeRawPtr<CSSStyleDeclaration> style = m_cssAgent->findEffectiveDeclaration(property, ruleList.get(), element->style());
+        RefPtrWillBeRawPtr<CSSStyleDeclaration> style = m_cssAgent->findEffectiveDeclaration(property, styles);
         // Ignore inline styles.
         if (!style || !style->parentStyleSheet() || !style->parentRule() || style->parentRule()->type() != CSSRule::STYLE_RULE)
             continue;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
index 4c39e02..22564014 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.cpp
@@ -113,29 +113,19 @@
     return style->getPropertyValue(shorthand);
 }
 
-PassRefPtrWillBeRawPtr<CSSRuleList> filterDuplicateRules(RefPtrWillBeRawPtr<CSSRuleList> ruleList)
+WillBeHeapVector<RefPtrWillBeMember<CSSStyleRule>> filterDuplicateRules(RefPtrWillBeRawPtr<CSSRuleList> ruleList)
 {
-    RefPtrWillBeRawPtr<StaticCSSRuleList> uniqRuleList = StaticCSSRuleList::create();
-    if (!ruleList)
-        return uniqRuleList.release();
-
-    WillBeHeapHashSet<RawPtrWillBeMember<CSSStyleRule>> uniqRulesSet;
-    WillBeHeapVector<RefPtrWillBeMember<CSSRule>> uniqRules;
-    for (unsigned i = ruleList->length(); i > 0; --i) {
+    WillBeHeapVector<RefPtrWillBeMember<CSSStyleRule>> uniqRules;
+    WillBeHeapHashSet<RawPtrWillBeMember<CSSRule>> uniqRulesSet;
+    for (unsigned i = ruleList ? ruleList->length() : 0; i > 0; --i) {
         CSSRule* rule = ruleList->item(i - 1);
-        if (!rule || rule->type() != CSSRule::STYLE_RULE)
+        if (!rule || rule->type() != CSSRule::STYLE_RULE || uniqRulesSet.contains(rule))
             continue;
-
-        CSSStyleRule* styleRule = toCSSStyleRule(rule);
-        if (uniqRulesSet.contains(styleRule))
-            continue;
-        uniqRulesSet.add(styleRule);
-        uniqRules.append(styleRule);
+        uniqRulesSet.add(rule);
+        uniqRules.append(toCSSStyleRule(rule));
     }
-
-    for (unsigned i = uniqRules.size(); i > 0; --i)
-        uniqRuleList->rules().append(uniqRules[i - 1]);
-    return uniqRuleList.release();
+    uniqRules.reverse();
+    return uniqRules;
 }
 
 // Get the elements which overlap the given rectangle.
@@ -1643,10 +1633,9 @@
     if (!ruleList)
         return result.release();
 
-    RefPtrWillBeRawPtr<CSSRuleList> uniqRules = filterDuplicateRules(ruleList);
-
-    for (unsigned i = 0; i < uniqRules->length(); ++i) {
-        CSSStyleRule* rule = asCSSStyleRule(uniqRules->item(i));
+    WillBeHeapVector<RefPtrWillBeMember<CSSStyleRule>> uniqRules = filterDuplicateRules(ruleList);
+    for (unsigned i = 0; i < uniqRules.size(); ++i) {
+        CSSStyleRule* rule = uniqRules.at(i).get();
         RefPtr<TypeBuilder::CSS::CSSRule> ruleObject = buildObjectForRule(rule);
         if (!ruleObject)
             continue;
@@ -1768,63 +1757,46 @@
         document->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Inspector));
 }
 
-PassRefPtrWillBeRawPtr<CSSRuleList> InspectorCSSAgent::matchedRulesList(Element* element)
+WillBeHeapVector<RefPtrWillBeMember<CSSStyleDeclaration>> InspectorCSSAgent::matchingStyles(Element* element)
 {
-    PseudoId elementPseudoId = element->pseudoId();
-    if (elementPseudoId) {
-        element = element->parentOrShadowHostElement();
-        if (!element)
-            return nullptr;
-    }
-
-    Document* ownerDocument = element->ownerDocument();
-    // A non-active document has no styles.
-    if (!ownerDocument->isActive())
-        return nullptr;
-
-    StyleResolver& styleResolver = ownerDocument->ensureStyleResolver();
+    PseudoId pseudoId = element->pseudoId();
+    if (pseudoId)
+        element = element->parentElement();
+    StyleResolver& styleResolver = element->ownerDocument()->ensureStyleResolver();
     element->updateDistribution();
-    return filterDuplicateRules(styleResolver.pseudoCSSRulesForElement(element, elementPseudoId, StyleResolver::AllCSSRules));
+
+    WillBeHeapVector<RefPtrWillBeMember<CSSStyleRule>> rules = filterDuplicateRules(styleResolver.pseudoCSSRulesForElement(element, pseudoId, StyleResolver::AllCSSRules));
+    WillBeHeapVector<RefPtrWillBeMember<CSSStyleDeclaration>> styles;
+    if (element->style())
+        styles.append(element->style());
+    for (unsigned i = rules.size(); i > 0; --i) {
+        CSSStyleSheet* parentStyleSheet = rules.at(i - 1)->parentStyleSheet();
+        if (!parentStyleSheet || !parentStyleSheet->ownerNode())
+            continue; // User agent.
+        styles.append(rules.at(i - 1)->style());
+    }
+    return styles;
 }
 
-PassRefPtrWillBeRawPtr<CSSStyleDeclaration> InspectorCSSAgent::findEffectiveDeclaration(CSSPropertyID propertyId, CSSRuleList* ruleList, CSSStyleDeclaration* inlineStyle)
+PassRefPtrWillBeRawPtr<CSSStyleDeclaration> InspectorCSSAgent::findEffectiveDeclaration(CSSPropertyID propertyId, const WillBeHeapVector<RefPtrWillBeMember<CSSStyleDeclaration>>& styles)
 {
-    if (!ruleList && !inlineStyle)
+    if (!styles.size())
         return nullptr;
 
     String longhand = getPropertyNameString(propertyId);
     RefPtrWillBeRawPtr<CSSStyleDeclaration> foundStyle = nullptr;
-    bool isImportant = false;
 
-    if (inlineStyle && !inlineStyle->getPropertyValue(longhand).isEmpty()) {
-        foundStyle = inlineStyle;
-        isImportant = inlineStyle->getPropertyPriority(longhand) == "important";
-    }
-
-    for (unsigned i = 0, size = ruleList ? ruleList->length() : 0; i < size; ++i) {
-        if (isImportant)
-            break;
-
-        if (ruleList->item(size - i - 1)->type() != CSSRule::STYLE_RULE)
-            continue;
-
-        CSSStyleRule* rule = toCSSStyleRule(ruleList->item(size - i - 1));
-        if (!rule)
-            continue;
-
-        CSSStyleDeclaration* style = rule->style();
-        if (!style)
-            continue;
-
+    for (unsigned i = 0; i < styles.size(); ++i) {
+        CSSStyleDeclaration* style = styles.at(i).get();
         if (style->getPropertyValue(longhand).isEmpty())
             continue;
-
-        isImportant = style->getPropertyPriority(longhand) == "important";
-        if (isImportant || !foundStyle)
+        if (style->getPropertyPriority(longhand) == "important")
+            return style;
+        if (!foundStyle)
             foundStyle = style;
     }
 
-    return foundStyle.release();
+    return foundStyle ? foundStyle.get() : styles.at(0).get();
 }
 
 void InspectorCSSAgent::setCSSPropertyValue(ErrorString* errorString, Element* element, RefPtrWillBeRawPtr<CSSStyleDeclaration> style, CSSPropertyID propertyId, const String& value, bool forceImportant)
@@ -1907,7 +1879,7 @@
 {
     // TODO: move testing from CSSAgent to layout editor.
     Element* element = elementForId(errorString, nodeId);
-    if (!element)
+    if (!element || element->pseudoId())
         return;
 
     CSSPropertyID property = cssPropertyID(propertyName);
@@ -1923,18 +1895,13 @@
     }
 
     CSSPropertyID propertyId = cssPropertyID(propertyName);
-    CSSStyleDeclaration* inlineStyle = element->style();
-    RefPtrWillBeRawPtr<CSSRuleList> ruleList = matchedRulesList(element);
-    RefPtrWillBeRawPtr<CSSStyleDeclaration> foundStyle = findEffectiveDeclaration(propertyId, ruleList.get(), inlineStyle);
-    if (!foundStyle || !foundStyle->parentStyleSheet())
-        foundStyle = inlineStyle;
-
-    if (!foundStyle) {
+    RefPtrWillBeRawPtr<CSSStyleDeclaration> style = findEffectiveDeclaration(propertyId, matchingStyles(element));
+    if (!style) {
         *errorString = "Can't find a style to edit";
         return;
     }
 
-    setCSSPropertyValue(errorString, element, foundStyle.get(), propertyId, value);
+    setCSSPropertyValue(errorString, element, style.get(), propertyId, value);
 }
 
 void InspectorCSSAgent::getBackgroundColors(ErrorString* errorString, int nodeId, RefPtr<TypeBuilder::Array<String>>& result)
diff --git a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
index 996dbc1..0d9b5de 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorCSSAgent.h
@@ -150,10 +150,10 @@
     PassRefPtr<TypeBuilder::CSS::CSSMedia> buildMediaObject(const MediaList*, MediaListSource, const String&, CSSStyleSheet*);
     PassRefPtr<TypeBuilder::Array<TypeBuilder::CSS::CSSMedia> > buildMediaListChain(CSSRule*);
 
-    PassRefPtrWillBeRawPtr<CSSStyleDeclaration> findEffectiveDeclaration(CSSPropertyID, CSSRuleList* matchedRulesList, CSSStyleDeclaration* inlineStyle);
+    PassRefPtrWillBeRawPtr<CSSStyleDeclaration> findEffectiveDeclaration(CSSPropertyID, const WillBeHeapVector<RefPtrWillBeMember<CSSStyleDeclaration>>& styles);
     void setCSSPropertyValue(ErrorString*, Element*, RefPtrWillBeRawPtr<CSSStyleDeclaration>, CSSPropertyID, const String& value, bool forceImportant = false);
 
-    PassRefPtrWillBeRawPtr<CSSRuleList> matchedRulesList(Element*);
+    WillBeHeapVector<RefPtrWillBeMember<CSSStyleDeclaration>> matchingStyles(Element*);
     String styleSheetId(CSSStyleSheet*);
 private:
     class StyleSheetAction;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.cpp
index 86d58872..fae4fff7 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.cpp
@@ -37,7 +37,6 @@
 #include "core/inspector/ScriptAsyncCallStack.h"
 #include "core/inspector/v8/V8Debugger.h"
 #include "platform/ScriptForbiddenScope.h"
-#include "wtf/Optional.h"
 
 namespace blink {
 
@@ -187,9 +186,9 @@
 
 void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const String& inCallFrameId, const String& inExpression, const String* inObjectGroup, const bool* inIncludeCommandLineAPI, const bool* inDoNotPauseOnExceptionsAndMuteConsole, const bool* inReturnByValue, const bool* inGeneratePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>& outResult, TypeBuilder::OptOutput<bool>* optOutWasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>& optOutExceptionDetails)
 {
-    Optional<MuteConsoleScope<InspectorDebuggerAgent>> muteScope;
+    MuteConsoleScope<InspectorDebuggerAgent> muteScope;
     if (asBool(inDoNotPauseOnExceptionsAndMuteConsole))
-        muteScope.emplace(this);
+        muteScope.enter(this);
     m_v8DebuggerAgent->evaluateOnCallFrame(errorString, inCallFrameId, inExpression, inObjectGroup, inIncludeCommandLineAPI, inDoNotPauseOnExceptionsAndMuteConsole, inReturnByValue, inGeneratePreview, outResult, optOutWasThrown, optOutExceptionDetails);
 }
 
@@ -200,9 +199,9 @@
 
 void InspectorDebuggerAgent::runScript(ErrorString* errorString, const String& inScriptId, int inExecutionContextId, const String* inObjectGroup, const bool* inDoNotPauseOnExceptionsAndMuteConsole, RefPtr<TypeBuilder::Runtime::RemoteObject>& outResult, RefPtr<TypeBuilder::Debugger::ExceptionDetails>& optOutExceptionDetails)
 {
-    Optional<MuteConsoleScope<InspectorDebuggerAgent>> muteScope;
+    MuteConsoleScope<InspectorDebuggerAgent> muteScope;
     if (asBool(inDoNotPauseOnExceptionsAndMuteConsole))
-        muteScope.emplace(this);
+        muteScope.enter(this);
     m_v8DebuggerAgent->runScript(errorString, inScriptId, inExecutionContextId, inObjectGroup, inDoNotPauseOnExceptionsAndMuteConsole, outResult, optOutExceptionDetails);
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorOverlayPage.html b/third_party/WebKit/Source/core/inspector/InspectorOverlayPage.html
index 4f473b03..6349c8c 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorOverlayPage.html
+++ b/third_party/WebKit/Source/core/inspector/InspectorOverlayPage.html
@@ -61,7 +61,7 @@
     background-color: rgba(0, 0, 0, 0.31);
 }
 
-#canvas, #labels-canvas, #layout-editor-matched-nodes-canvas {
+#canvas, #layout-editor-matched-nodes-canvas {
     pointer-events: none;
 }
 
@@ -146,12 +146,216 @@
     color: rgb(153, 69, 0);
 }
 
-.editor-anchor {
-    height: 12px;
-    width: 12px;
+.wall {
+    position: absolute;
+    z-index: -2;
+    opacity: 0.2;
+    pointer-events: none;
+}
+
+.wall.horizontal {
+    width: 8px;
+    height: 16px;
+}
+
+.wall.vertical {
+    height: 8px;
+    width: 16px;
+}
+
+.wall.padding {
+    background: repeating-linear-gradient(45deg, #FFFFFF 2px, #FFFFFF 4px, rgba(147, 196, 125, 1) 2px, rgba(147, 196, 125, 1) 10px)
+
+}
+
+.wall.margin {
+    background: repeating-linear-gradient(45deg, #FFFFFF 2px, #FFFFFF 4px, rgba(246, 178, 107, 1) 4px, rgba(246, 178, 107, 1) 10px)
+}
+
+.wall.highlighted {
+    z-index: 1;
+    opacity: 1;
+}
+
+.blur-rect {
+    position: absolute;
+    background-color: rgba(0, 0, 0, 0.1);
+}
+
+.control-lane {
     position: absolute;
 }
 
+.control-lane.padding {
+    background-color: rgba(147, 196, 125, 0.1);
+}
+
+.control-lane.margin {
+    background-color: rgba(246, 178, 107, 0.1);
+}
+
+.editor-anchor {
+    position: absolute;
+    -webkit-filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.34));
+}
+
+.editor-anchor.vertical {
+    height: 6px;
+    width: 16px;
+}
+
+.editor-anchor.horizontal {
+    width: 6px;
+    height: 16px;
+}
+
+.editor-anchor.horizontal::before {
+    content: "";
+    position: absolute;
+    height: 8px;
+    border-right: 2px dotted rgba(255, 255, 255, 0.4);
+    top: 4px;
+    left: 2px;
+}
+
+.editor-anchor.vertical::before {
+    content: "";
+    position: absolute;
+    width: 8px;
+    border-right: 2px dotted rgba(255, 255, 255, 0.4);
+    top: 2px;
+    left: 4px;
+}
+
+.editor-anchor.vertical:hover {
+    cursor: ns-resize;
+}
+
+.editor-anchor.horizontal:hover {
+    cursor: ew-resize;
+}
+
+.editor-anchor.padding {
+    background-color: rgb(107, 213, 0);
+}
+
+.editor-anchor.margin {
+    background-color: rgb(246, 167, 35);
+}
+
+.editor-anchor:hover {
+    z-index: 3;
+}
+
+.editor-anchor.padding.highlighted {
+    background-color: rgba(147, 196, 125, 1);
+}
+
+.editor-anchor.margin.highlighted {
+    background-color: rgba(246, 178, 107, 1);
+}
+
+.guide-line.horizontal {
+    border-top: dashed 1px;
+}
+
+.guide-line.vertical {
+    border-left: dashed 1px;
+}
+
+.guide-line.padding {
+    border-color: rgba(147, 196, 125, 0.56);
+}
+
+.guide-line.margin {
+    border-color: rgba(246, 178, 107, 0.56);
+}
+
+.guide-line.content {
+    border-color: rgba(147, 147, 147, 0.56)
+}
+
+.guide-line {
+    position: absolute;
+    pointer-events: none;
+}
+
+.label {
+    position: absolute;
+    font-size: 10px;
+    font-family: Arial, Roboto;
+    color: white;
+    line-height: 1em;
+    padding: 2px 5px;
+    -webkit-filter: drop-shadow(0px 1px 1px rgba(0, 0, 0, 0.34));
+    border-radius: 2px;
+    min-width: 30px;
+    z-index: 5;
+}
+
+.label.padding {
+    background-color: rgb(91, 181, 0);
+}
+
+.label.margin {
+    background-color: rgb(246, 167, 35);
+}
+
+.label.disabled {
+    background-color: rgb(159, 188, 191);
+}
+
+.label .dimension {
+    color: rgba(255, 255, 255, 0.7);
+}
+
+.label .name {
+    color: rgba(255, 255, 255, 0.7);
+    display: none;
+    border-radius: 4px;
+}
+
+.label.full .name {
+    display: inline;
+    z-index: 5;
+}
+
+.label::before {
+    content: '';
+    display: block;
+    position: absolute;
+    width: 0;
+    height: 0;
+    border-top: 6px solid transparent;
+    border-bottom: 6px solid transparent;
+    top: 1px;
+}
+
+.label.right-arrow::before {
+    border-left-width: 6px;
+    border-left-style: solid;
+    border-right: none;
+    left: auto;
+    right: -6px;
+}
+
+.label.left-arrow::before {
+    border-left: none;
+    border-right-width: 6px;
+    border-right-style: solid;
+    left: -6px;
+    right: auto;
+}
+
+.label.padding::before {
+    border-left-color: rgb(91, 181, 0);
+    border-right-color: rgb(91, 181, 0);
+}
+
+.label.margin::before {
+    border-left-color: rgb(246, 167, 35);
+    border-right-color: rgb(246, 167, 35);
+}
 
 /* Material */
 .hidden {
@@ -179,6 +383,7 @@
     background-clip: padding-box;
     will-change: transform;
     text-rendering: optimizeLegibility;
+    pointer-events: none;
 }
 
 .element-info {
@@ -449,7 +654,6 @@
     document.body.classList.remove("dimmed");
 
     window._gridPainted = false;
-    delete window.hoverableAreas;
 
     if (window.layoutEditor)
         window.layoutEditor.reset();
@@ -727,11 +931,9 @@
 
     var bounds = emptyBounds();
 
-    var areasDescription = new Map();
     for (var paths = highlight.paths.slice(); paths.length;) {
         var path = paths.pop();
-        var canvasPath = drawPath(context, path.path, path.fillColor, path.outlineColor, bounds);
-        areasDescription.set(path.name, canvasPath);
+        drawPath(context, path.path, path.fillColor, path.outlineColor, bounds);
         if (paths.length) {
             context.save();
             context.globalCompositeOperation = "destination-out";
@@ -757,7 +959,7 @@
     }
     context.restore();
 
-    return { areasDescription: areasDescription, bounds: bounds };
+    return { bounds: bounds };
 }
 
 function setPlatform(platform)
@@ -811,7 +1013,7 @@
 function showLayoutEditor(info)
 {
     if (!window.layoutEditor)
-        window.layoutEditor = new LayoutEditor(canvas);
+        window.layoutEditor = new LayoutEditor();
 
     window.layoutEditor.setState(info);
 }
@@ -824,88 +1026,387 @@
     window.layoutEditor.setSelector(selectorInfo);
 }
 
-function LayoutEditor(mainCanvas)
+/**
+ * @constructor
+ */
+function LayoutEditor()
 {
     this._boundConsumeEvent = this._consumeEvent.bind(this);
-    this._boundMouseMove = this._onMouseMove.bind(this);
     this._boundStrayClick = this._onStrayClick.bind(this);
     this._boundKeyDown = this._onKeyDown.bind(this);
     this._boundMouseWheel = this._onMouseWheel.bind(this);
 
-    this._anchorsByType = new Map();
-    this._hoverableAreas = new Map();
-    this._elementsBounds = emptyBounds();
-    this._editorElement = document.getElementById("editor");
+    this._paddingBounds = this._defaultBounds();
+    this._contentBounds = this._defaultBounds();
+    this._marginBounds = this._defaultBounds();
+    this._element = document.getElementById("editor");
+    this._editorElement = this._element.createChild("div");
+    this._selectorTooltipElement = this._element.createChild("div", "selector-tooltip-element");
     this._matchedNodesCanvas = createCanvas("layout-editor-matched-nodes-canvas");
-    mainCanvas.parentElement.insertBefore(this._matchedNodesCanvas, mainCanvas);
+    this._editorElement.parentElement.insertBefore(this._matchedNodesCanvas, this._editorElement);
 
-    this._labelsCanvas = createCanvas("labels-canvas");
-    mainCanvas.parentElement.insertBefore(this._labelsCanvas, mainCanvas.nextSibling);
-    this._mainContext = mainCanvas.getContext("2d");
+    this._wallsElements = new Map();
+    this._labelsElements = new Map();
+    this._anchorsElements = new Map();
+    this._anchorsInfo = new Map();
 }
 
+/**
+ * @typedef {{
+ *      type: string,
+ *      propertyName: number,
+ *      propertyValue: {value: number, unit: string, growInside: boolean, mutable: boolean}
+ * }}
+ */
+LayoutEditor.AnchorInfo;
+
+/**
+ * @typedef {{
+ *      left: number,
+ *      top: number,
+ *      right: number,
+ *      bottom: number
+ * }}
+ */
+LayoutEditor.Bounds;
+
+/**
+ * @typedef {{
+ *      orientation: string,
+ *      border1: string,
+ *      border2: string,
+ *      dimension1: string,
+ *      dimension2: string
+ * }}
+ */
+LayoutEditor.Bounds;
+
+/**
+ * @typedef {{
+ *      p1: !Point,
+ *      p2: !Point,
+ *      p3: !Point,
+ *      p4: !Point
+ * }}
+ */
+LayoutEditor.Quad;
+
+/**
+ * @typedef {{
+ *      contentQuad: !LayoutEditor.Quad,
+ *      marginQuad: !LayoutEditor.Quad,
+ *      paddingQuad: !LayoutEditor.Quad,
+ *      anchors: !Array.<!LayoutEditor.AnchorInfo>
+ * }}
+ */
+LayoutEditor.Info;
+
+LayoutEditor._controlLaneWidth = 16;
+LayoutEditor._wallWidth = 8;
+LayoutEditor._handleWidth = 8;
+LayoutEditor._labelOffset = 12;
+
 LayoutEditor.prototype = {
+    /**
+     * @return {!LayoutEditor.Bounds}
+     */
+    _defaultBounds: function ()
+    {
+        var bounds = {
+            left: Number.MAX_VALUE,
+            top: Number.MAX_VALUE,
+            right: Number.MIN_VALUE,
+            bottom: Number.MIN_VALUE,
+        };
+        return bounds;
+    },
+
     reset: function()
     {
-        this._anchorsByType.clear();
-        this._hoverableAreas.clear();
-        this._elementsBounds = emptyBounds();
+        this._anchorsInfo.clear();
+        this._anchorsElements.clear();
+        this._wallsElements.clear();
+        this._labelsElements.clear();
+        this._paddingBounds = this._defaultBounds();
+        this._contentBounds = this._defaultBounds();
+        this._marginBounds = this._defaultBounds();
 
         resetCanvas(this._matchedNodesCanvas);
-        this._resetLabelCanvas();
+        document.body.style.cursor = "";
 
-        this._editorElement.style.visibility = "hidden";
-        this._editorElement.textContent = "";
-
-        if (this._selectorTooltipElement) {
-            this._selectorTooltipElement.remove();
-            delete this._selectorTooltipElement;
-        }
+        this._editorElement.removeChildren();
+        this._selectorTooltipElement.removeChildren();
 
         document.removeEventListener("mousedown", this._boundConsumeEvent);
-        document.removeEventListener("mousemove", this._boundMouseMove);
         document.removeEventListener("mouseup", this._boundConsumeEvent);
         document.removeEventListener("click", this._boundStrayClick);
         document.removeEventListener("keydown", this._boundKeyDown);
         document.removeEventListener("mousewheel", this._boundMouseWheel);
+        document.removeEventListener("mousemove", this._boundConsumeEvent);
     },
 
+    /**
+     * @param {!LayoutEditor.Info} info
+     */
     setState: function(info)
     {
-        var highlightDescription = drawHighlight(info.nodeHighlight, this._mainContext);
-        this._hoverableAreas = highlightDescription.areasDescription;
-        this._elementsBounds = highlightDescription.bounds;
-
         this._editorElement.style.visibility = "visible";
-        var anchors = info.anchors;
-        this._anchorsByType.clear();
-        var selectedAnchorInfo = null;
-        for (var i = 0; i < anchors.length; ++i) {
-            var anchorInfo = anchors[i];
-            if (!this._anchorsByType.get(anchorInfo.type))
-                this._anchorsByType.set(anchorInfo.type, []);
-            this._anchorsByType.get(anchorInfo.type).push(anchorInfo);
-            this._editorElement.appendChild(this._createAnchor(anchorInfo));
-            if (anchorInfo.propertyName === this._draggedPropertyName)
-                selectedAnchorInfo = anchorInfo;
+
+        function buildBounds(quad)
+        {
+            var bounds = this._defaultBounds();
+            for (var i = 1; i <= 4; ++i) {
+                var point = quad["p" + i];
+                bounds.left = Math.min(bounds.left, point.x);
+                bounds.right = Math.max(bounds.right, point.x);
+                bounds.top = Math.min(bounds.top, point.y);
+                bounds.bottom = Math.max(bounds.bottom, point.y);
+            }
+            return bounds;
         }
 
-        if (selectedAnchorInfo)
-            this._showLabels(selectedAnchorInfo.type, selectedAnchorInfo.propertyName);
+        this._contentBounds = buildBounds.call(this, info.contentQuad);
+        this._paddingBounds = buildBounds.call(this, info.paddingQuad);
+        this._marginBounds = buildBounds.call(this, info.marginQuad);
+
+        this._anchorsInfo = new Map();
+        for (var i = 0; i < info.anchors.length; ++i)
+            this._anchorsInfo.set(info.anchors[i].propertyName, info.anchors[i])
 
         document.addEventListener("mousedown", this._boundConsumeEvent);
-        document.addEventListener("mousemove", this._boundMouseMove);
         document.addEventListener("mouseup", this._boundConsumeEvent);
         document.addEventListener("click", this._boundStrayClick);
         document.addEventListener("keydown", this._boundKeyDown);
         document.addEventListener("mousewheel", this._boundMouseWheel);
+
+        this._createBlurWindow();
+        this._createGuideLines();
+        this._createControlLanes(info.anchors);
+        document.addEventListener("mousemove", this._boundConsumeEvent);
+
+        if (this._draggedPropertyName) {
+            document.body.style.cursor = (this._draggedPropertyName.endsWith("left") || this._draggedPropertyName.endsWith("right")) ? "ew-resize" : "ns-resize";
+            this._toggleHighlightedState(this._draggedPropertyName, true);
+        }
+    },
+
+    _createBlurWindow: function()
+    {
+        var left = this._editorElement.createChild("div", "blur-rect");
+        left.style.height = canvasHeight + "px";
+        left.style.width = this._marginBounds.left + "px";
+        var top = this._editorElement.createChild("div", "blur-rect");
+        top.style.left = this._marginBounds.left + "px";
+        top.style.width = canvasWidth - this._marginBounds.left + "px";
+        top.style.height = this._marginBounds.top  + "px";
+        var right = this._editorElement.createChild("div", "blur-rect");
+        right.style.left = this._marginBounds.right + "px";
+        right.style.top = this._marginBounds.top + "px";
+        right.style.width = (canvasWidth - this._marginBounds.right) + "px";
+        right.style.height = (canvasHeight - this._marginBounds.top) + "px";
+        var bottom = this._editorElement.createChild("div", "blur-rect");
+        bottom.style.left = this._marginBounds.left + "px";
+        bottom.style.top = this._marginBounds.bottom + "px";
+        bottom.style.width = this._marginBounds.right - this._marginBounds.left + "px";
+        bottom.style.height = canvasHeight - this._marginBounds.bottom + "px";
+        top.addEventListener("click", this._boundStrayClick);
+        bottom.addEventListener("click", this._boundStrayClick);
+        left.addEventListener("click", this._boundStrayClick);
+        right.addEventListener("click", this._boundStrayClick);
+    },
+
+    _createGuideLines: function()
+    {
+        /**
+         * @param {number} x
+         * @param {string} type
+         * @this {LayoutEditor}
+         */
+        function verticalLine(x, type)
+        {
+            var verticalElement = this._editorElement.createChild("div", "guide-line vertical");
+            verticalElement.classList.add(type);
+            verticalElement.style.height = canvasHeight + "px";
+            verticalElement.style.top = "0px";
+            verticalElement.style.left = x + "px";
+        }
+
+        /**
+         * @param {number} y
+         * @param {string} type
+         * @this {LayoutEditor}
+         */
+        function horizontalLine(y, type)
+        {
+            var horizontalElement = this._editorElement.createChild("div", "guide-line horizontal");
+            horizontalElement.classList.add(type);
+            horizontalElement.style.width = canvasWidth + "px";
+            horizontalElement.style.left = "0px";
+            horizontalElement.style.top = y + "px";
+        }
+
+        /**
+         * @param {!LayoutEditor.Bounds} bounds
+         * @param {string} type
+         * @this {LayoutEditor}
+         */
+        function guideLines(bounds, type)
+        {
+            verticalLine.call(this, bounds.left, type);
+            verticalLine.call(this, bounds.right, type);
+            horizontalLine.call(this, bounds.top, type);
+            horizontalLine.call(this, bounds.bottom, type);
+        }
+
+        guideLines.call(this, this._contentBounds, "content");
+        guideLines.call(this, this._paddingBounds, "padding");
+        guideLines.call(this, this._marginBounds, "margin");
+    },
+
+    /**
+     * @param {!Element} parent
+     * @param {!Element} anchorElement
+     * @param {!LayoutEditor.AnchorInfo} anchorInfo
+     */
+    _createLabel: function(parent, anchorElement, anchorInfo)
+    {
+        var label = parent.createChild("div", "label " + anchorInfo.type);
+        var nameElement = label.createChild("span", "name");
+        var anchorName = anchorInfo.propertyName;
+        nameElement.textContent = anchorName + ": ";
+        var valueElement = label.createChild("span", "value");
+        valueElement.textContent = String(parseFloat(anchorInfo.propertyValue.value.toFixed(2)));
+        var dimensionElement = label.createChild("span", "dimension");
+        dimensionElement.textContent = "\u2009" + anchorInfo.propertyValue.unit;
+
+        var leftX = anchorElement.offsetLeft - LayoutEditor._labelOffset - label.offsetWidth;
+        var fitLeft = leftX > 0;
+        var rightX = anchorElement.offsetLeft + anchorElement.offsetWidth  + LayoutEditor._labelOffset;
+        var fitRight = rightX + label.offsetWidth < canvasWidth;
+        var growsInside = anchorInfo.propertyValue.growInside;
+        var toLeft = anchorName.endsWith("right") && growsInside ||  anchorName.endsWith("left") && !growsInside;
+        var startPosition;
+        if (!fitLeft || (!toLeft && fitRight)) {
+            startPosition = rightX;
+            label.classList.add("left-arrow");
+        } else {
+            startPosition = leftX;
+            label.classList.add("right-arrow");
+        }
+
+        var y = anchorElement.offsetTop + anchorElement.offsetHeight / 2;
+        label.style.left = (startPosition | 0) + "px";
+        label.style.top = ((y - label.offsetHeight / 2) | 0) + "px";
+
+        label.classList.add("hidden");
+        return label;
+    },
+
+    /**
+     * @param {string} anchorName
+     * @param {boolean} highlighted
+     */
+    _toggleHighlightedState: function(anchorName, highlighted)
+    {
+        this._anchorsElements.get(anchorName).classList.toggle("highlighted", highlighted);
+        this._wallsElements.get(anchorName).classList.toggle("highlighted", highlighted);
+        this._labelsElements.get(anchorName).classList.toggle("hidden", !highlighted);
+    },
+
+    _createControlLanes: function()
+    {
+        var descriptionH = {orientation: "horizontal", border1: "left", border2: "top", dimension1: "width", dimension2: "height"};
+        var descriptionV = {orientation: "vertical", border1: "top", border2: "left", dimension1: "height", dimension2: "width"};
+        var sidesByOrientation = {horizontal : ["left", "right"], vertical : ["top", "bottom"]};
+
+        /**
+         * @param {!Element} parent
+         * @param {!LayoutEditor.Bounds} innerBox
+         * @param {!LayoutEditor.Bounds} outerBox
+         * @param {string} type
+         * @param {string} side
+         * @param {!LayoutEditor.Description} description
+         * @param {number} border2Position
+         * @this {LayoutEditor}
+         */
+        function createAnchorWithWall(parent, innerBox, outerBox, type, side, description, border2Position)
+        {
+            var anchorName = type + "-" + side;
+            var anchorInfo = this._anchorsInfo.get(anchorName);
+            var growsInside = anchorInfo.propertyValue.growInside;
+
+            var anchorPosition = (growsInside ? innerBox[side] : outerBox[side]);
+            var anchorElement = parent.createChild("div", "editor-anchor " + description.orientation + " " + type);
+            var handleHalf = LayoutEditor._handleWidth / 2;
+            anchorElement.style[description.border1] = (anchorPosition - handleHalf) + "px";
+            anchorElement.style[description.border2] = border2Position + "px";
+            this._anchorsElements.set(anchorName, anchorElement);
+
+            if (anchorInfo.propertyValue.mutable)
+                anchorElement.addEventListener("mousedown", this._onAnchorMouseDown.bind(this, anchorName));
+
+            anchorElement.addEventListener("mouseenter", this._toggleHighlightedState.bind(this, anchorName, true));
+            anchorElement.addEventListener("mouseleave", this._toggleHighlightedState.bind(this, anchorName, false));
+
+            var wallElement = parent.createChild("div", "wall " + description.orientation + " " + type);
+            var wallPosition = (growsInside ? outerBox[side] : innerBox[side]);
+            var minSide = (side === "left" || side === "top");
+            wallPosition += (minSide === growsInside) ? - handleHalf - LayoutEditor._wallWidth : handleHalf;
+            wallElement.style[description.border1] = wallPosition + "px";
+            wallElement.style[description.border2] = border2Position + "px";
+            
+            this._wallsElements.set(anchorName, wallElement);
+
+            var labelElement = this._createLabel(parent, anchorElement, anchorInfo);
+            this._labelsElements.set(anchorName, labelElement);
+        }
+
+        /**
+         * @param {!Element} parent
+         * @param {!LayoutEditor.Bounds} innerBox
+         * @param {!LayoutEditor.Bounds} outerBox
+         * @param {string} type
+         * @param {!LayoutEditor.Description} description
+         * @param {number} border2Position
+         * @this {LayoutEditor}
+         */
+        function createLane(parent, innerBox, outerBox, type, description, border2Position)
+        {
+            var verticalElement = parent.createChild("div", "control-lane " + type);
+            var sides = sidesByOrientation[description.orientation];
+            verticalElement.style[description.border1] = outerBox[sides[0]] + "px";
+            verticalElement.style[description.border2] = border2Position + "px";
+            verticalElement.style[description.dimension1] = (outerBox[sides[1]] - outerBox[sides[0]]) + "px";
+            verticalElement.style[description.dimension2] = LayoutEditor._controlLaneWidth + "px";
+            createAnchorWithWall.call(this, parent, innerBox, outerBox, type, sides[0], description, border2Position);
+            createAnchorWithWall.call(this, parent, innerBox, outerBox, type, sides[1], description, border2Position);
+        }
+
+        var yPosition = 0;
+        var xPosition = 0;
+        if (this._marginBounds.bottom + 2 * LayoutEditor._controlLaneWidth <= canvasHeight)
+            yPosition = this._marginBounds.bottom;
+        else if (this._marginBounds.top - 2 * LayoutEditor._controlLaneWidth >= 0)
+            yPosition = this._marginBounds.top - 2 * LayoutEditor._controlLaneWidth;
+        else
+            yPosition = (this._contentBounds.top + this._contentBounds.bottom) / 2;
+
+        if (this._marginBounds.left - 2 * LayoutEditor._controlLaneWidth >= 0)
+            xPosition = this._marginBounds.left - 2 * LayoutEditor._controlLaneWidth;
+        else if (this._marginBounds.right + 2 * LayoutEditor._controlLaneWidth <= canvasWidth)
+            xPosition = this._marginBounds.right;
+        else
+            xPosition = (this._contentBounds.right + this._contentBounds.left) / 2;
+
+        createLane.call(this, this._editorElement, this._contentBounds, this._paddingBounds, "padding", descriptionH, yPosition);
+        createLane.call(this, this._editorElement, this._paddingBounds, this._marginBounds, "margin", descriptionH, yPosition + LayoutEditor._controlLaneWidth);
+        createLane.call(this, this._editorElement, this._contentBounds, this._paddingBounds, "padding", descriptionV, xPosition);
+        createLane.call(this, this._editorElement, this._paddingBounds, this._marginBounds, "margin", descriptionV, xPosition + LayoutEditor._controlLaneWidth);
     },
 
     setSelector: function(selectorInfo)
     {
-        if (this._selectorTooltipElement)
-            this._selectorTooltipElement.remove();
-
+        this._selectorTooltipElement.removeChildren();
         var containerElement = createElement("div");
 
         for (var i = (selectorInfo.medias || []).length - 1; i >= 0; --i)
@@ -914,8 +1415,10 @@
         var selectorElement = containerElement.createChild("div", "layout-editor-selector-tooltip");
         selectorElement.textContent = selectorInfo.selector.trimEnd(50);
 
-        this._selectorTooltipElement = document.body.insertBefore(createElement("div"), this._editorElement);
-        _createMaterialTooltip(this._selectorTooltipElement, this._elementsBounds, containerElement);
+        var margin = 40;
+        var bounds = {minX: this._marginBounds.left, maxX: this._marginBounds.right,
+                minY: this._marginBounds.top - margin, maxY: this._marginBounds.bottom + margin};
+        _createMaterialTooltip(this._selectorTooltipElement, bounds, containerElement);
         resetCanvas(this._matchedNodesCanvas);
 
         if (!selectorInfo.nodes)
@@ -925,49 +1428,58 @@
             drawHighlight(nodeHighlight, this._matchedNodesCanvas.getContext("2d"));
     },
 
-    _createAnchor: function(anchorInfo)
-    {
-        var handleWidth = 5;
-        this._mainContext.save();
-        this._mainContext.shadowColor = "rgba(0, 0, 0, 0.34)";
-        this._mainContext.shadowBlur = 2;
-        this._mainContext.fillStyle = this._anchorColorForProperty(anchorInfo);
-        this._mainContext.beginPath();
-        this._mainContext.arc(anchorInfo.x, anchorInfo.y, handleWidth, 0, 2 * Math.PI);
-        this._mainContext.fill();
-        this._mainContext.restore();
-
-        var anchorElement = createElement("div", "editor-anchor");
-        anchorElement.style.left = anchorInfo.x - handleWidth + "px";
-        anchorElement.style.top = anchorInfo.y - handleWidth + "px";
-        if (anchorInfo.propertyValue.mutable)
-            anchorElement.addEventListener("mousedown", this._onAnchorMouseDown.bind(this, anchorInfo));
-        anchorElement.addEventListener("mousemove", this._onAnchorMouseMove.bind(this, anchorInfo));
-        return anchorElement;
-    },
-
     _calculateDelta: function(deltaVector, moveDelta)
     {
         return scalarProduct(deltaVector, moveDelta) / Math.sqrt(scalarProduct(deltaVector, deltaVector));
     },
 
-    _onAnchorMouseDown: function(anchorInfo, event)
+    /**
+     * @param {string} anchorName
+     * @return {!Point}
+     */
+    _defaultDeltaVector: function(anchorName)
+    {
+        if (anchorName.endsWith("right"))
+            return new Point(1, 0);
+        if (anchorName.endsWith("left"))
+            return new Point(-1, 0);
+        if (anchorName.endsWith("top"))
+            return new Point(0, -1);
+        if (anchorName.endsWith("bottom"))
+            return new Point(0, 1);
+    },
+
+    /**
+     * @param {string} anchorName
+     * @param {!Event} event
+     */
+    _onAnchorMouseDown: function(anchorName, event)
     {
         // Only drag upon left button. Right will likely cause a context menu. So will ctrl-click on mac.
         if (event.button || (window.platform == "mac" && event.ctrlKey))
             return;
 
         event.preventDefault();
-        this._boundDragMove = this._onDragMove.bind(this, new Point(event.screenX, event.screenY), anchorInfo.deltaVector);
+        var deltaVector = this._defaultDeltaVector(anchorName);
+        var anchorInfo = this._anchorsInfo.get(anchorName);
+        if (anchorInfo.propertyValue.growInside)
+            deltaVector = new Point(-deltaVector.x, -deltaVector.y);
+
+        this._boundDragMove = this._onDragMove.bind(this, new Point(event.screenX, event.screenY), deltaVector);
         this._boundDragEnd = this._onDragEnd.bind(this);
         document.addEventListener("mousemove", this._boundDragMove);
         document.addEventListener("mouseup", this._boundDragEnd);
-        InspectorOverlayHost.startPropertyChange(anchorInfo.propertyName);
+        InspectorOverlayHost.startPropertyChange(anchorName);
         this._preciseDrag = !!event.shiftKey;
-        this._draggedPropertyName = anchorInfo.propertyName;
-        this._showLabels(anchorInfo.type, anchorInfo.propertyName);
+        this._draggedPropertyName = anchorName;
+        this._toggleHighlightedState(anchorName, true);
     },
 
+    /**
+     * @param {!Point} mouseDownPoint
+     * @param {!Point} deltaVector
+     * @param {!Event} event
+     */
     _onDragMove: function(mouseDownPoint, deltaVector, event)
     {
         if (event.buttons !== 1) {
@@ -989,181 +1501,35 @@
         InspectorOverlayHost.changeProperty(this._calculateDelta(deltaVector, new Point(event.screenX - mouseDownPoint.x, event.screenY - mouseDownPoint.y)) / preciseFactor);
     },
 
+    /**
+     * @param {!Event} event
+     */
     _onDragEnd: function(event)
     {
         document.removeEventListener("mousemove", this._boundDragMove);
         document.removeEventListener("mouseup", this._boundDragEnd);
         delete this._boundDragMove;
         delete this._boundDragEnd;
+        this._toggleHighlightedState(this._draggedPropertyName, false);
+        document.body.style.cursor = "";
         delete this._draggedPropertyName;
         delete this._preciseDrag;
         event.preventDefault();
         InspectorOverlayHost.endPropertyChange();
-        this._resetLabelCanvas();
     },
 
-    _showLabel: function(anchorInfo, showLongDescription)
-    {
-        var context = this._labelsCanvas.getContext("2d");
-        var secondaryColor = "rgba(255, 255, 255, 0.7)";
-        var labelColor = this._labelColorForProperty(anchorInfo);
-        var textDescription = [
-            {string: String(parseFloat(anchorInfo.propertyValue.value.toFixed(2))), color: "white"},
-            {string: "\u2009" + anchorInfo.propertyValue.unit, color: secondaryColor}
-        ];
-
-        if (showLongDescription)
-            textDescription.splice(0, 0, {string: anchorInfo.propertyName + ": ", color: secondaryColor});
-        this._drawLabel(context, anchorInfo.x, anchorInfo.y, labelColor, textDescription, anchorInfo.deltaVector.x < 0);
-    },
-
-    _showLabels: function(type, fullLabelName)
-    {
-        if (this._labelCanvasState && this._labelCanvasState.type === type && this._labelCanvasState.fullLabelName === fullLabelName)
-            return;
-
-        this._resetLabelCanvas();
-        this._labelCanvasState = {type: type, fullLabelName: fullLabelName};
-        var anchors = this._anchorsByType.get(type) || [];
-        var selectedAnchorInfo = null;
-
-        for (var anchorInfo of anchors) {
-            if (fullLabelName !== anchorInfo.propertyName)
-                this._showLabel(anchorInfo, false);
-            else
-                selectedAnchorInfo = anchorInfo;
-        }
-
-        if (!selectedAnchorInfo)
-            return;
-
-        this._showLabel(selectedAnchorInfo, true);
-        document.body.style.cursor = this._chooseAnchorPointer(selectedAnchorInfo.deltaVector);
-    },
-
-    _onAnchorMouseMove: function(anchorInfo, event)
-    {
-        if (this._draggedPropertyName)
-            return;
-
-        event.preventDefault();
-        event.stopPropagation();
-        this._showLabels(anchorInfo.type, anchorInfo.propertyName);
-    },
-
-    _drawLabel: function(context, anchorX, anchorY, labelColor, textDescription, toLeft)
-    {
-        var paddingX = 6;
-        var paddingY = 4;
-        var borderRadius = 2;
-        var arrowWidth = 6;
-        var offsetX = 6;
-        var fontSize = 10;
-
-        var wholeString = "";
-        for (var part of textDescription)
-            wholeString += part.string;
-
-        context.save();
-        context.font = fontSize + "px Arial, Roboto";
-
-        var textWidth = context.measureText(wholeString).width;
-        var fullWidth = textWidth + offsetX + arrowWidth + paddingX;
-        var height = fontSize + paddingY;
-        var fitRight = anchorX + fullWidth < viewportSize.width;
-        var fitLeft = anchorX - fullWidth > 0;
-        var mirror = !fitLeft || (!toLeft && fitRight);
-
-        var arrowX = -offsetX;
-        var arrowY = 0;
-        var right = arrowX - arrowWidth;
-        var top = arrowY - height / 2;
-        var bottom = arrowY + height / 2;
-        var left = -fullWidth;
-
-        context.save();
-        context.translate(anchorX, anchorY);
-        if (mirror)
-            context.scale(-1, 1);
-
-        context.fillStyle = labelColor;
-        context.shadowColor = "rgba(0, 0, 0, 0.34)";
-        context.shadowOffsetY = 1;
-        context.shadowBlur = 1;
-        context.beginPath();
-        context.moveTo(arrowX, arrowY);
-        context.lineTo(right, bottom);
-        context.lineTo(left + borderRadius, bottom);
-        context.quadraticCurveTo(left, bottom, left, bottom - borderRadius);
-        context.lineTo(left, top + borderRadius);
-        context.quadraticCurveTo(left, top, left + borderRadius, top);
-        context.lineTo(right, top);
-        context.lineTo(arrowX, arrowY);
-        context.closePath();
-        context.fill();
-        context.restore();
-
-        var textX = 0;
-        if (mirror)
-            textX = anchorX - right + paddingX / 2;
-        else
-            textX = anchorX + left + paddingX / 2;
-
-        var textY = anchorY + top + fontSize;
-        for (var part of textDescription) {
-            context.fillStyle = part.color;
-            context.fillText(part.string, textX, textY);
-            textX += context.measureText(part.string).width;
-        }
-        context.restore();
-    },
-
-    _labelColorForProperty: function(anchorInfo)
-    {
-        // TODO: find a better color
-        if (!anchorInfo.propertyValue.mutable)
-            return "rgb(159, 188, 191)";
-
-        var propertyName = anchorInfo.propertyName;
-        if (propertyName.startsWith("margin"))
-            return "rgb(246, 167, 35)";
-        return "rgb(91, 181, 0)";
-    },
-
-    _anchorColorForProperty: function(anchorInfo)
-    {
-        // TODO: find a better color
-        if (!anchorInfo.propertyValue.mutable)
-            return "rgb(159, 188, 191)";
-
-        var propertyName = anchorInfo.propertyName;
-        if (propertyName.startsWith("margin"))
-            return "rgb(246, 167, 35)";
-        return "rgb(107, 213, 0)";
-    },
-
-    _onMouseMove: function(event)
-    {
-        event.preventDefault();
-        if (!this._hoverableAreas.size)
-            return;
-        var types = ["padding", "margin"];
-        for (var type of types) {
-            var path = this._hoverableAreas.get(type);
-            if (path && this._mainContext.isPointInPath(path, deviceScaleFactor * event.x, deviceScaleFactor * event.y)) {
-                this._showLabels(type);
-                return;
-            }
-        }
-        this._resetLabelCanvas();
-    },
-
+    /**
+     * @param {!Event} event
+     */
     _onStrayClick: function(event)
     {
         event.preventDefault();
         InspectorOverlayHost.clearSelection(true);
     },
 
+    /**
+     * @param {!Event} event
+     */
     _onKeyDown: function(event)
     {
         if (this._draggedPropertyName)
@@ -1176,6 +1542,9 @@
         }
     },
 
+    /**
+     * @param {!Event} event
+     */
     _onMouseWheel: function(event)
     {
         event.preventDefault();
@@ -1185,37 +1554,20 @@
             InspectorOverlayHost.nextSelector();
     },
 
+    /**
+     * @param {!Event} event
+     */
     _consumeEvent: function(event)
     {
         event.preventDefault();
-    },
-
-    _resetLabelCanvas: function()
-    {
-        delete this._labelCanvasState;
-        resetCanvas(this._labelsCanvas);
-        if (!this._draggedPropertyName && document.body.style.cursor)
-            document.body.style.cursor = "";
-    },
-
-    _chooseAnchorPointer: function(direction)
-    {
-        var pointers = [{name: "ns-resize", vector: new Point(0, -1)}, {name: "ew-resize", vector: new Point(-1, 0)},
-            {name: "ns-resize", vector: new Point(0, 1)}, {name: "ew-resize", vector: new Point(1, 0)}];
-
-        var maxValue = scalarProduct(direction, pointers[0].vector);
-        var maxIndex = 0;
-        for (var i = 1; i < pointers.length; ++i) {
-            var currentValue = scalarProduct(direction, pointers[i].vector);
-            if (currentValue > maxValue) {
-                maxValue = currentValue;
-                maxIndex = i;
-            }
-        }
-        return pointers[maxIndex].name;
     }
 }
 
+/**
+ * @constructor
+ * @param {number} x
+ * @param {number} y
+ */
 function Point(x, y)
 {
     this.x = x;
@@ -1238,6 +1590,7 @@
 Element.prototype.createChild = function(tagName, className)
 {
     var element = createElement(tagName, className);
+    element.addEventListener("click", function(e) { e.stopPropagation(); }, false);
     this.appendChild(element);
     return element;
 }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
index 11cf4a10..5ce3fd9a 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.cpp
@@ -24,9 +24,9 @@
 
 namespace blink {
 
-class InspectorResourceContentLoader::ResourceClient final : private RawResourceClient, private StyleSheetResourceClient {
+class InspectorResourceContentLoader::ResourceClient final : public NoBaseWillBeGarbageCollectedFinalized<InspectorResourceContentLoader::ResourceClient>, private RawResourceClient, private StyleSheetResourceClient {
 public:
-    ResourceClient(InspectorResourceContentLoader* loader)
+    explicit ResourceClient(InspectorResourceContentLoader* loader)
         : m_loader(loader)
     {
     }
@@ -39,8 +39,13 @@
             resource->addClient(static_cast<StyleSheetResourceClient*>(this));
     }
 
+    DEFINE_INLINE_TRACE()
+    {
+        visitor->trace(m_loader);
+    }
+
 private:
-    InspectorResourceContentLoader* m_loader;
+    RawPtrWillBeMember<InspectorResourceContentLoader> m_loader;
 
     void setCSSStyleSheet(const String&, const KURL&, const String&, const CSSStyleSheetResource*) override;
     void notifyFinished(Resource*) override;
@@ -60,7 +65,9 @@
     else
         resource->removeClient(static_cast<StyleSheetResourceClient*>(this));
 
+#if !ENABLE(OILPAN)
     delete this;
+#endif
 }
 
 void InspectorResourceContentLoader::ResourceClient::setCSSStyleSheet(const String&, const KURL& url, const String&, const CSSStyleSheetResource* resource)
@@ -158,7 +165,10 @@
 
 DEFINE_TRACE(InspectorResourceContentLoader)
 {
+#if ENABLE(OILPAN)
     visitor->trace(m_inspectedFrame);
+    visitor->trace(m_pendingResourceClients);
+#endif
 }
 
 void InspectorResourceContentLoader::didCommitLoadForLocalFrame(LocalFrame* frame)
@@ -174,7 +184,7 @@
 
 void InspectorResourceContentLoader::stop()
 {
-    HashSet<ResourceClient*> pendingResourceClients;
+    WillBeHeapHashSet<RawPtrWillBeMember<ResourceClient>> pendingResourceClients;
     m_pendingResourceClients.swap(pendingResourceClients);
     for (const auto& client : pendingResourceClients)
         client->m_loader = nullptr;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.h b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.h
index 25c71f8e..ff9ab12 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorResourceContentLoader.h
@@ -46,8 +46,8 @@
     bool m_allRequestsStarted;
     bool m_started;
     RawPtrWillBeMember<LocalFrame> m_inspectedFrame;
-    HashSet<ResourceClient*> m_pendingResourceClients;
-    Vector<ResourcePtr<Resource> > m_resources;
+    WillBeHeapHashSet<RawPtrWillBeMember<ResourceClient>> m_pendingResourceClients;
+    Vector<ResourcePtr<Resource>> m_resources;
 
     friend class ResourceClient;
 };
diff --git a/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.cpp
index d648dc07..96a5263 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.cpp
@@ -40,7 +40,6 @@
 #include "core/inspector/v8/V8Debugger.h"
 #include "core/inspector/v8/V8RuntimeAgent.h"
 #include "platform/JSONValues.h"
-#include "wtf/Optional.h"
 
 using blink::TypeBuilder::Runtime::ExecutionContextDescription;
 
@@ -99,17 +98,17 @@
 void InspectorRuntimeAgent::evaluate(ErrorString* errorString, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const int* optExecutionContextId, const bool* const returnByValue, const bool* generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>& exceptionDetails)
 {
     int executionContextId = optExecutionContextId ? *optExecutionContextId : m_injectedScriptManager->injectedScriptIdFor(defaultScriptState());
-    Optional<MuteConsoleScope<InspectorRuntimeAgent>> muteScope;
+    MuteConsoleScope<InspectorRuntimeAgent> muteScope;
     if (asBool(doNotPauseOnExceptionsAndMuteConsole))
-        muteScope.emplace(this);
+        muteScope.enter(this);
     m_v8RuntimeAgent->evaluate(errorString, expression, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, &executionContextId, returnByValue, generatePreview, result, wasThrown, exceptionDetails);
 }
 
 void InspectorRuntimeAgent::callFunctionOn(ErrorString* errorString, const String& objectId, const String& expression, const RefPtr<JSONArray>* const optionalArguments, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<TypeBuilder::Runtime::RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown)
 {
-    Optional<MuteConsoleScope<InspectorRuntimeAgent>> muteScope;
+    MuteConsoleScope<InspectorRuntimeAgent> muteScope;
     if (asBool(doNotPauseOnExceptionsAndMuteConsole))
-        muteScope.emplace(this);
+        muteScope.enter(this);
     m_v8RuntimeAgent->callFunctionOn(errorString, objectId, expression, optionalArguments, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, result, wasThrown);
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
index dc5a961b..c912c79 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.cpp
@@ -398,54 +398,6 @@
     return value.release();
 }
 
-PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorSendRequestEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceRequest& request)
-{
-    String requestId = IdentifiersFactory::requestId(identifier);
-
-    RefPtr<TracedValue> value = TracedValue::create();
-    value->setString("requestId", requestId);
-    value->setString("frame", toHexString(frame));
-    value->setString("url", request.url().string());
-    value->setString("requestMethod", request.httpMethod());
-    setCallStack(value.get());
-    return value.release();
-}
-
-PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveResponseEvent::data(unsigned long identifier, LocalFrame* frame, const ResourceResponse& response)
-{
-    String requestId = IdentifiersFactory::requestId(identifier);
-
-    RefPtr<TracedValue> value = TracedValue::create();
-    value->setString("requestId", requestId);
-    value->setString("frame", toHexString(frame));
-    value->setInteger("statusCode", response.httpStatusCode());
-    value->setString("mimeType", response.mimeType().string().isolatedCopy());
-    return value.release();
-}
-
-PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorReceiveDataEvent::data(unsigned long identifier, LocalFrame* frame, int encodedDataLength)
-{
-    String requestId = IdentifiersFactory::requestId(identifier);
-
-    RefPtr<TracedValue> value = TracedValue::create();
-    value->setString("requestId", requestId);
-    value->setString("frame", toHexString(frame));
-    value->setInteger("encodedDataLength", encodedDataLength);
-    return value.release();
-}
-
-PassRefPtr<TraceEvent::ConvertableToTraceFormat> InspectorResourceFinishEvent::data(unsigned long identifier, double finishTime, bool didFail)
-{
-    String requestId = IdentifiersFactory::requestId(identifier);
-
-    RefPtr<TracedValue> value = TracedValue::create();
-    value->setString("requestId", requestId);
-    value->setBoolean("didFail", didFail);
-    if (finishTime)
-        value->setDouble("networkTime", finishTime);
-    return value.release();
-}
-
 static LocalFrame* frameForExecutionContext(ExecutionContext* context)
 {
     LocalFrame* frame = nullptr;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
index 8408427..55bc6f2 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
+++ b/third_party/WebKit/Source/core/inspector/InspectorTraceEvents.h
@@ -164,22 +164,6 @@
 PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(const LayoutObject&);
 }
 
-namespace InspectorSendRequestEvent {
-PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(unsigned long identifier, LocalFrame*, const ResourceRequest&);
-}
-
-namespace InspectorReceiveResponseEvent {
-PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(unsigned long identifier, LocalFrame*, const ResourceResponse&);
-}
-
-namespace InspectorReceiveDataEvent {
-PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(unsigned long identifier, LocalFrame*, int encodedDataLength);
-}
-
-namespace InspectorResourceFinishEvent {
-PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(unsigned long identifier, double finishTime, bool didFail);
-}
-
 namespace InspectorTimerInstallEvent {
 PassRefPtr<TraceEvent::ConvertableToTraceFormat> data(ExecutionContext*, int timerId, int timeout, bool singleShot);
 }
diff --git a/third_party/WebKit/Source/core/inspector/LayoutEditor.cpp b/third_party/WebKit/Source/core/inspector/LayoutEditor.cpp
index 482c3e8..2d19966 100644
--- a/third_party/WebKit/Source/core/inspector/LayoutEditor.cpp
+++ b/third_party/WebKit/Source/core/inspector/LayoutEditor.cpp
@@ -28,95 +28,31 @@
 
 namespace {
 
-PassRefPtr<JSONObject> createAnchor(const FloatPoint& point, const String& type, const String& propertyName, FloatPoint deltaVector, PassRefPtr<JSONObject> valueDescription)
+PassRefPtr<JSONObject> createAnchor(const String& type, const String& propertyName, PassRefPtr<JSONObject> valueDescription)
 {
     RefPtr<JSONObject> object = JSONObject::create();
-    object->setNumber("x", point.x());
-    object->setNumber("y", point.y());
     object->setString("type", type);
     object->setString("propertyName", propertyName);
-
-    RefPtr<JSONObject> deltaVectorJSON = JSONObject::create();
-    deltaVectorJSON->setNumber("x", deltaVector.x());
-    deltaVectorJSON->setNumber("y", deltaVector.y());
-    object->setObject("deltaVector", deltaVectorJSON.release());
     object->setObject("propertyValue", valueDescription);
     return object.release();
 }
 
-FloatPoint orthogonalVector(FloatPoint from, FloatPoint to, FloatPoint defaultVector)
+PassRefPtr<JSONObject> pointToJSON(FloatPoint point)
 {
-    if (from == to)
-        return defaultVector;
-
-    return FloatPoint(to.y() - from.y(), from.x() - to.x());
+    RefPtr<JSONObject> object = JSONObject::create();
+    object->setNumber("x", point.x());
+    object->setNumber("y", point.y());
+    return object.release();
 }
 
-FloatPoint mean(const FloatPoint& p1, const FloatPoint& p2)
+PassRefPtr<JSONObject> quadToJSON(FloatQuad& quad)
 {
-    float x = (p1.x() + p2.x()) / 2;
-    float y = (p1.y() + p2.y()) / 2;
-    return FloatPoint(x, y);
-}
-
-FloatQuad means(const FloatQuad& quad)
-{
-    FloatQuad result;
-    result.setP1(mean(quad.p1(), quad.p2()));
-    result.setP2(mean(quad.p2(), quad.p3()));
-    result.setP3(mean(quad.p3(), quad.p4()));
-    result.setP4(mean(quad.p4(), quad.p1()));
-    return result;
-}
-
-FloatQuad orthogonalVectors(const FloatQuad& quad)
-{
-    FloatQuad result;
-    result.setP1(orthogonalVector(quad.p1(), quad.p2(), FloatPoint(0, -1)));
-    result.setP2(orthogonalVector(quad.p2(), quad.p3(), FloatPoint(1, 0)));
-    result.setP3(orthogonalVector(quad.p3(), quad.p4(), FloatPoint(0, 1)));
-    result.setP4(orthogonalVector(quad.p4(), quad.p1(), FloatPoint(-1, 0)));
-    return result;
-}
-
-float det(float a11, float a12, float a21, float a22)
-{
-    return a11 * a22 - a12 * a21;
-}
-
-FloatPoint projection(const FloatPoint& anchor, const FloatPoint& orthogonalVector, const FloatPoint& point)
-{
-    float a1 = orthogonalVector.x();
-    float b1 = orthogonalVector.y();
-    float c1 = - anchor.x() * a1 - anchor.y() * b1;
-
-    float a2 = orthogonalVector.y();
-    float b2 = - orthogonalVector.x();
-    float c2 = - point.x() * a2 - point.y() * b2;
-    float d = det(a1, b1, a2, b2);
-    ASSERT(d < 0);
-    float x = - det(c1, b1, c2, b2) / d;
-    float y = - det(a1, c1, a2, c2) / d;
-    return FloatPoint(x, y);
-}
-
-FloatPoint translatePoint(const FloatPoint& point, const FloatPoint& orthogonalVector, float distance)
-{
-    float d = sqrt(orthogonalVector.x() * orthogonalVector.x() + orthogonalVector.y() * orthogonalVector.y());
-    float dx = - orthogonalVector.y() * distance / d;
-    float dy = orthogonalVector.x() * distance / d;
-    return FloatPoint(point.x() + dx, point.y() + dy);
-}
-
-FloatQuad translateAndProject(const FloatQuad& origin, const FloatQuad& orthogonals, const FloatQuad& projectOn, float distance)
-{
-    FloatQuad result;
-    result.setP1(projection(projectOn.p1(), orthogonals.p1(), translatePoint(origin.p1(), orthogonals.p1(), distance)));
-    result.setP2(projection(projectOn.p2(), orthogonals.p2(), translatePoint(origin.p2(), orthogonals.p2(), distance)));
-    // We want to translate at top and bottom point in the same direction, so we use p1 here.
-    result.setP3(projection(projectOn.p3(), orthogonals.p3(), translatePoint(origin.p3(), orthogonals.p1(), distance)));
-    result.setP4(projection(projectOn.p4(), orthogonals.p4(), translatePoint(origin.p4(), orthogonals.p2(), distance)));
-    return result;
+    RefPtr<JSONObject> object = JSONObject::create();
+    object->setObject("p1", pointToJSON(quad.p1()));
+    object->setObject("p2", pointToJSON(quad.p2()));
+    object->setObject("p3", pointToJSON(quad.p3()));
+    object->setObject("p4", pointToJSON(quad.p4()));
+    return object.release();
 }
 
 bool isMutableUnitType(CSSPrimitiveValue::UnitType unitType)
@@ -149,14 +85,6 @@
     return config;
 }
 
-InspectorHighlightConfig chosenNodeHighlightConfig()
-{
-    InspectorHighlightConfig config;
-    config.padding = Color(147, 196, 125, 140);
-    config.margin = Color(246, 178, 107, 168);
-    return config;
-}
-
 void collectMediaQueriesFromRule(CSSRule* rule, Vector<String>& mediaArray)
 {
     MediaList* mediaList;
@@ -209,8 +137,8 @@
     , m_changingProperty(CSSPropertyInvalid)
     , m_propertyInitialValue(0)
     , m_isDirty(false)
-    , m_matchedRules(m_cssAgent->matchedRulesList(element))
-    , m_currentRuleIndex(m_matchedRules->length())
+    , m_matchedStyles(cssAgent->matchingStyles(element))
+    , m_currentRuleIndex(0)
 {
 }
 
@@ -233,41 +161,39 @@
     visitor->trace(m_cssAgent);
     visitor->trace(m_domAgent);
     visitor->trace(m_scriptController);
-    visitor->trace(m_matchedRules);
+    visitor->trace(m_matchedStyles);
 }
 
-void LayoutEditor::rebuild() const
+void LayoutEditor::rebuild()
 {
-    FloatQuad content, padding, border, margin;
-    InspectorHighlight::buildNodeQuads(m_element.get(), &content, &padding, &border, &margin);
-    FloatQuad orthogonals = orthogonalVectors(padding);
-
     RefPtr<JSONObject> object = JSONObject::create();
     RefPtr<JSONArray> anchors = JSONArray::create();
-    FloatQuad contentMeans = means(content);
 
-    FloatQuad paddingHandles = translateAndProject(contentMeans, orthogonals, padding, 0);
-    appendAnchorFor(anchors.get(), "padding", "padding-top", paddingHandles.p1(), orthogonals.p1());
-    appendAnchorFor(anchors.get(), "padding", "padding-right", paddingHandles.p2(), orthogonals.p2());
-    appendAnchorFor(anchors.get(), "padding", "padding-bottom", paddingHandles.p3(), orthogonals.p3());
-    appendAnchorFor(anchors.get(), "padding", "padding-left", paddingHandles.p4(), orthogonals.p4());
+    appendAnchorFor(anchors.get(), "padding", "padding-top");
+    appendAnchorFor(anchors.get(), "padding", "padding-right");
+    appendAnchorFor(anchors.get(), "padding", "padding-bottom");
+    appendAnchorFor(anchors.get(), "padding", "padding-left");
 
-    FloatQuad marginHandles = translateAndProject(contentMeans, orthogonals, margin, 12);
-    appendAnchorFor(anchors.get(), "margin", "margin-top", marginHandles.p1(), orthogonals.p1());
-    appendAnchorFor(anchors.get(), "margin", "margin-right", marginHandles.p2(), orthogonals.p2());
-    appendAnchorFor(anchors.get(), "margin", "margin-bottom", marginHandles.p3(), orthogonals.p3());
-    appendAnchorFor(anchors.get(), "margin", "margin-left", marginHandles.p4(), orthogonals.p4());
+    appendAnchorFor(anchors.get(), "margin", "margin-top");
+    appendAnchorFor(anchors.get(), "margin", "margin-right");
+    appendAnchorFor(anchors.get(), "margin", "margin-bottom");
+    appendAnchorFor(anchors.get(), "margin", "margin-left");
 
     object->setArray("anchors", anchors.release());
-    InspectorHighlight highlight(m_element.get(), chosenNodeHighlightConfig(), false);
-    object->setObject("nodeHighlight", highlight.asJSONObject());
+
+    FloatQuad content, padding, border, margin;
+    InspectorHighlight::buildNodeQuads(m_element.get(), &content, &padding, &border, &margin);
+    object->setObject("contentQuad", quadToJSON(content));
+    object->setObject("paddingQuad", quadToJSON(padding));
+    object->setObject("marginQuad", quadToJSON(margin));
+    object->setObject("borderQuad", quadToJSON(border));
     evaluateInOverlay("showLayoutEditor", object.release());
     pushSelectorInfoInOverlay();
 }
 
 RefPtrWillBeRawPtr<CSSPrimitiveValue> LayoutEditor::getPropertyCSSValue(CSSPropertyID property) const
 {
-    RefPtrWillBeRawPtr<CSSStyleDeclaration> style = m_cssAgent->findEffectiveDeclaration(property, m_matchedRules.get(), m_element->style());
+    RefPtrWillBeRawPtr<CSSStyleDeclaration> style = m_cssAgent->findEffectiveDeclaration(property, m_matchedStyles);
     if (!style)
         return nullptr;
 
@@ -278,7 +204,59 @@
     return toCSSPrimitiveValue(cssValue.get());
 }
 
-PassRefPtr<JSONObject> LayoutEditor::createValueDescription(const String& propertyName) const
+bool LayoutEditor::growInside(String propertyName, CSSPrimitiveValue* value)
+{
+    FloatQuad content1, padding1, border1, margin1;
+    InspectorHighlight::buildNodeQuads(m_element.get(), &content1, &padding1, &border1, &margin1);
+
+    CSSStyleDeclaration* elementStyle = m_element->style();
+    if (!elementStyle)
+        return false;
+
+    String initialValue = elementStyle->getPropertyValue(propertyName);
+    String initialPriority = elementStyle->getPropertyPriority(propertyName);
+    String newValue;
+    if (value)
+        newValue = String::format("%f", value->getFloatValue() + 1) + CSSPrimitiveValue::unitTypeToString(value->typeWithCalcResolved());
+    else
+        newValue = "5px";
+
+    TrackExceptionState exceptionState;
+    elementStyle->setProperty(propertyName, newValue, "important", exceptionState);
+    m_element->ownerDocument()->updateLayout();
+
+    FloatQuad content2, padding2, border2, margin2;
+    InspectorHighlight::buildNodeQuads(m_element.get(), &content2, &padding2, &border2, &margin2);
+
+    elementStyle->setProperty(propertyName, initialValue, initialPriority, exceptionState);
+    m_element->ownerDocument()->updateLayout();
+
+    float eps = 0.0001;
+    FloatRect boundingBox1, boundingBox2;
+
+    if (propertyName.startsWith("padding")) {
+        boundingBox1 = padding1.boundingBox();
+        boundingBox2 = padding2.boundingBox();
+    } else {
+        boundingBox1 = margin1.boundingBox();
+        boundingBox2 = margin2.boundingBox();
+    }
+
+    if (propertyName.endsWith("left"))
+        return std::abs(boundingBox1.x() - boundingBox2.x() ) < eps;
+
+    if (propertyName.endsWith("right"))
+        return std::abs(boundingBox1.maxX() - boundingBox2.maxX() ) < eps;
+
+    if (propertyName.endsWith("top"))
+        return std::abs(boundingBox1.y() - boundingBox2.y()) < eps;
+
+    if (propertyName.endsWith("bottom"))
+        return std::abs(boundingBox1.maxY() - boundingBox2.maxY()) < eps;
+    return false;
+}
+
+PassRefPtr<JSONObject> LayoutEditor::createValueDescription(const String& propertyName)
 {
     RefPtrWillBeRawPtr<CSSPrimitiveValue> cssValue = getPropertyCSSValue(cssPropertyID(propertyName));
     if (cssValue && !(cssValue->isLength() || cssValue->isPercentage()))
@@ -289,14 +267,19 @@
     CSSPrimitiveValue::UnitType unitType = cssValue ? cssValue->typeWithCalcResolved() : CSSPrimitiveValue::UnitType::Pixels;
     object->setString("unit", CSSPrimitiveValue::unitTypeToString(unitType));
     object->setBoolean("mutable", isMutableUnitType(unitType));
+
+    if (!m_growsInside.contains(propertyName))
+        m_growsInside.set(propertyName, growInside(propertyName, cssValue.get()));
+
+    object->setBoolean("growInside", m_growsInside.get(propertyName));
     return object.release();
 }
 
-void LayoutEditor::appendAnchorFor(JSONArray* anchors, const String& type, const String& propertyName, const FloatPoint& position, const FloatPoint& orthogonalVector) const
+void LayoutEditor::appendAnchorFor(JSONArray* anchors, const String& type, const String& propertyName)
 {
     RefPtr<JSONObject> description = createValueDescription(propertyName);
     if (description)
-        anchors->pushObject(createAnchor(position, type, propertyName, orthogonalVector, description.release()));
+        anchors->pushObject(createAnchor(type, propertyName, description.release()));
 }
 
 void LayoutEditor::overlayStartedPropertyChange(const String& anchorName)
@@ -358,28 +341,24 @@
     m_domAgent->markUndoableState(&errorString);
 }
 
-bool LayoutEditor::currentStyleIsInline() const
-{
-    return m_currentRuleIndex == m_matchedRules->length();
-}
-
 void LayoutEditor::nextSelector()
 {
-    if (m_currentRuleIndex == 0)
+    if (m_currentRuleIndex == m_matchedStyles.size() - 1)
         return;
 
-    m_currentRuleIndex--;
+    ++m_currentRuleIndex;
     pushSelectorInfoInOverlay();
 }
 
 void LayoutEditor::previousSelector()
 {
-    if (currentStyleIsInline())
+    if (m_currentRuleIndex == 0)
         return;
 
-    m_currentRuleIndex++;
+    --m_currentRuleIndex;
     pushSelectorInfoInOverlay();
 }
+
 void LayoutEditor::pushSelectorInfoInOverlay() const
 {
     evaluateInOverlay("setSelectorInLayoutEditor", currentSelectorInfo());
@@ -388,15 +367,17 @@
 PassRefPtr<JSONObject> LayoutEditor::currentSelectorInfo() const
 {
     RefPtr<JSONObject> object = JSONObject::create();
-    String currentSelectorText = currentStyleIsInline() ? "inline style" : toCSSStyleRule(m_matchedRules->item(m_currentRuleIndex))->selectorText();
+    CSSStyleDeclaration* style = m_matchedStyles.at(m_currentRuleIndex).get();
+    CSSStyleRule* rule = style->parentRule() ? toCSSStyleRule(style->parentRule()) : nullptr;
+    String currentSelectorText = rule ? rule->selectorText() : "element.style";
     object->setString("selector", currentSelectorText);
 
     Document* ownerDocument = m_element->ownerDocument();
-    if (!ownerDocument->isActive() || currentStyleIsInline())
+    if (!ownerDocument->isActive() || !rule)
         return object.release();
 
     Vector<String> medias;
-    buildMediaListChain(m_matchedRules->item(m_currentRuleIndex), medias);
+    buildMediaListChain(rule, medias);
     RefPtr<JSONArray> mediasJSONArray = JSONArray::create();
     for (size_t i = 0; i < medias.size(); ++i)
         mediasJSONArray->pushString(medias[i]);
@@ -426,29 +407,8 @@
 
 bool LayoutEditor::setCSSPropertyValueInCurrentRule(const String& value)
 {
-    RefPtrWillBeRawPtr<CSSStyleDeclaration> effectiveDeclaration = m_cssAgent->findEffectiveDeclaration(m_changingProperty, m_matchedRules.get(), m_element->style());
-    bool forceImportant = false;
-
-    if (effectiveDeclaration) {
-        CSSStyleRule* effectiveRule = nullptr;
-        if (effectiveDeclaration->parentRule() && effectiveDeclaration->parentRule()->type() == CSSRule::STYLE_RULE)
-            effectiveRule = toCSSStyleRule(effectiveDeclaration->parentRule());
-
-        unsigned effectiveRuleIndex = m_matchedRules->length();
-        for (unsigned i = 0; i < m_matchedRules->length(); ++i) {
-            if (m_matchedRules->item(i) == effectiveRule) {
-                effectiveRuleIndex = i;
-                break;
-            }
-        }
-        forceImportant = effectiveDeclaration->getPropertyPriority(getPropertyNameString(m_changingProperty)) == "important";
-        forceImportant |= effectiveRuleIndex > m_currentRuleIndex;
-    }
-
-    CSSStyleDeclaration* style = currentStyleIsInline() ? m_element->style() : toCSSStyleRule(m_matchedRules->item(m_currentRuleIndex))->style();
-
     String errorString;
-    m_cssAgent->setCSSPropertyValue(&errorString, m_element.get(), style, m_changingProperty, value, forceImportant);
+    m_cssAgent->setCSSPropertyValue(&errorString, m_element.get(), m_matchedStyles.at(m_currentRuleIndex), m_changingProperty, value, false);
     return errorString.isEmpty();
 }
 
diff --git a/third_party/WebKit/Source/core/inspector/LayoutEditor.h b/third_party/WebKit/Source/core/inspector/LayoutEditor.h
index 19c137e..e06e679 100644
--- a/third_party/WebKit/Source/core/inspector/LayoutEditor.h
+++ b/third_party/WebKit/Source/core/inspector/LayoutEditor.h
@@ -42,19 +42,19 @@
     void commitChanges();
     void nextSelector();
     void previousSelector();
-    void rebuild() const;
+    void rebuild();
     DECLARE_TRACE();
 
 private:
     LayoutEditor(Element*, InspectorCSSAgent*, InspectorDOMAgent*, ScriptController*);
     RefPtrWillBeRawPtr<CSSPrimitiveValue> getPropertyCSSValue(CSSPropertyID) const;
-    PassRefPtr<JSONObject> createValueDescription(const String&) const;
-    void appendAnchorFor(JSONArray*, const String&, const String&, const FloatPoint&, const FloatPoint&) const;
+    PassRefPtr<JSONObject> createValueDescription(const String&);
+    void appendAnchorFor(JSONArray*, const String&, const String&);
     bool setCSSPropertyValueInCurrentRule(const String&);
-    bool currentStyleIsInline() const;
     void pushSelectorInfoInOverlay() const;
     void evaluateInOverlay(const String&, PassRefPtr<JSONValue>) const;
     PassRefPtr<JSONObject> currentSelectorInfo() const;
+    bool growInside(String propertyName, CSSPrimitiveValue*);
 
     RefPtrWillBeMember<Element> m_element;
     RawPtrWillBeMember<InspectorCSSAgent> m_cssAgent;
@@ -66,8 +66,8 @@
     CSSPrimitiveValue::UnitType m_valueUnitType;
     bool m_isDirty;
 
-    RefPtrWillBeMember<CSSRuleList> m_matchedRules;
-    // When m_currentRuleIndex == m_matchedRules.length(), current style is inline style.
+    WillBeHeapVector<RefPtrWillBeMember<CSSStyleDeclaration>> m_matchedStyles;
+    HashMap<String, bool> m_growsInside;
     unsigned m_currentRuleIndex;
 };
 
diff --git a/third_party/WebKit/Source/core/inspector/MuteConsoleScope.h b/third_party/WebKit/Source/core/inspector/MuteConsoleScope.h
index c5d323b3..b141fec 100644
--- a/third_party/WebKit/Source/core/inspector/MuteConsoleScope.h
+++ b/third_party/WebKit/Source/core/inspector/MuteConsoleScope.h
@@ -5,22 +5,44 @@
 #ifndef MuteConsoleScope_h
 #define MuteConsoleScope_h
 
+#include "platform/heap/Handle.h"
+
 namespace blink {
 
 template <class T>
 class MuteConsoleScope {
+    STACK_ALLOCATED();
 public:
-    explicit MuteConsoleScope(T* agent) : m_agent(agent)
+    MuteConsoleScope()
     {
-        m_agent->muteConsole();
+    }
+    explicit MuteConsoleScope(T* agent)
+    {
+        enter(agent);
     }
     ~MuteConsoleScope()
     {
+        exit();
+    }
+
+    void enter(T* agent)
+    {
+        ASSERT(!m_agent);
+        m_agent = agent;
+        m_agent->muteConsole();
+    }
+
+    void exit()
+    {
+        if (!m_agent)
+            return;
+
         m_agent->unmuteConsole();
+        m_agent = nullptr;
     }
 
 private:
-    T* m_agent;
+    RawPtrWillBeMember<T> m_agent = nullptr;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index 8569b99..e337c7de 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -1774,19 +1774,19 @@
 // FIXME: This function should go on LayoutObject as an instance method. Then
 // all cases in which positionForPoint recurs could call this instead to
 // prevent crossing editable boundaries. This would require many tests.
-static PositionWithAffinity positionForPointRespectingEditingBoundaries(LayoutBlock* parent, LayoutBox* child, const LayoutPoint& pointInParentCoordinates)
+static PositionWithAffinity positionForPointRespectingEditingBoundaries(LayoutBlock* parent, LineLayoutBox child, const LayoutPoint& pointInParentCoordinates)
 {
-    LayoutPoint childLocation = child->location();
-    if (child->isInFlowPositioned())
-        childLocation += child->offsetForInFlowPosition();
+    LayoutPoint childLocation = child.location();
+    if (child.isInFlowPositioned())
+        childLocation += child.offsetForInFlowPosition();
 
     // FIXME: This is wrong if the child's writing-mode is different from the parent's.
     LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
 
     // If this is an anonymous layoutObject, we just recur normally
-    Node* childNode = child->nonPseudoNode();
+    Node* childNode = child.nonPseudoNode();
     if (!childNode)
-        return child->positionForPoint(pointInChildCoordinates);
+        return child.positionForPoint(pointInChildCoordinates);
 
     // Otherwise, first make sure that the editability of the parent and child agree.
     // If they don't agree, then we return a visible position just before or after the child
@@ -1796,10 +1796,10 @@
 
     // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
     if (isEditingBoundary(ancestor, child))
-        return child->positionForPoint(pointInChildCoordinates);
+        return child.positionForPoint(pointInChildCoordinates);
 
     // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
-    LayoutUnit childMiddle = parent->logicalWidthForChild(*child) / 2;
+    LayoutUnit childMiddle = parent->logicalWidthForChildSize(child.size()) / 2;
     LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
     if (logicalLeft < childMiddle)
         return ancestor->createPositionWithAffinity(childNode->nodeIndex());
@@ -1876,7 +1876,7 @@
         if (!isHorizontalWritingMode())
             point = point.transposedPoint();
         if (closestBox->lineLayoutItem().isReplaced())
-            return positionForPointRespectingEditingBoundaries(this, &toLayoutBox(closestBox->layoutObject()), point);
+            return positionForPointRespectingEditingBoundaries(this, LineLayoutBox(closestBox->lineLayoutItem()), point);
         return closestBox->lineLayoutItem().positionForPoint(point);
     }
 
@@ -1936,7 +1936,7 @@
     if (lastCandidateBox) {
         if (pointInLogicalContents.y() > logicalTopForChild(*lastCandidateBox)
             || (!blocksAreFlipped && pointInLogicalContents.y() == logicalTopForChild(*lastCandidateBox)))
-            return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents);
+            return positionForPointRespectingEditingBoundaries(this, LineLayoutBox(lastCandidateBox), pointInContents);
 
         for (LayoutBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
             if (!isChildHitTestCandidate(childBox))
@@ -1945,7 +1945,7 @@
             // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
             if (isChildHitTestCandidate(childBox) && (pointInLogicalContents.y() < childLogicalBottom
                 || (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom)))
-                return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
+                return positionForPointRespectingEditingBoundaries(this, LineLayoutBox(childBox), pointInContents);
         }
     }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h
index de1c27804..729dbac 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -233,7 +233,8 @@
     int columnGap() const;
 
     // Accessors for logical width/height and margins in the containing block's block-flow direction.
-    LayoutUnit logicalWidthForChild(const LayoutBox& child) const { return isHorizontalWritingMode() ? child.size().width() : child.size().height(); }
+    LayoutUnit logicalWidthForChild(const LayoutBox& child) const { return logicalWidthForChildSize(child.size()); }
+    LayoutUnit logicalWidthForChildSize(LayoutSize childSize) const { return isHorizontalWritingMode() ? childSize.width() : childSize.height(); }
     LayoutUnit logicalHeightForChild(const LayoutBox& child) const { return isHorizontalWritingMode() ? child.size().height() : child.size().width(); }
     LayoutSize logicalSizeForChild(const LayoutBox& child) const { return isHorizontalWritingMode() ? child.size() : child.size().transposedSize(); }
     LayoutUnit logicalTopForChild(const LayoutBox& child) const { return isHorizontalWritingMode() ? child.location().y() : child.location().x(); }
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
index 9a33936..58f6568 100644
--- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -1417,9 +1417,11 @@
 void LayoutInline::invalidateDisplayItemClients(const LayoutBoxModelObject& paintInvalidationContainer, PaintInvalidationReason invalidationReason, const LayoutRect* paintInvalidationRect) const
 {
     LayoutBoxModelObject::invalidateDisplayItemClients(paintInvalidationContainer, invalidationReason, paintInvalidationRect);
-    // TODO(wangxianzhu): Pass current bounds of lineboxes to PaintController. crbug.com/547119.
+
+    // Use the paintInvalidationRect of LayoutInline for inline boxes, which saves the cost to calculate paint invalidation rect
+    // for every inline box. This won't cause more rasterization invalidations because the whole LayoutInline is being invalidated.
     for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox())
-        paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*box, invalidationReason, nullptr);
+        paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*box, invalidationReason, paintInvalidationRect);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/LayoutListItem.cpp b/third_party/WebKit/Source/core/layout/LayoutListItem.cpp
index fc73d5a..b644a12 100644
--- a/third_party/WebKit/Source/core/layout/LayoutListItem.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutListItem.cpp
@@ -350,6 +350,8 @@
         LayoutUnit lineTop = root.lineTop();
         LayoutUnit lineBottom = root.lineBottom();
 
+        // TODO(jchaffraix): Propagating the overflow to the line boxes seems
+        // pretty wrong (https://crbug.com/554160).
         // FIXME: Need to account for relative positioning in the layout overflow.
         if (style()->isLeftToRightDirection()) {
             LayoutUnit leftLineOffset = logicalLeftOffsetForLine(blockOffset, logicalLeftOffsetForLine(blockOffset, false), false);
@@ -370,7 +372,7 @@
                     if (box == root)
                         adjustOverflow = true;
                 }
-                box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom);
+                box->overrideOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom);
                 if (box->boxModelObject().hasSelfPaintingLayer())
                     hitSelfPaintingLayer = true;
             }
@@ -391,7 +393,7 @@
                     if (box == root)
                         adjustOverflow = true;
                 }
-                box->setOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom);
+                box->overrideOverflowFromLogicalRects(newLogicalLayoutOverflowRect, newLogicalVisualOverflowRect, lineTop, lineBottom);
 
                 if (box->boxModelObject().hasSelfPaintingLayer())
                     hitSelfPaintingLayer = true;
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp
index 98306bb..929cf22 100644
--- a/third_party/WebKit/Source/core/layout/LayoutText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -1877,12 +1877,13 @@
 {
     LayoutObject::invalidateDisplayItemClients(paintInvalidationContainer, invalidationReason, paintInvalidationRect);
 
-    // TODO(wangxianzhu): Pass current bounds of text boxes to PaintController. crbug.com/547119.
+    // Use the paintInvalidationRect of LayoutText for inline boxes, which saves the cost to calculate paint invalidation rect
+    // for every inline box. This won't cause more rasterization invalidations because the whole LayoutText is being invalidated.
     for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) {
-        paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*box, invalidationReason, nullptr);
+        paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*box, invalidationReason, paintInvalidationRect);
         if (box->truncation() != cNoTruncation) {
             if (EllipsisBox* ellipsisBox = box->root().ellipsisBox())
-                paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*ellipsisBox, invalidationReason, nullptr);
+                paintInvalidationContainer.invalidateDisplayItemClientOnBacking(*ellipsisBox, invalidationReason, paintInvalidationRect);
         }
     }
 }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutBox.h b/third_party/WebKit/Source/core/layout/api/LineLayoutBox.h
index dcbbb4e..b9c6249 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutBox.h
@@ -29,6 +29,16 @@
 
     LineLayoutBox() { }
 
+    LayoutPoint location() const
+    {
+        return toBox()->location();
+    }
+
+    LayoutSize size() const
+    {
+        return toBox()->size();
+    }
+
     void setLogicalHeight(LayoutUnit size)
     {
         toBox()->setLogicalHeight(size);
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutBoxModel.h b/third_party/WebKit/Source/core/layout/api/LineLayoutBoxModel.h
index 959294b..b579df4 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutBoxModel.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutBoxModel.h
@@ -178,6 +178,11 @@
         return toBoxModel()->boxShadowShouldBeAppliedToBackground(bleedAvoidance, inlineFlowBox);
     }
 
+    LayoutSize offsetForInFlowPosition() const
+    {
+        return toBoxModel()->offsetForInFlowPosition();
+    }
+
 private:
     LayoutBoxModelObject* toBoxModel() { return toLayoutBoxModelObject(layoutObject()); }
     const LayoutBoxModelObject* toBoxModel() const { return toLayoutBoxModelObject(layoutObject()); }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h b/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
index 760b76f5..fb64879 100644
--- a/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
+++ b/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
@@ -309,6 +309,11 @@
         return m_layoutObject->selectionBackgroundColor();
     }
 
+    bool isInFlowPositioned() const
+    {
+        return m_layoutObject->isInFlowPositioned();
+    }
+
     PositionWithAffinity positionForPoint(const LayoutPoint& point)
     {
         return m_layoutObject->positionForPoint(point);
diff --git a/third_party/WebKit/Source/core/layout/line/InlineBox.h b/third_party/WebKit/Source/core/layout/line/InlineBox.h
index dedadf4..05a5c9a0 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineBox.h
+++ b/third_party/WebKit/Source/core/layout/line/InlineBox.h
@@ -351,6 +351,13 @@
         ADD_BOOLEAN_BITFIELD(endsWithBreak, EndsWithBreak); // Whether the line ends with a <br>.
         // shared between RootInlineBox and InlineTextBox
         ADD_BOOLEAN_BITFIELD(hasSelectedChildrenOrCanHaveLeadingExpansion, HasSelectedChildrenOrCanHaveLeadingExpansion);
+
+        // This boolean will never be set if there is potential for overflow,
+        // but it will be eagerly cleared in the opposite case. As such, it's
+        // a conservative tracking of the absence of overflow.
+        //
+        // For whether we have overflow, callers should use m_overflow on
+        // InlineFlowBox.
         ADD_BOOLEAN_BITFIELD(knownToHaveNoOverflow, KnownToHaveNoOverflow);
         ADD_BOOLEAN_BITFIELD(hasEllipsisBoxOrHyphen, HasEllipsisBoxOrHyphen);
         // for InlineTextBox
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
index 6d44020..6a1dc44 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.cpp
@@ -375,8 +375,8 @@
     return logicalLeft;
 }
 
-// TODO(wkorman): needsWordSpacing may not need to be a reference in the below. Seek a test case.
-void InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild,
+// TODO(wkorman): needsWordSpacing doesn't need to be a reference in the below. Review all params for ref-required.
+LayoutUnit InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild,
     LayoutUnit& logicalLeft, LayoutUnit& minLogicalLeft, LayoutUnit& maxLogicalRight, bool& needsWordSpacing)
 {
     for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) {
@@ -425,16 +425,8 @@
             } else if (!curr->layoutObject().isListMarker() || toLayoutListMarker(curr->layoutObject()).isInside()) {
                 // The box can have a different writing-mode than the overall line, so this is a bit complicated.
                 // Just get all the physical margin and overflow values by hand based off |isHorizontal|.
-                LineLayoutBoxModel box = curr->boxModelObject();
-                LayoutUnit logicalLeftMargin;
-                LayoutUnit logicalRightMargin;
-                if (isHorizontal()) {
-                    logicalLeftMargin = box.marginLeft();
-                    logicalRightMargin = box.marginRight();
-                } else {
-                    logicalLeftMargin = box.marginTop();
-                    logicalRightMargin = box.marginBottom();
-                }
+                LayoutUnit logicalLeftMargin = isHorizontal() ? curr->boxModelObject().marginLeft() : curr->boxModelObject().marginTop();
+                LayoutUnit logicalRightMargin = isHorizontal() ? curr->boxModelObject().marginRight() : curr->boxModelObject().marginBottom();
 
                 logicalLeft += logicalLeftMargin;
                 curr->setLogicalLeft(logicalLeft);
@@ -449,6 +441,7 @@
             }
         }
     }
+    return logicalLeft;
 }
 
 FontBaseline InlineFlowBox::dominantBaseline() const
@@ -940,6 +933,7 @@
 
 void InlineFlowBox::setLayoutOverflow(const LayoutRect& rect, const LayoutRect& frameBox)
 {
+    ASSERT(!knownToHaveNoOverflow());
     if (frameBox.contains(rect) || rect.isEmpty())
         return;
 
@@ -951,6 +945,7 @@
 
 void InlineFlowBox::setVisualOverflow(const LayoutRect& rect, const LayoutRect& frameBox)
 {
+    ASSERT(!knownToHaveNoOverflow());
     if (frameBox.contains(rect) || rect.isEmpty())
         return;
 
@@ -962,6 +957,7 @@
 
 void InlineFlowBox::setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom)
 {
+    ASSERT(!knownToHaveNoOverflow());
     LayoutRect frameBox = frameRectIncludingLineHeight(lineTop, lineBottom);
 
     LayoutRect layoutOverflow(isHorizontal() ? logicalLayoutOverflow : logicalLayoutOverflow.transposedRect());
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h
index 87836f0..dc340c8 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h
+++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h
@@ -176,6 +176,15 @@
     void determineSpacingForFlowBoxes(bool lastLine, bool isLogicallyLastRunWrapped, LayoutObject* logicallyLastRunLayoutObject);
     LayoutUnit getFlowSpacingLogicalWidth();
     LayoutUnit placeBoxesInInlineDirection(LayoutUnit logicalLeft, bool& needsWordSpacing);
+    LayoutUnit placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild,
+        LayoutUnit& logicalLeft, LayoutUnit& minLogicalLeft, LayoutUnit& maxLogicalRight, bool& needsWordSpacing);
+    void beginPlacingBoxRangesInInlineDirection(LayoutUnit logicalLeft) { setLogicalLeft(logicalLeft); }
+    void endPlacingBoxRangesInInlineDirection(LayoutUnit logicalLeft, LayoutUnit logicalRight, LayoutUnit minLogicalLeft, LayoutUnit maxLogicalRight)
+    {
+        setLogicalWidth(logicalRight - logicalLeft);
+        if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight))
+            clearKnownToHaveNoOverflow();
+    }
 
     void computeLogicalBoxHeights(RootInlineBox*, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom, int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, bool noQuirksMode, GlyphOverflowAndFallbackFontsMap&, FontBaseline, VerticalPositionCache&);
     void adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom);
@@ -255,8 +264,6 @@
         return result;
     }
 
-    void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom);
-
     LayoutRect frameRectIncludingLineHeight(LayoutUnit lineTop, LayoutUnit lineBottom) const
     {
         if (isHorizontal())
@@ -280,17 +287,15 @@
     bool isFirstAfterPageBreak() const { return m_isFirstAfterPageBreak; }
     void setIsFirstAfterPageBreak(bool isFirstAfterPageBreak) { m_isFirstAfterPageBreak = isFirstAfterPageBreak; }
 
-private:
-    void placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild,
-        LayoutUnit& logicalLeft, LayoutUnit& minLogicalLeft, LayoutUnit& maxLogicalRight, bool& needsWordSpacing);
-    void beginPlacingBoxRangesInInlineDirection(LayoutUnit logicalLeft) { setLogicalLeft(logicalLeft); }
-    void endPlacingBoxRangesInInlineDirection(LayoutUnit logicalLeft, LayoutUnit logicalRight, LayoutUnit minLogicalLeft, LayoutUnit maxLogicalRight)
+    // Some callers (LayoutListItem) needs to set extra overflow on their line box.
+    void overrideOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom)
     {
-        setLogicalWidth(logicalRight - logicalLeft);
-        if (knownToHaveNoOverflow() && (minLogicalLeft < logicalLeft || maxLogicalRight > logicalRight))
-            clearKnownToHaveNoOverflow();
+        // If we are setting an overflow, then we can't pretend not to have an overflow.
+        clearKnownToHaveNoOverflow();
+        setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, lineTop, lineBottom);
     }
 
+private:
     void addBoxShadowVisualOverflow(LayoutRect& logicalVisualOverflow);
     void addBorderOutsetVisualOverflow(LayoutRect& logicalVisualOverflow);
     void addOutlineVisualOverflow(LayoutRect& logicalVisualOverflow);
@@ -300,6 +305,8 @@
     void setLayoutOverflow(const LayoutRect&, const LayoutRect&);
     void setVisualOverflow(const LayoutRect&, const LayoutRect&);
 
+    void setOverflowFromLogicalRects(const LayoutRect& logicalLayoutOverflow, const LayoutRect& logicalVisualOverflow, LayoutUnit lineTop, LayoutUnit lineBottom);
+
 protected:
     OwnPtr<OverflowModel> m_overflow;
 
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
index c1276fe5..7d3f682 100644
--- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -42,7 +42,6 @@
 #include "core/frame/LocalFrame.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
 #include "core/inspector/InspectorInstrumentation.h"
-#include "core/inspector/InspectorTraceEvents.h"
 #include "core/loader/CrossOriginPreflightResultCache.h"
 #include "core/loader/DocumentThreadableLoaderClient.h"
 #include "core/loader/FrameLoader.h"
@@ -562,7 +561,6 @@
 void DocumentThreadableLoader::reportResponseReceived(unsigned long identifier, const ResourceResponse& response)
 {
     DocumentLoader* loader = m_document.frame()->loader().documentLoader();
-    TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceiveResponse", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveResponseEvent::data(identifier, m_document.frame(), response));
     LocalFrame* frame = m_document.frame();
     InspectorInstrumentation::didReceiveResourceResponse(frame, identifier, loader, response, resource() ? resource()->loader() : 0);
     frame->console().reportResourceResponseReceived(loader, identifier, response);
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
index 6630e9b..3dc981c 100644
--- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
+++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -45,7 +45,6 @@
 #include "core/inspector/ConsoleMessage.h"
 #include "core/inspector/InspectorInstrumentation.h"
 #include "core/inspector/InspectorResourceAgent.h"
-#include "core/inspector/InspectorTraceEvents.h"
 #include "core/inspector/InstrumentingAgents.h"
 #include "core/loader/DocumentLoader.h"
 #include "core/loader/FrameLoader.h"
@@ -224,7 +223,6 @@
 {
     frame()->loader().applyUserAgent(request);
     frame()->loader().client()->dispatchWillSendRequest(m_documentLoader, identifier, request, redirectResponse);
-    TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceSendRequest", TRACE_EVENT_SCOPE_THREAD, "data", InspectorSendRequestEvent::data(identifier, frame(), request));
     InspectorInstrumentation::willSendRequest(frame(), identifier, ensureLoaderForNotifications(), request, redirectResponse, initiatorInfo);
 }
 
@@ -241,7 +239,6 @@
 
     frame()->loader().progress().incrementProgress(identifier, response);
     frame()->loader().client()->dispatchDidReceiveResponse(m_documentLoader, identifier, response);
-    TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceiveResponse", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveResponseEvent::data(identifier, frame(), response));
     DocumentLoader* documentLoader = ensureLoaderForNotifications();
     InspectorInstrumentation::didReceiveResourceResponse(frame(), identifier, documentLoader, response, resourceLoader);
     // It is essential that inspector gets resource response BEFORE console.
@@ -251,14 +248,12 @@
 void FrameFetchContext::dispatchDidReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
 {
     frame()->loader().progress().incrementProgress(identifier, dataLength);
-    TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceivedData", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveDataEvent::data(identifier, frame(), encodedDataLength));
     InspectorInstrumentation::didReceiveData(frame(), identifier, data, dataLength, encodedDataLength);
 }
 
 void FrameFetchContext::dispatchDidDownloadData(unsigned long identifier, int dataLength, int encodedDataLength)
 {
     frame()->loader().progress().incrementProgress(identifier, dataLength);
-    TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceReceivedData", TRACE_EVENT_SCOPE_THREAD, "data", InspectorReceiveDataEvent::data(identifier, frame(), encodedDataLength));
     InspectorInstrumentation::didReceiveData(frame(), identifier, 0, dataLength, encodedDataLength);
 }
 
@@ -266,8 +261,6 @@
 {
     frame()->loader().progress().completeProgress(identifier);
     frame()->loader().client()->dispatchDidFinishLoading(m_documentLoader, identifier);
-
-    TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(identifier, finishTime, false));
     InspectorInstrumentation::didFinishLoading(frame(), identifier, finishTime, encodedDataLength);
 }
 
@@ -275,7 +268,6 @@
 {
     frame()->loader().progress().completeProgress(identifier);
     frame()->loader().client()->dispatchDidFinishLoading(m_documentLoader, identifier);
-    TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(identifier, 0, true));
     InspectorInstrumentation::didFailLoading(frame(), identifier, error);
     // Notification to FrameConsole should come AFTER InspectorInstrumentation call, DevTools front-end relies on this.
     if (!isInternalRequest)
diff --git a/third_party/WebKit/Source/core/loader/PingLoader.cpp b/third_party/WebKit/Source/core/loader/PingLoader.cpp
index 8a11693..9686c880 100644
--- a/third_party/WebKit/Source/core/loader/PingLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/PingLoader.cpp
@@ -40,7 +40,6 @@
 #include "core/frame/FrameConsole.h"
 #include "core/frame/LocalFrame.h"
 #include "core/inspector/InspectorInstrumentation.h"
-#include "core/inspector/InspectorTraceEvents.h"
 #include "core/loader/FrameLoader.h"
 #include "core/loader/FrameLoaderClient.h"
 #include "core/loader/MixedContentChecker.h"
@@ -141,7 +140,6 @@
 {
     frame->loader().client()->didDispatchPingLoader(request.url());
 
-    TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceSendRequest", TRACE_EVENT_SCOPE_THREAD, "data", InspectorSendRequestEvent::data(m_identifier, frame, request));
     InspectorInstrumentation::willSendRequest(frame, m_identifier, frame->loader().documentLoader(), request, ResourceResponse(), initiatorInfo);
 
     m_loader = adoptPtr(Platform::current()->createURLLoader());
@@ -173,7 +171,6 @@
 void PingLoader::didReceiveResponse(WebURLLoader*, const WebURLResponse& response)
 {
     if (LocalFrame* frame = this->frame()) {
-        TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(m_identifier, 0, true));
         const ResourceResponse& resourceResponse = response.toResourceResponse();
         InspectorInstrumentation::didReceiveResourceResponse(frame, m_identifier, 0, resourceResponse, 0);
         didFailLoading(frame);
@@ -183,37 +180,29 @@
 
 void PingLoader::didReceiveData(WebURLLoader*, const char*, int, int)
 {
-    if (LocalFrame* frame = this->frame()) {
-        TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(m_identifier, 0, true));
+    if (LocalFrame* frame = this->frame())
         didFailLoading(frame);
-    }
     dispose();
 }
 
 void PingLoader::didFinishLoading(WebURLLoader*, double, int64_t)
 {
-    if (LocalFrame* frame = this->frame()) {
-        TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(m_identifier, 0, true));
+    if (LocalFrame* frame = this->frame())
         didFailLoading(frame);
-    }
     dispose();
 }
 
 void PingLoader::didFail(WebURLLoader*, const WebURLError& resourceError)
 {
-    if (LocalFrame* frame = this->frame()) {
-        TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(m_identifier, 0, true));
+    if (LocalFrame* frame = this->frame())
         didFailLoading(frame);
-    }
     dispose();
 }
 
 void PingLoader::timeout(Timer<PingLoader>*)
 {
-    if (LocalFrame* frame = this->frame()) {
-        TRACE_EVENT_INSTANT1("devtools.timeline", "ResourceFinish", TRACE_EVENT_SCOPE_THREAD, "data", InspectorResourceFinishEvent::data(m_identifier, 0, true));
+    if (LocalFrame* frame = this->frame())
         didFailLoading(frame);
-    }
     dispose();
 }
 
diff --git a/third_party/WebKit/Source/core/page/FocusController.cpp b/third_party/WebKit/Source/core/page/FocusController.cpp
index dfc0bd0..88f09226 100644
--- a/third_party/WebKit/Source/core/page/FocusController.cpp
+++ b/third_party/WebKit/Source/core/page/FocusController.cpp
@@ -641,6 +641,14 @@
     return nullptr;
 }
 
+bool FocusController::isDocumentFocused(const Document& document) const
+{
+    if (!isActive() || !isFocused())
+        return false;
+
+    return m_focusedFrame && m_focusedFrame->tree().isDescendantOf(document.frame());
+}
+
 void FocusController::setFocused(bool focused)
 {
     if (isFocused() == focused)
diff --git a/third_party/WebKit/Source/core/page/FocusController.h b/third_party/WebKit/Source/core/page/FocusController.h
index 6c8c017..40cf228 100644
--- a/third_party/WebKit/Source/core/page/FocusController.h
+++ b/third_party/WebKit/Source/core/page/FocusController.h
@@ -38,6 +38,7 @@
 
 struct FocusCandidate;
 struct FocusParams;
+class Document;
 class Element;
 class Frame;
 class HTMLFrameOwnerElement;
@@ -61,6 +62,10 @@
     // one of its descendant frames, is currently focused.
     HTMLFrameOwnerElement* focusedFrameOwnerElement(LocalFrame& currentFrame) const;
 
+    // Determines whether the provided Document has focus according to
+    // http://www.w3.org/TR/html5/editing.html#dom-document-hasfocus
+    bool isDocumentFocused(const Document&) const;
+
     bool setInitialFocus(WebFocusType);
     bool advanceFocus(WebFocusType type, InputDeviceCapabilities* sourceCapabilities = nullptr) { return advanceFocus(type, false, sourceCapabilities); }
     Element* findFocusableElement(WebFocusType, Node&);
diff --git a/third_party/WebKit/Source/devtools/BUILD.gn b/third_party/WebKit/Source/devtools/BUILD.gn
index 542f0843..c50d3202b 100644
--- a/third_party/WebKit/Source/devtools/BUILD.gn
+++ b/third_party/WebKit/Source/devtools/BUILD.gn
@@ -121,12 +121,8 @@
   deps = [
     ":devtools_frontend_resources",
   ]
-  static_files_list = "$target_gen_dir/devtools_static_grd_files.tmp"
   inputs = gypi_values.devtools_image_files + all_devtools_files
   inputs += gypi_values.devtools_compatibility_scripts
-  inputs += [ static_files_list ]
-
-  static_files = []
 
   if (debug_devtools) {
     # Debug: all files are picked as-is.
@@ -134,7 +130,15 @@
                         resources_out_dir + "inspector.html",
                         resources_out_dir + "toolbox.html",
                       ]
-    static_files += all_devtools_files + [ "front_end/Runtime.js" ]
+
+    # Use a response file since the static files can be too long for the
+    # command line. The args here will be added to the command line.
+    static_files = all_devtools_files + [ "front_end/Runtime.js" ]
+    response_file_contents = rebase_path(static_files, root_build_dir)
+    static_files_args = [
+      "--static_files_args",
+      "{{response_file_name}}",
+    ]
   } else {
     # Release: pick compiled non-remote files and lazy-loaded CSS.
     generated_files = [
@@ -169,9 +173,9 @@
       resources_out_dir + "ui_lazy_module.js",
       resources_out_dir + "devtools_extension_api.js",
     ]
+    static_files_args = []  # Nothing needed for this
   }
 
-  write_file(static_files_list, rebase_path(static_files, root_build_dir))
   images_path = "front_end/Images"
 
   inputs += generated_files
@@ -190,11 +194,8 @@
       rebase_path(generated_files, root_build_dir) +
       rebase_path(generated_files, root_build_dir) +
       rebase_path(gypi_values.devtools_compatibility_scripts, root_build_dir) +
-      [
-        "--static_files_list",
-        rebase_path(static_files_list, root_build_dir),
-        "--relative_path_dirs",
-      ] + rebase_path(relative_path_dirs, root_build_dir) +
+      static_files_args + [ "--relative_path_dirs" ] +
+      rebase_path(relative_path_dirs, root_build_dir) +
       [
         "--images",
         rebase_path(images_path, root_build_dir),
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
index 8ee139f..56ae9c1 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -2,7 +2,7 @@
     "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
     "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485",
-    "toolbarButtonGlyphs.svg": "0fd81a9a86e0e4822a92b0a145ae6927",
+    "toolbarButtonGlyphs.svg": "2ba1b991ca9d6c772c94c7fb8dad8ad7",
     "breakpoint.svg": "69cd92d807259c022791112809b97799",
     "responsiveDesign.svg": "1d6e963f88e5e448a7cff85f75a0e6b0"
 }
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
index 8ee139f..56ae9c1 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -2,7 +2,7 @@
     "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28",
     "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45",
     "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485",
-    "toolbarButtonGlyphs.svg": "0fd81a9a86e0e4822a92b0a145ae6927",
+    "toolbarButtonGlyphs.svg": "2ba1b991ca9d6c772c94c7fb8dad8ad7",
     "breakpoint.svg": "69cd92d807259c022791112809b97799",
     "responsiveDesign.svg": "1d6e963f88e5e448a7cff85f75a0e6b0"
 }
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
index 7b1a4b8..d0165ed 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
+++ b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
@@ -21,13 +21,13 @@
            rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><sodipodi:namedview
      showgrid="true"
      id="namedview3397"
-     inkscape:zoom="7.9999999"
-     inkscape:cx="111.32508"
-     inkscape:cy="22.300591"
-     inkscape:window-width="2560"
-     inkscape:window-height="1547"
+     inkscape:zoom="32"
+     inkscape:cx="221.62302"
+     inkscape:cy="18.923966"
+     inkscape:window-width="1920"
+     inkscape:window-height="1122"
      inkscape:window-x="0"
-     inkscape:window-y="0"
+     inkscape:window-y="25"
      inkscape:window-maximized="1"
      inkscape:current-layer="svg3395"
      inkscape:snap-global="false"
@@ -1060,4 +1060,16 @@
        style="fill-opacity:0.36000001" /><path
        id="path3486"
        d="m 119.56171,198.24443 -5.5,14 h 2.25 l 1.12,-3 h 6.25 l 1.12,3 h 2.25 l -5.49,-14 h -2 z m -1.38,9 2.38,-6.33 2.38,6.33 h -4.76 z"
-       inkscape:connector-curvature="0" /></g></svg>
\ No newline at end of file
+       inkscape:connector-curvature="0" /></g><path
+     inkscape:connector-curvature="0"
+     d="m 181.72728,149 h -11.45456 c -0.7,0 -1.27272,0.63 -1.27272,1.4 v 8.4 c 0,0.77 0.57272,1.4 1.27272,1.4 h 4.45456 v 1.4 h -1.27273 v 1.4 h 5.0909 v -1.4 h -1.27273 v -1.4 h 4.45456 c 0.7,0 1.27272,-0.63 1.27272,-1.4 v -8.4 c 0,-0.77 -0.57272,-1.4 -1.27272,-1.4 z m 0,9.8 h -11.45456 v -8.4 h 11.45456 v 8.4 z"
+     id="path6-2" /><path
+     inkscape:connector-curvature="0"
+     d="m 211.37405,148.89 c 2.46276,1.1625 4.2251,3.53999 4.49624,6.36001 H 217 C 216.61589,150.63 212.73724,147 208,147 l -0.49707,0.0225 2.86945,2.8575 1.00167,-0.99 z m -4.70711,-0.5775 c -0.44434,-0.44249 -1.15983,-0.44249 -1.59664,0 l -4.78997,4.77 c -0.44434,0.4425 -0.44434,1.155 0,1.59 l 9.05272,9.015 c 0.44435,0.44249 1.15984,0.44249 1.59665,0 l 4.78996,-4.76999 c 0.44435,-0.44251 0.44435,-1.15501 0,-1.59001 l -9.05272,-9.015 z m 3.46444,14.58 -9.05272,-9.01499 4.78996,-4.77001 9.05272,9.01499 -4.78996,4.77001 z m -5.50545,0.2175 c -2.46275,-1.155 -4.22509,-3.53999 -4.49622,-6.36001 H 199 C 199.38411,161.37 203.26276,165 208,165 l 0.49706,-0.0225 -2.86945,-2.8575 -1.00168,0.99 z"
+     id="path6" /><path
+     inkscape:connector-curvature="0"
+     d="m 235,151 0,10 10,0 0,-10 z m 1,1 8,0 0,8 -8,0 z"
+     id="path3055" /><path
+     inkscape:connector-curvature="0"
+     d="m 237,153 0,3 1,0 0,-1.27999 3.28,3.27999 -1.28,0 0,1 3,0 0,-3 -1,0 0,1.31 -3.30999,-3.31 1.30999,0 0,-1 z"
+     id="path3057" /></svg>
\ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
index e5725c2c..a7467cc 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
index c439029..690cd69 100644
--- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
+++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png
Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/animation/AnimationGroupPreviewUI.js b/third_party/WebKit/Source/devtools/front_end/animation/AnimationGroupPreviewUI.js
index b463ff6..3fe0679 100644
--- a/third_party/WebKit/Source/devtools/front_end/animation/AnimationGroupPreviewUI.js
+++ b/third_party/WebKit/Source/devtools/front_end/animation/AnimationGroupPreviewUI.js
@@ -10,6 +10,7 @@
 {
     this._model = model;
     this.element = createElementWithClass("div", "animation-buffer-preview");
+    this.element.createChild("div", "animation-paused fill");
     this._replayOverlayElement = this.element.createChild("div", "animation-buffer-preview-animation");
     this._svg = this.element.createSVGChild("svg");
     this._svg.setAttribute("width", "100%");
diff --git a/third_party/WebKit/Source/devtools/front_end/animation/AnimationModel.js b/third_party/WebKit/Source/devtools/front_end/animation/AnimationModel.js
index 0fe690c..44569ce 100644
--- a/third_party/WebKit/Source/devtools/front_end/animation/AnimationModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/animation/AnimationModel.js
@@ -327,8 +327,7 @@
         this._source.node().then(this._updateNodeStyle.bind(this, duration, delay));
         this._source._duration = duration;
         this._source._delay = delay;
-        if (this.type() !== WebInspector.AnimationModel.Animation.Type.CSSAnimation)
-            this.target().animationAgent().setTiming(this.id(), duration, delay);
+        this.target().animationAgent().setTiming(this.id(), duration, delay);
     },
 
     /**
@@ -692,6 +691,8 @@
      */
     togglePause: function(paused)
     {
+        if (paused === this._paused)
+            return;
         this._paused = paused;
         this.target().animationAgent().setPaused(this._animationIds(), paused);
     },
diff --git a/third_party/WebKit/Source/devtools/front_end/animation/AnimationTimeline.js b/third_party/WebKit/Source/devtools/front_end/animation/AnimationTimeline.js
index b8c018d..79a4041 100644
--- a/third_party/WebKit/Source/devtools/front_end/animation/AnimationTimeline.js
+++ b/third_party/WebKit/Source/devtools/front_end/animation/AnimationTimeline.js
@@ -200,7 +200,6 @@
             this._replay();
         else
             this._togglePause(true);
-        this._updateControlButton();
     },
 
     _updateControlButton: function()
@@ -256,6 +255,8 @@
         this._selectedGroup.togglePause(pause);
         if (this._scrubberPlayer)
             this._scrubberPlayer.playbackRate = this._effectivePlaybackRate();
+        this._previewMap.get(this._selectedGroup).element.classList.toggle("paused", pause);
+        this._updateControlButton();
     },
 
     _replay: function()
@@ -408,6 +409,7 @@
             this._addAnimation(anim);
         this.scheduleRedraw();
         this._timelineScrubber.classList.remove("hidden");
+        this._togglePause(false);
         this._replay();
     },
 
@@ -603,7 +605,6 @@
         this._selectedGroup.seekTo(seekTime);
         this._togglePause(true);
         this._animateTime(seekTime);
-        this._updateControlButton();
 
         // Interface with scrubber drag.
         this._originalScrubberTime = seekTime;
@@ -626,7 +627,6 @@
         this._originalMousePosition = event.x;
 
         this._togglePause(true);
-        this._updateControlButton();
         return true;
     },
 
@@ -671,8 +671,7 @@
         if (!node)
             return;
         this._node = node;
-        WebInspector.DOMPresentationUtils.decorateNodeLabel(node, this._description);
-        this.element.addEventListener("click", WebInspector.Revealer.reveal.bind(WebInspector.Revealer, node, undefined), false);
+        this._description.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(node));
     }
 
     this._rows = [];
diff --git a/third_party/WebKit/Source/devtools/front_end/animation/animationTimeline.css b/third_party/WebKit/Source/devtools/front_end/animation/animationTimeline.css
index 3ba9c11..14fd8d7 100644
--- a/third_party/WebKit/Source/devtools/front_end/animation/animationTimeline.css
+++ b/third_party/WebKit/Source/devtools/front_end/animation/animationTimeline.css
@@ -359,6 +359,28 @@
     background-color: hsl(217, 89%, 61%);
 }
 
+.animation-paused {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: hsla(0,0%,70%,0.5);
+    display: none;
+}
+
+.animation-paused:before, .animation-paused:after {
+    content: "";
+    background: hsl(0, 100%, 100%);
+    width: 7px;
+    height: 20px;
+    border-radius: 2px;
+    margin: 2px;
+    border: 1px solid #ccc;
+}
+
+.animation-buffer-preview:not(.selected).paused .animation-paused {
+    display: flex;
+}
+
 .animation-buffer-preview.selected > svg > line {
     stroke: white !important;
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/components/InspectorView.js b/third_party/WebKit/Source/devtools/front_end/components/InspectorView.js
index 1ec9f35..bf8964a 100644
--- a/third_party/WebKit/Source/devtools/front_end/components/InspectorView.js
+++ b/third_party/WebKit/Source/devtools/front_end/components/InspectorView.js
@@ -73,15 +73,17 @@
     this._closeBracketIdentifiers = ["U+005D", "U+00DD"].keySet();
     this._lastActivePanelSetting = WebInspector.settings.createSetting("lastActivePanel", "elements");
 
-    InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.ShowConsole, showConsole.bind(this));
+    InspectorFrontendHost.events.addEventListener(InspectorFrontendHostAPI.Events.ShowPanel, showPanel.bind(this));
     this._loadPanelDesciptors();
 
     /**
      * @this {WebInspector.InspectorView}
+     * @param {!WebInspector.Event} event
      */
-    function showConsole()
+    function showPanel(event)
     {
-        this.showPanel("console");
+        var panelName = /** @type {string} */ (event.data);
+        this.showPanel(panelName);
     }
 
     WebInspector.targetManager.addEventListener(WebInspector.TargetManager.Events.SuspendStateChanged, this._onSuspendStateChanged.bind(this));
diff --git a/third_party/WebKit/Source/devtools/front_end/devtools.js b/third_party/WebKit/Source/devtools/front_end/devtools.js
index efc0cce..84a2265f 100644
--- a/third_party/WebKit/Source/devtools/front_end/devtools.js
+++ b/third_party/WebKit/Source/devtools/front_end/devtools.js
@@ -274,9 +274,12 @@
         this._dispatchOnInspectorFrontendAPI("setUseSoftMenu", [useSoftMenu]);
     },
 
-    showConsole: function()
+    /**
+     * @param {string} panelName
+     */
+    showPanel: function(panelName)
     {
-        this._dispatchOnInspectorFrontendAPI("showConsole", []);
+        this._dispatchOnInspectorFrontendAPI("showPanel", [panelName]);
     },
 
     /**
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElementHighlighter.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElementHighlighter.js
index b0c9e5a..0a41042 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElementHighlighter.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElementHighlighter.js
@@ -23,6 +23,9 @@
      */
     _highlightNode: function(event)
     {
+        if (!WebInspector.moduleSetting("highlightNodeOnHoverInOverlay").get())
+            return;
+
         var domNode = /** @type {!WebInspector.DOMNode} */ (event.data);
 
         this._throttler.schedule(callback.bind(this));
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/module.json b/third_party/WebKit/Source/devtools/front_end/elements/module.json
index 11cbdf2..bc3fca6 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/elements/module.json
@@ -25,6 +25,7 @@
         {
             "type": "setting",
             "category": "Elements",
+            "order": 0,
             "title": "Color format:",
             "settingName": "colorFormat",
             "settingType": "enum",
@@ -39,6 +40,7 @@
         {
             "type": "setting",
             "category": "Elements",
+            "order":1,
             "title": "Show user agent shadow DOM",
             "settingName": "showUAShadowDOM",
             "settingType": "boolean",
@@ -47,6 +49,7 @@
         {
             "type": "setting",
             "category": "Elements",
+            "order": 2,
             "title": "Word wrap",
             "settingName": "domWordWrap",
             "settingType": "boolean",
@@ -55,12 +58,22 @@
         {
             "type": "setting",
             "category": "Elements",
+            "order": 3,
             "title": "Show rulers",
             "settingName": "showMetricsRulers",
             "settingType": "boolean",
             "defaultValue": false
         },
         {
+            "type": "setting",
+            "category": "Elements",
+            "order": 4,
+            "title": "Reveal DOM node on hover.",
+            "settingName": "highlightNodeOnHoverInOverlay",
+            "settingType": "boolean",
+            "defaultValue": true
+        },
+        {
             "type": "@WebInspector.ToolbarItem.Provider",
             "className": "WebInspector.ElementStatePaneWidget.ButtonProvider",
             "order": 1,
diff --git a/third_party/WebKit/Source/devtools/front_end/emulated_devices/module.json b/third_party/WebKit/Source/devtools/front_end/emulated_devices/module.json
index dc1ad57..7668fb2a 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulated_devices/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/emulated_devices/module.json
@@ -56,7 +56,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
+                "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B137 Safari/601.1",
                 "type": "phone",
                 "modes": [
                     {
@@ -92,7 +92,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4",
+                "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1",
                 "type": "phone",
                 "modes": [
                     {
@@ -158,7 +158,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4",
+                "user-agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1",
                 "type": "phone",
                 "modes": [
                     {
@@ -230,7 +230,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.122 Mobile Safari/537.36",
+                "user-agent": "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36",
                 "type": "phone",
                 "modes": [
                     {
@@ -271,7 +271,7 @@
             "device": {
                 "title": "Google Nexus 5",
                 "type": "phone",
-                "user-agent": "Mozilla/5.0 (Linux; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36",
+                "user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36",
                 "capabilities": [
                     "touch",
                     "mobile"
@@ -348,7 +348,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.20 Mobile Safari/537.36",
+                "user-agent": "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36",
                 "type": "phone",
                 "modes": [
                     {
@@ -404,7 +404,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Mobile Safari/537.36",
+                "user-agent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/46.0.2490.76 Mobile Safari/537.36",
                 "type": "phone",
                 "modes": [
                     {
@@ -548,7 +548,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36",
+                "user-agent": "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36",
                 "type": "phone",
                 "modes": [
                     {
@@ -656,7 +656,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
+                "user-agent": "Mozilla/5.0 (iPad; CPU OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B137 Safari/601.1",
                 "type": "tablet",
                 "modes": [
                     {
@@ -728,7 +728,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2307.2 Safari/537.36",
+                "user-agent": "Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Safari/537.36",
                 "type": "tablet",
                 "modes": [
                     {
@@ -764,7 +764,7 @@
                     "touch",
                     "mobile"
                 ],
-                "user-agent": "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2307.2 Safari/537.36",
+                "user-agent": "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Safari/537.36",
                 "type": "tablet",
                 "modes": [
                     {
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
index c24f452..2873541 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
@@ -15,15 +15,22 @@
     this._fitScale = 1;
     this._availableSize = new Size(1, 1);
     this._deviceMetricsThrottler = new WebInspector.Throttler(0);
+    this._appliedDeviceSize = new Size(1, 1);
+    this._currentDeviceScaleFactor = window.devicePixelRatio;
+    this._appliedDeviceScaleFactor = 0;
 
-    this._fitSetting = WebInspector.settings.createSetting("deviceFitWindow", true);
+    // Zero means "fit", positive number is a scale itself.
+    this._fitSetting = WebInspector.settings.createSetting("emulation.deviceFit", 0);
     this._fitSetting.addChangeListener(this._fitSettingChanged, this);
-    this._genericWidthSetting = WebInspector.settings.createSetting("deviceGenericWidth", 0);
-    this._genericWidthSetting.set(0);
-    this._genericWidthSetting.addChangeListener(this._genericWidthSettingChanged, this);
+    this._widthSetting = WebInspector.settings.createSetting("emulation.deviceWidth", 400);
+    this._widthSetting.addChangeListener(this._widthSettingChanged, this);
+    this._deviceScaleFactorSetting = WebInspector.settings.createSetting("emulation.deviceScaleFactor", 0);
+    this._deviceScaleFactorSetting.addChangeListener(this._deviceScaleFactorSettingChanged, this);
 
     /** @type {!WebInspector.DeviceModeModel.Type} */
     this._type = WebInspector.DeviceModeModel.Type.Desktop;
+    this._fitSetting.set(0);
+    this._deviceScaleFactorSetting.set(0);
     /** @type {?WebInspector.EmulatedDevice} */
     this._device = null;
     /** @type {?WebInspector.EmulatedDevice.Mode} */
@@ -36,10 +43,6 @@
     this._screenOrientation = "";
     /** @type {number} */
     this._fixedFitScale = 0;
-    /** @type {string} */
-    this._warning = "";
-    /** @type {boolean} */
-    this._emulatingMobile = false;
 
     /** @type {?WebInspector.Target} */
     this._target = null;
@@ -48,9 +51,8 @@
 
 /** @enum {string} */
 WebInspector.DeviceModeModel.Type = {
-    Mobile: "Mobile",
-    Tablet: "Tablet",
     Desktop: "Desktop",
+    Mobile: "Mobile",
     Device: "Device"
 }
 
@@ -62,15 +64,25 @@
  */
 WebInspector.DeviceModeModel.deviceSizeValidator = function(value)
 {
-    if (!value || (/^[\d]+$/.test(value) && value >= 0 && value <= WebInspector.OverridesSupport.MaxDeviceSize))
+    if (/^[\d]+$/.test(value) && value > 0 && value <= WebInspector.DeviceModeModel.MaxDeviceSize)
         return "";
-    return WebInspector.UIString("Value must be non-negative integer");
+    return WebInspector.UIString("Value must be positive integer");
+}
+
+/**
+ * @param {string} value
+ * @return {string}
+ */
+WebInspector.DeviceModeModel.deviceScaleFactorValidator = function(value)
+{
+    if (!value || (/^[\d]+(\.\d+)?|\.\d+$/.test(value) && value >= 0 && value <= 10))
+        return "";
+    return WebInspector.UIString("Value must be non-negative float");
 }
 
 WebInspector.DeviceModeModel._touchEventsScriptIdSymbol = Symbol("DeviceModeModel.touchEventsScriptIdSymbol");
-// TODO(paulirish): decide on these.
-WebInspector.DeviceModeModel._genericMobileUserAgent = "Mozilla/5.0 (Linux; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36";
-WebInspector.DeviceModeModel._genericTabletUserAgent = "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2307.2 Safari/537.36";
+WebInspector.DeviceModeModel._defaultMobileUserAgent = "Mozilla/5.0 (Linux; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile Safari/537.36";
+WebInspector.DeviceModeModel._defaultMobileScaleFactor = 2;
 
 WebInspector.DeviceModeModel.prototype = {
     /**
@@ -85,21 +97,24 @@
     /**
      * @param {!WebInspector.DeviceModeModel.Type} type
      * @param {?WebInspector.EmulatedDevice} device
+     * @param {?WebInspector.EmulatedDevice.Mode} mode
      */
-    emulate: function(type, device)
+    emulate: function(type, device, mode)
     {
         this._type = type;
 
         if (type === WebInspector.DeviceModeModel.Type.Device) {
-            console.assert(device, "Must pass a device for device emulation");
+            console.assert(device && mode, "Must pass device and mode for device emulation");
             this._device = device;
-            this._mode = device.modes[0];
+            this._mode = mode;
         } else {
             this._device = null;
             this._mode = null;
-            this._genericWidthSetting.removeChangeListener(this._genericWidthSettingChanged, this);
-            this._genericWidthSetting.set(type === WebInspector.DeviceModeModel.Type.Desktop ? 0 : (type === WebInspector.DeviceModeModel.Type.Mobile ? 480 : 768));
-            this._genericWidthSetting.addChangeListener(this._genericWidthSettingChanged, this);
+            if (type === WebInspector.DeviceModeModel.Type.Desktop) {
+                this._fitSetting.removeChangeListener(this._fitSettingChanged, this);
+                this._fitSetting.set(0);
+                this._fitSetting.addChangeListener(this._fitSettingChanged, this);
+            }
         }
 
         this._calculateAndEmulate(true);
@@ -114,6 +129,14 @@
     },
 
     /**
+     * @return {?WebInspector.EmulatedDevice.Mode}
+     */
+    mode: function()
+    {
+        return this._mode;
+    },
+
+    /**
      * @return {!WebInspector.DeviceModeModel.Type}
      */
     type: function()
@@ -158,7 +181,23 @@
      */
     appliedDeviceSize: function()
     {
-        return new Size(Math.round(this._screenRect.width / this._fitScale), Math.round(this._screenRect.height / this._fitScale));
+        return this._appliedDeviceSize;
+    },
+
+    /**
+     * @return {number}
+     */
+    appliedDeviceScaleFactor: function()
+    {
+        return this._appliedDeviceScaleFactor;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isResizable: function()
+    {
+        return this._type === WebInspector.DeviceModeModel.Type.Mobile || (this._type === WebInspector.DeviceModeModel.Type.Desktop && this._fitSetting.get());
     },
 
     /**
@@ -172,9 +211,30 @@
     /**
      * @return {!WebInspector.Setting}
      */
-    genericWidthSetting: function()
+    widthSetting: function()
     {
-        return this._genericWidthSetting;
+        return this._widthSetting;
+    },
+
+    /**
+     * @return {!WebInspector.Setting}
+     */
+    deviceScaleFactorSetting: function()
+    {
+        return this._deviceScaleFactorSetting;
+    },
+
+    /**
+     * @return {number}
+     */
+    defaultDeviceScaleFactor: function()
+    {
+        if (this._type === WebInspector.DeviceModeModel.Type.Mobile)
+            return WebInspector.DeviceModeModel._defaultMobileScaleFactor;
+        else if (this._type === WebInspector.DeviceModeModel.Type.Device)
+            return this._device.deviceScaleFactor;
+        else
+            return this._currentDeviceScaleFactor;
     },
 
     suspendFitScaleChanges: function()
@@ -188,18 +248,11 @@
             this._calculateAndEmulate(false);
     },
 
-    /**
-     * @return {string}
-     */
-    warning: function()
+    reset: function()
     {
-        return this._warning;
-    },
-
-    clearWarning: function()
-    {
-        this._warning = "";
-        this._updateCallback.call(this);
+        this._deviceScaleFactorSetting.set(0);
+        this._fitSetting.set(0);
+        this._widthSetting.set(400);
     },
 
     /**
@@ -208,10 +261,8 @@
      */
     targetAdded: function(target)
     {
-        if (!this._target) {
+        if (!this._target)
             this._target = target;
-            this._target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this.clearWarning, this);
-        }
     },
 
     /**
@@ -220,10 +271,8 @@
      */
     targetRemoved: function(target)
     {
-        if (this._target === target) {
-            this._target.resourceTreeModel.removeEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this.clearWarning, this);
+        if (this._target === target)
             this._target = null;
-        }
     },
 
     _fitSettingChanged: function()
@@ -231,7 +280,12 @@
         this._calculateAndEmulate(false);
     },
 
-    _genericWidthSettingChanged: function()
+    _widthSettingChanged: function()
+    {
+        this._calculateAndEmulate(false);
+    },
+
+    _deviceScaleFactorSettingChanged: function()
     {
         this._calculateAndEmulate(false);
     },
@@ -245,57 +299,57 @@
             var orientation = this._device.orientationByName(this._mode.orientation);
             var screenWidth = orientation.width;
             var screenHeight = orientation.height;
-            var scale = 1;
-            // Deliberately ignore fixedFitScale.
-            if (this._fitSetting.get()) {
-                while (this._availableSize.width < screenWidth * scale || this._availableSize.height < screenHeight * scale)
-                    scale *= 0.8;
-            }
+            var scale = this._calculateScale(screenWidth, screenHeight);
             this._applyDeviceMetrics(new Size(screenWidth, screenHeight), this._mode.insets, scale, this._device.deviceScaleFactor, this._device.mobile(), resetScrollAndPageScale);
             this._applyUserAgent(this._device.userAgent);
             this._applyTouch(this._device.touch(), this._device.mobile());
             this._applyScreenOrientation(this._mode.orientation == WebInspector.EmulatedDevice.Horizontal ? "landscapePrimary" : "portraitPrimary");
-        } else {
-            // Zero means fill available size.
-            var screenWidth = this._genericWidthSetting.get() || this._availableSize.width;
-            var deviceScaleFactor = this._type === WebInspector.DeviceModeModel.Type.Desktop ? 0 : 2;
-            var mobile = this._type !== WebInspector.DeviceModeModel.Type.Desktop;
-
-            var scale = 1;
-            if (this._fitSetting.get()) {
-                if (this._fixedFitScale) {
-                    scale = this._fitScale;
-                } else {
-                    while (this._availableSize.width < screenWidth * scale)
-                        scale *= 0.8;
-                }
-            }
+        } else if (this._type === WebInspector.DeviceModeModel.Type.Desktop) {
+            var screenWidth = this._fitSetting.get() ? this._widthSetting.get() : this._availableSize.width;
+            var scale = this._calculateScale(screenWidth, 0);
             var screenHeight = Math.floor(this._availableSize.height / scale);
-            this._applyDeviceMetrics(new Size(screenWidth, screenHeight), new Insets(0, 0, 0, 0), scale, deviceScaleFactor, mobile, resetScrollAndPageScale);
-            this._applyUserAgent(
-                this._type === WebInspector.DeviceModeModel.Type.Mobile ? WebInspector.DeviceModeModel._genericMobileUserAgent :
-                (this._type === WebInspector.DeviceModeModel.Type.Tablet ? WebInspector.DeviceModeModel._genericTabletUserAgent : ""));
-            this._applyTouch(this._type !== WebInspector.DeviceModeModel.Type.Desktop, mobile);
-            if (this._type === WebInspector.DeviceModeModel.Type.Desktop)
-                this._applyScreenOrientation("");
-            else
-                this._applyScreenOrientation(screenHeight >= screenWidth ? "portraitPrimary" : "landscapePrimary");
+            this._applyDeviceMetrics(new Size(screenWidth, screenHeight), new Insets(0, 0, 0, 0), scale, this._deviceScaleFactorSetting.get(), false, resetScrollAndPageScale);
+            this._applyUserAgent("");
+            this._applyTouch(false, false);
+            this._applyScreenOrientation("");
+        } else if (this._type === WebInspector.DeviceModeModel.Type.Mobile) {
+            var screenWidth = this._widthSetting.get();
+            var scale = this._calculateScale(screenWidth, 0);
+            var screenHeight = Math.floor(this._availableSize.height / scale);
+            this._applyDeviceMetrics(new Size(screenWidth, screenHeight), new Insets(0, 0, 0, 0), scale, this._deviceScaleFactorSetting.get() || WebInspector.DeviceModeModel._defaultMobileScaleFactor, true, resetScrollAndPageScale);
+            this._applyUserAgent(WebInspector.DeviceModeModel._defaultMobileUserAgent);
+            this._applyTouch(true, true);
+            this._applyScreenOrientation(screenHeight >= screenWidth ? "portraitPrimary" : "landscapePrimary");
         }
         this._updateCallback.call(null);
     },
 
     /**
+     * @param {number} screenWidth
+     * @param {number} screenHeight
+     * @return {number}
+     */
+    _calculateScale: function(screenWidth, screenHeight)
+    {
+        var scale = this._fitSetting.get();
+        if (!scale) {
+            if (!screenHeight && this._fixedFitScale) {
+                scale = this._fitScale;
+            } else {
+                scale = 1;
+                while (this._availableSize.width < screenWidth * scale || (!screenHeight && this._availableSize.height < screenHeight * scale))
+                    scale *= 0.8;
+            }
+        }
+        return scale;
+    },
+
+    /**
      * @param {string} userAgent
      */
     _applyUserAgent: function(userAgent)
     {
-        var current = WebInspector.multitargetNetworkManager.userAgentOverride();
-        if (current !== userAgent) {
-            WebInspector.multitargetNetworkManager.setUserAgentOverride(userAgent);
-            if (!this._warning)
-                this._warning = WebInspector.UIString("You might need to reload the page for proper user agent spoofing and viewport rendering.");
-        }
-
+        WebInspector.multitargetNetworkManager.setUserAgentOverride(userAgent);
     },
 
     /**
@@ -313,6 +367,7 @@
         var positionX = insets.left;
         var positionY = insets.top;
 
+        this._appliedDeviceSize = screenSize;
         this._screenRect = new WebInspector.Rect(
             Math.max(0, (this._availableSize.width - screenSize.width * scale) / 2),
             Math.max(0, (this._availableSize.height - screenSize.height * scale) / 2),
@@ -324,6 +379,7 @@
             Math.min(pageWidth * scale, this._availableSize.width - this._screenRect.left - positionX * scale),
             Math.min(pageHeight * scale, this._availableSize.height - this._screenRect.top - positionY * scale));
         this._fitScale = scale;
+        this._appliedDeviceScaleFactor = deviceScaleFactor;
 
         if (scale === 1 && this._availableSize.width >= screenSize.width && this._availableSize.height >= screenSize.height) {
             // When we have enough space, no page size override is required. This will speed things up and remove lag.
@@ -344,35 +400,13 @@
 
             var clear = !pageWidth && !pageHeight && !mobile && !deviceScaleFactor && scale === 1;
             var setDevicePromise = clear ?
-                this._target.emulationAgent().clearDeviceMetricsOverride(apiCallback.bind(this)) :
-                this._target.emulationAgent().setDeviceMetricsOverride(pageWidth, pageHeight, deviceScaleFactor, mobile, false, scale, 0, 0, screenSize.width, screenSize.height, positionX, positionY, apiCallback.bind(this));
+                this._target.emulationAgent().clearDeviceMetricsOverride(this._deviceMetricsOverrideAppliedForTest.bind(this)) :
+                this._target.emulationAgent().setDeviceMetricsOverride(pageWidth, pageHeight, deviceScaleFactor, mobile, false, scale, 0, 0, screenSize.width, screenSize.height, positionX, positionY, this._deviceMetricsOverrideAppliedForTest.bind(this));
             var allPromises = [ setDevicePromise ];
             if (resetScrollAndPageScale)
                 allPromises.push(this._target.emulationAgent().resetScrollAndPageScaleFactor());
             return Promise.all(allPromises);
         }
-
-        /**
-         * @param {?Protocol.Error} error
-         * @this {WebInspector.DeviceModeModel}
-         */
-        function apiCallback(error)
-        {
-            if (error) {
-                this._warning = WebInspector.UIString("Screen emulation is not available on this page.");
-                this._updateCallback.call(null);
-                this._deviceMetricsOverrideAppliedForTest();
-                return;
-            }
-
-            if (mobile !== this._emulatingMobile && !this._warning) {
-                this._warning = WebInspector.UIString("You might need to reload the page for proper user agent spoofing and viewport rendering.");
-                this._updateCallback.call(null);
-            }
-            this._emulatingMobile = mobile;
-            this._deviceMetricsOverrideAppliedForTest();
-        }
-
     },
 
     _deviceMetricsOverrideAppliedForTest: function()
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
index d4948c9..a3874a6 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
@@ -16,19 +16,26 @@
     WebInspector.Tooltip.addNativeOverrideContainer(this.contentElement);
 
     this._model = new WebInspector.DeviceModeModel(this._updateUI.bind(this));
-    this._mediaInspector = new WebInspector.MediaQueryInspector(this._model.genericWidthSetting());
-    // TODO(dgozman): better full control, controlling mode, persist type/device, more fit options.
+    this._mediaInspector = new WebInspector.MediaQueryInspector(this._model.widthSetting());
+    // TODO(dgozman): remove CountUpdated event.
+    // TODO(dgozman): better media inspector UI.
+    this._mediaInspector.addEventListener(WebInspector.MediaQueryInspector.Events.HeightUpdated, this.onResize.bind(this));
+    this._showMediaInspectorSetting = WebInspector.settings.createSetting("showMediaQueryInspector", false);
+    this._showMediaInspectorSetting.addChangeListener(this._showMediaInspectorSettingChanged, this);
 
     this._inspectedPagePlaceholder = inspectedPagePlaceholder;
     this._createUI();
+    this._updateMediaInspector();
     WebInspector.zoomManager.addEventListener(WebInspector.ZoomManager.Events.ZoomChanged, this._updateUI, this);
 };
 
 WebInspector.DeviceModeView.prototype = {
     _createUI: function()
     {
-        var toolbarContainer = this.contentElement.createChild("div", "device-mode-toolbar");
-        var mediaInspectorContainer = this.contentElement.createChild("div", "device-mode-media-container");
+        this._toolbar = new WebInspector.DeviceModeView.Toolbar(this._model, this._showMediaInspectorSetting);
+        this.contentElement.appendChild(this._toolbar.element());
+
+        this._mediaInspectorContainer = this.contentElement.createChild("div", "device-mode-media-container");
         this._contentArea = this.contentElement.createChild("div", "device-mode-content-area");
 
         this._screenArea = this._contentArea.createChild("div", "device-mode-screen-area");
@@ -36,6 +43,8 @@
         this._screenImage.addEventListener("load", this._onScreenImageLoaded.bind(this, true), false);
         this._screenImage.addEventListener("error", this._onScreenImageLoaded.bind(this, false), false);
 
+        this._screenArea.appendChild(this._toolbar.screenOptionsElement());
+
         this._resizerElement = this._screenArea.createChild("div", "device-mode-resizer");
         this._resizerElement.createChild("div", "");
         this._createResizer(this._resizerElement);
@@ -43,128 +52,21 @@
         this._pageArea = this._screenArea.createChild("div", "device-mode-page-area");
         this._inspectedPagePlaceholder.clearMinimumSizeAndMargins();
         this._inspectedPagePlaceholder.show(this._pageArea);
-
-        this._warningInfobar = new WebInspector.Infobar(WebInspector.Infobar.Type.Warning, WebInspector.moduleSetting("disableOverridesWarning"));
-        this._warningInfobar.element.classList.add("device-mode-warning");
-        this._warningInfobar.setCloseCallback(this._model.clearWarning.bind(this._model));
-        this._contentArea.appendChild(this._warningInfobar.element);
-        this._warningMessage = this._warningInfobar.element.createChild("span");
-
-        this._createToolbar(toolbarContainer, mediaInspectorContainer);
     },
 
-    /**
-     * @param {!Element} toolbarContainer
-     * @param {!Element} mediaInspectorContainer
-     */
-    _createToolbar: function(toolbarContainer, mediaInspectorContainer)
+    _showMediaInspectorSettingChanged: function()
     {
-        var toolbar = new WebInspector.Toolbar(toolbarContainer);
-
-        var deviceSelect = this._createDeviceSelect();
-        var deviceSelectItem = new WebInspector.ToolbarItem(this._wrapToolbarItem(deviceSelect));
-        toolbar.appendToolbarItem(deviceSelectItem);
-        toolbar.appendSeparator();
-
-        var genericWidthInput = createElementWithClass("input", "device-mode-size-input");
-        genericWidthInput.maxLength = 5;
-        genericWidthInput.placeholder = WebInspector.UIString("Full");
-        WebInspector.SettingsUI.bindSettingInputField(genericWidthInput, this._model.genericWidthSetting(), true, WebInspector.DeviceModeModel.deviceSizeValidator, true, true);
-        this._genericWidthItem = new WebInspector.ToolbarItem(this._wrapToolbarItem(genericWidthInput));
-        toolbar.appendToolbarItem(this._genericWidthItem);
-
-        this._deviceSizeInput = createElementWithClass("input", "device-mode-size-input");
-        this._deviceSizeInput.disabled = true;
-        this._deviceSizeInput.style.opacity = "0.7";
-        this._deviceSizeItem = new WebInspector.ToolbarItem(this._wrapToolbarItem(this._deviceSizeInput));
-        toolbar.appendToolbarItem(this._deviceSizeItem);
-        toolbar.appendSeparator();
-
-        var fitCheckbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Fit"), this._model.fitSetting(), true, WebInspector.UIString("Zoom to fit available space"));
-        var fitItem = new WebInspector.ToolbarItem(fitCheckbox);
-        toolbar.appendToolbarItem(fitItem);
-        toolbar.appendSeparator();
-
-        var mediaInspectorButton = new WebInspector.DeviceModeView.MediaInspectorButton(this._mediaInspector, mediaInspectorContainer, this.onResize.bind(this));
-        toolbar.appendToolbarItem(mediaInspectorButton.button());
+        this._updateMediaInspector();
+        this.onResize();
     },
 
-    /**
-     * @param {!Element} element
-     * @return {!Element}
-     */
-    _wrapToolbarItem: function(element)
+    _updateMediaInspector: function()
     {
-        var container = createElement("div");
-        var shadowRoot = WebInspector.createShadowRootWithCoreStyles(container);
-        shadowRoot.appendChild(WebInspector.Widget.createStyleElement("emulation/deviceModeToolbar.css"));
-        shadowRoot.appendChild(element);
-        return container;
-    },
-
-    /**
-     * @return {!Element}
-     */
-    _createDeviceSelect: function()
-    {
-        var select = createElementWithClass("select", "device-mode-device-select");
-        WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevicesList.Events.CustomDevicesUpdated, deviceListChanged, this);
-        WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevicesList.Events.StandardDevicesUpdated, deviceListChanged, this);
-        deviceListChanged.call(this);
-        select.addEventListener("change", optionSelected.bind(this), false);
-        return select;
-
-        /**
-         * @this {WebInspector.DeviceModeView}
-         */
-        function deviceListChanged()
-        {
-            select.removeChildren();
-
-            var genericGroup = select.createChild("optgroup");
-            genericGroup.label = WebInspector.UIString("Generic");
-            addOption.call(this, genericGroup, WebInspector.DeviceModeModel.Type.Mobile, null);
-            addOption.call(this, genericGroup, WebInspector.DeviceModeModel.Type.Tablet, null);
-            addOption.call(this, genericGroup, WebInspector.DeviceModeModel.Type.Desktop, null);
-
-            var deviceGroup = select.createChild("optgroup");
-            deviceGroup.label = WebInspector.UIString("Devices");
-            var devices = WebInspector.emulatedDevicesList.custom().concat(WebInspector.emulatedDevicesList.standard());
-            devices.sort(WebInspector.EmulatedDevice.compareByTitle);
-            for (var device of devices) {
-                if (device.show())
-                    addOption.call(this, deviceGroup, WebInspector.DeviceModeModel.Type.Device, device);
-            }
-        }
-
-        /**
-         * @param {!Element} group
-         * @param {!WebInspector.DeviceModeModel.Type} type
-         * @param {?WebInspector.EmulatedDevice} device
-         * @this {WebInspector.DeviceModeView}
-         */
-        function addOption(group, type, device)
-        {
-            var title = type === WebInspector.DeviceModeModel.Type.Device ? device.title : WebInspector.UIString(type);
-            var option = new Option(title, title);
-            option.device = device;
-            option.type = type;
-            group.appendChild(option);
-
-            if (type === this._model.type() && device === this._model.device())
-                select.selectedIndex = Array.prototype.slice.call(select.options).indexOf(option);
-        }
-
-        /**
-         * @this {WebInspector.DeviceModeView}
-         */
-        function optionSelected()
-        {
-            var option = select.options[select.selectedIndex];
-            this._model.emulate(option.type, option.device);
-            if (option.type !== WebInspector.DeviceModeModel.Type.Desktop)
-                WebInspector.userMetrics.actionTaken(WebInspector.UserMetrics.Action.DeviceModeEnabled);
-        }
+        var show = this._showMediaInspectorSetting.get();
+        if (this._mediaInspector.isShowing() && !show)
+            this._mediaInspector.detach();
+        if (!this._mediaInspector.isShowing() && show)
+            this._mediaInspector.show(this._mediaInspectorContainer);
     },
 
     /**
@@ -208,7 +110,7 @@
         var newWidth = this._resizeStart + dipOffset * 2;
         newWidth = Math.round(newWidth / this._model.fitScale());
         newWidth = Math.max(Math.min(newWidth, WebInspector.DeviceModeModel.MaxDeviceSize), 1);
-        this._model.genericWidthSetting().set(newWidth);
+        this._model.widthSetting().set(newWidth);
     },
 
     /**
@@ -231,53 +133,39 @@
             return;
 
         var zoomFactor = WebInspector.zoomManager.zoomFactor();
-
-        var cssScreenRect = this._model.screenRect().scale(1 / zoomFactor);
-        var cssVisiblePageRect = this._model.visiblePageRect().scale(1 / zoomFactor);
         var resizePagePlaceholder = false;
 
+        var cssScreenRect = this._model.screenRect().scale(1 / zoomFactor);
         if (!cssScreenRect.isEqual(this._cachedCssScreenRect)) {
             this._screenArea.style.left = cssScreenRect.left + "px";
             this._screenArea.style.top = cssScreenRect.top + "px";
             this._screenArea.style.width = cssScreenRect.width + "px";
             this._screenArea.style.height = cssScreenRect.height + "px";
             resizePagePlaceholder = true;
+            this._cachedCssScreenRect = cssScreenRect;
         }
 
+        var cssVisiblePageRect = this._model.visiblePageRect().scale(1 / zoomFactor);
         if (!cssVisiblePageRect.isEqual(this._cachedCssVisiblePageRect)) {
             this._pageArea.style.left = cssVisiblePageRect.left + "px";
             this._pageArea.style.top = cssVisiblePageRect.top + "px";
             this._pageArea.style.width = cssVisiblePageRect.width + "px";
             this._pageArea.style.height = cssVisiblePageRect.height + "px";
             resizePagePlaceholder = true;
+            this._cachedCssVisiblePageRect = cssVisiblePageRect;
         }
 
-        if (this._model.type() !== this._cachedModelType) {
-            var isDevice = this._model.type() === WebInspector.DeviceModeModel.Type.Device;
-            this._resizerElement.classList.toggle("hidden", isDevice);
-            this._genericWidthItem.setVisible(!isDevice);
-            this._deviceSizeItem.setVisible(isDevice);
+        var resizable = this._model.isResizable();
+        if (resizable !== this._cachedResizable) {
+            this._resizerElement.classList.toggle("hidden", !resizable);
+            this._cachedResizable = resizable;
         }
 
-        var warning = this._model.warning();
-        if (warning !== this._cachedWarning) {
-            this._warningMessage.textContent = warning;
-            this._warningInfobar.setVisible(!!warning);
-        }
-
-        if (this._model.type() === WebInspector.DeviceModeModel.Type.Device) {
-            var deviceSize = this._model.appliedDeviceSize();
-            this._deviceSizeInput.value = deviceSize.width + "x" + deviceSize.height;
-        }
+        this._toolbar.update();
         this._loadScreenImage(this._model.screenImage());
         if (resizePagePlaceholder)
             this._inspectedPagePlaceholder.onResize();
         this._mediaInspector.setAxisTransform(-cssScreenRect.left, this._model.fitScale());
-
-        this._cachedCssScreenRect = cssScreenRect;
-        this._cachedCssVisiblePageRect = cssVisiblePageRect;
-        this._cachedModelType = this._model.type();
-        this._cachedWarning = warning;
     },
 
     /**
@@ -329,73 +217,398 @@
     __proto__: WebInspector.VBox.prototype
 }
 
-
 /**
- * @param {!WebInspector.MediaQueryInspector} mediaInspector
- * @param {!Element} container
- * @param {function()} resizeCallback
+ * @param {!WebInspector.DeviceModeModel} model
+ * @param {!WebInspector.Setting} showMediaInspectorSetting
  * @constructor
  */
-WebInspector.DeviceModeView.MediaInspectorButton = function(mediaInspector, container, resizeCallback)
+WebInspector.DeviceModeView.Toolbar = function(model, showMediaInspectorSetting)
 {
-    this._mediaInspector = mediaInspector;
-    this._mediaInspector.addEventListener(WebInspector.MediaQueryInspector.Events.CountUpdated, this._updateButton, this);
-    this._mediaInspector.addEventListener(WebInspector.MediaQueryInspector.Events.HeightUpdated, resizeCallback);
+    this._model = model;
+    this._showMediaInspectorSetting = showMediaInspectorSetting;
+    /** @type {!Map<!WebInspector.EmulatedDevice, !WebInspector.EmulatedDevice.Mode>} */
+    this._lastMode = new Map();
+    /** @type {?WebInspector.EmulatedDevice} */
+    this._lastDevice = null;
 
-    this._resizeCallback = resizeCallback;
-    this._container = container;
+    this._modeToolbar = new WebInspector.Toolbar();
+    this._modeToolbar.element.classList.add("device-mode-screen-options");
+    var modeButton = new WebInspector.ToolbarButton(WebInspector.UIString("Screen options"), "rotate-screen-toolbar-item");
+    modeButton.addEventListener("click", this._modeMenuClicked, this);
+    this._modeToolbar.appendToolbarItem(modeButton);
 
-    this._setting = WebInspector.settings.createSetting("showMediaQueryInspector", false);
-    this._setting.addChangeListener(this._settingChanged, this);
+    this._element = createElementWithClass("div", "device-mode-toolbar");
 
-    this._button = new WebInspector.ToolbarButton(WebInspector.UIString("Media queries not found"), "waterfall-toolbar-item");
-    this._button.setToggled(this._setting.get());
-    this._button.setEnabled(false);
-    this._button.addEventListener("click", this._buttonClick, this);
+    var buttonsToolbarContainer = this._element.createChild("div", "device-mode-buttons-toolbar");
+    buttonsToolbarContainer.createChild("div", "flex-auto");
+    var buttonsToolbar = new WebInspector.Toolbar(buttonsToolbarContainer);
+    this._desktopItem = new WebInspector.ToolbarButton(WebInspector.UIString("Desktop"), "desktop-toolbar-item");
+    buttonsToolbar.appendToolbarItem(this._desktopItem);
+    this._desktopItem.addEventListener("click", this._desktopButtonClick, this);
+    this._mobileItem = new WebInspector.ToolbarButton(WebInspector.UIString("Mobile"), "emulation-toolbar-item");
+    buttonsToolbar.appendToolbarItem(this._mobileItem);
+    this._mobileItem.addEventListener("click", this._mobileButtonClick, this);
 
-    this._updateMediaInspector();
+    this._optionsToolbar = new WebInspector.Toolbar(this._element);
+    this._optionsToolbar.element.classList.add("device-mode-options-toolbar");
+    this._optionsToolbar.appendSeparator();
+
+    this._deviceSelect = this._createDeviceSelect();
+    this._deviceSelectItem = this._wrapToolbarItem(this._deviceSelect);
+    this._optionsToolbar.appendToolbarItem(this._deviceSelectItem);
+
+    var widthInput = createElementWithClass("input", "device-mode-size-input");
+    widthInput.maxLength = 5;
+    widthInput.title = WebInspector.UIString("Width");
+    WebInspector.SettingsUI.bindSettingInputField(widthInput, this._model.widthSetting(), true, WebInspector.DeviceModeModel.deviceSizeValidator, true);
+    this._widthItem = this._wrapToolbarItem(widthInput);
+    this._optionsToolbar.appendToolbarItem(this._widthItem);
+
+    this._appliedWidthInput = createElementWithClass("input", "device-mode-size-input");
+    this._appliedWidthInput.title = WebInspector.UIString("Width");
+    this._appliedWidthInput.disabled = true;
+    this._appliedWidthItem = this._wrapToolbarItem(this._appliedWidthInput);
+    this._optionsToolbar.appendToolbarItem(this._appliedWidthItem);
+
+    var xElement = createElementWithClass("div", "device-mode-x");
+    xElement.textContent = "\u00D7";
+    this._xItem = this._wrapToolbarItem(xElement);
+    this._optionsToolbar.appendToolbarItem(this._xItem);
+
+    this._appliedHeightInput = createElementWithClass("input", "device-mode-size-input");
+    this._appliedHeightInput.title = WebInspector.UIString("Height");
+    this._appliedHeightInput.disabled = true;
+    this._appliedHeightItem = this._wrapToolbarItem(this._appliedHeightInput);
+    this._optionsToolbar.appendToolbarItem(this._appliedHeightItem);
+
+    this._deviceScaleFactorItem = new WebInspector.ToolbarText("", "fullscreen-toolbar-item");
+    this._deviceScaleFactorItem.element.title = WebInspector.UIString("Device pixel ratio");
+    this._deviceScaleFactorItem.showGlyph();
+    this._optionsToolbar.appendToolbarItem(this._deviceScaleFactorItem);
+
+    this._optionsToolbar.appendSeparator();
+
+    this._optionsToolbar.appendToolbarItem(new WebInspector.ToolbarMenuButton(WebInspector.UIString("More options"), "menu-toolbar-item", this._appendMenuItems.bind(this)));
 }
 
-WebInspector.DeviceModeView.MediaInspectorButton.prototype = {
+WebInspector.DeviceModeView.Toolbar.prototype = {
     /**
-     * @return {!WebInspector.ToolbarButton}
+     * @param {!WebInspector.ContextMenu} contextMenu
      */
-    button: function()
+    _appendMenuItems: function(contextMenu)
     {
-        return this._button;
+        var fitSetting = this._model.fitSetting();
+        appendFitItem(WebInspector.UIString("Fit"), 0);
+        appendFitItem(WebInspector.UIString("50%"), 0.5);
+        appendFitItem(WebInspector.UIString("100%"), 1);
+        appendFitItem(WebInspector.UIString("200%"), 2);
+
+        /**
+         * @param {string} title
+         * @param {number} value
+         */
+        function appendFitItem(title, value)
+        {
+            contextMenu.appendCheckboxItem(title, fitSetting.set.bind(fitSetting, value), fitSetting.get() === value, false);
+        }
+
+        contextMenu.appendSeparator();
+
+        contextMenu.appendCheckboxItem(WebInspector.UIString("Show media queries"), this._toggleMediaInspector.bind(this), this._showMediaInspectorSetting.get(), false);
+
+        var submenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Device pixel ratio"), false);
+        if (this._model.type() === WebInspector.DeviceModeModel.Type.Device) {
+            submenu.appendCheckboxItem(WebInspector.UIString("Default: %f", this._model.device().deviceScaleFactor), function(){}, true, false);
+        } else {
+            var deviceScaleFactorSetting = this._model.deviceScaleFactorSetting();
+
+            /**
+             * @param {string} title
+             * @param {number} value
+             */
+            function appendScaleFactorItem(title, value)
+            {
+                submenu.appendCheckboxItem(title, deviceScaleFactorSetting.set.bind(deviceScaleFactorSetting, value), deviceScaleFactorSetting.get() === value, false);
+            }
+
+            appendScaleFactorItem(WebInspector.UIString("Default: %f", this._model.defaultDeviceScaleFactor()), 0);
+            appendScaleFactorItem(WebInspector.UIString("1"), 1);
+            appendScaleFactorItem(WebInspector.UIString("2"), 2);
+            appendScaleFactorItem(WebInspector.UIString("3"), 3);
+        }
+
+        contextMenu.appendItem(WebInspector.UIString("Configure network\u2026"), this._openNetworkConfig.bind(this), false);
+
+        if (this._model.type() !== WebInspector.DeviceModeModel.Type.Device)
+            contextMenu.appendItem(WebInspector.UIString("Reset to default"), this._model.reset.bind(this._model), false);
     },
 
-    _settingChanged: function()
+    _toggleMediaInspector: function()
     {
-        this._updateMediaInspector();
-        this._resizeCallback.call(null);
+        this._showMediaInspectorSetting.set(!this._showMediaInspectorSetting.get());
     },
 
-    _buttonClick: function()
+    _openNetworkConfig: function()
     {
-        this._setting.set(!this._button.toggled());
+        InspectorFrontendHost.bringToFront();
+        // TODO(dgozman): make it explicit.
+        WebInspector.actionRegistry.action("network.show-config").execute();
     },
 
-    _updateMediaInspector: function()
+    /**
+     * @param {!Element} element
+     * @return {!WebInspector.ToolbarItem}
+     */
+    _wrapToolbarItem: function(element)
     {
-        var show = this._setting.get();
-        this._button.setToggled(show);
-        if (this._mediaInspector.isShowing() && !show)
-            this._mediaInspector.detach();
-        if (!this._mediaInspector.isShowing() && show)
-            this._mediaInspector.show(this._container);
+        var container = createElement("div");
+        var shadowRoot = WebInspector.createShadowRootWithCoreStyles(container);
+        shadowRoot.appendChild(WebInspector.Widget.createStyleElement("emulation/deviceModeToolbar.css"));
+        shadowRoot.appendChild(element);
+        return new WebInspector.ToolbarItem(container);
+    },
+
+    _desktopButtonClick: function()
+    {
+        this._model.emulate(WebInspector.DeviceModeModel.Type.Desktop, null, null);
+    },
+
+    _mobileButtonClick: function()
+    {
+        for (var i = 0; i < this._deviceSelect.options.length; ++i) {
+            var option = this._deviceSelect.options[i];
+            if (option.device === this._lastDevice) {
+                this._emulateDeviceSelectOption(option);
+                return;
+            }
+        }
+        this._emulateDeviceSelectOption(this._deviceSelect.options[0]);
+    },
+
+    /**
+     * @return {!Element}
+     */
+    _createDeviceSelect: function()
+    {
+        var select = createElementWithClass("select", "device-mode-device-select");
+        WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevicesList.Events.CustomDevicesUpdated, deviceListChanged, this);
+        WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevicesList.Events.StandardDevicesUpdated, deviceListChanged, this);
+        deviceListChanged.call(this);
+        select.addEventListener("change", optionSelected.bind(this), false);
+        return select;
+
+        /**
+         * @this {WebInspector.DeviceModeView.Toolbar}
+         */
+        function deviceListChanged()
+        {
+            select.removeChildren();
+
+            addOption.call(this, select, WebInspector.DeviceModeModel.Type.Mobile, null, WebInspector.UIString("Responsive"));
+
+            var group = select.createChild("optgroup");
+            group.label = WebInspector.UIString("Devices");
+            addGroup.call(this, group, WebInspector.emulatedDevicesList.custom());
+            addGroup.call(this, group, WebInspector.emulatedDevicesList.standard());
+        }
+
+        /**
+         * @param {!Element} parent
+         * @param {!Array<!WebInspector.EmulatedDevice>} devices
+         * @this {WebInspector.DeviceModeView.Toolbar}
+         */
+        function addGroup(parent, devices)
+        {
+            devices = devices.filter(function(d) { return d.show(); });
+            devices.sort(WebInspector.EmulatedDevice.compareByTitle);
+            for (var device of devices)
+                addOption.call(this, parent, WebInspector.DeviceModeModel.Type.Device, device, device.title);
+        }
+
+        /**
+         * @param {!Element} parent
+         * @param {!WebInspector.DeviceModeModel.Type} type
+         * @param {?WebInspector.EmulatedDevice} device
+         * @param {string} title
+         * @this {WebInspector.DeviceModeView.Toolbar}
+         */
+        function addOption(parent, type, device, title)
+        {
+            var option = new Option(title, title);
+            option.device = device;
+            option.type = type;
+            parent.appendChild(option);
+
+            if (type === this._model.type() && device === this._model.device())
+                select.selectedIndex = Array.prototype.slice.call(select.options).indexOf(option);
+        }
+
+        /**
+         * @this {WebInspector.DeviceModeView.Toolbar}
+         */
+        function optionSelected()
+        {
+            this._emulateDeviceSelectOption(select.options[select.selectedIndex]);
+        }
+    },
+
+    /**
+     * @param {!Option} option
+     */
+    _emulateDeviceSelectOption: function(option)
+    {
+        this._model.emulate(option.type, option.device, option.device ? (this._lastMode.get(option.device) || option.device.modes[0]) : null);
     },
 
     /**
      * @param {!WebInspector.Event} event
      */
-    _updateButton: function(event)
+    _modeMenuClicked: function(event)
     {
-        var count = /** @type {number} */ (event.data);
-        this._button.setEnabled(!!count);
-        if (!count)
-            this._button.setTitle(WebInspector.UIString("Media queries not found"));
-        else
-            this._button.setTitle(WebInspector.UIString((count === 1 ? "%d media query found" : "%d media queries found"), count));
+        var device = this._model.device();
+        var model = this._model;
+
+        if (device.modes.length === 2 && device.modes[0].orientation !== device.modes[1].orientation) {
+            model.emulate(model.type(), model.device(), model.mode() === device.modes[0] ? device.modes[1] : device.modes[0]);
+            return;
+        }
+
+        var contextMenu = new WebInspector.ContextMenu(/** @type {!Event} */ (event.data),
+            false,
+            event.target.element.totalOffsetLeft(),
+            event.target.element.totalOffsetTop() + event.target.element.offsetHeight);
+        addOrientation(WebInspector.EmulatedDevice.Vertical, WebInspector.UIString("Portrait"));
+        addOrientation(WebInspector.EmulatedDevice.Horizontal, WebInspector.UIString("Landscape"));
+        contextMenu.show();
+
+        /**
+         * @param {string} orientation
+         * @param {string} title
+         */
+        function addOrientation(orientation, title)
+        {
+            var modes = device.modesForOrientation(orientation);
+            if (!modes.length)
+                return;
+            if (modes.length === 1) {
+                addMode(modes[0], title);
+            } else {
+                for (var index = 0; index < modes.length; index++)
+                    addMode(modes[index], title + " \u2013 " + modes[index].title);
+            }
+        }
+
+        /**
+         * @param {!WebInspector.EmulatedDevice.Mode} mode
+         * @param {string} title
+         */
+        function addMode(mode, title)
+        {
+            contextMenu.appendCheckboxItem(title, applyMode.bind(null, mode), model.mode() === mode, false);
+        }
+
+        /**
+         * @param {!WebInspector.EmulatedDevice.Mode} mode
+         */
+        function applyMode(mode)
+        {
+            model.emulate(model.type(), model.device(), mode);
+        }
+    },
+
+    /**
+     * @return {!Element}
+     */
+    element: function()
+    {
+        return this._element;
+    },
+
+    /**
+     * @return {!Element}
+     */
+    screenOptionsElement: function()
+    {
+        return this._modeToolbar.element;
+    },
+
+    update: function()
+    {
+        if (this._model.type() !== this._cachedModelType) {
+            var isDesktop = this._model.type() === WebInspector.DeviceModeModel.Type.Desktop;
+            this._desktopItem.setToggled(isDesktop);
+            this._mobileItem.setToggled(!isDesktop);
+            this._deviceSelectItem.setVisible(!isDesktop);
+            this._cachedModelType = this._model.type();
+        }
+
+        var resizable = this._model.isResizable();
+        if (resizable !== this._cachedResizable) {
+            this._widthItem.setVisible(resizable);
+            this._cachedResizable = resizable;
+        }
+
+        var showWidth = this._model.type() === WebInspector.DeviceModeModel.Type.Device || (this._model.type() === WebInspector.DeviceModeModel.Type.Desktop && !resizable);
+        if (showWidth !== this._cachedShowWidth) {
+            this._appliedWidthItem.setVisible(showWidth);
+            this._cachedShowWidth = showWidth;
+        }
+
+        if (showWidth) {
+            var width = this._model.appliedDeviceSize().width;
+            if (width !== this._cachedWidth) {
+                this._appliedWidthInput.value = width;
+                this._cachedWidth = width;
+            }
+        }
+
+        var showHeight = true;
+        if (showHeight !== this._cachedShowHeight) {
+            this._appliedHeightItem.setVisible(showHeight);
+            this._xItem.setVisible(showHeight);
+            this._cachedShowHeight = showHeight;
+        }
+
+        if (showHeight) {
+            var height = this._model.appliedDeviceSize().height;
+            if (height !== this._cachedHeight) {
+                this._appliedHeightInput.value = height;
+                this._cachedHeight = height;
+            }
+        }
+
+        var showDeviceScale = !!this._model.deviceScaleFactorSetting().get() || this._model.type() === WebInspector.DeviceModeModel.Type.Device;
+        if (showDeviceScale !== this._cachedShowDeviceScale) {
+            this._deviceScaleFactorItem.setVisible(showDeviceScale);
+            this._cachedShowDeviceScale = showDeviceScale;
+        }
+
+        if (showDeviceScale) {
+            var deviceScaleFactor = this._model.appliedDeviceScaleFactor();
+            if (deviceScaleFactor !== this._cachedDeviceScaleFactor) {
+                this._deviceScaleFactorItem.setText(String(deviceScaleFactor));
+                this._cachedDeviceScaleFactor = deviceScaleFactor;
+            }
+        }
+
+        if (this._model.device() !== this._cachedModelDevice) {
+            var device = this._model.device();
+
+            var modeCount = device ? device.modes.length : 0;
+            this._modeToolbar.element.classList.toggle("hidden", modeCount < 2);
+
+            for (var i = 0; i < this._deviceSelect.options.length; ++i) {
+                if (this._deviceSelect.options[i].device === this._model.device())
+                    this._deviceSelect.selectedIndex = i;
+            }
+
+            this._cachedModelDevice = device;
+        }
+
+        if (this._model.device() && this._model.mode())
+            this._lastMode.set(/** @type {!WebInspector.EmulatedDevice} */ (this._model.device()), /** @type {!WebInspector.EmulatedDevice.Mode} */ (this._model.mode()));
+
+        if (this._model.type() !== WebInspector.DeviceModeModel.Type.Desktop)
+            this._lastDevice = this._model.device();
     }
 }
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeToolbar.css b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeToolbar.css
index 734f8ff..38546a5 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeToolbar.css
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeToolbar.css
@@ -5,15 +5,26 @@
  */
 
 .device-mode-size-input {
-    width: 80px !important;
+    background: hsl(0, 0%, 100%);
+    border: none;
+    padding: 2px 4px;
+    width: 45px !important;
+    margin: 0;
     text-align: center;
-    background: hsl(0, 0%, 97%);
-    border: 1px solid rgb(216, 216, 216);
 }
 
-.device-mode-size-input:hover,
-.device-mode-size-input:focus {
-    border: 1px solid rgb(202, 202, 202);
+.device-mode-size-input.error-input {
+    outline: auto 2px red;
+}
+
+.device-mode-size-input:disabled {
+    background: transparent;
+    -webkit-user-select: none;
+}
+
+.device-mode-x {
+    margin: 0 1px;
+    font-size: 16px;
 }
 
 .device-mode-device-select {
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
index 0839b77..679adcc 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
+++ b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
@@ -18,7 +18,19 @@
     display: flex;
     flex-direction: row;
     align-items: stretch;
-    justify-content: center;
+}
+
+.device-mode-toolbar .toolbar {
+    padding: 0;
+}
+
+.device-mode-buttons-toolbar {
+    flex: 3 0 0;
+    display: flex;
+}
+
+.device-mode-options-toolbar {
+    flex: 5 0 0;
 }
 
 .device-mode-media-container {
@@ -29,15 +41,7 @@
 .device-mode-content-area {
     flex: auto;
     position: relative;
-    margin: 25px 0 23px 0;
-}
-
-.device-mode-warning {
-    position: absolute;
-    bottom: -24px;
-    left: 0;
-    right: 0;
-    border-top: 1px solid #ccc;
+    margin: 0;
 }
 
 .device-mode-screen-area {
@@ -47,7 +51,7 @@
     width: 0;
     height: 0;
     background-color: #171717;
-    box-shadow: hsl(0, 0%, 88%) 0 0 0 1px, hsla(0, 0%, 80%, 0.6) 0 0 16px;
+    box-shadow: hsl(0, 0%, 88%) 1px 1px 0 1px, hsla(0, 0%, 80%, 0.6) 0 0 16px;
 }
 
 .device-mode-screen-image {
@@ -58,6 +62,19 @@
     height: 100%;
 }
 
+.device-mode-screen-options {
+    position: absolute;
+    right: -35px;
+    top: 0;
+    border-radius: 3px;
+    padding: 0;
+    margin: 0;
+}
+
+.device-mode-screen-options:hover {
+    background-color: hsl(0, 0%, 90%);
+}
+
 .device-mode-resizer {
     position: absolute;
     top: 0;
diff --git a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
index 5821f4c..07c2837 100644
--- a/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
+++ b/third_party/WebKit/Source/devtools/front_end/host/InspectorFrontendHostAPI.js
@@ -55,7 +55,7 @@
     SearchCompleted: "searchCompleted",
     SetInspectedTabId: "setInspectedTabId",
     SetUseSoftMenu: "setUseSoftMenu",
-    ShowConsole: "showConsole"
+    ShowPanel: "showPanel"
 }
 
 InspectorFrontendHostAPI.EventDescriptors = [
@@ -87,7 +87,7 @@
     [InspectorFrontendHostAPI.Events.SearchCompleted, ["requestId", "fileSystemPath", "files"]],
     [InspectorFrontendHostAPI.Events.SetInspectedTabId, ["tabId"]],
     [InspectorFrontendHostAPI.Events.SetUseSoftMenu, ["useSoftMenu"]],
-    [InspectorFrontendHostAPI.Events.ShowConsole, []]
+    [InspectorFrontendHostAPI.Events.ShowPanel, ["panelName"]]
 ];
 
 InspectorFrontendHostAPI.prototype = {
diff --git a/third_party/WebKit/Source/devtools/front_end/security/sidebar.css b/third_party/WebKit/Source/devtools/front_end/security/sidebar.css
index 5486562b..76217142 100644
--- a/third_party/WebKit/Source/devtools/front_end/security/sidebar.css
+++ b/third_party/WebKit/Source/devtools/front_end/security/sidebar.css
@@ -86,6 +86,7 @@
 .security-sidebar-tree-item.selected .security-property-secure {
     -webkit-mask-image: url(Images/securityPropertySecure.svg);
 }
+
 .sidebar-tree-item.security-main-view-reload-message .title {
     color: rgba(0, 0, 0, 0.5);
     padding-left: 8px;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js b/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js
index 6b17268..72259dbb 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/CountersGraph.js
@@ -35,8 +35,9 @@
  * @param {string} title
  * @param {!WebInspector.TimelineModeViewDelegate} delegate
  * @param {!WebInspector.TimelineModel} model
+ * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
  */
-WebInspector.CountersGraph = function(title, delegate, model)
+WebInspector.CountersGraph = function(title, delegate, model, filters)
 {
     WebInspector.SplitWidget.call(this, true, false, "memoryCountersSidebar");
 
@@ -44,6 +45,7 @@
 
     this._delegate = delegate;
     this._model = model;
+    this._filters = filters;
     this._calculator = new WebInspector.TimelineCalculator(this._model);
 
     this._graphsContainer = new WebInspector.VBox();
@@ -205,7 +207,7 @@
          */
         function findRecordToReveal(record)
         {
-            if (!this._model.isVisible(record.traceEvent()))
+            if (!WebInspector.TimelineModel.isVisible(this._filters, record.traceEvent()))
                 return false;
             if (record.startTime() <= time && time <= record.endTime()) {
                 recordToReveal = record;
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/MemoryCountersGraph.js b/third_party/WebKit/Source/devtools/front_end/timeline/MemoryCountersGraph.js
index 5e6931e..c4704c4 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/MemoryCountersGraph.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/MemoryCountersGraph.js
@@ -34,10 +34,11 @@
  * @implements {WebInspector.TimelineModeView}
  * @param {!WebInspector.TimelineModeViewDelegate} delegate
  * @param {!WebInspector.TimelineModel} model
+ * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
  */
-WebInspector.MemoryCountersGraph = function(delegate, model)
+WebInspector.MemoryCountersGraph = function(delegate, model, filters)
 {
-    WebInspector.CountersGraph.call(this, WebInspector.UIString("MEMORY"), delegate, model);
+    WebInspector.CountersGraph.call(this, WebInspector.UIString("MEMORY"), delegate, model, filters);
     this._countersByName = {};
     this._countersByName["jsHeapSizeUsed"] = this.createCounter(WebInspector.UIString("JS Heap"), WebInspector.UIString("JS Heap: %s"), "hsl(220, 90%, 43%)", Number.bytesToString);
     this._countersByName["documents"] = this.createCounter(WebInspector.UIString("Documents"), WebInspector.UIString("Documents: %s"), "hsl(0, 90%, 43%)");
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineModel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineModel.js
index cd72128..2caedad 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineModel.js
@@ -39,7 +39,6 @@
 WebInspector.TimelineModel = function(tracingModel, eventFilter)
 {
     WebInspector.Object.call(this);
-    this._filters = [];
     this._tracingModel = tracingModel;
     this._eventFilter = eventFilter;
     this._targets = [];
@@ -166,7 +165,6 @@
     RecordsCleared: "RecordsCleared",
     RecordingStarted: "RecordingStarted",
     RecordingStopped: "RecordingStopped",
-    RecordFilterChanged: "RecordFilterChanged",
     BufferUsage: "BufferUsage",
     RetrieveEventsProgress: "RetrieveEventsProgress"
 }
@@ -470,18 +468,10 @@
     },
 
     /**
-     * @param {!WebInspector.TimelineModel.Filter} filter
-     */
-    addFilter: function(filter)
-    {
-        this._filters.push(filter);
-        filter.addEventListener(WebInspector.TimelineModel.Filter.Events.Changed, this._filterChanged, this);
-    },
-
-    /**
+     * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
      * @param {function(!WebInspector.TimelineModel.Record)|function(!WebInspector.TimelineModel.Record,number)} callback
      */
-    forAllFilteredRecords: function(callback)
+    forAllFilteredRecords: function(filters, callback)
     {
         /**
          * @param {!WebInspector.TimelineModel.Record} record
@@ -491,11 +481,9 @@
          */
         function processRecord(record, depth)
         {
-            var visible = this.isVisible(record.traceEvent());
-            if (visible) {
-                if (callback(record, depth))
-                    return true;
-            }
+            var visible = WebInspector.TimelineModel.isVisible(filters, record.traceEvent());
+            if (visible && callback(record, depth))
+                return true;
 
             for (var i = 0; i < record.children().length; ++i) {
                 if (processRecord.call(this, record.children()[i], visible ? depth + 1 : depth))
@@ -508,23 +496,6 @@
             processRecord.call(this, this._records[i], 0);
     },
 
-    /**
-     * @param {!WebInspector.TracingModel.Event} event
-     * @return {boolean}
-     */
-    isVisible: function(event)
-    {
-        for (var i = 0; i < this._filters.length; ++i) {
-            if (!this._filters[i].accept(event))
-                return false;
-        }
-        return true;
-    },
-
-    _filterChanged: function()
-    {
-        this.dispatchEventToListeners(WebInspector.TimelineModel.Events.RecordFilterChanged);
-    },
 
     /**
      * @return {!Array.<!WebInspector.TimelineModel.Record>}
@@ -1460,6 +1431,20 @@
 }
 
 /**
+ * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
+ * @param {!WebInspector.TracingModel.Event} event
+ * @return {boolean}
+ */
+WebInspector.TimelineModel.isVisible = function(filters, event)
+{
+    for (var i = 0; i < filters.length; ++i) {
+        if (!filters[i].accept(event))
+            return false;
+    }
+    return true;
+}
+
+/**
  * @constructor
  */
 WebInspector.TimelineModel.ProfileTreeNode = function()
@@ -1503,23 +1488,10 @@
 
     /**
      * @param {!WebInspector.TracingModel.Event} e
-     * @return {boolean}
-     */
-    function filter(e)
-    {
-        for (var i = 0, l = filters.length; i < l; ++i) {
-            if (!filters[i].accept(e))
-                return false;
-        }
-        return true;
-    }
-
-    /**
-     * @param {!WebInspector.TracingModel.Event} e
      */
     function onStartEvent(e)
     {
-        if (!filter(e))
+        if (!WebInspector.TimelineModel.isVisible(filters, e))
             return;
         var time = e.endTime ? Math.min(endTime, e.endTime) - Math.max(startTime, e.startTime) : 0;
         var id = eventIdCallback ? eventIdCallback(e) : Symbol("uniqueEventId");
@@ -1552,7 +1524,7 @@
      */
     function onEndEvent(e)
     {
-        if (!filter(e))
+        if (!WebInspector.TimelineModel.isVisible(filters, e))
             return;
         parent = parent.parent;
     }
@@ -1678,15 +1650,9 @@
 
 /**
  * @constructor
- * @extends {WebInspector.Object}
  */
 WebInspector.TimelineModel.Filter = function()
 {
-    WebInspector.Object.call(this);
-}
-
-WebInspector.TimelineModel.Filter.Events = {
-    Changed: "Changed"
 }
 
 WebInspector.TimelineModel.Filter.prototype = {
@@ -1697,14 +1663,7 @@
     accept: function(event)
     {
         return true;
-    },
-
-    notifyFilterChanged: function()
-    {
-        this.dispatchEventToListeners(WebInspector.TimelineModel.Filter.Events.Changed, this);
-    },
-
-    __proto__: WebInspector.Object.prototype
+    }
 }
 
 /**
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
index 2b7db80..0f767b88 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -58,14 +58,15 @@
     this._model.addEventListener(WebInspector.TimelineModel.Events.RecordingStarted, this._onRecordingStarted, this);
     this._model.addEventListener(WebInspector.TimelineModel.Events.RecordingStopped, this._onRecordingStopped, this);
     this._model.addEventListener(WebInspector.TimelineModel.Events.RecordsCleared, this._onRecordsCleared, this);
-    this._model.addEventListener(WebInspector.TimelineModel.Events.RecordFilterChanged, this._refreshViews, this);
     this._model.addEventListener(WebInspector.TimelineModel.Events.BufferUsage, this._onTracingBufferUsage, this);
     this._model.addEventListener(WebInspector.TimelineModel.Events.RetrieveEventsProgress, this._onRetrieveEventsProgress, this);
 
-    this._filters = new WebInspector.TimelineFilters();
-    for (var filter of this._filters.filters())
-        this._model.addFilter(filter);
-    this._model.addFilter(new WebInspector.TimelineStaticFilter());
+    this._waterfallFilters = [new WebInspector.TimelineStaticFilter()];
+    if (!Runtime.experiments.isEnabled("timelineEventsTreeView")) {
+        this._filtersControl = new WebInspector.TimelineFilters();
+        this._filtersControl.addEventListener(WebInspector.TimelineFilters.Events.FilterChanged, this._refreshViews, this);
+        this._waterfallFilters = this._waterfallFilters.concat(this._filtersControl.filters());
+    }
 
     /** @type {!Array.<!WebInspector.TimelineModeView>} */
     this._currentViews = [];
@@ -292,7 +293,7 @@
     _addModeView: function(modeView)
     {
         modeView.setWindowTimes(this.windowStartTime(), this.windowEndTime());
-        modeView.refreshRecords(this._filters.searchRegExp());
+        modeView.refreshRecords(this._filterRegExp);
         this._stackView.appendView(modeView.view(), "timelinePanelTimelineStackSplitViewState", undefined, 112);
         modeView.view().addEventListener(WebInspector.SplitWidget.Events.SidebarSizeChanged, this._sidebarResized, this);
         this._currentViews.push(modeView);
@@ -345,7 +346,8 @@
         this._panelToolbar.appendToolbarItem(clearButton);
         this._panelToolbar.appendSeparator();
 
-        this._panelToolbar.appendToolbarItem(this._filters.filterButton());
+        if (this._filtersControl)
+            this._panelToolbar.appendToolbarItem(this._filtersControl.filterButton());
 
         var garbageCollectButton = new WebInspector.ToolbarButton(WebInspector.UIString("Collect garbage"), "garbage-collect-toolbar-item");
         garbageCollectButton.addEventListener("click", this._garbageCollectButtonClicked, this);
@@ -396,7 +398,8 @@
         this._progressToolbarItem.setVisible(false);
         this._panelToolbar.appendToolbarItem(this._progressToolbarItem);
 
-        this.element.appendChild(this._filters.filtersElement());
+        if (this._filtersControl)
+            this.element.appendChild(this._filtersControl.filtersElement());
     },
 
     /**
@@ -501,9 +504,10 @@
 
     _refreshViews: function()
     {
+        this._filterRegExp = this._filtersControl && this._filtersControl.searchRegExp();
         for (var i = 0; i < this._currentViews.length; ++i) {
             var view = this._currentViews[i];
-            view.refreshRecords(this._filters.searchRegExp());
+            view.refreshRecords(this._filterRegExp);
         }
         this._updateSelectionDetails();
     },
@@ -535,25 +539,24 @@
             this._stackView.show(this._searchableView.element);
         }
         this._flameChart = null;
+        if (this._filtersControl)
+            this._filtersControl.setEnabled(viewMode === WebInspector.TimelinePanel.ViewMode.Waterfall);
         if (viewMode === WebInspector.TimelinePanel.ViewMode.FlameChart) {
-            this._filters.setEnabled(false);
             this._flameChart = new WebInspector.TimelineFlameChartView(this, this._model, this._frameModel);
             this._flameChart.enableNetworkPane(this._captureNetworkSetting.get());
             this._addModeView(this._flameChart);
         } else if (viewMode === WebInspector.TimelinePanel.ViewMode.Waterfall) {
-            this._filters.setEnabled(true);
-            var timelineView = new WebInspector.TimelineView(this, this._model);
+            var timelineView = new WebInspector.TimelineView(this, this._model, this._waterfallFilters);
             this._addModeView(timelineView);
             timelineView.setFrameModel(this._frameModel);
         } else if (viewMode === WebInspector.TimelinePanel.ViewMode.CallTree || viewMode === WebInspector.TimelinePanel.ViewMode.BottomUp) {
-            this._filters.setEnabled(false);
             var innerView = viewMode === WebInspector.TimelinePanel.ViewMode.BottomUp ? new WebInspector.BottomUpTimelineTreeView(this._model) : new WebInspector.CallTreeTimelineTreeView(this._model);
             var treeView = new WebInspector.TimelineTreeModeView(this, innerView);
             this._addModeView(treeView);
         }
 
         if (this._captureMemorySetting.get() && viewMode !== WebInspector.TimelinePanel.ViewMode.CallTree && viewMode !== WebInspector.TimelinePanel.ViewMode.BottomUp)
-            this._addModeView(new WebInspector.MemoryCountersGraph(this, this._model));
+            this._addModeView(new WebInspector.MemoryCountersGraph(this, this._model, this._waterfallFilters));
 
         this.doResize();
         this.select(null);
@@ -881,7 +884,7 @@
      */
     _updateSearchHighlight: function(revealRecord, shouldJump, jumpBackwards)
     {
-        if (this._filters.searchRegExp() || !this._searchRegex) {
+        if (this._filterRegExp || !this._searchRegex) {
             this._clearHighlight();
             return;
         }
@@ -915,7 +918,7 @@
             if (WebInspector.TimelineUIUtils.testContentMatching(record.traceEvent(), searchRegExp))
                 matches.push(record);
         }
-        this._model.forAllFilteredRecords(processRecord.bind(this));
+        this._model.forAllFilteredRecords(this._waterfallFilters, processRecord.bind(this));
 
         var matchesCount = matches.length;
         if (matchesCount) {
@@ -1596,7 +1599,6 @@
     setMinimumRecordDuration: function(value)
     {
         this._minimumRecordDuration = value;
-        this.notifyFilterChanged();
     },
 
     /**
@@ -1630,7 +1632,6 @@
     _setRegExp: function(regExp)
     {
         this._regExp = regExp;
-        this.notifyFilterChanged();
     },
 
     /**
@@ -1864,9 +1865,12 @@
 
 /**
  * @constructor
+ * @extends {WebInspector.Object}
  */
 WebInspector.TimelineFilters = function()
 {
+    WebInspector.Object.call(this);
+
     this._categoryFilter = new WebInspector.TimelineCategoryFilter();
     this._durationFilter = new WebInspector.TimelineIsLongFilter();
     this._textFilter = new WebInspector.TimelineTextFilter();
@@ -1875,6 +1879,10 @@
     this._createFilterBar();
 }
 
+WebInspector.TimelineFilters.Events = {
+    FilterChanged: Symbol("FilterChanged")
+};
+
 WebInspector.TimelineFilters._durationFilterPresetsMs = [0, 1, 15];
 
 WebInspector.TimelineFilters.prototype = {
@@ -1965,6 +1973,7 @@
         {
             var searchQuery = this._textFilterUI.value();
             this._textFilter._setRegExp(searchQuery ? createPlainTextSearchRegex(searchQuery, "i") : null);
+            this._notifyFiltersChanged();
         }
 
         /**
@@ -1975,6 +1984,7 @@
             var duration = durationFilterUI.value();
             var minimumRecordDuration = parseInt(duration, 10);
             this._durationFilter.setMinimumRecordDuration(minimumRecordDuration);
+            this._notifyFiltersChanged();
         }
 
         /**
@@ -1985,7 +1995,14 @@
         {
             var categories = WebInspector.TimelineUIUtils.categories();
             categories[name].hidden = !categoryFiltersUI[name].checked();
-            this._categoryFilter.notifyFilterChanged();
+            this._notifyFiltersChanged();
         }
-    }
+    },
+
+    _notifyFiltersChanged: function()
+    {
+        this.dispatchEventToListeners(WebInspector.TimelineFilters.Events.FilterChanged);
+    },
+
+    __proto__: WebInspector.Object.prototype
 };
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePresentationModel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePresentationModel.js
index 3bee9ee..3b8cff2b 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePresentationModel.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePresentationModel.js
@@ -33,11 +33,12 @@
  * @constructor
  * @extends {WebInspector.Object}
  * @param {!WebInspector.TimelineModel} model
+ * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
  */
-WebInspector.TimelinePresentationModel = function(model)
+WebInspector.TimelinePresentationModel = function(model, filters)
 {
     this._model = model;
-    this._filters = [];
+    this._filters = filters;
     /**
      * @type {!Map.<!WebInspector.TimelineModel.Record, !WebInspector.TimelinePresentationModel.Record>}
      */
@@ -246,7 +247,7 @@
                 var record = records[entry.index];
                 ++entry.index;
                 if (record.startTime() < this._windowEndTime && record.endTime() > this._windowStartTime) {
-                    if (this._model.isVisible(record.record().traceEvent())) {
+                    if (WebInspector.TimelineModel.isVisible(this._filters, record.record().traceEvent())) {
                         record._presentationParent._expandable = true;
                         if (this._textFilter)
                             revealRecordsInStack();
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineView.js
index 6353e48..18eee89 100644
--- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineView.js
+++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineView.js
@@ -35,15 +35,16 @@
  * @implements {WebInspector.TimelineModeView}
  * @param {!WebInspector.TimelineModeViewDelegate} delegate
  * @param {!WebInspector.TimelineModel} model
+ * @param {!Array<!WebInspector.TimelineModel.Filter>} filters
  */
-WebInspector.TimelineView = function(delegate, model)
+WebInspector.TimelineView = function(delegate, model, filters)
 {
     WebInspector.VBox.call(this);
     this.element.classList.add("timeline-view");
 
     this._delegate = delegate;
     this._model = model;
-    this._presentationModel = new WebInspector.TimelinePresentationModel(model);
+    this._presentationModel = new WebInspector.TimelinePresentationModel(model, filters);
     this._calculator = new WebInspector.TimelineCalculator(model);
     this._linkifier = new WebInspector.Linkifier();
     this._frameStripByFrame = new Map();
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/SettingsUI.js b/third_party/WebKit/Source/devtools/front_end/ui/SettingsUI.js
index ced4d4a0..05c2a7ca 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/SettingsUI.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/SettingsUI.js
@@ -202,6 +202,7 @@
         if (clearForZero && !value)
             value = "";
         inputElement.value = value;
+        validate();
     }
     onSettingChange();
 
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
index ee06ed41..cfac7ffe 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
+++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -288,7 +288,7 @@
     WebInspector.ToolbarItem.call(this, createElementWithClass("span", "toolbar-text"));
     if (className)
         this.element.classList.add(className);
-    this.element.textContent = text;
+    this._textElement = this.element.createTextChild(text);
 }
 
 WebInspector.ToolbarText.prototype = {
@@ -297,7 +297,16 @@
      */
     setText: function(text)
     {
-        this.element.textContent = text;
+        this._textElement.textContent = text;
+    },
+
+    showGlyph: function()
+    {
+        if (!this._glyphElement) {
+            this.element.classList.add("toolbar-text-glyphed");
+            this._glyphElement = createElementWithClass("div", "glyph toolbar-button-theme");
+            this.element.insertBefore(this._glyphElement, this._textElement);
+        }
     },
 
     __proto__: WebInspector.ToolbarItem.prototype
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
index be87c61..4720c2d 100644
--- a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
+++ b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
@@ -55,6 +55,15 @@
     margin-left: 6px;
 }
 
+.toolbar-text-glyphed {
+    margin-left: 0;
+}
+
+.toolbar-text .glyph {
+    width: 24px !important;
+    margin: 0 3px 0 -3px;
+}
+
 .toolbar-item:active {
     position: relative;
     z-index: 200;
@@ -541,3 +550,14 @@
     background-color: rgb(216, 0, 0) !important;
 }
 
+.desktop-toolbar-item .glyph {
+    -webkit-mask-position: -160px -144px;
+}
+
+.rotate-screen-toolbar-item .glyph {
+    -webkit-mask-position: -192px -144px;
+}
+
+.fullscreen-toolbar-item .glyph {
+    -webkit-mask-position: -224px -144px;
+}
diff --git a/third_party/WebKit/Source/devtools/protocol.json b/third_party/WebKit/Source/devtools/protocol.json
index cee2240..1c867e03 100644
--- a/third_party/WebKit/Source/devtools/protocol.json
+++ b/third_party/WebKit/Source/devtools/protocol.json
@@ -3353,8 +3353,8 @@
             {
                 "name": "layoutEditorChange",
                 "parameters": [
-                    { "name": "styleSheetId", "$ref": "StyleSheetId", "description": "Identifier of the stylesheet where the modification occurred."},
-                    { "name": "changeRange", "$ref": "SourceRange", "description": "Range where the modification occurred."}
+                    { "name": "styleSheetId", "$ref": "StyleSheetId", "description": "Identifier of the stylesheet where the modification occurred." },
+                    { "name": "changeRange", "$ref": "SourceRange", "description": "Range where the modification occurred." }
                 ]
             }
         ]
diff --git a/third_party/WebKit/Source/devtools/scripts/generate_devtools_grd.py b/third_party/WebKit/Source/devtools/scripts/generate_devtools_grd.py
index d990feb..95f86b7d3 100755
--- a/third_party/WebKit/Source/devtools/scripts/generate_devtools_grd.py
+++ b/third_party/WebKit/Source/devtools/scripts/generate_devtools_grd.py
@@ -35,6 +35,7 @@
 
 import errno
 import os
+import shlex
 import shutil
 import sys
 from xml.dom import minidom
@@ -67,14 +68,36 @@
 
 
 def parse_args(argv):
-    static_files_list_position = argv.index('--static_files_list')
+    # The arguments are of the format:
+    #   [ <source_files> ]*
+    #   [ (--static_files_list <file>) | (--static_files_args <file>) ]
+    #   --relative_path_dirs [ <directory> ]*
+    #   --images [ <image_dirs> ]*
+    #   --output <output_file>
+    #
+    # --static_files_list means the file contains newline-separated filenames
+    # from GYP, and --static_files_args means the file looks like a shell
+    # string from GN.
     relative_path_dirs_position = argv.index('--relative_path_dirs')
     images_position = argv.index('--images')
     output_position = argv.index('--output')
-    static_files_list_path = argv[static_files_list_position + 1]
-    source_files = argv[:static_files_list_position]
-    with open(static_files_list_path, 'r') as static_list_file:
-        source_files.extend([line.rstrip('\n') for line in static_list_file.readlines()])
+
+    if '--static_files_list' in argv:
+        # This branch can be removed when GYP support is no longer necessary.
+        static_files_list_position = argv.index('--static_files_list')
+        static_files_list_path = argv[static_files_list_position + 1]
+        source_files = argv[:static_files_list_position]
+        with open(static_files_list_path, 'r') as static_list_file:
+            source_files.extend([line.rstrip('\n') for line in static_list_file.readlines()])
+    elif '--static_files_args' in argv:
+        static_files_args_position = argv.index('--static_files_args')
+        static_files_args_path = argv[static_files_args_position + 1]
+        source_files = argv[:static_files_args_position]
+        with open(static_files_args_path, 'r') as static_args_file:
+            source_files.extend(shlex.split(static_args_file))
+    else:
+        source_files = argv[:relative_path_dirs_position]
+
     relative_path_dirs = argv[relative_path_dirs_position + 1:images_position]
     image_dirs = argv[images_position + 1:output_position]
     return ParsedArgs(source_files, relative_path_dirs, image_dirs, argv[output_position + 1])
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTCharacteristic.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTCharacteristic.cpp
index b76c2eb..dcc1aa6 100644
--- a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTCharacteristic.cpp
+++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTCharacteristic.cpp
@@ -107,14 +107,15 @@
     // Partial implementation of writeValue algorithm:
     // https://webbluetoothchrome.github.io/web-bluetooth/#dom-bluetoothgattcharacteristic-writevalue
 
-    // Let valueVector be a copy of the bytes held by value.
-    std::vector<uint8_t> valueVector(value.bytes(), value.bytes() + value.byteLength());
     // If bytes is more than 512 bytes long (the maximum length of an attribute
     // value, per Long Attribute Values) return a promise rejected with an
     // InvalidModificationError and abort.
-    if (valueVector.size() > 512)
+    if (value.byteLength() > 512)
         return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(InvalidModificationError, "Value can't exceed 512 bytes."));
 
+    // Let valueVector be a copy of the bytes held by value.
+    WebVector<uint8_t> valueVector(value.bytes(), value.byteLength());
+
     ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
 
     ScriptPromise promise = resolver->promise();
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.cpp b/third_party/WebKit/Source/modules/nfc/NFC.cpp
index 1be5558..ffd1cf7 100644
--- a/third_party/WebKit/Source/modules/nfc/NFC.cpp
+++ b/third_party/WebKit/Source/modules/nfc/NFC.cpp
@@ -11,16 +11,15 @@
 
 namespace blink {
 
-NFC::NFC(ExecutionContext* context, LocalFrame* frame)
-    : ActiveDOMObject(context)
-    , DOMWindowProperty(frame)
+NFC::NFC(LocalFrame* frame)
+    : LocalFrameLifecycleObserver(frame)
+    , PageLifecycleObserver(frame ? frame->page() : 0)
 {
 }
 
-NFC* NFC::create(ExecutionContext* context, LocalFrame* frame)
+NFC* NFC::create(LocalFrame* frame)
 {
-    NFC* nfc = new NFC(context, frame);
-    nfc->suspendIfNeeded();
+    NFC* nfc = new NFC(frame);
     return nfc;
 }
 
@@ -34,10 +33,22 @@
     return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
 }
 
+void NFC::willDetachFrameHost()
+{
+    // TODO(shalamov): To be implemented.
+}
+
+void NFC::pageVisibilityChanged()
+{
+    // TODO(shalamov): To be implemented. When visibility is lost,
+    // NFC operations should be suspended.
+    // https://w3c.github.io/web-nfc/#nfc-suspended
+}
+
 DEFINE_TRACE(NFC)
 {
-    ActiveDOMObject::trace(visitor);
-    DOMWindowProperty::trace(visitor);
+    LocalFrameLifecycleObserver::trace(visitor);
+    PageLifecycleObserver::trace(visitor);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.h b/third_party/WebKit/Source/modules/nfc/NFC.h
index 413cb6f..ffb5845f 100644
--- a/third_party/WebKit/Source/modules/nfc/NFC.h
+++ b/third_party/WebKit/Source/modules/nfc/NFC.h
@@ -7,31 +7,41 @@
 
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptWrappable.h"
-#include "core/dom/ActiveDOMObject.h"
-#include "core/frame/DOMWindowProperty.h"
-#include "platform/heap/Handle.h"
+#include "core/frame/LocalFrameLifecycleObserver.h"
+#include "core/page/PageLifecycleObserver.h"
 
 namespace blink {
 
 class NFC final
     : public GarbageCollectedFinalized<NFC>
     , public ScriptWrappable
-    , public ActiveDOMObject
-    , public DOMWindowProperty {
+    , public LocalFrameLifecycleObserver
+    , public PageLifecycleObserver {
     DEFINE_WRAPPERTYPEINFO();
     WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(NFC);
 
 public:
-    static NFC* create(ExecutionContext*, LocalFrame*);
+    static NFC* create(LocalFrame*);
+#if ENABLE(OILPAN)
+    ~NFC();
+#else
     ~NFC() override;
+#endif
 
     // Get an adapter object providing NFC functionality.
     ScriptPromise requestAdapter(ScriptState*);
 
+    // Implementation of LocalFrameLifecycleObserver.
+    void willDetachFrameHost() override;
+
+    // Implementation of PageLifecycleObserver
+    void pageVisibilityChanged() override;
+
+    // Interface required by garbage collection.
     DECLARE_VIRTUAL_TRACE();
 
 private:
-    NFC(ExecutionContext*, LocalFrame*);
+    NFC(LocalFrame*);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.idl b/third_party/WebKit/Source/modules/nfc/NFC.idl
index 6deb627f..cc38e16f 100644
--- a/third_party/WebKit/Source/modules/nfc/NFC.idl
+++ b/third_party/WebKit/Source/modules/nfc/NFC.idl
@@ -6,7 +6,6 @@
 
 [
   GarbageCollected,
-  ActiveDOMObject,
   RuntimeEnabled=WebNFC,
 ] interface NFC {
    [CallWith=ScriptState] Promise<NFCAdapter> requestAdapter ();
diff --git a/third_party/WebKit/Source/modules/nfc/NavigatorNFC.cpp b/third_party/WebKit/Source/modules/nfc/NavigatorNFC.cpp
index 0d2fc26..6bd3259a 100644
--- a/third_party/WebKit/Source/modules/nfc/NavigatorNFC.cpp
+++ b/third_party/WebKit/Source/modules/nfc/NavigatorNFC.cpp
@@ -29,13 +29,13 @@
     return *supplement;
 }
 
-NFC* NavigatorNFC::nfc(ExecutionContext* context, Navigator& navigator)
+NFC* NavigatorNFC::nfc(Navigator& navigator)
 {
     NavigatorNFC& self = NavigatorNFC::from(navigator);
     if (!self.m_nfc) {
         if (!navigator.frame())
             return nullptr;
-        self.m_nfc = NFC::create(context, navigator.frame());
+        self.m_nfc = NFC::create(navigator.frame());
     }
     return self.m_nfc.get();
 }
diff --git a/third_party/WebKit/Source/modules/nfc/NavigatorNFC.h b/third_party/WebKit/Source/modules/nfc/NavigatorNFC.h
index 2c9854c..7dfea19 100644
--- a/third_party/WebKit/Source/modules/nfc/NavigatorNFC.h
+++ b/third_party/WebKit/Source/modules/nfc/NavigatorNFC.h
@@ -12,7 +12,6 @@
 
 class NFC;
 class Navigator;
-class ExecutionContext;
 
 class NavigatorNFC final
     : public GarbageCollected<NavigatorNFC>
@@ -23,7 +22,7 @@
     // Gets, or creates, NavigatorNFC supplement on Navigator.
     static NavigatorNFC& from(Navigator&);
 
-    static NFC* nfc(ExecutionContext*, Navigator&);
+    static NFC* nfc(Navigator&);
 
     DECLARE_TRACE();
 
diff --git a/third_party/WebKit/Source/modules/nfc/NavigatorNFC.idl b/third_party/WebKit/Source/modules/nfc/NavigatorNFC.idl
index 88f976f..1b6d2e6 100644
--- a/third_party/WebKit/Source/modules/nfc/NavigatorNFC.idl
+++ b/third_party/WebKit/Source/modules/nfc/NavigatorNFC.idl
@@ -7,5 +7,5 @@
 [
   RuntimeEnabled=WebNFC,
 ] partial interface Navigator {
-    [CallWith=ExecutionContext] readonly attribute NFC nfc;
+    readonly attribute NFC nfc;
 };
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationConnection.cpp b/third_party/WebKit/Source/modules/presentation/PresentationConnection.cpp
index 8230ce1..ed9a912 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationConnection.cpp
+++ b/third_party/WebKit/Source/modules/presentation/PresentationConnection.cpp
@@ -314,13 +314,13 @@
     ASSERT_NOT_REACHED();
 }
 
-void PresentationConnection::close()
+void PresentationConnection::terminate()
 {
     if (m_state != WebPresentationConnectionState::Connected)
         return;
     WebPresentationClient* client = presentationClient(executionContext());
     if (client)
-        client->closeSession(m_url, m_id);
+        client->terminateSession(m_url, m_id);
 
     // Cancel current Blob loading if any.
     if (m_blobLoader) {
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationConnection.h b/third_party/WebKit/Source/modules/presentation/PresentationConnection.h
index 7644a6e..29b1653f 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationConnection.h
+++ b/third_party/WebKit/Source/modules/presentation/PresentationConnection.h
@@ -52,7 +52,7 @@
     void send(PassRefPtr<DOMArrayBuffer>, ExceptionState&);
     void send(PassRefPtr<DOMArrayBufferView>, ExceptionState&);
     void send(Blob*, ExceptionState&);
-    void close();
+    void terminate();
 
     String binaryType() const;
     void setBinaryType(const String&);
diff --git a/third_party/WebKit/Source/modules/presentation/PresentationConnection.idl b/third_party/WebKit/Source/modules/presentation/PresentationConnection.idl
index 1e1d50c..2e9a88f00 100644
--- a/third_party/WebKit/Source/modules/presentation/PresentationConnection.idl
+++ b/third_party/WebKit/Source/modules/presentation/PresentationConnection.idl
@@ -16,7 +16,7 @@
 ] interface PresentationConnection : EventTarget {
     readonly attribute DOMString? id;
     readonly attribute PresentationConnectionState state;
-    [MeasureAs=PresentationConnectionClose] void close();
+    [MeasureAs=PresentationConnectionTerminate] void terminate();
     attribute EventHandler onstatechange;
 
     // Communication
diff --git a/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp b/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
index 60f3edc..51a7ea57 100644
--- a/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/AudioNode.cpp
@@ -323,8 +323,11 @@
         if (silentInputs && propagatesSilence()) {
             silenceOutputs();
         } else {
-            process(framesToProcess);
+            // Unsilence the outputs first because the processing of the node may cause the outputs
+            // to go silent and we want to propagate that hint to the downstream nodes!  (For
+            // example, a Gain node with a gain of 0 will want to silence its output.)
             unsilenceOutputs();
+            process(framesToProcess);
         }
     }
 }
diff --git a/third_party/WebKit/Source/modules/webaudio/GainNode.cpp b/third_party/WebKit/Source/modules/webaudio/GainNode.cpp
index b61c475..d680f87 100644
--- a/third_party/WebKit/Source/modules/webaudio/GainNode.cpp
+++ b/third_party/WebKit/Source/modules/webaudio/GainNode.cpp
@@ -73,7 +73,13 @@
             }
         } else {
             // Apply the gain with de-zippering into the output bus.
-            outputBus->copyWithGainFrom(*inputBus, &m_lastGain, m_gain->value());
+            if (!m_lastGain && m_lastGain == m_gain->value()) {
+                // If the gain is 0 (and we've converged on dezippering), just zero the bus and set
+                // the silence hint.
+                outputBus->zero();
+            } else {
+                outputBus->copyWithGainFrom(*inputBus, &m_lastGain, m_gain->value());
+            }
         }
     }
 }
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
index 41eba55f..3d04ecf 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -144,10 +144,6 @@
     m_currentBooleanOcclusionQuery = nullptr;
     m_currentTransformFeedbackPrimitivesWrittenQuery = nullptr;
 
-    m_max3DTextureSize = 0;
-    webContext()->getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &m_max3DTextureSize);
-    m_max3DTextureLevel = WebGLTexture::computeLevelCount(m_max3DTextureSize, m_max3DTextureSize, m_max3DTextureSize);
-
     m_maxArrayTextureLayers = 0;
     webContext()->getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &m_maxArrayTextureLayers);
 
@@ -644,7 +640,7 @@
     tex->setTexStorageInfo(target, levels, internalformat, width, height, depth);
 }
 
-bool WebGL2RenderingContextBase::validateTexImage3D(const char* functionName, GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type)
+bool WebGL2RenderingContextBase::validateTexImage3D(const char* functionName, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type)
 {
     switch (target) {
     case GL_TEXTURE_3D:
@@ -658,7 +654,7 @@
     if (!validateTexFuncLevel(functionName, target, level))
         return false;
 
-    if (!validateTexFuncFormatAndType(functionName, internalformat, format, type, level))
+    if (!validateTexFuncParameters(functionName, NotTexSubImage2D, target, level, internalformat, width, height, depth, border, format, type))
         return false;
 
     return true;
@@ -666,7 +662,7 @@
 
 void WebGL2RenderingContextBase::texImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, DOMArrayBufferView* pixels)
 {
-    if (isContextLost() || !validateTexImage3D("texImage3D", target, level, internalformat, format, type)
+    if (isContextLost() || !validateTexImage3D("texImage3D", target, level, internalformat, width, height, depth, border, format, type)
         || !validateTexFuncData("texImage3D", level, width, height, format, type, pixels, NullAllowed))
         return;
 
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
index 2db7de0..3ab1aad 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -195,7 +195,7 @@
         TexStorageType3D,
     };
     bool validateTexStorage(const char*, GLenum, GLsizei, GLenum, GLsizei, GLsizei, GLsizei, TexStorageType);
-    bool validateTexImage3D(const char* functionName, GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type);
+    bool validateTexImage3D(const char* functionName, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type);
     bool validateTexSubImage3D(const char*, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLenum format, GLenum type, GLsizei width, GLsizei height, GLsizei depth);
 
     ScriptValue getInt64Parameter(ScriptState*, GLenum);
@@ -234,8 +234,6 @@
 
     PersistentWillBeMember<WebGLFramebuffer> m_readFramebufferBinding;
     PersistentWillBeMember<WebGLTransformFeedback> m_transformFeedbackBinding;
-    GLint m_max3DTextureSize;
-    GLint m_max3DTextureLevel;
     GLint m_maxArrayTextureLayers;
 
     std::set<GLenum> m_supportedInternalFormatsStorage;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
index 04a9eec..2fc71ec 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -1044,6 +1044,12 @@
     m_maxTextureLevel = WebGLTexture::computeLevelCount(m_maxTextureSize, m_maxTextureSize, 1);
     m_maxCubeMapTextureSize = 0;
     webContext()->getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &m_maxCubeMapTextureSize);
+    m_max3DTextureSize = 0;
+    m_max3DTextureLevel = 0;
+    if (isWebGL2OrHigher()) {
+        webContext()->getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &m_max3DTextureSize);
+        m_max3DTextureLevel = WebGLTexture::computeLevelCount(m_max3DTextureSize, m_max3DTextureSize, m_max3DTextureSize);
+    }
     m_maxCubeMapTextureLevel = WebGLTexture::computeLevelCount(m_maxCubeMapTextureSize, m_maxCubeMapTextureSize, 1);
     m_maxRenderbufferSize = 0;
     webContext()->getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &m_maxRenderbufferSize);
@@ -1941,7 +1947,7 @@
         return;
     if (!validateTexFuncLevel("copyTexImage2D", target, level))
         return;
-    if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage2D, target, level, internalformat, width, height, border, internalformat, GL_UNSIGNED_BYTE))
+    if (!validateTexFuncParameters("copyTexImage2D", NotTexSubImage2D, target, level, internalformat, width, height, 1, border, internalformat, GL_UNSIGNED_BYTE))
         return;
     if (!validateSettableTexFormat("copyTexImage2D", internalformat))
         return;
@@ -4197,7 +4203,7 @@
 
     if (internalformat == 0)
         internalformat = texture->getInternalFormat(target, level);
-    if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, border, format, type))
+    if (!validateTexFuncParameters(functionName, functionType, target, level, internalformat, width, height, 1, border, format, type))
         return false;
 
     if (functionType == NotTexSubImage2D) {
@@ -5641,10 +5647,10 @@
 }
 
 bool WebGLRenderingContextBase::validateTexFuncDimensions(const char* functionName, TexImageFunctionType functionType,
-    GLenum target, GLint level, GLsizei width, GLsizei height)
+    GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth)
 {
-    if (width < 0 || height < 0) {
-        synthesizeGLError(GL_INVALID_VALUE, functionName, "width or height < 0");
+    if (width < 0 || height < 0 || depth < 0) {
+        synthesizeGLError(GL_INVALID_VALUE, functionName, "width, height or depth < 0");
         return false;
     }
 
@@ -5672,6 +5678,15 @@
             return false;
         }
         break;
+    case GL_TEXTURE_3D:
+    case GL_TEXTURE_2D_ARRAY:
+        if (isWebGL2OrHigher()) {
+            if (width > (m_max3DTextureSize >> level) || height > (m_max3DTextureSize >> level) || depth > (m_max3DTextureSize >> level)) {
+                synthesizeGLError(GL_INVALID_VALUE, functionName, "width, height or depth out of range");
+                return false;
+            }
+            break;
+        }
     default:
         synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid target");
         return false;
@@ -5680,7 +5695,7 @@
 }
 
 bool WebGLRenderingContextBase::validateTexFuncParameters(const char* functionName, TexImageFunctionType functionType, GLenum target,
-    GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type)
+    GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type)
 {
     // We absolutely have to validate the format and type combination.
     // The texImage2D entry points taking HTMLImage, etc. will produce
@@ -5688,7 +5703,7 @@
     if (!validateTexFuncFormatAndType(functionName, internalformat, format, type, level))
         return false;
 
-    if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height))
+    if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height, depth))
         return false;
 
     if (border) {
@@ -5952,7 +5967,7 @@
 
 bool WebGLRenderingContextBase::validateCompressedTexDimensions(const char* functionName, TexImageFunctionType functionType, GLenum target, GLint level, GLsizei width, GLsizei height, GLenum format)
 {
-    if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height))
+    if (!validateTexFuncDimensions(functionName, functionType, target, level, width, height, 1))
         return false;
 
     bool widthValid = false;
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
index a5fb75a..748c4ed 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.h
@@ -599,10 +599,12 @@
 
     GLint m_maxTextureSize;
     GLint m_maxCubeMapTextureSize;
+    GLint m_max3DTextureSize;
     GLint m_maxRenderbufferSize;
     GLint m_maxViewportDims[2];
     GLint m_maxTextureLevel;
     GLint m_maxCubeMapTextureLevel;
+    GLint m_max3DTextureLevel;
 
     GLint m_maxDrawBuffers;
     GLint m_maxColorAttachments;
@@ -918,11 +920,11 @@
 
     // Helper function to check input width and height for functions {copy, compressed}Tex{Sub}Image.
     // Generates GL error and returns false if width or height is invalid.
-    bool validateTexFuncDimensions(const char* functionName, TexImageFunctionType, GLenum target, GLint level, GLsizei width, GLsizei height);
+    bool validateTexFuncDimensions(const char* functionName, TexImageFunctionType, GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth);
 
     // Helper function to check input parameters for functions {copy}Tex{Sub}Image.
     // Generates GL error and returns false if parameters are invalid.
-    bool validateTexFuncParameters(const char* functionName, TexImageFunctionType, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type);
+    bool validateTexFuncParameters(const char* functionName, TexImageFunctionType, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type);
 
     enum NullDisposition {
         NullAllowed,
diff --git a/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp b/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
index f68c767..0a61dcf 100644
--- a/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
+++ b/third_party/WebKit/Source/modules/websockets/DOMWebSocket.cpp
@@ -234,7 +234,9 @@
 
 DOMWebSocket::~DOMWebSocket()
 {
-    ASSERT(!m_channel);
+    WebSocketChannel* channel = m_channel;
+    // TODO(yhirano): Use ASSERT instead when crbug.com/550632 is fixed.
+    RELEASE_ASSERT(!channel);
 }
 
 void DOMWebSocket::logError(const String& message)
@@ -571,7 +573,8 @@
 void DOMWebSocket::contextDestroyed()
 {
     WTF_LOG(Network, "WebSocket %p contextDestroyed()", this);
-    ASSERT(!m_channel);
+    // TODO(yhirano): Use ASSERT instead when crbug.com/550632 is fixed.
+    RELEASE_ASSERT(!m_channel);
     ASSERT(m_state == CLOSED);
     ActiveDOMObject::contextDestroyed();
 }
diff --git a/third_party/WebKit/Source/platform/audio/AudioBus.cpp b/third_party/WebKit/Source/platform/audio/AudioBus.cpp
index caca83fa..e57367f5 100644
--- a/third_party/WebKit/Source/platform/audio/AudioBus.cpp
+++ b/third_party/WebKit/Source/platform/audio/AudioBus.cpp
@@ -488,8 +488,21 @@
 
     // Apply constant gain after de-zippering has converged on target gain.
     if (framesToDezipper < framesToProcess) {
-        for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex)
-            vsmul(sources[channelIndex], 1, &gain, destinations[channelIndex], 1, framesToProcess - framesToDezipper);
+        // Handle gains of 0 and 1 (exactly) specially.
+        if (gain == 1) {
+            for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
+                memcpy(destinations[channelIndex], sources[channelIndex],
+                    (framesToProcess - framesToDezipper) * sizeof(*destinations[channelIndex]));
+            }
+        } else if (gain == 0) {
+            for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex) {
+                memset(destinations[channelIndex], 0,
+                    (framesToProcess - framesToDezipper) * sizeof(*destinations[channelIndex]));
+            }
+        } else {
+            for (unsigned channelIndex = 0; channelIndex < numberOfChannels; ++channelIndex)
+                vsmul(sources[channelIndex], 1, &gain, destinations[channelIndex], 1, framesToProcess - framesToDezipper);
+        }
     }
 
     // Save the target gain as the starting point for next time around.
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index e47adddb..0aaf6ce 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -432,6 +432,11 @@
       'fonts/shaping/RunSegmenter.h',
       'fonts/shaping/RunSegmenter.cpp',
       'fonts/shaping/ShapeCache.h',
+      'fonts/shaping/ShapeResult.cpp',
+      'fonts/shaping/ShapeResult.h',
+      'fonts/shaping/ShapeResultInlineHeaders.h',
+      'fonts/shaping/ShapeResultTestInfo.cpp',
+      'fonts/shaping/ShapeResultTestInfo.h',
       'fonts/shaping/Shaper.cpp',
       'fonts/shaping/Shaper.h',
       'fonts/shaping/SimpleShaper.cpp',
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp
index 79f7842a..0d9f4806 100644
--- a/third_party/WebKit/Source/platform/fonts/Font.cpp
+++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -35,6 +35,7 @@
 #include "platform/fonts/GlyphBuffer.h"
 #include "platform/fonts/GlyphPageTreeNode.h"
 #include "platform/fonts/SimpleFontData.h"
+#include "platform/fonts/shaping/CachingWordShaper.h"
 #include "platform/fonts/shaping/HarfBuzzFace.h"
 #include "platform/fonts/shaping/HarfBuzzShaper.h"
 #include "platform/fonts/shaping/SimpleShaper.h"
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp
index 799220f..3d308fe 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.cpp
@@ -25,7 +25,6 @@
     , m_currentFontDataIndex(0)
     , m_segmentedIndex(0)
     , m_fallbackStage(FontGroupFonts)
-    , m_currentFamily(&description.family())
 {
 }
 
@@ -102,13 +101,8 @@
     if (!fontData->isSegmented()) {
         // Skip forward to the next font family for the next call to next().
         m_currentFontDataIndex++;
-        m_currentFamily = m_currentFamily->next();
         if (!fontData->isLoading()) {
             RefPtr<SimpleFontData> nonSegmented = const_cast<SimpleFontData*>(toSimpleFontData(fontData));
-            // TODO crbug.com/546465: Investigate if we might need to do
-            // something like
-            // toSimpleFontData(fontData)->customFontData()->beginLoadIfNeeded()
-            // here to trigger loading.
             return FontDataRange(nonSegmented);
         }
         return next(hintList);
@@ -125,18 +119,17 @@
     ASSERT(m_segmentedIndex < segmented->numRanges());
     FontDataRange currentRange = segmented->rangeAt(m_segmentedIndex);
     m_segmentedIndex++;
-    AtomicString segmentedFamily = m_currentFamily->family();
 
     if (m_segmentedIndex == segmented->numRanges()) {
         // Switch from iterating over a segmented face to the next family from
         // the font-family: group of fonts.
         m_fallbackStage = FontGroupFonts;
         m_currentFontDataIndex++;
-        m_currentFamily = m_currentFamily->next();
     }
 
     if (rangeContributesForHint(hintList, currentRange)) {
-        willUseRange(segmentedFamily, currentRange);
+        if (currentRange.fontData()->customFontData())
+            currentRange.fontData()->customFontData()->beginLoadIfNeeded();
         if (!currentRange.fontData()->isLoading())
             return currentRange;
         m_loadingCustomFontForRanges.append(currentRange);
diff --git a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h
index 2d3a58c..4e054bb7 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h
+++ b/third_party/WebKit/Source/platform/fonts/FontFallbackIterator.h
@@ -63,7 +63,6 @@
     };
 
     FallbackStage m_fallbackStage;
-    const FontFamily* m_currentFamily;
     HashMap<UChar32, RefPtr<SimpleFontData>> m_visitedSystemFonts;
     Vector<FontDataRange> m_loadingCustomFontForRanges;
 };
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
index d66080e3..65d2ee7 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShapeIterator.h
@@ -26,6 +26,7 @@
 #ifndef CachingWordShapeIterator_h
 #define CachingWordShapeIterator_h
 
+#include "platform/fonts/Font.h"
 #include "platform/fonts/SimpleFontData.h"
 #include "platform/fonts/shaping/CachingWordShapeIterator.h"
 #include "platform/fonts/shaping/HarfBuzzShaper.h"
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
index 51d2360..048cc5d 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CachingWordShaperTest.cpp
@@ -7,6 +7,7 @@
 #include "platform/fonts/FontCache.h"
 #include "platform/fonts/GlyphBuffer.h"
 #include "platform/fonts/shaping/CachingWordShapeIterator.h"
+#include "platform/fonts/shaping/ShapeResultTestInfo.h"
 #include <gtest/gtest.h>
 
 namespace blink {
@@ -42,6 +43,11 @@
     hb_script_t script = HB_SCRIPT_INVALID;
 };
 
+static inline ShapeResultTestInfo* testInfo(RefPtr<ShapeResult>& result)
+{
+    return static_cast<ShapeResultTestInfo*>(result.get());
+}
+
 TEST_F(CachingWordShaperTest, LatinLeftToRightByWord)
 {
     TextRun textRun(reinterpret_cast<const LChar*>("ABC DEF."), 8);
@@ -49,19 +55,19 @@
     RefPtr<ShapeResult> result;
     CachingWordShapeIterator iterator(cache, textRun, font);
     ASSERT_TRUE(iterator.next(&result));
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(3u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_LATIN, script);
 
     ASSERT_TRUE(iterator.next(&result));
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_COMMON, script);
 
     ASSERT_TRUE(iterator.next(&result));
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(4u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -78,21 +84,21 @@
     RefPtr<ShapeResult> result;
     CachingWordShapeIterator iterator(cache, textRun, font);
     ASSERT_TRUE(iterator.next(&result));
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, offset + startIndex);
     EXPECT_EQ(3u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_COMMON, script);
     offset += result->numCharacters();
 
     ASSERT_TRUE(iterator.next(&result));
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(3u, offset + startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_COMMON, script);
     offset += result->numCharacters();
 
     ASSERT_TRUE(iterator.next(&result));
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(4u, offset + startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_COMMON, script);
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
index c118ab60..0678568 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -32,7 +32,6 @@
 #include "config.h"
 #include "platform/fonts/shaping/HarfBuzzShaper.h"
 
-#include "hb.h"
 #include "platform/Logging.h"
 #include "platform/fonts/Character.h"
 #include "platform/fonts/Font.h"
@@ -41,549 +40,20 @@
 #include "platform/fonts/UTF16TextIterator.h"
 #include "platform/fonts/shaping/HarfBuzzFace.h"
 #include "platform/fonts/shaping/RunSegmenter.h"
+#include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
 #include "platform/text/TextBreakIterator.h"
 #include "wtf/Compiler.h"
 #include "wtf/MathExtras.h"
 #include "wtf/text/Unicode.h"
 
 #include <algorithm>
+#include <hb.h>
 #include <unicode/normlzr.h>
 #include <unicode/uchar.h>
 #include <unicode/uscript.h>
 
 namespace blink {
 
-struct HarfBuzzRunGlyphData {
-    uint16_t glyph;
-    uint16_t characterIndex;
-    float advance;
-    FloatSize offset;
-};
-
-struct ShapeResult::RunInfo {
-    RunInfo(const SimpleFontData* font, hb_direction_t dir, hb_script_t script,
-        unsigned startIndex, unsigned numGlyphs, unsigned numCharacters)
-        : m_fontData(const_cast<SimpleFontData*>(font)), m_direction(dir), m_script(script)
-        , m_startIndex(startIndex), m_numCharacters(numCharacters)
-        , m_numGlyphs(numGlyphs), m_width(0.0f)
-    {
-        m_glyphData.resize(m_numGlyphs);
-    }
-
-    bool rtl() const { return HB_DIRECTION_IS_BACKWARD(m_direction); }
-    float xPositionForVisualOffset(unsigned) const;
-    float xPositionForOffset(unsigned) const;
-    int characterIndexForXPosition(float) const;
-    void setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance,
-        float offsetX, float offsetY);
-
-    void addAdvance(unsigned index, float advance)
-    {
-        m_glyphData[index].advance += advance;
-    }
-
-    size_t glyphToCharacterIndex(size_t i) const
-    {
-        return m_startIndex + m_glyphData[i].characterIndex;
-    }
-
-    RefPtr<SimpleFontData> m_fontData;
-    hb_direction_t m_direction;
-    hb_script_t m_script;
-    Vector<HarfBuzzRunGlyphData> m_glyphData;
-    unsigned m_startIndex;
-    unsigned m_numCharacters;
-    unsigned m_numGlyphs;
-    float m_width;
-};
-
-float ShapeResult::RunInfo::xPositionForVisualOffset(unsigned offset) const
-{
-    ASSERT(offset < m_numCharacters);
-    if (rtl())
-        offset = m_numCharacters - offset - 1;
-    return xPositionForOffset(offset);
-}
-
-float ShapeResult::RunInfo::xPositionForOffset(unsigned offset) const
-{
-    ASSERT(offset <= m_numCharacters);
-    unsigned glyphIndex = 0;
-    float position = 0;
-    if (rtl()) {
-        while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex > offset) {
-            position += m_glyphData[glyphIndex].advance;
-            ++glyphIndex;
-        }
-        // For RTL, we need to return the right side boundary of the character.
-        // Add advance of glyphs which are part of the character.
-        while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) {
-            position += m_glyphData[glyphIndex].advance;
-            ++glyphIndex;
-        }
-        position += m_glyphData[glyphIndex].advance;
-    } else {
-        while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex < offset) {
-            position += m_glyphData[glyphIndex].advance;
-            ++glyphIndex;
-        }
-    }
-    return position;
-}
-
-int ShapeResult::RunInfo::characterIndexForXPosition(float targetX) const
-{
-    ASSERT(targetX <= m_width);
-    float currentX = 0;
-    float currentAdvance = m_glyphData[0].advance;
-    unsigned glyphIndex = 0;
-
-    // Sum up advances that belong to the first character.
-    while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex)
-        currentAdvance += m_glyphData[++glyphIndex].advance;
-    currentAdvance = currentAdvance / 2.0;
-    if (targetX <= currentAdvance)
-        return rtl() ? m_numCharacters : 0;
-
-    currentX = currentAdvance;
-    ++glyphIndex;
-    while (glyphIndex < m_numGlyphs) {
-        unsigned prevCharacterIndex = m_glyphData[glyphIndex - 1].characterIndex;
-        float prevAdvance = currentAdvance;
-        currentAdvance = m_glyphData[glyphIndex].advance;
-        while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex)
-            currentAdvance += m_glyphData[++glyphIndex].advance;
-        currentAdvance = currentAdvance / 2.0;
-        float nextX = currentX + prevAdvance + currentAdvance;
-        if (currentX <= targetX && targetX <= nextX)
-            return rtl() ? prevCharacterIndex : m_glyphData[glyphIndex].characterIndex;
-        currentX = nextX;
-        ++glyphIndex;
-    }
-
-    return rtl() ? 0 : m_numCharacters;
-}
-
-void ShapeResult::RunInfo::setGlyphAndPositions(unsigned index,
-    uint16_t glyphId, float advance, float offsetX, float offsetY)
-{
-    HarfBuzzRunGlyphData& data = m_glyphData[index];
-    data.glyph = glyphId;
-    data.advance = advance;
-    data.offset = FloatSize(offsetX, offsetY);
-}
-
-ShapeResult::ShapeResult(const Font* font, unsigned numCharacters, TextDirection direction)
-    : m_width(0)
-    , m_primaryFont(const_cast<SimpleFontData*>(font->primaryFont()))
-    , m_numCharacters(numCharacters)
-    , m_numGlyphs(0)
-    , m_direction(direction)
-{
-}
-
-ShapeResult::~ShapeResult()
-{
-}
-
-static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance,
-    hb_direction_t direction, const SimpleFontData* fontData,
-    const HarfBuzzRunGlyphData& glyphData)
-{
-    FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction)
-        ? FloatPoint(advance, 0)
-        : FloatPoint(0, advance);
-    glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset);
-}
-
-template<TextDirection direction>
-float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer,
-    const RunInfo* run, float initialAdvance, unsigned from, unsigned to,
-    unsigned runOffset)
-{
-    if (!run)
-        return 0;
-    float advanceSoFar = initialAdvance;
-    unsigned numGlyphs = run->m_numGlyphs;
-    for (unsigned i = 0; i < numGlyphs; ++i) {
-        const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
-        uint16_t currentCharacterIndex = run->m_startIndex +
-            glyphData.characterIndex + runOffset;
-        if ((direction == RTL && currentCharacterIndex >= to)
-            || (direction == LTR && currentCharacterIndex < from)) {
-            advanceSoFar += glyphData.advance;
-        } else if ((direction == RTL && currentCharacterIndex >= from)
-            || (direction == LTR && currentCharacterIndex < to)) {
-            addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction,
-                run->m_fontData.get(), glyphData);
-            advanceSoFar += glyphData.advance;
-        }
-    }
-    return advanceSoFar - initialAdvance;
-}
-
-static inline unsigned countGraphemesInCluster(const UChar* str,
-    unsigned strLength, uint16_t startIndex, uint16_t endIndex)
-{
-    if (startIndex > endIndex) {
-        uint16_t tempIndex = startIndex;
-        startIndex = endIndex;
-        endIndex = tempIndex;
-    }
-    uint16_t length = endIndex - startIndex;
-    ASSERT(static_cast<unsigned>(startIndex + length) <= strLength);
-    TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startIndex], length);
-
-    int cursorPos = cursorPosIterator->current();
-    int numGraphemes = -1;
-    while (0 <= cursorPos) {
-        cursorPos = cursorPosIterator->next();
-        numGraphemes++;
-    }
-    return std::max(0, numGraphemes);
-}
-
-static inline void addEmphasisMark(GlyphBuffer* buffer,
-    const GlyphData* emphasisData, FloatPoint glyphCenter,
-    float midGlyphOffset)
-{
-    ASSERT(buffer);
-    ASSERT(emphasisData);
-
-    const SimpleFontData* emphasisFontData = emphasisData->fontData;
-    ASSERT(emphasisFontData);
-
-    bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright()
-        && emphasisFontData->verticalData();
-
-    if (!isVertical) {
-        buffer->add(emphasisData->glyph, emphasisFontData,
-            midGlyphOffset - glyphCenter.x());
-    } else {
-        buffer->add(emphasisData->glyph, emphasisFontData,
-            FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y()));
-    }
-}
-
-float ShapeResult::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer,
-    const RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData,
-    float initialAdvance, unsigned from, unsigned to, unsigned runOffset)
-{
-    if (!run)
-        return 0;
-
-    unsigned graphemesInCluster = 1;
-    float clusterAdvance = 0;
-
-    FloatPoint glyphCenter = emphasisData->fontData->
-        boundsForGlyph(emphasisData->glyph).center();
-
-    TextDirection direction = textRun.direction();
-
-    // A "cluster" in this context means a cluster as it is used by HarfBuzz:
-    // The minimal group of characters and corresponding glyphs, that cannot be broken
-    // down further from a text shaping point of view.
-    // A cluster can contain multiple glyphs and grapheme clusters, with mutually
-    // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters,
-    // then linearly split the sum of corresponding glyph advances by the number of
-    // grapheme clusters in order to find positions for emphasis mark drawing.
-    uint16_t clusterStart = direction == RTL
-        ? run->m_startIndex + run->m_numCharacters + runOffset
-        : run->glyphToCharacterIndex(0) + runOffset;
-
-    float advanceSoFar = initialAdvance;
-    unsigned numGlyphs = run->m_numGlyphs;
-    for (unsigned i = 0; i < numGlyphs; ++i) {
-        const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
-        uint16_t currentCharacterIndex = run->m_startIndex + glyphData.characterIndex + runOffset;
-        bool isRunEnd = (i + 1 == numGlyphs);
-        bool isClusterEnd =  isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != currentCharacterIndex);
-
-        if ((direction == RTL && currentCharacterIndex >= to) || (direction != RTL && currentCharacterIndex < from)) {
-            advanceSoFar += glyphData.advance;
-            direction == RTL ? --clusterStart : ++clusterStart;
-            continue;
-        }
-
-        clusterAdvance += glyphData.advance;
-
-        if (textRun.is8Bit()) {
-            float glyphAdvanceX = glyphData.advance;
-            if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) {
-                addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
-            }
-            advanceSoFar += glyphAdvanceX;
-        } else if (isClusterEnd) {
-            uint16_t clusterEnd;
-            if (direction == RTL)
-                clusterEnd = currentCharacterIndex;
-            else
-                clusterEnd = isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(i + 1) + runOffset;
-
-            graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd);
-            if (!graphemesInCluster || !clusterAdvance)
-                continue;
-
-            float glyphAdvanceX = clusterAdvance / graphemesInCluster;
-            for (unsigned j = 0; j < graphemesInCluster; ++j) {
-                // Do not put emphasis marks on space, separator, and control characters.
-                if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex]))
-                    addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
-                advanceSoFar += glyphAdvanceX;
-            }
-            clusterStart = clusterEnd;
-            clusterAdvance = 0;
-        }
-    }
-    return advanceSoFar - initialAdvance;
-}
-
-float ShapeResult::fillGlyphBuffer(Vector<RefPtr<ShapeResult>>& results,
-    GlyphBuffer* glyphBuffer, const TextRun& textRun,
-    unsigned from, unsigned to)
-{
-    float advance = 0;
-    if (textRun.rtl()) {
-        unsigned wordOffset = textRun.length();
-        for (unsigned j = 0; j < results.size(); j++) {
-            unsigned resolvedIndex = results.size() - 1 - j;
-            RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
-            for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
-                advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer,
-                    wordResult->m_runs[i].get(), advance, from, to,
-                    wordOffset - wordResult->numCharacters());
-            }
-            wordOffset -= wordResult->numCharacters();
-        }
-    } else {
-        unsigned wordOffset = 0;
-        for (unsigned j = 0; j < results.size(); j++) {
-            RefPtr<ShapeResult>& wordResult = results[j];
-            for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
-                advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer,
-                    wordResult->m_runs[i].get(), advance, from, to, wordOffset);
-            }
-            wordOffset += wordResult->numCharacters();
-        }
-    }
-
-    return advance;
-}
-
-float ShapeResult::fillGlyphBufferForTextEmphasis(
-    Vector<RefPtr<ShapeResult>>& results, GlyphBuffer* glyphBuffer,
-    const TextRun& textRun, const GlyphData* emphasisData,
-    unsigned from, unsigned to)
-{
-    float advance = 0;
-    unsigned wordOffset = textRun.rtl() ? textRun.length() : 0;
-    for (unsigned j = 0; j < results.size(); j++) {
-        unsigned resolvedIndex = textRun.rtl() ? results.size() - 1 - j : j;
-        RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
-        for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
-            unsigned resolvedOffset = wordOffset -
-                (textRun.rtl() ? wordResult->numCharacters() : 0);
-            advance += wordResult->fillGlyphBufferForTextEmphasisRun(
-                glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData,
-                advance, from, to, resolvedOffset);
-        }
-        wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1);
-    }
-
-    return advance;
-}
-
-FloatRect ShapeResult::selectionRect(Vector<RefPtr<ShapeResult>>& results,
-    TextDirection direction, float totalWidth, const FloatPoint& point,
-    int height, unsigned absoluteFrom, unsigned absoluteTo)
-{
-    float currentX = 0;
-    float fromX = 0;
-    float toX = 0;
-    bool foundFromX = false;
-    bool foundToX = false;
-
-    if (direction == RTL)
-        currentX = totalWidth;
-
-    // The absoluteFrom and absoluteTo arguments represent the start/end offset
-    // for the entire run, from/to are continuously updated to be relative to
-    // the current word (ShapeResult instance).
-    int from = absoluteFrom;
-    int to = absoluteTo;
-
-    unsigned totalNumCharacters = 0;
-    for (unsigned j = 0; j < results.size(); j++) {
-        RefPtr<ShapeResult> result = results[j];
-        if (direction == RTL) {
-            // Convert logical offsets to visual offsets, because results are in
-            // logical order while runs are in visual order.
-            if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result->numCharacters())
-                from = result->numCharacters() - from - 1;
-            if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numCharacters())
-                to = result->numCharacters() - to - 1;
-            currentX -= result->width();
-        }
-        for (unsigned i = 0; i < result->m_runs.size(); i++) {
-            if (!result->m_runs[i])
-                continue;
-            ASSERT((direction == RTL) == result->m_runs[i]->rtl());
-            int numCharacters = result->m_runs[i]->m_numCharacters;
-            if (!foundFromX && from >= 0 && from < numCharacters) {
-                fromX = result->m_runs[i]->xPositionForVisualOffset(from) + currentX;
-                foundFromX = true;
-            } else {
-                from -= numCharacters;
-            }
-
-            if (!foundToX && to >= 0 && to < numCharacters) {
-                toX = result->m_runs[i]->xPositionForVisualOffset(to) + currentX;
-                foundToX = true;
-            } else {
-                to -= numCharacters;
-            }
-
-            if (foundFromX && foundToX)
-                break;
-            currentX += result->m_runs[i]->m_width;
-        }
-        if (direction == RTL)
-            currentX -= result->width();
-        totalNumCharacters += result->numCharacters();
-    }
-
-    // The position in question might be just after the text.
-    if (!foundFromX && absoluteFrom == totalNumCharacters) {
-        fromX = direction == RTL ? 0 : totalWidth;
-        foundFromX = true;
-    }
-    if (!foundToX && absoluteTo == totalNumCharacters) {
-        toX = direction == RTL ? 0 : totalWidth;
-        foundToX = true;
-    }
-    if (!foundFromX)
-        fromX = 0;
-    if (!foundToX)
-        toX = direction == RTL ? 0 : totalWidth;
-
-    // None of our runs is part of the selection, possibly invalid arguments.
-    if (!foundToX && !foundFromX)
-        fromX = toX = 0;
-    if (fromX < toX)
-        return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
-    return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
-}
-
-int ShapeResult::offsetForPosition(Vector<RefPtr<ShapeResult>>& results,
-    const TextRun& run, float targetX)
-{
-    unsigned totalOffset;
-    if (run.rtl()) {
-        totalOffset = run.length();
-        for (unsigned i = results.size(); i; --i) {
-            const RefPtr<ShapeResult>& wordResult = results[i - 1];
-            if (!wordResult)
-                continue;
-            totalOffset -= wordResult->numCharacters();
-            if (targetX >= 0 && targetX <= wordResult->width()) {
-                int offsetForWord = wordResult->offsetForPosition(targetX);
-                return totalOffset + offsetForWord;
-            }
-            targetX -= wordResult->width();
-        }
-    } else {
-        totalOffset = 0;
-        for (auto& wordResult : results) {
-            if (!wordResult)
-                continue;
-            int offsetForWord = wordResult->offsetForPosition(targetX);
-            ASSERT(offsetForWord >= 0);
-            totalOffset += offsetForWord;
-            if (targetX >= 0 && targetX <= wordResult->width())
-                return totalOffset;
-            targetX -= wordResult->width();
-        }
-    }
-    return totalOffset;
-}
-
-int ShapeResult::offsetForPosition(float targetX)
-{
-    int charactersSoFar = 0;
-    float currentX = 0;
-
-    if (m_direction == RTL) {
-        charactersSoFar = m_numCharacters;
-        for (unsigned i = 0; i < m_runs.size(); ++i) {
-            if (!m_runs[i])
-                continue;
-            charactersSoFar -= m_runs[i]->m_numCharacters;
-            float nextX = currentX + m_runs[i]->m_width;
-            float offsetForRun = targetX - currentX;
-            if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
-                // The x value in question is within this script run.
-                const unsigned index = m_runs[i]->characterIndexForXPosition(offsetForRun);
-                return charactersSoFar + index;
-            }
-            currentX = nextX;
-        }
-    } else {
-        for (unsigned i = 0; i < m_runs.size(); ++i) {
-            if (!m_runs[i])
-                continue;
-            float nextX = currentX + m_runs[i]->m_width;
-            float offsetForRun = targetX - currentX;
-            if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
-                const unsigned index = m_runs[i]->characterIndexForXPosition(offsetForRun);
-                return charactersSoFar + index;
-            }
-            charactersSoFar += m_runs[i]->m_numCharacters;
-            currentX = nextX;
-        }
-    }
-
-    return charactersSoFar;
-}
-
-void ShapeResult::fallbackFonts(HashSet<const SimpleFontData*>* fallback) const
-{
-    ASSERT(fallback);
-    ASSERT(m_primaryFont);
-    for (unsigned i = 0; i < m_runs.size(); ++i) {
-        if (m_runs[i] && m_runs[i]->m_fontData != m_primaryFont
-            && !m_runs[i]->m_fontData->isTextOrientationFallbackOf(m_primaryFont.get())) {
-            fallback->add(m_runs[i]->m_fontData.get());
-        }
-    }
-}
-
-unsigned ShapeResult::numberOfRunsForTesting() const
-{
-    return m_runs.size();
-}
-
-bool ShapeResult::runInfoForTesting(unsigned runIndex, unsigned& startIndex,
-    unsigned& numGlyphs, hb_script_t& script)
-{
-    if (runIndex < m_runs.size() && m_runs[runIndex]) {
-        startIndex = m_runs[runIndex]->m_startIndex;
-        numGlyphs = m_runs[runIndex]->m_numGlyphs;
-        script = m_runs[runIndex]->m_script;
-        return true;
-    }
-    return false;
-}
-
-uint16_t ShapeResult::glyphForTesting(unsigned runIndex, size_t glyphIndex)
-{
-    return m_runs[runIndex]->m_glyphData[glyphIndex].glyph;
-}
-
-float ShapeResult::advanceForTesting(unsigned runIndex, size_t glyphIndex)
-{
-    return m_runs[runIndex]->m_glyphData[glyphIndex].advance;
-}
-
 template<typename T>
 class HarfBuzzScopedPtr {
 public:
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
index 71141f64..ea7817bb 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.h
@@ -32,6 +32,7 @@
 #define HarfBuzzShaper_h
 
 #include "hb.h"
+#include "platform/fonts/shaping/ShapeResult.h"
 #include "platform/fonts/shaping/Shaper.h"
 #include "platform/geometry/FloatPoint.h"
 #include "platform/geometry/FloatRect.h"
@@ -52,70 +53,6 @@
 class SimpleFontData;
 class HarfBuzzShaper;
 
-class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> {
-public:
-    static PassRefPtr<ShapeResult> create(const Font* font,
-        unsigned numCharacters, TextDirection direction)
-    {
-        return adoptRef(new ShapeResult(font, numCharacters, direction));
-    }
-    static PassRefPtr<ShapeResult> createForTabulationCharacters(const Font*,
-        const TextRun&, float positionOffset, unsigned count);
-    ~ShapeResult();
-
-    float width() { return m_width; }
-    FloatRect bounds() { return m_glyphBoundingBox; }
-    unsigned numCharacters() const { return m_numCharacters; }
-    void fallbackFonts(HashSet<const SimpleFontData*>*) const;
-
-    static int offsetForPosition(Vector<RefPtr<ShapeResult>>&,
-        const TextRun&, float targetX);
-    static float fillGlyphBuffer(Vector<RefPtr<ShapeResult>>&,
-        GlyphBuffer*, const TextRun&, unsigned from, unsigned to);
-    static float fillGlyphBufferForTextEmphasis(Vector<RefPtr<ShapeResult>>&,
-        GlyphBuffer*, const TextRun&, const GlyphData* emphasisData,
-        unsigned from, unsigned to);
-    static FloatRect selectionRect(Vector<RefPtr<ShapeResult>>&,
-        TextDirection, float totalWidth, const FloatPoint&, int height,
-        unsigned from, unsigned to);
-
-    unsigned numberOfRunsForTesting() const;
-    bool runInfoForTesting(unsigned runIndex, unsigned& startIndex,
-        unsigned& numGlyphs, hb_script_t&);
-    uint16_t glyphForTesting(unsigned runIndex, size_t glyphIndex);
-    float advanceForTesting(unsigned runIndex, size_t glyphIndex);
-
-private:
-    struct RunInfo;
-
-    ShapeResult(const Font*, unsigned numCharacters, TextDirection);
-
-    int offsetForPosition(float targetX);
-    template<TextDirection>
-    float fillGlyphBufferForRun(GlyphBuffer*, const RunInfo*,
-        float initialAdvance, unsigned from, unsigned to, unsigned runOffset);
-
-    float fillGlyphBufferForTextEmphasisRun(GlyphBuffer*, const RunInfo*,
-        const TextRun&, const GlyphData*, float initialAdvance,
-        unsigned from, unsigned to, unsigned runOffset);
-
-    float m_width;
-    FloatRect m_glyphBoundingBox;
-    Vector<OwnPtr<RunInfo>> m_runs;
-    RefPtr<SimpleFontData> m_primaryFont;
-
-    unsigned m_numCharacters;
-    unsigned m_numGlyphs : 31;
-
-    // Overall direction for the TextRun, dictates which order each individual
-    // sub run (represented by RunInfo structs in the m_runs vector) can have a
-    // different text direction.
-    unsigned m_direction : 1;
-
-    friend class HarfBuzzShaper;
-};
-
-
 // Shaping text runs is split into several stages: Run segmentation, shaping the
 // initial segment, identify shaped and non-shaped sequences of the shaping
 // result, and processing sub-runs by trying to shape them with a fallback font
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
index e09e2fa..2d239f4 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp
@@ -8,6 +8,7 @@
 #include "platform/fonts/Font.h"
 #include "platform/fonts/FontCache.h"
 #include "platform/fonts/GlyphPage.h"
+#include "platform/fonts/shaping/ShapeResultTestInfo.h"
 #include "platform/text/TextRun.h"
 #include "wtf/Vector.h"
 #include <gtest/gtest.h>
@@ -37,6 +38,10 @@
     hb_script_t script = HB_SCRIPT_INVALID;
 };
 
+static inline ShapeResultTestInfo* testInfo(RefPtr<ShapeResult>& result)
+{
+    return static_cast<ShapeResultTestInfo*>(result.get());
+}
 
 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLatin)
 {
@@ -44,8 +49,8 @@
     HarfBuzzShaper shaper(font, latinCommon);
     RefPtr<ShapeResult> result = shaper.shapeResult();
 
-    ASSERT_EQ(1u, result->numberOfRunsForTesting());
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(8u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -57,8 +62,8 @@
     HarfBuzzShaper shaper(font, leadingCommon);
     RefPtr<ShapeResult> result = shaper.shapeResult();
 
-    ASSERT_EQ(1u, result->numberOfRunsForTesting());
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(8u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -83,8 +88,8 @@
         HarfBuzzShaper shaper(font, run);
         RefPtr<ShapeResult> result = shaper.shapeResult();
 
-        EXPECT_EQ(1u, result->numberOfRunsForTesting()) << test.name;
-        ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script)) << test.name;
+        EXPECT_EQ(1u, testInfo(result)->numberOfRunsForTesting()) << test.name;
+        ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)) << test.name;
         EXPECT_EQ(0u, startIndex) << test.name;
         if (numGlyphs == 2) {
             // If the specified VS is not in the font, it's mapped to .notdef.
@@ -93,9 +98,9 @@
             // OpenType recommends Glyph ID 3 for a space; not a hard requirement though.
             // https://www.microsoft.com/typography/otspec/recom.htm
 #if !OS(MACOSX)
-            EXPECT_EQ(3u, result->glyphForTesting(0, 1)) << test.name;
+            EXPECT_EQ(3u, testInfo(result)->glyphForTesting(0, 1)) << test.name;
 #endif
-            EXPECT_EQ(0.f, result->advanceForTesting(0, 1)) << test.name;
+            EXPECT_EQ(0.f, testInfo(result)->advanceForTesting(0, 1)) << test.name;
         } else {
             EXPECT_EQ(1u, numGlyphs) << test.name;
         }
@@ -110,13 +115,13 @@
     HarfBuzzShaper shaper(font, devanagariCommonLatin);
     RefPtr<ShapeResult> result = shaper.shapeResult();
 
-    ASSERT_EQ(2u, result->numberOfRunsForTesting());
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_EQ(2u, testInfo(result)->numberOfRunsForTesting());
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
 
-    ASSERT_TRUE(result->runInfoForTesting(1, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
     EXPECT_EQ(3u, startIndex);
     EXPECT_EQ(3u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
@@ -129,18 +134,18 @@
     HarfBuzzShaper shaper(font, devanagariCommonLatin);
     RefPtr<ShapeResult> result = shaper.shapeResult();
 
-    ASSERT_EQ(3u, result->numberOfRunsForTesting());
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_EQ(3u, testInfo(result)->numberOfRunsForTesting());
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
 
-    ASSERT_TRUE(result->runInfoForTesting(1, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
     EXPECT_EQ(3u, startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
 
-    ASSERT_TRUE(result->runInfoForTesting(2, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(2, startIndex, numGlyphs, script));
     EXPECT_EQ(4u, startIndex);
     EXPECT_EQ(3u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -153,23 +158,23 @@
     HarfBuzzShaper shaper(font, mixed);
     RefPtr<ShapeResult> result = shaper.shapeResult();
 
-    ASSERT_EQ(4u, result->numberOfRunsForTesting());
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_EQ(4u, testInfo(result)->numberOfRunsForTesting());
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(3u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_ARABIC, script);
 
-    ASSERT_TRUE(result->runInfoForTesting(1, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
     EXPECT_EQ(3u, startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_THAI, script);
 
-    ASSERT_TRUE(result->runInfoForTesting(2, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(2, startIndex, numGlyphs, script));
     EXPECT_EQ(4u, startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_HAN, script);
 
-    ASSERT_TRUE(result->runInfoForTesting(3, startIndex, numGlyphs, script));
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(3, startIndex, numGlyphs, script));
     EXPECT_EQ(5u, startIndex);
     EXPECT_EQ(1u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_LATIN, script);
@@ -182,8 +187,8 @@
     HarfBuzzShaper shaper(font, arabic);
     RefPtr<ShapeResult> result = shaper.shapeResult();
 
-    ASSERT_EQ(1u, result->numberOfRunsForTesting());
-    ASSERT_TRUE(result->runInfoForTesting(0, startIndex, numGlyphs, script));
+    ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
+    ASSERT_TRUE(testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
     EXPECT_EQ(0u, startIndex);
     EXPECT_EQ(3u, numGlyphs);
     EXPECT_EQ(HB_SCRIPT_ARABIC, script);
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
index ac8278c3..9755ed3 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
@@ -27,7 +27,7 @@
 #ifndef ShapeCache_h
 #define ShapeCache_h
 
-#include "platform/fonts/shaping/HarfBuzzShaper.h"
+#include "platform/fonts/shaping/ShapeResult.h"
 #include "platform/text/TextRun.h"
 #include "wtf/Forward.h"
 #include "wtf/HashFunctions.h"
@@ -40,7 +40,6 @@
 class Font;
 class GlyphBuffer;
 class SimpleFontData;
-class HarfBuzzShaper;
 
 struct ShapeCacheEntry {
     ShapeCacheEntry()
@@ -171,10 +170,8 @@
             value = &addResult.storedValue->value;
         }
 
-        // Cache hit: ramp up by sampling the next few words.
-        if (!isNewEntry) {
+        if (!isNewEntry)
             return value;
-        }
 
         if (m_singleCharMap.size() + m_shortStringMap.size() < s_maxSize) {
             return value;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
new file mode 100644
index 0000000..1d015a7
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.cpp
@@ -0,0 +1,502 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "platform/fonts/shaping/ShapeResult.h"
+
+#include "platform/fonts/Font.h"
+#include "platform/fonts/GlyphBuffer.h"
+#include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
+#include "platform/text/TextBreakIterator.h"
+
+namespace blink {
+
+float ShapeResult::RunInfo::xPositionForVisualOffset(unsigned offset) const
+{
+    ASSERT(offset < m_numCharacters);
+    if (rtl())
+        offset = m_numCharacters - offset - 1;
+    return xPositionForOffset(offset);
+}
+
+float ShapeResult::RunInfo::xPositionForOffset(unsigned offset) const
+{
+    ASSERT(offset <= m_numCharacters);
+    unsigned glyphIndex = 0;
+    float position = 0;
+    if (rtl()) {
+        while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex > offset) {
+            position += m_glyphData[glyphIndex].advance;
+            ++glyphIndex;
+        }
+        // For RTL, we need to return the right side boundary of the character.
+        // Add advance of glyphs which are part of the character.
+        while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex) {
+            position += m_glyphData[glyphIndex].advance;
+            ++glyphIndex;
+        }
+        position += m_glyphData[glyphIndex].advance;
+    } else {
+        while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterIndex < offset) {
+            position += m_glyphData[glyphIndex].advance;
+            ++glyphIndex;
+        }
+    }
+    return position;
+}
+
+int ShapeResult::RunInfo::characterIndexForXPosition(float targetX) const
+{
+    ASSERT(targetX <= m_width);
+    float currentX = 0;
+    float currentAdvance = m_glyphData[0].advance;
+    unsigned glyphIndex = 0;
+
+    // Sum up advances that belong to the first character.
+    while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex)
+        currentAdvance += m_glyphData[++glyphIndex].advance;
+    currentAdvance = currentAdvance / 2.0;
+    if (targetX <= currentAdvance)
+        return rtl() ? m_numCharacters : 0;
+
+    currentX = currentAdvance;
+    ++glyphIndex;
+    while (glyphIndex < m_numGlyphs) {
+        unsigned prevCharacterIndex = m_glyphData[glyphIndex - 1].characterIndex;
+        float prevAdvance = currentAdvance;
+        currentAdvance = m_glyphData[glyphIndex].advance;
+        while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterIndex == m_glyphData[glyphIndex + 1].characterIndex)
+            currentAdvance += m_glyphData[++glyphIndex].advance;
+        currentAdvance = currentAdvance / 2.0;
+        float nextX = currentX + prevAdvance + currentAdvance;
+        if (currentX <= targetX && targetX <= nextX)
+            return rtl() ? prevCharacterIndex : m_glyphData[glyphIndex].characterIndex;
+        currentX = nextX;
+        ++glyphIndex;
+    }
+
+    return rtl() ? 0 : m_numCharacters;
+}
+
+void ShapeResult::RunInfo::setGlyphAndPositions(unsigned index,
+    uint16_t glyphId, float advance, float offsetX, float offsetY)
+{
+    HarfBuzzRunGlyphData& data = m_glyphData[index];
+    data.glyph = glyphId;
+    data.advance = advance;
+    data.offset = FloatSize(offsetX, offsetY);
+}
+
+ShapeResult::ShapeResult(const Font* font, unsigned numCharacters, TextDirection direction)
+    : m_width(0)
+    , m_primaryFont(const_cast<SimpleFontData*>(font->primaryFont()))
+    , m_numCharacters(numCharacters)
+    , m_numGlyphs(0)
+    , m_direction(direction)
+{
+}
+
+ShapeResult::~ShapeResult()
+{
+}
+
+static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance,
+    hb_direction_t direction, const SimpleFontData* fontData,
+    const HarfBuzzRunGlyphData& glyphData)
+{
+    FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction)
+        ? FloatPoint(advance, 0)
+        : FloatPoint(0, advance);
+    glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset);
+}
+
+template<TextDirection direction>
+float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer,
+    const RunInfo* run, float initialAdvance, unsigned from, unsigned to,
+    unsigned runOffset)
+{
+    if (!run)
+        return 0;
+    float advanceSoFar = initialAdvance;
+    unsigned numGlyphs = run->m_numGlyphs;
+    for (unsigned i = 0; i < numGlyphs; ++i) {
+        const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
+        uint16_t currentCharacterIndex = run->m_startIndex +
+            glyphData.characterIndex + runOffset;
+        if ((direction == RTL && currentCharacterIndex >= to)
+            || (direction == LTR && currentCharacterIndex < from)) {
+            advanceSoFar += glyphData.advance;
+        } else if ((direction == RTL && currentCharacterIndex >= from)
+            || (direction == LTR && currentCharacterIndex < to)) {
+            addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction,
+                run->m_fontData.get(), glyphData);
+            advanceSoFar += glyphData.advance;
+        }
+    }
+    return advanceSoFar - initialAdvance;
+}
+
+static inline unsigned countGraphemesInCluster(const UChar* str,
+    unsigned strLength, uint16_t startIndex, uint16_t endIndex)
+{
+    if (startIndex > endIndex) {
+        uint16_t tempIndex = startIndex;
+        startIndex = endIndex;
+        endIndex = tempIndex;
+    }
+    uint16_t length = endIndex - startIndex;
+    ASSERT(static_cast<unsigned>(startIndex + length) <= strLength);
+    TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startIndex], length);
+
+    int cursorPos = cursorPosIterator->current();
+    int numGraphemes = -1;
+    while (0 <= cursorPos) {
+        cursorPos = cursorPosIterator->next();
+        numGraphemes++;
+    }
+    return std::max(0, numGraphemes);
+}
+
+static inline void addEmphasisMark(GlyphBuffer* buffer,
+    const GlyphData* emphasisData, FloatPoint glyphCenter,
+    float midGlyphOffset)
+{
+    ASSERT(buffer);
+    ASSERT(emphasisData);
+
+    const SimpleFontData* emphasisFontData = emphasisData->fontData;
+    ASSERT(emphasisFontData);
+
+    bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright()
+        && emphasisFontData->verticalData();
+
+    if (!isVertical) {
+        buffer->add(emphasisData->glyph, emphasisFontData,
+            midGlyphOffset - glyphCenter.x());
+    } else {
+        buffer->add(emphasisData->glyph, emphasisFontData,
+            FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y()));
+    }
+}
+
+float ShapeResult::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer,
+    const RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData,
+    float initialAdvance, unsigned from, unsigned to, unsigned runOffset)
+{
+    if (!run)
+        return 0;
+
+    unsigned graphemesInCluster = 1;
+    float clusterAdvance = 0;
+
+    FloatPoint glyphCenter = emphasisData->fontData->
+        boundsForGlyph(emphasisData->glyph).center();
+
+    TextDirection direction = textRun.direction();
+
+    // A "cluster" in this context means a cluster as it is used by HarfBuzz:
+    // The minimal group of characters and corresponding glyphs, that cannot be broken
+    // down further from a text shaping point of view.
+    // A cluster can contain multiple glyphs and grapheme clusters, with mutually
+    // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clusters,
+    // then linearly split the sum of corresponding glyph advances by the number of
+    // grapheme clusters in order to find positions for emphasis mark drawing.
+    uint16_t clusterStart = direction == RTL
+        ? run->m_startIndex + run->m_numCharacters + runOffset
+        : run->glyphToCharacterIndex(0) + runOffset;
+
+    float advanceSoFar = initialAdvance;
+    unsigned numGlyphs = run->m_numGlyphs;
+    for (unsigned i = 0; i < numGlyphs; ++i) {
+        const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
+        uint16_t currentCharacterIndex = run->m_startIndex + glyphData.characterIndex + runOffset;
+        bool isRunEnd = (i + 1 == numGlyphs);
+        bool isClusterEnd =  isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != currentCharacterIndex);
+
+        if ((direction == RTL && currentCharacterIndex >= to) || (direction != RTL && currentCharacterIndex < from)) {
+            advanceSoFar += glyphData.advance;
+            direction == RTL ? --clusterStart : ++clusterStart;
+            continue;
+        }
+
+        clusterAdvance += glyphData.advance;
+
+        if (textRun.is8Bit()) {
+            float glyphAdvanceX = glyphData.advance;
+            if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) {
+                addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
+            }
+            advanceSoFar += glyphAdvanceX;
+        } else if (isClusterEnd) {
+            uint16_t clusterEnd;
+            if (direction == RTL)
+                clusterEnd = currentCharacterIndex;
+            else
+                clusterEnd = isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset : run->glyphToCharacterIndex(i + 1) + runOffset;
+
+            graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd);
+            if (!graphemesInCluster || !clusterAdvance)
+                continue;
+
+            float glyphAdvanceX = clusterAdvance / graphemesInCluster;
+            for (unsigned j = 0; j < graphemesInCluster; ++j) {
+                // Do not put emphasis marks on space, separator, and control characters.
+                if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex]))
+                    addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
+                advanceSoFar += glyphAdvanceX;
+            }
+            clusterStart = clusterEnd;
+            clusterAdvance = 0;
+        }
+    }
+    return advanceSoFar - initialAdvance;
+}
+
+float ShapeResult::fillGlyphBuffer(Vector<RefPtr<ShapeResult>>& results,
+    GlyphBuffer* glyphBuffer, const TextRun& textRun,
+    unsigned from, unsigned to)
+{
+    float advance = 0;
+    if (textRun.rtl()) {
+        unsigned wordOffset = textRun.length();
+        for (unsigned j = 0; j < results.size(); j++) {
+            unsigned resolvedIndex = results.size() - 1 - j;
+            RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
+            for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
+                advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer,
+                    wordResult->m_runs[i].get(), advance, from, to,
+                    wordOffset - wordResult->numCharacters());
+            }
+            wordOffset -= wordResult->numCharacters();
+        }
+    } else {
+        unsigned wordOffset = 0;
+        for (unsigned j = 0; j < results.size(); j++) {
+            RefPtr<ShapeResult>& wordResult = results[j];
+            for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
+                advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer,
+                    wordResult->m_runs[i].get(), advance, from, to, wordOffset);
+            }
+            wordOffset += wordResult->numCharacters();
+        }
+    }
+
+    return advance;
+}
+
+float ShapeResult::fillGlyphBufferForTextEmphasis(
+    Vector<RefPtr<ShapeResult>>& results, GlyphBuffer* glyphBuffer,
+    const TextRun& textRun, const GlyphData* emphasisData,
+    unsigned from, unsigned to)
+{
+    float advance = 0;
+    unsigned wordOffset = textRun.rtl() ? textRun.length() : 0;
+    for (unsigned j = 0; j < results.size(); j++) {
+        unsigned resolvedIndex = textRun.rtl() ? results.size() - 1 - j : j;
+        RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
+        for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
+            unsigned resolvedOffset = wordOffset -
+                (textRun.rtl() ? wordResult->numCharacters() : 0);
+            advance += wordResult->fillGlyphBufferForTextEmphasisRun(
+                glyphBuffer, wordResult->m_runs[i].get(), textRun, emphasisData,
+                advance, from, to, resolvedOffset);
+        }
+        wordOffset += wordResult->numCharacters() * (textRun.rtl() ? -1 : 1);
+    }
+
+    return advance;
+}
+
+FloatRect ShapeResult::selectionRect(Vector<RefPtr<ShapeResult>>& results,
+    TextDirection direction, float totalWidth, const FloatPoint& point,
+    int height, unsigned absoluteFrom, unsigned absoluteTo)
+{
+    float currentX = 0;
+    float fromX = 0;
+    float toX = 0;
+    bool foundFromX = false;
+    bool foundToX = false;
+
+    if (direction == RTL)
+        currentX = totalWidth;
+
+    // The absoluteFrom and absoluteTo arguments represent the start/end offset
+    // for the entire run, from/to are continuously updated to be relative to
+    // the current word (ShapeResult instance).
+    int from = absoluteFrom;
+    int to = absoluteTo;
+
+    unsigned totalNumCharacters = 0;
+    for (unsigned j = 0; j < results.size(); j++) {
+        RefPtr<ShapeResult> result = results[j];
+        if (direction == RTL) {
+            // Convert logical offsets to visual offsets, because results are in
+            // logical order while runs are in visual order.
+            if (!foundFromX && from >= 0 && static_cast<unsigned>(from) < result->numCharacters())
+                from = result->numCharacters() - from - 1;
+            if (!foundToX && to >= 0 && static_cast<unsigned>(to) < result->numCharacters())
+                to = result->numCharacters() - to - 1;
+            currentX -= result->width();
+        }
+        for (unsigned i = 0; i < result->m_runs.size(); i++) {
+            if (!result->m_runs[i])
+                continue;
+            ASSERT((direction == RTL) == result->m_runs[i]->rtl());
+            int numCharacters = result->m_runs[i]->m_numCharacters;
+            if (!foundFromX && from >= 0 && from < numCharacters) {
+                fromX = result->m_runs[i]->xPositionForVisualOffset(from) + currentX;
+                foundFromX = true;
+            } else {
+                from -= numCharacters;
+            }
+
+            if (!foundToX && to >= 0 && to < numCharacters) {
+                toX = result->m_runs[i]->xPositionForVisualOffset(to) + currentX;
+                foundToX = true;
+            } else {
+                to -= numCharacters;
+            }
+
+            if (foundFromX && foundToX)
+                break;
+            currentX += result->m_runs[i]->m_width;
+        }
+        if (direction == RTL)
+            currentX -= result->width();
+        totalNumCharacters += result->numCharacters();
+    }
+
+    // The position in question might be just after the text.
+    if (!foundFromX && absoluteFrom == totalNumCharacters) {
+        fromX = direction == RTL ? 0 : totalWidth;
+        foundFromX = true;
+    }
+    if (!foundToX && absoluteTo == totalNumCharacters) {
+        toX = direction == RTL ? 0 : totalWidth;
+        foundToX = true;
+    }
+    if (!foundFromX)
+        fromX = 0;
+    if (!foundToX)
+        toX = direction == RTL ? 0 : totalWidth;
+
+    // None of our runs is part of the selection, possibly invalid arguments.
+    if (!foundToX && !foundFromX)
+        fromX = toX = 0;
+    if (fromX < toX)
+        return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
+    return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
+}
+
+int ShapeResult::offsetForPosition(Vector<RefPtr<ShapeResult>>& results,
+    const TextRun& run, float targetX)
+{
+    unsigned totalOffset;
+    if (run.rtl()) {
+        totalOffset = run.length();
+        for (unsigned i = results.size(); i; --i) {
+            const RefPtr<ShapeResult>& wordResult = results[i - 1];
+            if (!wordResult)
+                continue;
+            totalOffset -= wordResult->numCharacters();
+            if (targetX >= 0 && targetX <= wordResult->width()) {
+                int offsetForWord = wordResult->offsetForPosition(targetX);
+                return totalOffset + offsetForWord;
+            }
+            targetX -= wordResult->width();
+        }
+    } else {
+        totalOffset = 0;
+        for (auto& wordResult : results) {
+            if (!wordResult)
+                continue;
+            int offsetForWord = wordResult->offsetForPosition(targetX);
+            ASSERT(offsetForWord >= 0);
+            totalOffset += offsetForWord;
+            if (targetX >= 0 && targetX <= wordResult->width())
+                return totalOffset;
+            targetX -= wordResult->width();
+        }
+    }
+    return totalOffset;
+}
+
+int ShapeResult::offsetForPosition(float targetX)
+{
+    int charactersSoFar = 0;
+    float currentX = 0;
+
+    if (m_direction == RTL) {
+        charactersSoFar = m_numCharacters;
+        for (unsigned i = 0; i < m_runs.size(); ++i) {
+            if (!m_runs[i])
+                continue;
+            charactersSoFar -= m_runs[i]->m_numCharacters;
+            float nextX = currentX + m_runs[i]->m_width;
+            float offsetForRun = targetX - currentX;
+            if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
+                // The x value in question is within this script run.
+                const unsigned index = m_runs[i]->characterIndexForXPosition(offsetForRun);
+                return charactersSoFar + index;
+            }
+            currentX = nextX;
+        }
+    } else {
+        for (unsigned i = 0; i < m_runs.size(); ++i) {
+            if (!m_runs[i])
+                continue;
+            float nextX = currentX + m_runs[i]->m_width;
+            float offsetForRun = targetX - currentX;
+            if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
+                const unsigned index = m_runs[i]->characterIndexForXPosition(offsetForRun);
+                return charactersSoFar + index;
+            }
+            charactersSoFar += m_runs[i]->m_numCharacters;
+            currentX = nextX;
+        }
+    }
+
+    return charactersSoFar;
+}
+
+void ShapeResult::fallbackFonts(HashSet<const SimpleFontData*>* fallback) const
+{
+    ASSERT(fallback);
+    ASSERT(m_primaryFont);
+    for (unsigned i = 0; i < m_runs.size(); ++i) {
+        if (m_runs[i] && m_runs[i]->m_fontData != m_primaryFont
+            && !m_runs[i]->m_fontData->isTextOrientationFallbackOf(m_primaryFont.get())) {
+            fallback->add(m_runs[i]->m_fontData.get());
+        }
+    }
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
new file mode 100644
index 0000000..811232c
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResult.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ShapeResult_h
+#define ShapeResult_h
+
+#include "platform/geometry/FloatPoint.h"
+#include "platform/geometry/FloatRect.h"
+#include "platform/text/TextRun.h"
+#include "wtf/HashSet.h"
+#include "wtf/OwnPtr.h"
+#include "wtf/Vector.h"
+
+namespace blink {
+
+class Font;
+class GlyphBuffer;
+class SimpleFontData;
+class HarfBuzzShaper;
+struct GlyphData;
+
+class PLATFORM_EXPORT ShapeResult : public RefCounted<ShapeResult> {
+public:
+    static PassRefPtr<ShapeResult> create(const Font* font,
+        unsigned numCharacters, TextDirection direction)
+    {
+        return adoptRef(new ShapeResult(font, numCharacters, direction));
+    }
+    static PassRefPtr<ShapeResult> createForTabulationCharacters(const Font*,
+        const TextRun&, float positionOffset, unsigned count);
+    ~ShapeResult();
+
+    float width() { return m_width; }
+    FloatRect bounds() { return m_glyphBoundingBox; }
+    unsigned numCharacters() const { return m_numCharacters; }
+    void fallbackFonts(HashSet<const SimpleFontData*>*) const;
+
+    static int offsetForPosition(Vector<RefPtr<ShapeResult>>&,
+        const TextRun&, float targetX);
+    static float fillGlyphBuffer(Vector<RefPtr<ShapeResult>>&,
+        GlyphBuffer*, const TextRun&, unsigned from, unsigned to);
+    static float fillGlyphBufferForTextEmphasis(Vector<RefPtr<ShapeResult>>&,
+        GlyphBuffer*, const TextRun&, const GlyphData* emphasisData,
+        unsigned from, unsigned to);
+    static FloatRect selectionRect(Vector<RefPtr<ShapeResult>>&,
+        TextDirection, float totalWidth, const FloatPoint&, int height,
+        unsigned from, unsigned to);
+
+protected:
+    struct RunInfo;
+
+    ShapeResult(const Font*, unsigned numCharacters, TextDirection);
+
+    int offsetForPosition(float targetX);
+    template<TextDirection>
+    float fillGlyphBufferForRun(GlyphBuffer*, const RunInfo*,
+        float initialAdvance, unsigned from, unsigned to, unsigned runOffset);
+
+    float fillGlyphBufferForTextEmphasisRun(GlyphBuffer*, const RunInfo*,
+        const TextRun&, const GlyphData*, float initialAdvance,
+        unsigned from, unsigned to, unsigned runOffset);
+
+    float m_width;
+    FloatRect m_glyphBoundingBox;
+    Vector<OwnPtr<RunInfo>> m_runs;
+    RefPtr<SimpleFontData> m_primaryFont;
+
+    unsigned m_numCharacters;
+    unsigned m_numGlyphs : 31;
+
+    // Overall direction for the TextRun, dictates which order each individual
+    // sub run (represented by RunInfo structs in the m_runs vector) can have a
+    // different text direction.
+    unsigned m_direction : 1;
+
+    friend class HarfBuzzShaper;
+};
+
+} // namespace blink
+
+#endif // ShapeResult_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h
new file mode 100644
index 0000000..c0985a22
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultInlineHeaders.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ShapeResultInlineHeaders_h
+#define ShapeResultInlineHeaders_h
+
+#include "platform/fonts/shaping/ShapeResult.h"
+
+#include <hb.h>
+
+namespace blink {
+
+class Font;
+class GlyphBuffer;
+class SimpleFontData;
+class HarfBuzzShaper;
+
+struct HarfBuzzRunGlyphData {
+    uint16_t glyph;
+    uint16_t characterIndex;
+    float advance;
+    FloatSize offset;
+};
+
+struct ShapeResult::RunInfo {
+    RunInfo(const SimpleFontData* font, hb_direction_t dir, hb_script_t script,
+        unsigned startIndex, unsigned numGlyphs, unsigned numCharacters)
+        : m_fontData(const_cast<SimpleFontData*>(font)), m_direction(dir)
+        , m_script(script), m_startIndex(startIndex)
+        , m_numCharacters(numCharacters) , m_numGlyphs(numGlyphs), m_width(0.0f)
+    {
+        m_glyphData.resize(m_numGlyphs);
+    }
+
+    bool rtl() const { return HB_DIRECTION_IS_BACKWARD(m_direction); }
+    float xPositionForVisualOffset(unsigned) const;
+    float xPositionForOffset(unsigned) const;
+    int characterIndexForXPosition(float) const;
+    void setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance,
+        float offsetX, float offsetY);
+
+    void addAdvance(unsigned index, float advance)
+    {
+        m_glyphData[index].advance += advance;
+    }
+
+    size_t glyphToCharacterIndex(size_t i) const
+    {
+        return m_startIndex + m_glyphData[i].characterIndex;
+    }
+
+    RefPtr<SimpleFontData> m_fontData;
+    hb_direction_t m_direction;
+    hb_script_t m_script;
+    Vector<HarfBuzzRunGlyphData> m_glyphData;
+    unsigned m_startIndex;
+    unsigned m_numCharacters;
+    unsigned m_numGlyphs;
+    float m_width;
+};
+
+} // namespace blink
+
+#endif // ShapeResultInlineHeaders_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp
new file mode 100644
index 0000000..e9fedda
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.cpp
@@ -0,0 +1,42 @@
+// Copyright 2015 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 "config.h"
+#include "platform/fonts/shaping/ShapeResultTestInfo.h"
+
+#include "platform/fonts/Font.h"
+#include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
+
+namespace blink {
+
+unsigned ShapeResultTestInfo::numberOfRunsForTesting() const
+{
+    return m_runs.size();
+}
+
+bool ShapeResultTestInfo::runInfoForTesting(unsigned runIndex,
+    unsigned& startIndex, unsigned& numGlyphs, hb_script_t& script)
+{
+    if (runIndex < m_runs.size() && m_runs[runIndex]) {
+        startIndex = m_runs[runIndex]->m_startIndex;
+        numGlyphs = m_runs[runIndex]->m_numGlyphs;
+        script = m_runs[runIndex]->m_script;
+        return true;
+    }
+    return false;
+}
+
+uint16_t ShapeResultTestInfo::glyphForTesting(unsigned runIndex,
+    size_t glyphIndex)
+{
+    return m_runs[runIndex]->m_glyphData[glyphIndex].glyph;
+}
+
+float ShapeResultTestInfo::advanceForTesting(unsigned runIndex,
+    size_t glyphIndex)
+{
+    return m_runs[runIndex]->m_glyphData[glyphIndex].advance;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h
new file mode 100644
index 0000000..d8dd283
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeResultTestInfo.h
@@ -0,0 +1,25 @@
+// Copyright 2015 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.
+
+#ifndef ShapeResultTestInfo_h
+#define ShapeResultTestInfo_h
+
+#include "platform/fonts/shaping/HarfBuzzShaper.h"
+
+#include <hb.h>
+
+namespace blink {
+
+class PLATFORM_EXPORT ShapeResultTestInfo : public ShapeResult {
+public:
+    unsigned numberOfRunsForTesting() const;
+    bool runInfoForTesting(unsigned runIndex, unsigned& startIndex,
+        unsigned& numGlyphs, hb_script_t&);
+    uint16_t glyphForTesting(unsigned runIndex, size_t glyphIndex);
+    float advanceForTesting(unsigned runIndex, size_t glyphIndex);
+};
+
+} // namespace blink
+
+#endif // ShapeResultTestInfo_h
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp
index d3c0db4b..3a63f49 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/Shaper.cpp
@@ -31,6 +31,7 @@
 #include "config.h"
 #include "platform/fonts/shaping/Shaper.h"
 
+#include "platform/fonts/Font.h"
 #include "platform/fonts/GlyphBuffer.h"
 #include "platform/fonts/GlyphPage.h"
 #include "platform/text/TextRun.h"
@@ -74,4 +75,14 @@
     }
 }
 
+void Shaper::trackNonPrimaryFallbackFont(const SimpleFontData* fontData)
+{
+    ASSERT(m_fallbackFonts);
+
+    if (fontData == m_font->primaryFont())
+        return;
+
+    m_fallbackFonts->add(fontData);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/Shaper.h b/third_party/WebKit/Source/platform/fonts/shaping/Shaper.h
index 42fc1fe..ba3b5fbc 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/Shaper.h
+++ b/third_party/WebKit/Source/platform/fonts/shaping/Shaper.h
@@ -32,12 +32,13 @@
 #define Shaper_h
 
 #include "platform/PlatformExport.h"
-#include "platform/fonts/Font.h"
+#include "platform/geometry/FloatPoint.h"
 #include "wtf/HashSet.h"
 
 namespace blink {
 
 class FloatRect;
+class Font;
 class GlyphBuffer;
 class SimpleFontData;
 class TextRun;
@@ -70,16 +71,6 @@
     FloatPoint m_emphasisGlyphCenter;
 };
 
-inline void Shaper::trackNonPrimaryFallbackFont(const SimpleFontData* fontData)
-{
-    ASSERT(m_fallbackFonts);
-
-    if (fontData == m_font->primaryFont())
-        return;
-
-    m_fallbackFonts->add(fontData);
-}
-
 } // namespace blink
 
 #endif // Shaper_h
diff --git a/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp b/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp
index 1b30b676..fc1c648 100644
--- a/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DrawLooperBuilder.cpp
@@ -67,6 +67,10 @@
 void DrawLooperBuilder::addShadow(const FloatSize& offset, float blur, const Color& color,
     ShadowTransformMode shadowTransformMode, ShadowAlphaMode shadowAlphaMode)
 {
+    // Negative blurs are not allowed, so just pin the value to 0
+    if (blur < 0)
+        blur = 0;
+
     // Detect when there's no effective shadow.
     if (!color.alpha())
         return;
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp
index 7b34e954..a0baa6d2 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp
@@ -62,6 +62,7 @@
 {
     RefPtr<SharedBuffer> data = readFile(file);
     ASSERT_TRUE(data.get());
+    ASSERT_TRUE(data->data());
 
     Vector<unsigned> baselineHashes;
     createDecodingBaseline(createDecoder, data.get(), &baselineHashes);
@@ -72,9 +73,14 @@
     size_t framesDecoded = 0;
 
     // Pass data to decoder byte by byte.
+    RefPtr<SharedBuffer> sourceData[2] = { SharedBuffer::create(), SharedBuffer::create() };
+    const char* source = data->data();
+
     for (size_t length = 1; length <= data->size() && !decoder->failed(); ++length) {
-        RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), length);
-        decoder->setData(tempData.get(), length == data->size());
+        sourceData[0]->append(source, 1);
+        sourceData[1]->append(source++, 1);
+        // Alternate the buffers to cover the JPEGImageDecoder::onSetData restart code.
+        decoder->setData(sourceData[length & 1].get(), length == data->size());
 
         EXPECT_LE(frameCount, decoder->frameCount());
         frameCount = decoder->frameCount();
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
index 218864a1..9668023 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
@@ -231,13 +231,19 @@
     ASSERT_FALSE(decoder->canDecodeToYUV());
 }
 
-TEST(JPEGImageDecoderTest, byteByByte)
+TEST(JPEGImageDecoderTest, byteByByteBaselineJPEGWithColorProfileAndRestartMarkers)
 {
-    testByteByByteDecode(&createDecoder, "/LayoutTests/fast/images/resources/lenna.jpg", 1u, cAnimationNone);
-    // Progressive image
-    testByteByByteDecode(&createDecoder, "/LayoutTests/fast/images/resources/flowchart.jpg", 1u, cAnimationNone);
-    // Image with restart markers
-    testByteByByteDecode(&createDecoder, "/LayoutTests/fast/images/resources/red-at-12-oclock-with-color-profile.jpg", 1u, cAnimationNone);
+    testByteByByteDecode(&createDecoder, "/LayoutTests/fast/images/resources/small-square-with-colorspin-profile.jpg", 1u, cAnimationNone);
+}
+
+TEST(JPEGImageDecoderTest, byteByByteProgressiveJPEG)
+{
+    testByteByByteDecode(&createDecoder, "/LayoutTests/fast/images/resources/bug106024.jpg", 1u, cAnimationNone);
+}
+
+TEST(JPEGImageDecoderTest, byteByByteRGBJPEGWithAdobeMarkers)
+{
+    testByteByByteDecode(&createDecoder, "/LayoutTests/fast/images/resources/rgb-jpeg-with-adobe-marker-only.jpg", 1u, cAnimationNone);
 }
 
 // This test verifies that calling SharedBuffer::mergeSegmentsIntoBuffer() does
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
index f759d64..f3280030 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -472,7 +472,7 @@
 void FrameLoaderClientImpl::dispatchDidFailProvisionalLoad(
     const ResourceError& error, HistoryCommitType commitType)
 {
-    OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().provisionalDocumentLoader());
+    OwnPtrWillBeRawPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().provisionalDocumentLoader());
     m_webFrame->didFail(error, true, commitType);
     if (observer)
         observer->didFailLoading(error);
@@ -480,7 +480,7 @@
 
 void FrameLoaderClientImpl::dispatchDidFailLoad(const ResourceError& error, HistoryCommitType commitType)
 {
-    OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().documentLoader());
+    OwnPtrWillBeRawPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().documentLoader());
     m_webFrame->didFail(error, false, commitType);
     if (observer)
         observer->didFailLoading(error);
@@ -492,7 +492,7 @@
 
 void FrameLoaderClientImpl::dispatchDidFinishLoad()
 {
-    OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().documentLoader());
+    OwnPtrWillBeRawPtr<WebPluginLoadObserver> observer = pluginLoadObserver(m_webFrame->frame()->loader().documentLoader());
 
     if (m_webFrame->client())
         m_webFrame->client()->didFinishLoad(m_webFrame);
@@ -838,7 +838,7 @@
     return ObjectContentNone;
 }
 
-PassOwnPtr<WebPluginLoadObserver> FrameLoaderClientImpl::pluginLoadObserver(DocumentLoader* loader)
+PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> FrameLoaderClientImpl::pluginLoadObserver(DocumentLoader* loader)
 {
     return WebDataSourceImpl::fromDocumentLoader(loader)->releasePluginLoadObserver();
 }
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
index 77092961..8c67485 100644
--- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
+++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -182,7 +182,7 @@
 
     bool isFrameLoaderClientImpl() const override { return true; }
 
-    PassOwnPtr<WebPluginLoadObserver> pluginLoadObserver(DocumentLoader*);
+    PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> pluginLoadObserver(DocumentLoader*);
 
     // The WebFrame that owns this object and manages its lifetime. Therefore,
     // the web frame object is guaranteed to exist.
diff --git a/third_party/WebKit/Source/web/InspectorOverlay.cpp b/third_party/WebKit/Source/web/InspectorOverlay.cpp
index af68d4c..6ceaa31 100644
--- a/third_party/WebKit/Source/web/InspectorOverlay.cpp
+++ b/third_party/WebKit/Source/web/InspectorOverlay.cpp
@@ -771,10 +771,10 @@
 
 void InspectorOverlay::initializeLayoutEditorIfNeeded(Node* node)
 {
-    if (node && node->isElementNode() && m_inspectMode == InspectorDOMAgent::ShowLayoutEditor && !m_layoutEditor) {
-        m_layoutEditor = LayoutEditor::create(toElement(node), m_cssAgent, m_domAgent, &overlayMainFrame()->script());
-        toChromeClientImpl(m_webViewImpl->page()->chromeClient()).setCursorOverridden(true);
-    }
+    if (m_inspectMode != InspectorDOMAgent::ShowLayoutEditor || !node || !node->isElementNode() || !node->ownerDocument()->isActive())
+        return;
+    m_layoutEditor = LayoutEditor::create(toElement(node), m_cssAgent, m_domAgent, &overlayMainFrame()->script());
+    toChromeClientImpl(m_webViewImpl->page()->chromeClient()).setCursorOverridden(true);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebColorName.cpp b/third_party/WebKit/Source/web/WebColorName.cpp
deleted file mode 100644
index dd5b3a8c..0000000
--- a/third_party/WebKit/Source/web/WebColorName.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "public/web/WebColorName.h"
-
-#include "core/CSSValueKeywords.h"
-#include "core/layout/LayoutTheme.h"
-#include "platform/graphics/Color.h"
-#include "public/platform/WebColor.h"
-
-namespace blink {
-
-static int toCSSValueKeyword(WebColorName name)
-{
-    switch (name) {
-    case WebColorActiveBorder:
-        return CSSValueActiveborder;
-    case WebColorActiveCaption:
-        return CSSValueActivecaption;
-    case WebColorAppworkspace:
-        return CSSValueAppworkspace;
-    case WebColorBackground:
-        return CSSValueBackground;
-    case WebColorButtonFace:
-        return CSSValueButtonface;
-    case WebColorButtonHighlight:
-        return CSSValueButtonhighlight;
-    case WebColorButtonShadow:
-        return CSSValueButtonshadow;
-    case WebColorButtonText:
-        return CSSValueButtontext;
-    case WebColorCaptionText:
-        return CSSValueCaptiontext;
-    case WebColorGrayText:
-        return CSSValueGraytext;
-    case WebColorHighlight:
-        return CSSValueHighlight;
-    case WebColorHighlightText:
-        return CSSValueHighlighttext;
-    case WebColorInactiveBorder:
-        return CSSValueInactiveborder;
-    case WebColorInactiveCaption:
-        return CSSValueInactivecaption;
-    case WebColorInactiveCaptionText:
-        return CSSValueInactivecaptiontext;
-    case WebColorInfoBackground:
-        return CSSValueInfobackground;
-    case WebColorInfoText:
-        return CSSValueInfotext;
-    case WebColorMenu:
-        return CSSValueMenu;
-    case WebColorMenuText:
-        return CSSValueMenutext;
-    case WebColorScrollbar:
-        return CSSValueScrollbar;
-    case WebColorText:
-        return CSSValueText;
-    case WebColorThreedDarkShadow:
-        return CSSValueThreeddarkshadow;
-    case WebColorThreedShadow:
-        return CSSValueThreedshadow;
-    case WebColorThreedFace:
-        return CSSValueThreedface;
-    case WebColorThreedHighlight:
-        return CSSValueThreedhighlight;
-    case WebColorThreedLightShadow:
-        return CSSValueThreedlightshadow;
-    case WebColorWebkitFocusRingColor:
-        return CSSValueWebkitFocusRingColor;
-    case WebColorWindow:
-        return CSSValueWindow;
-    case WebColorWindowFrame:
-        return CSSValueWindowframe;
-    case WebColorWindowText:
-        return CSSValueWindowtext;
-    default:
-        return CSSValueInvalid;
-    }
-}
-
-void setNamedColors(const WebColorName* colorNames, const WebColor* colors, size_t length)
-{
-    for (size_t i = 0; i < length; ++i) {
-        WebColorName colorName = colorNames[i];
-        WebColor color = colors[i];
-
-        // Convert color to internal value identifier.
-        int internalColorName = toCSSValueKeyword(colorName);
-        if (internalColorName == CSSValueWebkitFocusRingColor) {
-            LayoutTheme::theme().setCustomFocusRingColor(color);
-            continue;
-        }
-    }
-
-    // TODO(jeremy): Tell LayoutTheme to update colors.
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/web/WebDOMCustomEvent.cpp b/third_party/WebKit/Source/web/WebDOMCustomEvent.cpp
deleted file mode 100644
index 4de4858..0000000
--- a/third_party/WebKit/Source/web/WebDOMCustomEvent.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "public/web/WebDOMCustomEvent.h"
-
-#include "bindings/core/v8/SerializedScriptValue.h"
-#include "core/events/CustomEvent.h"
-#include "public/platform/WebString.h"
-
-namespace blink {
-
-WebDOMCustomEvent::WebDOMCustomEvent(const WebString& type)
-    : WebDOMEvent(CustomEvent::create())
-{
-    unwrap<CustomEvent>()->initCustomEvent(type, false, false, nullptr);
-}
-
-} // namespace blink
diff --git a/third_party/WebKit/Source/web/WebDataSourceImpl.cpp b/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
index 4b7bbd80..45a6748 100644
--- a/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
+++ b/third_party/WebKit/Source/web/WebDataSourceImpl.cpp
@@ -38,9 +38,9 @@
 
 namespace blink {
 
-static OwnPtr<WebPluginLoadObserver>& nextPluginLoadObserver()
+static OwnPtrWillBePersistent<WebPluginLoadObserver>& nextPluginLoadObserver()
 {
-    DEFINE_STATIC_LOCAL(OwnPtr<WebPluginLoadObserver>, nextPluginLoadObserver, ());
+    DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<WebPluginLoadObserver>, nextPluginLoadObserver, ());
     return nextPluginLoadObserver;
 }
 
@@ -137,7 +137,7 @@
     }
 }
 
-void WebDataSourceImpl::setNextPluginLoadObserver(PassOwnPtr<WebPluginLoadObserver> observer)
+void WebDataSourceImpl::setNextPluginLoadObserver(PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> observer)
 {
     nextPluginLoadObserver() = observer;
 }
@@ -175,6 +175,7 @@
 
 DEFINE_TRACE(WebDataSourceImpl)
 {
+    visitor->trace(m_pluginLoadObserver);
     DocumentLoader::trace(visitor);
 }
 
diff --git a/third_party/WebKit/Source/web/WebDataSourceImpl.h b/third_party/WebKit/Source/web/WebDataSourceImpl.h
index 1c960aad..77e8580 100644
--- a/third_party/WebKit/Source/web/WebDataSourceImpl.h
+++ b/third_party/WebKit/Source/web/WebDataSourceImpl.h
@@ -44,8 +44,6 @@
 
 namespace blink {
 
-class WebPluginLoadObserver;
-
 class WebDataSourceImpl final : public DocumentLoader, public WebDataSource {
 public:
     static PassRefPtrWillBeRawPtr<WebDataSourceImpl> create(LocalFrame*, const ResourceRequest&, const SubstituteData&);
@@ -72,8 +70,8 @@
 
     static WebNavigationType toWebNavigationType(NavigationType);
 
-    PassOwnPtr<WebPluginLoadObserver> releasePluginLoadObserver() { return m_pluginLoadObserver.release(); }
-    static void setNextPluginLoadObserver(PassOwnPtr<WebPluginLoadObserver>);
+    PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> releasePluginLoadObserver() { return m_pluginLoadObserver.release(); }
+    static void setNextPluginLoadObserver(PassOwnPtrWillBeRawPtr<WebPluginLoadObserver>);
 
     DECLARE_VIRTUAL_TRACE();
 
@@ -90,7 +88,7 @@
     mutable WrappedResourceResponse m_responseWrapper;
 
     OwnPtr<ExtraData> m_extraData;
-    OwnPtr<WebPluginLoadObserver> m_pluginLoadObserver;
+    OwnPtrWillBeMember<WebPluginLoadObserver> m_pluginLoadObserver;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
index a710e85d..94cae36 100644
--- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
+++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.cpp
@@ -412,11 +412,10 @@
     page()->focusController().setFocused(enable);
     if (enable) {
         page()->focusController().setActive(true);
-        RefPtrWillBeRawPtr<Frame> focusedFrame = page()->focusController().focusedFrame();
-        if (focusedFrame && focusedFrame->isLocalFrame()) {
-            LocalFrame* localFrame = toLocalFrame(focusedFrame.get());
-            Element* element = localFrame->document()->focusedElement();
-            if (element && localFrame->selection().selection().isNone()) {
+        RefPtrWillBeRawPtr<LocalFrame> focusedFrame = page()->focusController().focusedFrame();
+        if (focusedFrame) {
+            Element* element = focusedFrame->document()->focusedElement();
+            if (element && focusedFrame->selection().selection().isNone()) {
                 // If the selection was cleared while the WebView was not
                 // focused, then the focus element shows with a focus ring but
                 // no caret and does respond to keyboard inputs.
@@ -428,7 +427,7 @@
                     // instead. Note that this has the side effect of moving the
                     // caret back to the beginning of the text.
                     Position position(element, 0);
-                    localFrame->selection().setSelection(VisibleSelection(position, SEL_DEFAULT_AFFINITY));
+                    focusedFrame->selection().setSelection(VisibleSelection(position, SEL_DEFAULT_AFFINITY));
                 }
             }
         }
@@ -957,11 +956,11 @@
 
 Element* WebFrameWidgetImpl::focusedElement() const
 {
-    Frame* frame = page()->focusController().focusedFrame();
-    if (!frame || !frame->isLocalFrame())
+    LocalFrame* frame = page()->focusController().focusedFrame();
+    if (!frame)
         return nullptr;
 
-    Document* document = toLocalFrame(frame)->document();
+    Document* document = frame->document();
     if (!document)
         return nullptr;
 
diff --git a/third_party/WebKit/Source/web/WebFrameWidgetImpl.h b/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
index 8f51c66..cf573f27 100644
--- a/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
+++ b/third_party/WebKit/Source/web/WebFrameWidgetImpl.h
@@ -88,7 +88,7 @@
     bool hasTouchEventHandlersAt(const WebPoint&) override;
 
     void applyViewportDeltas(
-        const WebFloatSize& pinchViewportDelta,
+        const WebFloatSize& visualViewportDelta,
         const WebFloatSize& mainFrameDelta,
         const WebFloatSize& elasticOverscrollDelta,
         float pageScaleDelta,
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
index 72629f3..60ab35cf 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -497,9 +497,10 @@
         // FIXME: This is a bit of hack to allow us to observe completion of
         // our frame request.  It would be better to evolve FrameLoader to
         // support a completion callback instead.
-        OwnPtr<WebPluginLoadObserver> observer = adoptPtr(new WebPluginLoadObserver(this, request.url(), notifyData));
-        // FIXME: Calling get here is dangerous! What if observer is freed?
+        OwnPtrWillBeRawPtr<WebPluginLoadObserver> observer = WebPluginLoadObserver::create(this, request.url(), notifyData);
+#if !ENABLE(OILPAN)
         m_pluginLoadObservers.append(observer.get());
+#endif
         WebDataSourceImpl::setNextPluginLoadObserver(observer.release());
     }
 
@@ -679,6 +680,7 @@
     return m_wantsWheelEvents;
 }
 
+#if !ENABLE(OILPAN)
 void WebPluginContainerImpl::willDestroyPluginLoadObserver(WebPluginLoadObserver* observer)
 {
     size_t pos = m_pluginLoadObservers.find(observer);
@@ -686,6 +688,7 @@
         return;
     m_pluginLoadObservers.remove(pos);
 }
+#endif
 
 // Private methods -------------------------------------------------------------
 
@@ -722,21 +725,25 @@
     if (m_element && m_touchEventRequestType != TouchEventRequestTypeNone && m_element->document().frameHost())
         m_element->document().frameHost()->eventHandlerRegistry().didRemoveEventHandler(*m_element, EventHandlerRegistry::TouchEvent);
 
-    for (size_t i = 0; i < m_pluginLoadObservers.size(); ++i)
-        m_pluginLoadObservers[i]->clearPluginContainer();
+#if !ENABLE(OILPAN)
+    for (const auto& observer : m_pluginLoadObservers)
+        observer->clearPluginContainer();
+#endif
 
     if (m_webPlugin) {
         RELEASE_ASSERT(!m_webPlugin->container() || m_webPlugin->container() == this);
         m_webPlugin->destroy();
+        m_webPlugin = nullptr;
     }
-    m_webPlugin = nullptr;
 
     if (m_webLayer) {
         GraphicsLayer::unregisterContentsLayer(m_webLayer);
         m_webLayer = nullptr;
     }
 
+#if !ENABLE(OILPAN)
     m_pluginLoadObservers.clear();
+#endif
     m_element = nullptr;
 }
 
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.h b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
index eaff5bd..dad54db 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.h
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
@@ -114,7 +114,8 @@
     WebPoint rootFrameToLocalPoint(const WebPoint&) override;
     WebPoint localToRootFramePoint(const WebPoint&) override;
 
-    // This cannot be null.
+    // Non-Oilpan, this cannot be null. With Oilpan, it will be
+    // null when in a disposed state, pending finalization during the next GC.
     WebPlugin* plugin() override { return m_webPlugin; }
     void setPlugin(WebPlugin*) override;
 
@@ -154,7 +155,9 @@
     void didFinishLoading() override;
     void didFailLoading(const ResourceError&) override;
 
+#if !ENABLE(OILPAN)
     void willDestroyPluginLoadObserver(WebPluginLoadObserver*);
+#endif
 
     DECLARE_VIRTUAL_TRACE();
     void dispose() override;
@@ -198,7 +201,9 @@
 
     RawPtrWillBeMember<HTMLPlugInElement> m_element;
     WebPlugin* m_webPlugin;
+#if !ENABLE(OILPAN)
     Vector<WebPluginLoadObserver*> m_pluginLoadObservers;
+#endif
 
     WebLayer* m_webLayer;
 
diff --git a/third_party/WebKit/Source/web/WebPluginLoadObserver.cpp b/third_party/WebKit/Source/web/WebPluginLoadObserver.cpp
index 8e1adfc..911a7519 100644
--- a/third_party/WebKit/Source/web/WebPluginLoadObserver.cpp
+++ b/third_party/WebKit/Source/web/WebPluginLoadObserver.cpp
@@ -38,20 +38,31 @@
 
 WebPluginLoadObserver::~WebPluginLoadObserver()
 {
+#if !ENABLE(OILPAN)
     if (m_pluginContainer)
         m_pluginContainer->willDestroyPluginLoadObserver(this);
+#endif
+}
+
+DEFINE_TRACE(WebPluginLoadObserver)
+{
+    visitor->trace(m_pluginContainer);
 }
 
 void WebPluginLoadObserver::didFinishLoading()
 {
-    if (m_pluginContainer)
-        m_pluginContainer->plugin()->didFinishLoadingFrameRequest(m_notifyURL, m_notifyData);
+    if (!m_pluginContainer)
+        return;
+    if (WebPlugin* plugin = m_pluginContainer->plugin())
+        plugin->didFinishLoadingFrameRequest(m_notifyURL, m_notifyData);
 }
 
 void WebPluginLoadObserver::didFailLoading(const WebURLError& error)
 {
-    if (m_pluginContainer)
-        m_pluginContainer->plugin()->didFailLoadingFrameRequest(m_notifyURL, m_notifyData, error);
+    if (!m_pluginContainer)
+        return;
+    if (WebPlugin* plugin = m_pluginContainer->plugin())
+        plugin->didFailLoadingFrameRequest(m_notifyURL, m_notifyData, error);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/WebPluginLoadObserver.h b/third_party/WebKit/Source/web/WebPluginLoadObserver.h
index 3e191686..25ecd7a1 100644
--- a/third_party/WebKit/Source/web/WebPluginLoadObserver.h
+++ b/third_party/WebKit/Source/web/WebPluginLoadObserver.h
@@ -31,6 +31,7 @@
 #ifndef WebPluginLoadObserver_h
 #define WebPluginLoadObserver_h
 
+#include "platform/heap/Handle.h"
 #include "public/platform/WebURL.h"
 
 namespace blink {
@@ -38,26 +39,33 @@
 class WebPluginContainerImpl;
 struct WebURLError;
 
-class WebPluginLoadObserver {
+class WebPluginLoadObserver final : public NoBaseWillBeGarbageCollectedFinalized<WebPluginLoadObserver> {
 public:
-    WebPluginLoadObserver(WebPluginContainerImpl* pluginContainer,
-                          const WebURL& notifyURL, void* notifyData)
+    static PassOwnPtrWillBeRawPtr<WebPluginLoadObserver> create(WebPluginContainerImpl* pluginContainer, const WebURL& notifyURL, void* notifyData)
+    {
+        return adoptPtrWillBeNoop(new WebPluginLoadObserver(pluginContainer, notifyURL, notifyData));
+    }
+    ~WebPluginLoadObserver();
+
+    const WebURL& url() const { return m_notifyURL; }
+
+#if !ENABLE(OILPAN)
+    void clearPluginContainer() { m_pluginContainer = nullptr; }
+#endif
+    void didFinishLoading();
+    void didFailLoading(const WebURLError&);
+
+    DECLARE_TRACE();
+
+private:
+    WebPluginLoadObserver(WebPluginContainerImpl* pluginContainer, const WebURL& notifyURL, void* notifyData)
         : m_pluginContainer(pluginContainer)
         , m_notifyURL(notifyURL)
         , m_notifyData(notifyData)
     {
     }
 
-    ~WebPluginLoadObserver();
-
-    const WebURL& url() const { return m_notifyURL; }
-
-    void clearPluginContainer() { m_pluginContainer = 0; }
-    void didFinishLoading();
-    void didFailLoading(const WebURLError&);
-
-private:
-    WebPluginContainerImpl* m_pluginContainer;
+    RawPtrWillBeWeakMember<WebPluginContainerImpl> m_pluginContainer;
     WebURL m_notifyURL;
     void* m_notifyData;
 };
diff --git a/third_party/WebKit/Source/web/WebViewFrameWidget.cpp b/third_party/WebKit/Source/web/WebViewFrameWidget.cpp
index f476913..c6ff2070 100644
--- a/third_party/WebKit/Source/web/WebViewFrameWidget.cpp
+++ b/third_party/WebKit/Source/web/WebViewFrameWidget.cpp
@@ -123,13 +123,13 @@
 }
 
 void WebViewFrameWidget::applyViewportDeltas(
-    const WebFloatSize& pinchViewportDelta,
+    const WebFloatSize& visualViewportDelta,
     const WebFloatSize& layoutViewportDelta,
     const WebFloatSize& elasticOverscrollDelta,
     float scaleFactor,
     float topControlsShownRatioDelta)
 {
-    return m_webView->applyViewportDeltas(pinchViewportDelta, layoutViewportDelta, elasticOverscrollDelta, scaleFactor, topControlsShownRatioDelta);
+    return m_webView->applyViewportDeltas(visualViewportDelta, layoutViewportDelta, elasticOverscrollDelta, scaleFactor, topControlsShownRatioDelta);
 }
 
 void WebViewFrameWidget::recordFrameTimingEvent(FrameTimingEventType eventType, int64_t rectId, const WebVector<WebFrameTimingEvent>& events)
diff --git a/third_party/WebKit/Source/web/WebViewFrameWidget.h b/third_party/WebKit/Source/web/WebViewFrameWidget.h
index e6e8677..677787d 100644
--- a/third_party/WebKit/Source/web/WebViewFrameWidget.h
+++ b/third_party/WebKit/Source/web/WebViewFrameWidget.h
@@ -57,7 +57,7 @@
     void setCursorVisibilityState(bool isVisible) override;
     bool hasTouchEventHandlersAt(const WebPoint&) override;
     void applyViewportDeltas(
-        const WebFloatSize& pinchViewportDelta,
+        const WebFloatSize& visualViewportDelta,
         const WebFloatSize& layoutViewportDelta,
         const WebFloatSize& elasticOverscrollDelta,
         float scaleFactor,
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp
index bc4fb6b..a66ca85 100644
--- a/third_party/WebKit/Source/web/WebViewImpl.cpp
+++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -2184,11 +2184,10 @@
     m_page->focusController().setFocused(enable);
     if (enable) {
         m_page->focusController().setActive(true);
-        RefPtrWillBeRawPtr<Frame> focusedFrame = m_page->focusController().focusedFrame();
-        if (focusedFrame && focusedFrame->isLocalFrame()) {
-            LocalFrame* localFrame = toLocalFrame(focusedFrame.get());
-            Element* element = localFrame->document()->focusedElement();
-            if (element && localFrame->selection().selection().isNone()) {
+        RefPtrWillBeRawPtr<LocalFrame> focusedFrame = m_page->focusController().focusedFrame();
+        if (focusedFrame) {
+            Element* element = focusedFrame->document()->focusedElement();
+            if (element && focusedFrame->selection().selection().isNone()) {
                 // If the selection was cleared while the WebView was not
                 // focused, then the focus element shows with a focus ring but
                 // no caret and does respond to keyboard inputs.
@@ -2200,7 +2199,7 @@
                     // instead. Note that this has the side effect of moving the
                     // caret back to the beginning of the text.
                     Position position(element, 0);
-                    localFrame->selection().setSelection(VisibleSelection(position, SEL_DEFAULT_AFFINITY));
+                    focusedFrame->selection().setSelection(VisibleSelection(position, SEL_DEFAULT_AFFINITY));
                 }
             }
         }
@@ -2217,16 +2216,16 @@
         if (!frame)
             return;
 
-        RefPtrWillBeRawPtr<Frame> focusedFrame = m_page->focusController().focusedFrame();
-        if (focusedFrame && focusedFrame->isLocalFrame()) {
+        RefPtrWillBeRawPtr<LocalFrame> focusedFrame = m_page->focusController().focusedFrame();
+        if (focusedFrame) {
             // Finish an ongoing composition to delete the composition node.
-            if (toLocalFrame(focusedFrame.get())->inputMethodController().hasComposition()) {
-                WebAutofillClient* autofillClient = WebLocalFrameImpl::fromFrame(toLocalFrame(focusedFrame.get()))->autofillClient();
+            if (focusedFrame->inputMethodController().hasComposition()) {
+                WebAutofillClient* autofillClient = WebLocalFrameImpl::fromFrame(focusedFrame.get())->autofillClient();
 
                 if (autofillClient)
                     autofillClient->setIgnoreTextChanges(true);
 
-                toLocalFrame(focusedFrame.get())->inputMethodController().confirmComposition();
+                focusedFrame->inputMethodController().confirmComposition();
 
                 if (autofillClient)
                     autofillClient->setIgnoreTextChanges(false);
@@ -2398,17 +2397,16 @@
 
 WebTextInputType WebViewImpl::textInputType()
 {
-    Frame* focusedFrame = m_page->focusController().focusedFrame();
-    if (!focusedFrame || !focusedFrame->isLocalFrame())
+    LocalFrame* focusedFrame = m_page->focusController().focusedFrame();
+    if (!focusedFrame)
         return WebTextInputTypeNone;
 
     // It's important to preserve the equivalence of textInputInfo().type and textInputType(),
     // so perform the same rootEditableElement() existence check here for consistency.
-    LocalFrame* focused = toLocalFrame(focusedFrame);
-    if (!focused || !focused->selection().selection().rootEditableElement())
+    if (!focusedFrame || !focusedFrame->selection().selection().rootEditableElement())
         return WebTextInputTypeNone;
 
-    Document* document = focused->document();
+    Document* document = focusedFrame->document();
     if (!document)
         return WebTextInputTypeNone;
 
@@ -4072,11 +4070,11 @@
 
 Element* WebViewImpl::focusedElement() const
 {
-    Frame* frame = m_page->focusController().focusedFrame();
-    if (!frame || !frame->isLocalFrame())
+    LocalFrame* frame = m_page->focusController().focusedFrame();
+    if (!frame)
         return nullptr;
 
-    Document* document = toLocalFrame(frame)->document();
+    Document* document = frame->document();
     if (!document)
         return nullptr;
 
diff --git a/third_party/WebKit/Source/web/default/WebRenderTheme.cpp b/third_party/WebKit/Source/web/default/WebRenderTheme.cpp
index f92aa0b..a3571d4 100644
--- a/third_party/WebKit/Source/web/default/WebRenderTheme.cpp
+++ b/third_party/WebKit/Source/web/default/WebRenderTheme.cpp
@@ -31,14 +31,23 @@
 #include "config.h"
 #include "public/web/default/WebRenderTheme.h"
 
+#include "core/layout/LayoutTheme.h"
 #include "core/layout/LayoutThemeDefault.h"
-#include "public/web/WebView.h"
+#include "platform/graphics/Color.h"
+#include "public/platform/WebColor.h"
 
 namespace blink {
 
+// TODO(esprehn): Make sense of LayoutThemeDefault and LayoutTheme::theme().
+
 void setCaretBlinkInterval(double interval)
 {
     LayoutThemeDefault::setCaretBlinkInterval(interval);
 }
 
+void setFocusRingColor(WebColor color)
+{
+    LayoutTheme::theme().setCustomFocusRingColor(color);
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp b/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
index 6dbafb4..d3d34f2f 100644
--- a/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
+++ b/third_party/WebKit/Source/web/tests/ChromeClientImplTest.cpp
@@ -119,7 +119,7 @@
     WebViewImpl* m_webView;
     WebFrame* m_mainFrame;
     TestWebFrameClient m_webFrameClient;
-    ChromeClientImpl* m_chromeClientImpl;
+    RawPtrWillBePersistent<ChromeClientImpl> m_chromeClientImpl;
 };
 
 TEST_F(GetNavigationPolicyTest, LeftClick)
diff --git a/third_party/WebKit/Source/web/web.gypi b/third_party/WebKit/Source/web/web.gypi
index b9851e7..68dbb20 100644
--- a/third_party/WebKit/Source/web/web.gypi
+++ b/third_party/WebKit/Source/web/web.gypi
@@ -113,13 +113,11 @@
       'WebBindings.cpp',
       'WebBlob.cpp',
       'WebCache.cpp',
-      'WebColorName.cpp',
       'WebColorSuggestion.cpp',
       'WebCryptoNormalize.cpp',
       'WebCustomElement.cpp',
       'WebCSSParser.cpp',
       'WebDOMActivityLogger.cpp',
-      'WebDOMCustomEvent.cpp',
       'WebDOMEvent.cpp',
       'WebDOMFileSystem.cpp',
       'WebDOMMediaStreamTrack.cpp',
diff --git a/third_party/WebKit/Source/wtf/PartitionAlloc.cpp b/third_party/WebKit/Source/wtf/PartitionAlloc.cpp
index 322fe887..9528fb4 100644
--- a/third_party/WebKit/Source/wtf/PartitionAlloc.cpp
+++ b/third_party/WebKit/Source/wtf/PartitionAlloc.cpp
@@ -166,9 +166,9 @@
 
 void partitionAllocGenericInit(PartitionRootGeneric* root)
 {
-    partitionAllocBaseInit(root);
+    spinLockLock(&root->lock);
 
-    root->lock = 0;
+    partitionAllocBaseInit(root);
 
     // Precalculate some shift and mask constants used in the hot path.
     // Example: malloc(41) == 101001 binary.
@@ -243,6 +243,8 @@
     // And there's one last bucket lookup that will be hit for e.g. malloc(-1),
     // which tries to overflow to a non-existant order.
     *bucketPtr = &PartitionRootGeneric::gPagedBucket;
+
+    spinLockUnlock(&root->lock);
 }
 
 static bool partitionAllocShutdownBucket(PartitionBucket* bucket)
diff --git a/third_party/WebKit/Source/wtf/Partitions.cpp b/third_party/WebKit/Source/wtf/Partitions.cpp
index ced2e54..39914b4 100644
--- a/third_party/WebKit/Source/wtf/Partitions.cpp
+++ b/third_party/WebKit/Source/wtf/Partitions.cpp
@@ -67,18 +67,26 @@
 
 void Partitions::shutdown()
 {
+    spinLockLock(&s_initializationLock);
+
     // We could ASSERT here for a memory leak within the partition, but it leads
     // to very hard to diagnose ASSERTs, so it's best to leave leak checking for
     // the valgrind and heapcheck bots, which run without partitions.
-    (void) m_layoutAllocator.shutdown();
-    (void) m_nodeAllocator.shutdown();
-    (void) m_bufferAllocator.shutdown();
-    (void) m_fastMallocAllocator.shutdown();
+    if (s_initialized) {
+        (void) m_layoutAllocator.shutdown();
+        (void) m_nodeAllocator.shutdown();
+        (void) m_bufferAllocator.shutdown();
+        (void) m_fastMallocAllocator.shutdown();
+    }
+
+    spinLockUnlock(&s_initializationLock);
 }
 
 void Partitions::decommitFreeableMemory()
 {
-    ASSERT(isMainThread());
+    RELEASE_ASSERT(isMainThread());
+    if (!s_initialized)
+        return;
 
     partitionPurgeMemoryGeneric(bufferPartition(), PartitionPurgeDecommitEmptyPages);
     partitionPurgeMemoryGeneric(fastMallocPartition(), PartitionPurgeDecommitEmptyPages);
diff --git a/third_party/WebKit/public/blink_headers.gypi b/third_party/WebKit/public/blink_headers.gypi
index 45c5335..4f17989 100644
--- a/third_party/WebKit/public/blink_headers.gypi
+++ b/third_party/WebKit/public/blink_headers.gypi
@@ -27,7 +27,6 @@
       "platform/WebColor.h",
       "platform/WebCommon.h",
       "platform/WebCompositeAndReadbackAsyncCallback.h",
-      "platform/WebCompositedDisplayList.h",
       "platform/WebCompositorAnimation.h",
       "platform/WebCompositorAnimationCurve.h",
       "platform/WebCompositorAnimationDelegate.h",
@@ -63,9 +62,7 @@
       "platform/WebDatabaseObserver.h",
       "platform/WebDeviceLightListener.h",
       "platform/WebDiscardableMemory.h",
-      "platform/WebDisplayItemClipTree.h",
       "platform/WebDisplayItemList.h",
-      "platform/WebDisplayItemTransformTree.h",
       "platform/WebDisplayMode.h",
       "platform/WebDoublePoint.h",
       "platform/WebDragData.h",
@@ -99,7 +96,6 @@
       "platform/WebFloatRect.h",
       "platform/WebFloatSize.h",
       "platform/WebFocusType.h",
-      "platform/WebFrameHostScheduler.h",
       "platform/WebFrameScheduler.h",
       "platform/WebFrameTimingEvent.h",
       "platform/WebGamepad.h",
@@ -199,26 +195,6 @@
       "platform/WebScrollbarThemePainter.h",
       "platform/WebSecurityOrigin.h",
       "platform/WebSelectionBound.h",
-      "platform/WebServiceWorker.h",
-      "platform/WebServiceWorkerCache.h",
-      "platform/WebServiceWorkerCacheError.h",
-      "platform/WebServiceWorkerCacheStorage.h",
-      "platform/WebServiceWorkerClientQueryOptions.h",
-      "platform/WebServiceWorkerClientType.h",
-      "platform/WebServiceWorkerClientsClaimCallbacks.h",
-      "platform/WebServiceWorkerClientsInfo.h",
-      "platform/WebServiceWorkerError.h",
-      "platform/WebServiceWorkerEventResult.h",
-      "platform/WebServiceWorkerProvider.h",
-      "platform/WebServiceWorkerProviderClient.h",
-      "platform/WebServiceWorkerProxy.h",
-      "platform/WebServiceWorkerRegistration.h",
-      "platform/WebServiceWorkerRegistrationProxy.h",
-      "platform/WebServiceWorkerRequest.h",
-      "platform/WebServiceWorkerResponse.h",
-      "platform/WebServiceWorkerResponseType.h",
-      "platform/WebServiceWorkerSkipWaitingCallbacks.h",
-      "platform/WebServiceWorkerState.h",
       "platform/WebSetSinkIdCallbacks.h",
       "platform/WebSize.h",
       "platform/WebSocketHandle.h",
@@ -315,7 +291,6 @@
       "platform/modules/presentation/WebPresentationClient.h",
       "platform/modules/presentation/WebPresentationController.h",
       "platform/modules/presentation/WebPresentationError.h",
-      "platform/modules/presentation/WebPresentationSessionClient.h",
       "platform/modules/push_messaging/WebPushClient.h",
       "platform/modules/push_messaging/WebPushError.h",
       "platform/modules/push_messaging/WebPushPermissionStatus.h",
@@ -327,6 +302,26 @@
       "platform/modules/screen_orientation/WebScreenOrientationClient.h",
       "platform/modules/screen_orientation/WebScreenOrientationLockType.h",
       "platform/modules/screen_orientation/WebScreenOrientationType.h",
+      "platform/modules/serviceworker/WebServiceWorker.h",
+      "platform/modules/serviceworker/WebServiceWorkerCache.h",
+      "platform/modules/serviceworker/WebServiceWorkerCacheError.h",
+      "platform/modules/serviceworker/WebServiceWorkerCacheStorage.h",
+      "platform/modules/serviceworker/WebServiceWorkerClientQueryOptions.h",
+      "platform/modules/serviceworker/WebServiceWorkerClientType.h",
+      "platform/modules/serviceworker/WebServiceWorkerClientsClaimCallbacks.h",
+      "platform/modules/serviceworker/WebServiceWorkerClientsInfo.h",
+      "platform/modules/serviceworker/WebServiceWorkerError.h",
+      "platform/modules/serviceworker/WebServiceWorkerEventResult.h",
+      "platform/modules/serviceworker/WebServiceWorkerProvider.h",
+      "platform/modules/serviceworker/WebServiceWorkerProviderClient.h",
+      "platform/modules/serviceworker/WebServiceWorkerProxy.h",
+      "platform/modules/serviceworker/WebServiceWorkerRegistration.h",
+      "platform/modules/serviceworker/WebServiceWorkerRegistrationProxy.h",
+      "platform/modules/serviceworker/WebServiceWorkerRequest.h",
+      "platform/modules/serviceworker/WebServiceWorkerResponse.h",
+      "platform/modules/serviceworker/WebServiceWorkerResponseType.h",
+      "platform/modules/serviceworker/WebServiceWorkerSkipWaitingCallbacks.h",
+      "platform/modules/serviceworker/WebServiceWorkerState.h",
       "platform/modules/vr/WebVR.h",
       "platform/modules/vr/WebVRClient.h",
       "platform/modules/webusb/WebUSBClient.h",
@@ -349,7 +344,6 @@
       "web/WebCache.h",
       "web/WebColorChooser.h",
       "web/WebColorChooserClient.h",
-      "web/WebColorName.h",
       "web/WebColorSuggestion.h",
       "web/WebCompositionUnderline.h",
       "web/WebConsoleMessage.h",
@@ -360,7 +354,6 @@
       "web/WebCryptoNormalize.h",
       "web/WebCustomElement.h",
       "web/WebDOMActivityLogger.h",
-      "web/WebDOMCustomEvent.h",
       "web/WebDOMEvent.h",
       "web/WebDOMFileSystem.h",
       "web/WebDOMMediaStreamTrack.h",
@@ -472,9 +465,6 @@
       "web/WebSelector.h",
       "web/WebSerializedScriptValue.h",
       "web/WebSerializedScriptValueVersion.h",
-      "web/WebServiceWorkerContextClient.h",
-      "web/WebServiceWorkerContextProxy.h",
-      "web/WebServiceWorkerNetworkProvider.h",
       "web/WebSettings.h",
       "web/WebSharedWorker.h",
       "web/WebSharedWorkerClient.h",
@@ -522,6 +512,9 @@
       "web/mac/WebScrollbarTheme.h",
       "web/mac/WebSubstringUtil.h",
       "web/modules/notifications/WebNotificationPermissionCallback.h",
+      "web/modules/serviceworker/WebServiceWorkerContextClient.h",
+      "web/modules/serviceworker/WebServiceWorkerContextProxy.h",
+      "web/modules/serviceworker/WebServiceWorkerNetworkProvider.h",
       "web/win/WebFontRendering.h",
     ],
   },
diff --git a/third_party/WebKit/public/platform/WebGraphicsContext3D.h b/third_party/WebKit/public/platform/WebGraphicsContext3D.h
index b1362df1..5c4d0460 100644
--- a/third_party/WebKit/public/platform/WebGraphicsContext3D.h
+++ b/third_party/WebKit/public/platform/WebGraphicsContext3D.h
@@ -451,8 +451,6 @@
     // GL_EXT_draw_buffers
     virtual void drawBuffersEXT(WGC3Dsizei n, const WGC3Denum* bufs) { }
 
-    virtual GrGLInterface* createGrGLInterface() { return nullptr; }
-
     // GL_CHROMIUM_image
     virtual void destroyImageCHROMIUM(WGC3Duint imageId) { }
 
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h
index 1435071..8d74751f 100644
--- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h
+++ b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h
@@ -10,7 +10,6 @@
 #include "public/platform/WebString.h"
 #include "public/platform/WebVector.h"
 #include "public/platform/modules/bluetooth/WebBluetoothError.h"
-#include <vector>
 
 namespace blink {
 
@@ -78,8 +77,8 @@
     virtual void readValue(const WebString& characteristicInstanceID,
         WebBluetoothReadValueCallbacks*) { }
     virtual void writeValue(const WebString& characteristicInstanceID,
-        const std::vector<uint8_t>& value,
-        WebBluetoothWriteValueCallbacks*) { }
+        const WebVector<uint8_t>& value,
+        WebBluetoothWriteValueCallbacks*) {}
     virtual void startNotifications(const WebString& characteristicInstanceID,
         WebBluetoothGATTCharacteristic*,
         WebBluetoothNotificationsCallbacks*) {}
diff --git a/third_party/WebKit/public/platform/modules/presentation/WebPresentationClient.h b/third_party/WebKit/public/platform/modules/presentation/WebPresentationClient.h
index 43744ac..4edf577 100644
--- a/third_party/WebKit/public/platform/modules/presentation/WebPresentationClient.h
+++ b/third_party/WebKit/public/platform/modules/presentation/WebPresentationClient.h
@@ -52,8 +52,8 @@
     // Embedder copies the |data| and the ownership is not transferred.
     virtual void sendBlobData(const WebString& presentationUrl, const WebString& presentationId, const uint8_t* data, size_t length) = 0;
 
-    // Called when the frame requests to close an existing session.
-    virtual void closeSession(const WebString& presentationUrl, const WebString& presentationId) = 0;
+    // Called when the frame requests to terminate an existing session.
+    virtual void terminateSession(const WebString& presentationUrl, const WebString& presentationId) = 0;
 
     // Called when the frame wants to know the availability of a presentation
     // display for |availabilityUrl|.  The ownership of the callbacks argument
diff --git a/third_party/WebKit/public/web/WebColorName.h b/third_party/WebKit/public/web/WebColorName.h
deleted file mode 100644
index 53ef76ab..0000000
--- a/third_party/WebKit/public/web/WebColorName.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
-* Copyright (C) 2009 Google Inc. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions are
-* met:
-*
-*     * Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-*     * Redistributions in binary form must reproduce the above
-* copyright notice, this list of conditions and the following disclaimer
-* in the documentation and/or other materials provided with the
-* distribution.
-*     * Neither the name of Google Inc. nor the names of its
-* contributors may be used to endorse or promote products derived from
-* this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef WebColorName_h
-#define WebColorName_h
-
-#include "../platform/WebColor.h"
-#include "../platform/WebCommon.h"
-
-namespace blink {
-
-enum WebColorName {
-    WebColorActiveBorder,
-    WebColorActiveCaption,
-    WebColorAppworkspace,
-    WebColorBackground,
-    WebColorButtonFace,
-    WebColorButtonHighlight,
-    WebColorButtonShadow,
-    WebColorButtonText,
-    WebColorCaptionText,
-    WebColorGrayText,
-    WebColorHighlight,
-    WebColorHighlightText,
-    WebColorInactiveBorder,
-    WebColorInactiveCaption,
-    WebColorInactiveCaptionText,
-    WebColorInfoBackground,
-    WebColorInfoText,
-    WebColorMenu,
-    WebColorMenuText,
-    WebColorScrollbar,
-    WebColorText,
-    WebColorThreedDarkShadow,
-    WebColorThreedShadow,
-    WebColorThreedFace,
-    WebColorThreedHighlight,
-    WebColorThreedLightShadow,
-    WebColorWebkitFocusRingColor,
-    WebColorWindow,
-    WebColorWindowFrame,
-    WebColorWindowText
-};
-
-// Sets the values of a set of named colors.
-BLINK_EXPORT void setNamedColors(const WebColorName*, const WebColor*, size_t length);
-
-} // namespace blink
-
-#endif
diff --git a/third_party/WebKit/public/web/WebDOMCustomEvent.h b/third_party/WebKit/public/web/WebDOMCustomEvent.h
deleted file mode 100644
index 7d0c486f7..0000000
--- a/third_party/WebKit/public/web/WebDOMCustomEvent.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#ifndef WebDOMCustomEvent_h
-#define WebDOMCustomEvent_h
-
-#include "WebDOMEvent.h"
-
-namespace blink {
-
-class WebString;
-
-// TODO(esprehn): Remove this and IPCEcho which appears to just be dead code.
-class WebDOMCustomEvent : public WebDOMEvent {
-public:
-    BLINK_EXPORT WebDOMCustomEvent(const WebString& type);
-    WebDOMCustomEvent() { }
-};
-
-} // namespace blink
-
-#endif
diff --git a/third_party/WebKit/public/web/WebViewClient.h b/third_party/WebKit/public/web/WebViewClient.h
index fc9d41b1..4ece8d1 100644
--- a/third_party/WebKit/public/web/WebViewClient.h
+++ b/third_party/WebKit/public/web/WebViewClient.h
@@ -199,7 +199,7 @@
     virtual void didUpdateLayout() { }
 
     // Return true to swallow the input event if the embedder will start a disambiguation popup
-    virtual bool didTapMultipleTargets(const WebSize& pinchViewportOffset, const WebRect& touchRect, const WebVector<WebRect>& targetRects) { return false; }
+    virtual bool didTapMultipleTargets(const WebSize& visualViewportOffset, const WebRect& touchRect, const WebVector<WebRect>& targetRects) { return false; }
 
     // Returns comma separated list of accept languages.
     virtual WebString acceptLanguages() { return WebString(); }
diff --git a/third_party/WebKit/public/web/default/WebRenderTheme.h b/third_party/WebKit/public/web/default/WebRenderTheme.h
index 7fc653c9..885089f7 100644
--- a/third_party/WebKit/public/web/default/WebRenderTheme.h
+++ b/third_party/WebKit/public/web/default/WebRenderTheme.h
@@ -31,6 +31,7 @@
 #ifndef WebRenderTheme_h
 #define WebRenderTheme_h
 
+#include "../../platform/WebColor.h"
 #include "../../platform/WebCommon.h"
 
 namespace blink {
@@ -38,6 +39,8 @@
 // Set caret blink interval for text input areas.
 BLINK_EXPORT void setCaretBlinkInterval(double);
 
+BLINK_EXPORT void setFocusRingColor(WebColor);
+
 } // namespace blink
 
 #endif
diff --git a/third_party/libaddressinput/BUILD.gn b/third_party/libaddressinput/BUILD.gn
index 0191886..36fed6f 100644
--- a/third_party/libaddressinput/BUILD.gn
+++ b/third_party/libaddressinput/BUILD.gn
@@ -92,6 +92,18 @@
     "address_input_strings_zh-TW.pak",
   ]
 
+  if (is_ios) {
+    # iOS uses "pt" for pt-BR" and "es-MX" for "es-419".
+    outputs -= [
+      "address_input_strings_pt-BR.pak",
+      "address_input_strings_es-419.pak",
+    ]
+    outputs += [
+      "address_input_strings_pt.pak",
+      "address_input_strings_es-MX.pak",
+    ]
+  }
+
   configs = [ ":no-newline-eof-warning" ]
 }
 
diff --git a/third_party/mojo/src/mojo/edk/embedder/BUILD.gn b/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
index f54d9cb4..94d561f 100644
--- a/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/embedder/BUILD.gn
@@ -2,9 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../mojo_edk.gni")
-
-mojo_edk_source_set("headers") {
+source_set("headers") {
   sources = [
     "channel_info_forward.h",
     "configuration.h",
@@ -13,10 +11,13 @@
   ]
 }
 
-mojo_edk_source_set("embedder") {
+source_set("embedder") {
   # This isn't really a standalone target; it must be linked into the
   # mojo_system_impl component.
-  mojo_edk_visibility = [ "mojo/edk/system" ]
+  visibility = [
+    "//components/nacl",
+    "//third_party/mojo/src/mojo/edk/system",
+  ]
 
   sources = [
     "embedder.cc",
@@ -35,27 +36,27 @@
     "MOJO_SYSTEM_IMPLEMENTATION",
   ]
 
-  mojo_edk_configs = [ "mojo/edk/system:system_config" ]
+  configs += [ "//third_party/mojo/src/mojo/edk/system:system_config" ]
 
   public_deps = [
     ":delegates",
     ":headers",
     ":platform",
+    "//mojo/public/cpp/system",
   ]
 
-  mojo_sdk_public_deps = [ "mojo/public/cpp/system" ]
-
   deps = [
     "//base",
   ]
 }
 
-mojo_edk_source_set("platform") {
+source_set("platform") {
   # This isn't really a standalone target; it must be linked into the
   # mojo_system_impl component.
-  visibility = [ ":embedder" ]
-
-  mojo_edk_visibility = [ "mojo/edk/system" ]
+  visibility = [
+    ":embedder",
+    "//third_party/mojo/src/mojo/edk/system",
+  ]
 
   sources = [
     "platform_channel_pair.cc",
@@ -84,9 +85,11 @@
 
   defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
 
-  mojo_edk_configs = [ "mojo/edk/system:system_config" ]
+  configs += [ "//third_party/mojo/src/mojo/edk/system:system_config" ]
 
-  mojo_sdk_public_deps = [ "mojo/public/cpp/system" ]
+  public_deps = [
+    "//mojo/public/cpp/system",
+  ]
 
   deps = [
     "//base",
@@ -97,12 +100,13 @@
   }
 }
 
-mojo_edk_source_set("delegates") {
+source_set("delegates") {
   # This isn't really a standalone target; it must be linked into the
   # mojo_system_impl component.
-  visibility = [ ":embedder" ]
-
-  mojo_edk_visibility = [ "mojo/edk/system" ]
+  visibility = [
+    ":embedder",
+    "//third_party/mojo/src/mojo/edk/system",
+  ]
 
   sources = [
     "master_process_delegate.h",
@@ -114,14 +118,15 @@
 
   defines = [ "MOJO_SYSTEM_IMPL_IMPLEMENTATION" ]
 
-  mojo_edk_configs = [ "mojo/edk/system:system_config" ]
+  configs += [ "//third_party/mojo/src/mojo/edk/system:system_config" ]
 
-  mojo_sdk_public_deps = [ "mojo/public/cpp/system" ]
+  public_deps = [
+    "//mojo/public/cpp/system",
+  ]
 }
 
-mojo_edk_source_set("embedder_unittests") {
+source_set("embedder_unittests") {
   testonly = true
-  mojo_edk_visibility = [ "mojo/edk/system:mojo_system_unittests" ]
 
   sources = [
     "embedder_unittest.cc",
@@ -133,11 +138,8 @@
     "//base",
     "//base/test:test_support",
     "//testing/gtest",
-  ]
-
-  mojo_edk_deps = [
-    "mojo/edk/test:test_support",
-    "mojo/edk/system",
-    "mojo/edk/system:test_utils",
+    "//third_party/mojo/src/mojo/edk/test:test_support",
+    "//third_party/mojo/src/mojo/edk/system",
+    "//third_party/mojo/src/mojo/edk/system:test_utils",
   ]
 }
diff --git a/third_party/mojo/src/mojo/edk/js/BUILD.gn b/third_party/mojo/src/mojo/edk/js/BUILD.gn
index ed1b81f..057c4e83 100644
--- a/third_party/mojo/src/mojo/edk/js/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/js/BUILD.gn
@@ -2,8 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../mojo_edk.gni")
-
 # TODO(hansmuller): The organization of tests in this directory is weird:
 #   * Really, js_unittests tests public stuff, so that should live in public
 #     and be reworked as some sort of apptest.
@@ -18,7 +16,7 @@
   ]
 }
 
-mojo_edk_source_set("js") {
+source_set("js") {
   sources = [
     "core.cc",
     "core.h",
@@ -43,26 +41,22 @@
     "//v8",
   ]
 
-  mojo_sdk_deps = [
-    "mojo/public/cpp/environment",
-    "mojo/public/cpp/system",
+  deps = [
+    "//mojo/public/cpp/environment",
+    "//mojo/public/cpp/system",
   ]
 }
 
-mojo_edk_source_set("js_unittests") {
+source_set("js_unittests") {
   testonly = true
   sources = [
     "handle_unittest.cc",
   ]
 
   deps = [
+    "//mojo/public/cpp/system",
     "//testing/gtest",
+    "//third_party/mojo/src/mojo/edk/js",
+    "//third_party/mojo/src/mojo/edk/test:test_support",
   ]
-
-  mojo_edk_deps = [
-    "mojo/edk/js",
-    "mojo/edk/test:test_support",
-  ]
-
-  mojo_sdk_deps = [ "mojo/public/cpp/system" ]
 }
diff --git a/third_party/mojo/src/mojo/edk/js/tests/BUILD.gn b/third_party/mojo/src/mojo/edk/js/tests/BUILD.gn
index d372a68..883cf4e 100644
--- a/third_party/mojo/src/mojo/edk/js/tests/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/js/tests/BUILD.gn
@@ -2,27 +2,20 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../../mojo_edk.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
 
-mojo_edk_source_set("js_to_cpp_tests") {
+source_set("js_to_cpp_tests") {
   testonly = true
 
   deps = [
     ":js_to_cpp_bindings",
     "//gin:gin_test",
-  ]
-
-  mojo_edk_deps = [
-    "mojo/edk/js",
-    "mojo/edk/test:test_support",
-  ]
-
-  mojo_sdk_deps = [
-    "mojo/public/cpp/bindings",
-    "mojo/public/cpp/system",
-    "mojo/public/interfaces/bindings/tests:test_interfaces",
-    "mojo/public/interfaces/bindings/tests:test_interfaces_experimental",
+    "//mojo/public/cpp/bindings",
+    "//mojo/public/cpp/system",
+    "//mojo/public/interfaces/bindings/tests:test_interfaces",
+    "//mojo/public/interfaces/bindings/tests:test_interfaces_experimental",
+    "//third_party/mojo/src/mojo/edk/js",
+    "//third_party/mojo/src/mojo/edk/test:test_support",
   ]
 
   sources = [
diff --git a/third_party/mojo/src/mojo/edk/mojo_edk.gni b/third_party/mojo/src/mojo/edk/mojo_edk.gni
deleted file mode 100644
index 19133a9..0000000
--- a/third_party/mojo/src/mojo/edk/mojo_edk.gni
+++ /dev/null
@@ -1,93 +0,0 @@
-# Copyright 2014 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.
-
-import("//mojo/public/mojo_sdk.gni")
-
-# A mojo_edk_source_set is a mojo_sdk_source_set that does not restrict
-# external dependencies and understands the following additional variables, all
-# of which admit a list of the relevant elements specified relative to the
-# location of the Mojo EDK:
-# mojo_edk_configs
-# mojo_edk_public_deps
-# mojo_edk_deps
-
-# Note that it is assumed that the Mojo EDK is a sibling of the Mojo SDK in a
-# client repo; the distinctions made above are for the sake of clarity in
-# writing targets.
-template("mojo_edk_source_set") {
-  mojo_sdk_source_set(target_name) {
-    if (defined(invoker.public_deps) || defined(invoker.deps)) {
-      restrict_external_deps = false
-    }
-
-    if (defined(invoker.visibility)) {
-      visibility = invoker.visibility
-    }
-    if (defined(invoker.mojo_edk_visibility)) {
-      mojo_edk_visibility = invoker.mojo_edk_visibility
-    }
-    if (defined(invoker.testonly)) {
-      testonly = invoker.testonly
-    }
-    if (defined(invoker.sources)) {
-      sources = invoker.sources
-    }
-    if (defined(invoker.defines)) {
-      defines = invoker.defines
-    }
-    if (defined(invoker.public_configs)) {
-      public_configs = invoker.public_configs
-    }
-
-    configs = []
-    if (defined(invoker.configs)) {
-      configs = invoker.configs
-    }
-    if (defined(invoker.mojo_edk_configs)) {
-      foreach(edk_config, invoker.mojo_edk_configs) {
-        # Check that the EDK config was not mistakenly given as an absolute
-        # path.
-        assert(get_path_info(edk_config, "abspath") != edk_config)
-        configs += [ rebase_path(edk_config, ".", "//third_party/mojo/src") ]
-      }
-    }
-
-    allow_circular_includes_from = []
-    if (defined(invoker.allow_circular_includes_from)) {
-      allow_circular_includes_from += invoker.allow_circular_includes_from
-    }
-
-    if (defined(invoker.public_deps)) {
-      public_deps = invoker.public_deps
-    }
-    mojo_edk_public_deps = []
-    if (defined(invoker.mojo_edk_public_deps)) {
-      mojo_edk_public_deps += invoker.mojo_edk_public_deps
-    }
-    mojo_sdk_public_deps = []
-    if (defined(invoker.mojo_sdk_public_deps)) {
-      mojo_sdk_public_deps += invoker.mojo_sdk_public_deps
-    }
-
-    if (defined(invoker.deps)) {
-      deps = invoker.deps
-    }
-    mojo_edk_deps = []
-    if (defined(invoker.mojo_edk_deps)) {
-      # The EDK is required to be a sibling of the SDK, so the relative
-      # dependencies are rewritten in the same way.
-      mojo_edk_deps += invoker.mojo_edk_deps
-    }
-    mojo_sdk_deps = []
-    if (defined(invoker.mojo_sdk_deps)) {
-      mojo_sdk_deps += invoker.mojo_sdk_deps
-    }
-  }
-}
-
-# Build EDK things with static thread annotation analysis enabled.
-# TODO(vtl): Should we set this at a higher level?
-if (is_clang) {
-  cflags = [ "-Wthread-safety" ]
-}
diff --git a/third_party/mojo/src/mojo/edk/system/BUILD.gn b/third_party/mojo/src/mojo/edk/system/BUILD.gn
index 961eec0..c782a785 100644
--- a/third_party/mojo/src/mojo/edk/system/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/system/BUILD.gn
@@ -2,7 +2,6 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../mojo_edk.gni")
 import("//testing/test.gni")
 
 if (is_android) {
@@ -151,7 +150,7 @@
   ]
 }
 
-mojo_edk_source_set("test_utils") {
+source_set("test_utils") {
   testonly = true
 
   sources = [
@@ -159,9 +158,9 @@
     "test_utils.h",
   ]
 
-  mojo_sdk_public_deps = [
-    "mojo/public/c/system",
-    "mojo/public/cpp/system",
+  public_deps = [
+    "//mojo/public/c/system",
+    "//mojo/public/cpp/system",
   ]
 
   deps = [
diff --git a/third_party/mojo/src/mojo/edk/test/BUILD.gn b/third_party/mojo/src/mojo/edk/test/BUILD.gn
index 73351a0..05e5904 100644
--- a/third_party/mojo/src/mojo/edk/test/BUILD.gn
+++ b/third_party/mojo/src/mojo/edk/test/BUILD.gn
@@ -2,10 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("../mojo_edk.gni")
 import("//testing/test.gni")
 
-mojo_edk_source_set("test_support") {
+source_set("test_support") {
   testonly = true
   sources = [
     "multiprocess_test_helper.cc",
@@ -21,14 +20,15 @@
     "//base",
     "//base/test:test_support",
     "//testing/gtest",
+    "//third_party/mojo/src/mojo/edk/system",
   ]
 
-  mojo_edk_deps = [ "mojo/edk/system" ]
-
-  mojo_sdk_public_deps = [ "mojo/public/cpp/system" ]
+  public_deps = [
+    "//mojo/public/cpp/system",
+  ]
 }
 
-mojo_edk_source_set("run_all_unittests") {
+source_set("run_all_unittests") {
   testonly = true
   sources = [
     "run_all_unittests.cc",
@@ -38,42 +38,36 @@
     ":test_support_impl",
     "//base",
     "//base/test:test_support",
+    "//mojo/public/c/test_support",
     "//testing/gtest",
+    "//third_party/mojo/src/mojo/edk/system",
   ]
-
-  mojo_edk_deps = [ "mojo/edk/system" ]
-
-  mojo_sdk_deps = [ "mojo/public/c/test_support" ]
 }
 
-mojo_edk_source_set("run_all_perftests") {
+source_set("run_all_perftests") {
   testonly = true
   deps = [
     ":test_support_impl",
     "//base",
     "//base/test:test_support",
+    "//mojo/public/c/test_support",
+    "//third_party/mojo/src/mojo/edk/system",
   ]
 
-  mojo_edk_deps = [ "mojo/edk/system" ]
-
-  mojo_sdk_deps = [ "mojo/public/c/test_support" ]
-
   sources = [
     "run_all_perftests.cc",
   ]
 }
 
-mojo_edk_source_set("test_support_impl") {
+source_set("test_support_impl") {
   testonly = true
   deps = [
     "//base",
     "//base/test:test_support",
+    "//mojo/public/c/test_support",
+    "//mojo/public/cpp/system",
   ]
 
-  mojo_sdk_deps = [ "mojo/public/c/test_support" ]
-
-  mojo_sdk_public_deps = [ "mojo/public/cpp/system" ]
-
   sources = [
     "test_support_impl.cc",
     "test_support_impl.h",
diff --git a/third_party/openh264/LICENSE b/third_party/openh264/LICENSE
deleted file mode 100644
index 8e730c4..0000000
--- a/third_party/openh264/LICENSE
+++ /dev/null
@@ -1,23 +0,0 @@
-Copyright (c) 2013, Cisco Systems
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright notice, this
-  list of conditions and the following disclaimer.
-
-* Redistributions in binary form must reproduce the above copyright notice, this
-  list of conditions and the following disclaimer in the documentation and/or
-  other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
-ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
-LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/third_party/openh264/OWNERS b/third_party/openh264/OWNERS
index 88f08e9a..7187271a 100644
--- a/third_party/openh264/OWNERS
+++ b/third_party/openh264/OWNERS
@@ -1 +1,2 @@
 hbos@chromium.org
+mflodman@chromium.org
diff --git a/third_party/openh264/README.chromium b/third_party/openh264/README.chromium
index 4e1893b8..d7e92f8 100644
--- a/third_party/openh264/README.chromium
+++ b/third_party/openh264/README.chromium
@@ -3,7 +3,7 @@
 URL: http://www.openh264.org/
 Version: v.1.4.0
 License: 2-Clause BSD
-License File: LICENSE
+License File: src/LICENSE
 Security Critical: yes
 
 Description:
@@ -15,6 +15,3 @@
 
 Local Modifications:
 N/A
-
-   Note: OpenH264 src has not yet been pulled in. A proper README.chromium file
-   was added anyway due to presubmit check.
diff --git a/third_party/openh264/tests/BUILD.gn b/third_party/openh264/tests/BUILD.gn
deleted file mode 100644
index 5441a99..0000000
--- a/third_party/openh264/tests/BUILD.gn
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2015 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.
-
-import("//testing/test.gni")
-
-test("openh264_unittests") {
-  include_dirs = [
-    "//",
-    "//third_party",
-  ]
-
-  deps = [
-    "//testing/gtest",
-  ]
-
-  sources = [
-    "openh264_unittests.cc",
-  ]
-}
diff --git a/third_party/openh264/tests/openh264_unittests.cc b/third_party/openh264/tests/openh264_unittests.cc
deleted file mode 100644
index 443d27f..0000000
--- a/third_party/openh264/tests/openh264_unittests.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2015 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 "testing/gtest/include/gtest/gtest.h"
-
-namespace openh264 {
-
-class OpenH264Tests : public testing::Test {
-};
-
-TEST_F(OpenH264Tests, DummyTestAlwaysPass) {
-}
-
-}  // namespace openh264
-
-int main(int argc, char **argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-  return RUN_ALL_TESTS();
-}
diff --git a/third_party/openh264/tests/openh264_unittests.gyp b/third_party/openh264/tests/openh264_unittests.gyp
deleted file mode 100644
index 72143a3..0000000
--- a/third_party/openh264/tests/openh264_unittests.gyp
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2015 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.
-
-{
-  'targets': [
-    {
-      'target_name': 'openh264_unittests',
-      'type': '<(gtest_target_type)',
-      'include_dirs': [
-        '<(DEPTH)',
-        '<(DEPTH)/third_party',
-      ],
-      'dependencies': [
-        '<(DEPTH)/testing/gtest.gyp:gtest',
-      ],
-      'sources': [
-        'openh264_unittests.cc',
-      ],
-    },
-  ],
-}
diff --git a/third_party/wayland/BUILD.gn b/third_party/wayland/BUILD.gn
new file mode 100644
index 0000000..e9652b38
--- /dev/null
+++ b/third_party/wayland/BUILD.gn
@@ -0,0 +1,98 @@
+# Copyright 2015 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.
+
+config("wayland_config") {
+  include_dirs = [
+    "include/src",
+    "include/protocol",
+    "src/src",
+  ]
+}
+
+source_set("wayland_util") {
+  sources = [
+    "src/src/wayland-util.c",
+    "src/src/wayland-util.h",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+
+  public_configs = [ ":wayland_config" ]
+}
+
+source_set("wayland_private") {
+  sources = [
+    "src/src/connection.c",
+    "src/src/wayland-os.c",
+    "src/src/wayland-os.h",
+    "src/src/wayland-private.h",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//build/config/linux:libffi",
+    ":wayland_config",
+  ]
+}
+
+source_set("wayland_protocol") {
+  sources = [
+    "protocol/wayland-protocol.c",
+  ]
+
+  deps = [
+    ":wayland_util",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [ "//build/config/compiler:no_chromium_code" ]
+
+  public_configs = [ ":wayland_config" ]
+}
+
+source_set("wayland_server") {
+  sources = [
+    "include/protocol/wayland-server-protocol.h",
+    "src/src/event-loop.c",
+    "src/src/wayland-server.c",
+    "src/src/wayland-shm.c",
+  ]
+
+  deps = [
+    ":wayland_private",
+    ":wayland_protocol",
+    ":wayland_util",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//build/config/linux:libffi",
+  ]
+
+  public_configs = [ ":wayland_config" ]
+}
+
+source_set("wayland_client") {
+  sources = [
+    "include/protocol/wayland-client-protocol.h",
+    "src/src/wayland-client.c",
+  ]
+
+  deps = [
+    ":wayland_private",
+    ":wayland_protocol",
+    ":wayland_util",
+  ]
+
+  configs -= [ "//build/config/compiler:chromium_code" ]
+  configs += [
+    "//build/config/compiler:no_chromium_code",
+    "//build/config/linux:libffi",
+  ]
+
+  public_configs = [ ":wayland_config" ]
+}
diff --git a/third_party/wayland/LICENSE b/third_party/wayland/LICENSE
new file mode 100644
index 0000000..bd433a8
--- /dev/null
+++ b/third_party/wayland/LICENSE
@@ -0,0 +1,25 @@
+wayland/COPYING
+
+Copyright © 2008-2012 Kristian Høgsberg
+Copyright © 2010-2012 Intel Corporation
+Copyright © 2011 Benjamin Franzke
+Copyright © 2012 Collabora, Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/wayland/OWNERS b/third_party/wayland/OWNERS
new file mode 100644
index 0000000..fe51e0c
--- /dev/null
+++ b/third_party/wayland/OWNERS
@@ -0,0 +1,2 @@
+reveman@chromium.org
+piman@chromium.org
diff --git a/third_party/wayland/README.chromium b/third_party/wayland/README.chromium
new file mode 100644
index 0000000..ccf8020
--- /dev/null
+++ b/third_party/wayland/README.chromium
@@ -0,0 +1,22 @@
+Name: wayland
+URL: http://wayland.freedesktop.org/
+Version: 1.9.0
+License: MIT
+License File: src/COPYING
+Security Critical: yes
+
+Description:
+Wayland is a protocol for a compositor to talk to its clients as well as a C
+library implementation of that protocol.
+
+Modifications:
+- None
+
+To import a new snapshot of wayland:
+- Checkout the latest release tag: git checkout 1.9.0
+- Change the DEPS entry to the newly checked out commit.
+- Update generated files:
+    ./autogen.sh && make
+    rsync -R $(git ls-files --others '*.h') ../include
+    rsync -R $(git ls-files --others 'protocol/*-protocol.c') ..
+- Update this README to reflect the new version number.
diff --git a/third_party/wayland/include/config.h b/third_party/wayland/include/config.h
new file mode 100644
index 0000000..14f40dc1
--- /dev/null
+++ b/third_party/wayland/include/config.h
@@ -0,0 +1,78 @@
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the `accept4' function. */
+#define HAVE_ACCEPT4 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <execinfo.h> header file. */
+#define HAVE_EXECINFO_H 1
+
+/* Define to 1 if you have the <expat.h> header file. */
+/* #undef HAVE_EXPAT_H */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `mkostemp' function. */
+#define HAVE_MKOSTEMP 1
+
+/* Define to 1 if you have the `posix_fallocate' function. */
+#define HAVE_POSIX_FALLOCATE 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "wayland"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "https://bugs.freedesktop.org/enter_bug.cgi?product=Wayland&component=wayland&version=1.9.0"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "wayland"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "wayland 1.9.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "wayland"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL "http://wayland.freedesktop.org/"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.9.0"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "1.9.0"
diff --git a/third_party/wayland/include/protocol/wayland-client-protocol-core.h b/third_party/wayland/include/protocol/wayland-client-protocol-core.h
new file mode 100644
index 0000000..fbf170f
--- /dev/null
+++ b/third_party/wayland/include/protocol/wayland-client-protocol-core.h
@@ -0,0 +1,2523 @@
+/* 
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ * 
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_CLIENT_PROTOCOL_H
+#define WAYLAND_CLIENT_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client-core.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct wl_buffer;
+struct wl_callback;
+struct wl_compositor;
+struct wl_data_device;
+struct wl_data_device_manager;
+struct wl_data_offer;
+struct wl_data_source;
+struct wl_display;
+struct wl_keyboard;
+struct wl_output;
+struct wl_pointer;
+struct wl_region;
+struct wl_registry;
+struct wl_seat;
+struct wl_shell;
+struct wl_shell_surface;
+struct wl_shm;
+struct wl_shm_pool;
+struct wl_subcompositor;
+struct wl_subsurface;
+struct wl_surface;
+struct wl_touch;
+
+extern const struct wl_interface wl_display_interface;
+extern const struct wl_interface wl_registry_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_compositor_interface;
+extern const struct wl_interface wl_shm_pool_interface;
+extern const struct wl_interface wl_shm_interface;
+extern const struct wl_interface wl_buffer_interface;
+extern const struct wl_interface wl_data_offer_interface;
+extern const struct wl_interface wl_data_source_interface;
+extern const struct wl_interface wl_data_device_interface;
+extern const struct wl_interface wl_data_device_manager_interface;
+extern const struct wl_interface wl_shell_interface;
+extern const struct wl_interface wl_shell_surface_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_touch_interface;
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_region_interface;
+extern const struct wl_interface wl_subcompositor_interface;
+extern const struct wl_interface wl_subsurface_interface;
+
+#ifndef WL_DISPLAY_ERROR_ENUM
+#define WL_DISPLAY_ERROR_ENUM
+/**
+ * wl_display_error - global error values
+ * @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
+ * @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the
+ *	specified interface
+ * @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
+ *
+ * These errors are global and can be emitted in response to any server
+ * request.
+ */
+enum wl_display_error {
+	WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
+	WL_DISPLAY_ERROR_INVALID_METHOD = 1,
+	WL_DISPLAY_ERROR_NO_MEMORY = 2,
+};
+#endif /* WL_DISPLAY_ERROR_ENUM */
+
+/**
+ * wl_display - core global object
+ * @error: fatal error event
+ * @delete_id: acknowledge object ID deletion
+ *
+ * The core global object. This is a special singleton object. It is used
+ * for internal Wayland protocol features.
+ */
+struct wl_display_listener {
+	/**
+	 * error - fatal error event
+	 * @object_id: (none)
+	 * @code: (none)
+	 * @message: (none)
+	 *
+	 * The error event is sent out when a fatal (non-recoverable)
+	 * error has occurred. The object_id argument is the object where
+	 * the error occurred, most often in response to a request to that
+	 * object. The code identifies the error and is defined by the
+	 * object interface. As such, each interface defines its own set of
+	 * error codes. The message is an brief description of the error,
+	 * for (debugging) convenience.
+	 */
+	void (*error)(void *data,
+		      struct wl_display *wl_display,
+		      void *object_id,
+		      uint32_t code,
+		      const char *message);
+	/**
+	 * delete_id - acknowledge object ID deletion
+	 * @id: (none)
+	 *
+	 * This event is used internally by the object ID management
+	 * logic. When a client deletes an object, the server will send
+	 * this event to acknowledge that it has seen the delete request.
+	 * When the client receive this event, it will know that it can
+	 * safely reuse the object ID.
+	 */
+	void (*delete_id)(void *data,
+			  struct wl_display *wl_display,
+			  uint32_t id);
+};
+
+static inline int
+wl_display_add_listener(struct wl_display *wl_display,
+			const struct wl_display_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_display,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DISPLAY_SYNC	0
+#define WL_DISPLAY_GET_REGISTRY	1
+
+static inline void
+wl_display_set_user_data(struct wl_display *wl_display, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data);
+}
+
+static inline void *
+wl_display_get_user_data(struct wl_display *wl_display)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_display);
+}
+
+static inline struct wl_callback *
+wl_display_sync(struct wl_display *wl_display)
+{
+	struct wl_proxy *callback;
+
+	callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display,
+			 WL_DISPLAY_SYNC, &wl_callback_interface, NULL);
+
+	return (struct wl_callback *) callback;
+}
+
+static inline struct wl_registry *
+wl_display_get_registry(struct wl_display *wl_display)
+{
+	struct wl_proxy *registry;
+
+	registry = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display,
+			 WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, NULL);
+
+	return (struct wl_registry *) registry;
+}
+
+/**
+ * wl_registry - global registry object
+ * @global: announce global object
+ * @global_remove: announce removal of global object
+ *
+ * The global registry object. The server has a number of global objects
+ * that are available to all clients. These objects typically represent an
+ * actual object in the server (for example, an input device) or they are
+ * singleton objects that provide extension functionality.
+ *
+ * When a client creates a registry object, the registry object will emit a
+ * global event for each global currently in the registry. Globals come and
+ * go as a result of device or monitor hotplugs, reconfiguration or other
+ * events, and the registry will send out global and global_remove events
+ * to keep the client up to date with the changes. To mark the end of the
+ * initial burst of events, the client can use the wl_display.sync request
+ * immediately after calling wl_display.get_registry.
+ *
+ * A client can bind to a global object by using the bind request. This
+ * creates a client-side handle that lets the object emit events to the
+ * client and lets the client invoke requests on the object.
+ */
+struct wl_registry_listener {
+	/**
+	 * global - announce global object
+	 * @name: (none)
+	 * @interface: (none)
+	 * @version: (none)
+	 *
+	 * Notify the client of global objects.
+	 *
+	 * The event notifies the client that a global object with the
+	 * given name is now available, and it implements the given version
+	 * of the given interface.
+	 */
+	void (*global)(void *data,
+		       struct wl_registry *wl_registry,
+		       uint32_t name,
+		       const char *interface,
+		       uint32_t version);
+	/**
+	 * global_remove - announce removal of global object
+	 * @name: (none)
+	 *
+	 * Notify the client of removed global objects.
+	 *
+	 * This event notifies the client that the global identified by
+	 * name is no longer available. If the client bound to the global
+	 * using the bind request, the client should now destroy that
+	 * object.
+	 *
+	 * The object remains valid and requests to the object will be
+	 * ignored until the client destroys it, to avoid races between the
+	 * global going away and a client sending a request to it.
+	 */
+	void (*global_remove)(void *data,
+			      struct wl_registry *wl_registry,
+			      uint32_t name);
+};
+
+static inline int
+wl_registry_add_listener(struct wl_registry *wl_registry,
+			 const struct wl_registry_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_registry,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_REGISTRY_BIND	0
+
+static inline void
+wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data);
+}
+
+static inline void *
+wl_registry_get_user_data(struct wl_registry *wl_registry)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_registry);
+}
+
+static inline void
+wl_registry_destroy(struct wl_registry *wl_registry)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_registry);
+}
+
+static inline void *
+wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_registry,
+			 WL_REGISTRY_BIND, interface, name, interface->name, version, NULL);
+
+	return (void *) id;
+}
+
+/**
+ * wl_callback - callback object
+ * @done: done event
+ *
+ * Clients can handle the 'done' event to get notified when the related
+ * request is done.
+ */
+struct wl_callback_listener {
+	/**
+	 * done - done event
+	 * @callback_data: request-specific data for the wl_callback
+	 *
+	 * Notify the client when the related request is done.
+	 */
+	void (*done)(void *data,
+		     struct wl_callback *wl_callback,
+		     uint32_t callback_data);
+};
+
+static inline int
+wl_callback_add_listener(struct wl_callback *wl_callback,
+			 const struct wl_callback_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_callback,
+				     (void (**)(void)) listener, data);
+}
+
+static inline void
+wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data);
+}
+
+static inline void *
+wl_callback_get_user_data(struct wl_callback *wl_callback)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_callback);
+}
+
+static inline void
+wl_callback_destroy(struct wl_callback *wl_callback)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_callback);
+}
+
+#define WL_COMPOSITOR_CREATE_SURFACE	0
+#define WL_COMPOSITOR_CREATE_REGION	1
+
+static inline void
+wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data);
+}
+
+static inline void *
+wl_compositor_get_user_data(struct wl_compositor *wl_compositor)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor);
+}
+
+static inline void
+wl_compositor_destroy(struct wl_compositor *wl_compositor)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_compositor);
+}
+
+static inline struct wl_surface *
+wl_compositor_create_surface(struct wl_compositor *wl_compositor)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
+			 WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, NULL);
+
+	return (struct wl_surface *) id;
+}
+
+static inline struct wl_region *
+wl_compositor_create_region(struct wl_compositor *wl_compositor)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
+			 WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, NULL);
+
+	return (struct wl_region *) id;
+}
+
+#define WL_SHM_POOL_CREATE_BUFFER	0
+#define WL_SHM_POOL_DESTROY	1
+#define WL_SHM_POOL_RESIZE	2
+
+static inline void
+wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data);
+}
+
+static inline void *
+wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool);
+}
+
+static inline struct wl_buffer *
+wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, NULL, offset, width, height, stride, format);
+
+	return (struct wl_buffer *) id;
+}
+
+static inline void
+wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_shm_pool);
+}
+
+static inline void
+wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_RESIZE, size);
+}
+
+#ifndef WL_SHM_ERROR_ENUM
+#define WL_SHM_ERROR_ENUM
+/**
+ * wl_shm_error - wl_shm error values
+ * @WL_SHM_ERROR_INVALID_FORMAT: buffer format is not known
+ * @WL_SHM_ERROR_INVALID_STRIDE: invalid size or stride during pool or
+ *	buffer creation
+ * @WL_SHM_ERROR_INVALID_FD: mmapping the file descriptor failed
+ *
+ * These errors can be emitted in response to wl_shm requests.
+ */
+enum wl_shm_error {
+	WL_SHM_ERROR_INVALID_FORMAT = 0,
+	WL_SHM_ERROR_INVALID_STRIDE = 1,
+	WL_SHM_ERROR_INVALID_FD = 2,
+};
+#endif /* WL_SHM_ERROR_ENUM */
+
+#ifndef WL_SHM_FORMAT_ENUM
+#define WL_SHM_FORMAT_ENUM
+/**
+ * wl_shm_format - pixel formats
+ * @WL_SHM_FORMAT_ARGB8888: 32-bit ARGB format
+ * @WL_SHM_FORMAT_XRGB8888: 32-bit RGB format
+ * @WL_SHM_FORMAT_C8: (none)
+ * @WL_SHM_FORMAT_RGB332: (none)
+ * @WL_SHM_FORMAT_BGR233: (none)
+ * @WL_SHM_FORMAT_XRGB4444: (none)
+ * @WL_SHM_FORMAT_XBGR4444: (none)
+ * @WL_SHM_FORMAT_RGBX4444: (none)
+ * @WL_SHM_FORMAT_BGRX4444: (none)
+ * @WL_SHM_FORMAT_ARGB4444: (none)
+ * @WL_SHM_FORMAT_ABGR4444: (none)
+ * @WL_SHM_FORMAT_RGBA4444: (none)
+ * @WL_SHM_FORMAT_BGRA4444: (none)
+ * @WL_SHM_FORMAT_XRGB1555: (none)
+ * @WL_SHM_FORMAT_XBGR1555: (none)
+ * @WL_SHM_FORMAT_RGBX5551: (none)
+ * @WL_SHM_FORMAT_BGRX5551: (none)
+ * @WL_SHM_FORMAT_ARGB1555: (none)
+ * @WL_SHM_FORMAT_ABGR1555: (none)
+ * @WL_SHM_FORMAT_RGBA5551: (none)
+ * @WL_SHM_FORMAT_BGRA5551: (none)
+ * @WL_SHM_FORMAT_RGB565: (none)
+ * @WL_SHM_FORMAT_BGR565: (none)
+ * @WL_SHM_FORMAT_RGB888: (none)
+ * @WL_SHM_FORMAT_BGR888: (none)
+ * @WL_SHM_FORMAT_XBGR8888: (none)
+ * @WL_SHM_FORMAT_RGBX8888: (none)
+ * @WL_SHM_FORMAT_BGRX8888: (none)
+ * @WL_SHM_FORMAT_ABGR8888: (none)
+ * @WL_SHM_FORMAT_RGBA8888: (none)
+ * @WL_SHM_FORMAT_BGRA8888: (none)
+ * @WL_SHM_FORMAT_XRGB2101010: (none)
+ * @WL_SHM_FORMAT_XBGR2101010: (none)
+ * @WL_SHM_FORMAT_RGBX1010102: (none)
+ * @WL_SHM_FORMAT_BGRX1010102: (none)
+ * @WL_SHM_FORMAT_ARGB2101010: (none)
+ * @WL_SHM_FORMAT_ABGR2101010: (none)
+ * @WL_SHM_FORMAT_RGBA1010102: (none)
+ * @WL_SHM_FORMAT_BGRA1010102: (none)
+ * @WL_SHM_FORMAT_YUYV: (none)
+ * @WL_SHM_FORMAT_YVYU: (none)
+ * @WL_SHM_FORMAT_UYVY: (none)
+ * @WL_SHM_FORMAT_VYUY: (none)
+ * @WL_SHM_FORMAT_AYUV: (none)
+ * @WL_SHM_FORMAT_NV12: (none)
+ * @WL_SHM_FORMAT_NV21: (none)
+ * @WL_SHM_FORMAT_NV16: (none)
+ * @WL_SHM_FORMAT_NV61: (none)
+ * @WL_SHM_FORMAT_YUV410: (none)
+ * @WL_SHM_FORMAT_YVU410: (none)
+ * @WL_SHM_FORMAT_YUV411: (none)
+ * @WL_SHM_FORMAT_YVU411: (none)
+ * @WL_SHM_FORMAT_YUV420: (none)
+ * @WL_SHM_FORMAT_YVU420: (none)
+ * @WL_SHM_FORMAT_YUV422: (none)
+ * @WL_SHM_FORMAT_YVU422: (none)
+ * @WL_SHM_FORMAT_YUV444: (none)
+ * @WL_SHM_FORMAT_YVU444: (none)
+ *
+ * This describes the memory layout of an individual pixel.
+ *
+ * All renderers should support argb8888 and xrgb8888 but any other formats
+ * are optional and may not be supported by the particular renderer in use.
+ */
+enum wl_shm_format {
+	WL_SHM_FORMAT_ARGB8888 = 0,
+	WL_SHM_FORMAT_XRGB8888 = 1,
+	WL_SHM_FORMAT_C8 = 0x20203843,
+	WL_SHM_FORMAT_RGB332 = 0x38424752,
+	WL_SHM_FORMAT_BGR233 = 0x38524742,
+	WL_SHM_FORMAT_XRGB4444 = 0x32315258,
+	WL_SHM_FORMAT_XBGR4444 = 0x32314258,
+	WL_SHM_FORMAT_RGBX4444 = 0x32315852,
+	WL_SHM_FORMAT_BGRX4444 = 0x32315842,
+	WL_SHM_FORMAT_ARGB4444 = 0x32315241,
+	WL_SHM_FORMAT_ABGR4444 = 0x32314241,
+	WL_SHM_FORMAT_RGBA4444 = 0x32314152,
+	WL_SHM_FORMAT_BGRA4444 = 0x32314142,
+	WL_SHM_FORMAT_XRGB1555 = 0x35315258,
+	WL_SHM_FORMAT_XBGR1555 = 0x35314258,
+	WL_SHM_FORMAT_RGBX5551 = 0x35315852,
+	WL_SHM_FORMAT_BGRX5551 = 0x35315842,
+	WL_SHM_FORMAT_ARGB1555 = 0x35315241,
+	WL_SHM_FORMAT_ABGR1555 = 0x35314241,
+	WL_SHM_FORMAT_RGBA5551 = 0x35314152,
+	WL_SHM_FORMAT_BGRA5551 = 0x35314142,
+	WL_SHM_FORMAT_RGB565 = 0x36314752,
+	WL_SHM_FORMAT_BGR565 = 0x36314742,
+	WL_SHM_FORMAT_RGB888 = 0x34324752,
+	WL_SHM_FORMAT_BGR888 = 0x34324742,
+	WL_SHM_FORMAT_XBGR8888 = 0x34324258,
+	WL_SHM_FORMAT_RGBX8888 = 0x34325852,
+	WL_SHM_FORMAT_BGRX8888 = 0x34325842,
+	WL_SHM_FORMAT_ABGR8888 = 0x34324241,
+	WL_SHM_FORMAT_RGBA8888 = 0x34324152,
+	WL_SHM_FORMAT_BGRA8888 = 0x34324142,
+	WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
+	WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
+	WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
+	WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
+	WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
+	WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
+	WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
+	WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
+	WL_SHM_FORMAT_YUYV = 0x56595559,
+	WL_SHM_FORMAT_YVYU = 0x55595659,
+	WL_SHM_FORMAT_UYVY = 0x59565955,
+	WL_SHM_FORMAT_VYUY = 0x59555956,
+	WL_SHM_FORMAT_AYUV = 0x56555941,
+	WL_SHM_FORMAT_NV12 = 0x3231564e,
+	WL_SHM_FORMAT_NV21 = 0x3132564e,
+	WL_SHM_FORMAT_NV16 = 0x3631564e,
+	WL_SHM_FORMAT_NV61 = 0x3136564e,
+	WL_SHM_FORMAT_YUV410 = 0x39565559,
+	WL_SHM_FORMAT_YVU410 = 0x39555659,
+	WL_SHM_FORMAT_YUV411 = 0x31315559,
+	WL_SHM_FORMAT_YVU411 = 0x31315659,
+	WL_SHM_FORMAT_YUV420 = 0x32315559,
+	WL_SHM_FORMAT_YVU420 = 0x32315659,
+	WL_SHM_FORMAT_YUV422 = 0x36315559,
+	WL_SHM_FORMAT_YVU422 = 0x36315659,
+	WL_SHM_FORMAT_YUV444 = 0x34325559,
+	WL_SHM_FORMAT_YVU444 = 0x34325659,
+};
+#endif /* WL_SHM_FORMAT_ENUM */
+
+/**
+ * wl_shm - shared memory support
+ * @format: pixel format description
+ *
+ * A global singleton object that provides support for shared memory.
+ *
+ * Clients can create wl_shm_pool objects using the create_pool request.
+ *
+ * At connection setup time, the wl_shm object emits one or more format
+ * events to inform clients about the valid pixel formats that can be used
+ * for buffers.
+ */
+struct wl_shm_listener {
+	/**
+	 * format - pixel format description
+	 * @format: (none)
+	 *
+	 * Informs the client about a valid pixel format that can be used
+	 * for buffers. Known formats include argb8888 and xrgb8888.
+	 */
+	void (*format)(void *data,
+		       struct wl_shm *wl_shm,
+		       uint32_t format);
+};
+
+static inline int
+wl_shm_add_listener(struct wl_shm *wl_shm,
+		    const struct wl_shm_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_shm,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SHM_CREATE_POOL	0
+
+static inline void
+wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data);
+}
+
+static inline void *
+wl_shm_get_user_data(struct wl_shm *wl_shm)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shm);
+}
+
+static inline void
+wl_shm_destroy(struct wl_shm *wl_shm)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shm);
+}
+
+static inline struct wl_shm_pool *
+wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm,
+			 WL_SHM_CREATE_POOL, &wl_shm_pool_interface, NULL, fd, size);
+
+	return (struct wl_shm_pool *) id;
+}
+
+/**
+ * wl_buffer - content for a wl_surface
+ * @release: compositor releases buffer
+ *
+ * A buffer provides the content for a wl_surface. Buffers are created
+ * through factory interfaces such as wl_drm, wl_shm or similar. It has a
+ * width and a height and can be attached to a wl_surface, but the
+ * mechanism by which a client provides and updates the contents is defined
+ * by the buffer factory interface.
+ */
+struct wl_buffer_listener {
+	/**
+	 * release - compositor releases buffer
+	 *
+	 * Sent when this wl_buffer is no longer used by the compositor.
+	 * The client is now free to re-use or destroy this buffer and its
+	 * backing storage.
+	 *
+	 * If a client receives a release event before the frame callback
+	 * requested in the same wl_surface.commit that attaches this
+	 * wl_buffer to a surface, then the client is immediately free to
+	 * re-use the buffer and its backing storage, and does not need a
+	 * second buffer for the next surface content update. Typically
+	 * this is possible, when the compositor maintains a copy of the
+	 * wl_surface contents, e.g. as a GL texture. This is an important
+	 * optimization for GL(ES) compositors with wl_shm clients.
+	 */
+	void (*release)(void *data,
+			struct wl_buffer *wl_buffer);
+};
+
+static inline int
+wl_buffer_add_listener(struct wl_buffer *wl_buffer,
+		       const struct wl_buffer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_buffer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_BUFFER_DESTROY	0
+
+static inline void
+wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data);
+}
+
+static inline void *
+wl_buffer_get_user_data(struct wl_buffer *wl_buffer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer);
+}
+
+static inline void
+wl_buffer_destroy(struct wl_buffer *wl_buffer)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_buffer,
+			 WL_BUFFER_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_buffer);
+}
+
+/**
+ * wl_data_offer - offer to transfer data
+ * @offer: advertise offered mime type
+ *
+ * A wl_data_offer represents a piece of data offered for transfer by
+ * another client (the source client). It is used by the copy-and-paste and
+ * drag-and-drop mechanisms. The offer describes the different mime types
+ * that the data can be converted to and provides the mechanism for
+ * transferring the data directly from the source client.
+ */
+struct wl_data_offer_listener {
+	/**
+	 * offer - advertise offered mime type
+	 * @mime_type: (none)
+	 *
+	 * Sent immediately after creating the wl_data_offer object. One
+	 * event per offered mime type.
+	 */
+	void (*offer)(void *data,
+		      struct wl_data_offer *wl_data_offer,
+		      const char *mime_type);
+};
+
+static inline int
+wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer,
+			   const struct wl_data_offer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_OFFER_ACCEPT	0
+#define WL_DATA_OFFER_RECEIVE	1
+#define WL_DATA_OFFER_DESTROY	2
+
+static inline void
+wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data);
+}
+
+static inline void *
+wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer);
+}
+
+static inline void
+wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_ACCEPT, serial, mime_type);
+}
+
+static inline void
+wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_RECEIVE, mime_type, fd);
+}
+
+static inline void
+wl_data_offer_destroy(struct wl_data_offer *wl_data_offer)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_data_offer);
+}
+
+/**
+ * wl_data_source - offer to transfer data
+ * @target: a target accepts an offered mime type
+ * @send: send the data
+ * @cancelled: selection was cancelled
+ *
+ * The wl_data_source object is the source side of a wl_data_offer. It is
+ * created by the source client in a data transfer and provides a way to
+ * describe the offered data and a way to respond to requests to transfer
+ * the data.
+ */
+struct wl_data_source_listener {
+	/**
+	 * target - a target accepts an offered mime type
+	 * @mime_type: (none)
+	 *
+	 * Sent when a target accepts pointer_focus or motion events. If
+	 * a target does not accept any of the offered types, type is NULL.
+	 *
+	 * Used for feedback during drag-and-drop.
+	 */
+	void (*target)(void *data,
+		       struct wl_data_source *wl_data_source,
+		       const char *mime_type);
+	/**
+	 * send - send the data
+	 * @mime_type: (none)
+	 * @fd: (none)
+	 *
+	 * Request for data from the client. Send the data as the
+	 * specified mime type over the passed file descriptor, then close
+	 * it.
+	 */
+	void (*send)(void *data,
+		     struct wl_data_source *wl_data_source,
+		     const char *mime_type,
+		     int32_t fd);
+	/**
+	 * cancelled - selection was cancelled
+	 *
+	 * This data source has been replaced by another data source. The
+	 * client should clean up and destroy this data source.
+	 */
+	void (*cancelled)(void *data,
+			  struct wl_data_source *wl_data_source);
+};
+
+static inline int
+wl_data_source_add_listener(struct wl_data_source *wl_data_source,
+			    const struct wl_data_source_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_source,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_SOURCE_OFFER	0
+#define WL_DATA_SOURCE_DESTROY	1
+
+static inline void
+wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data);
+}
+
+static inline void *
+wl_data_source_get_user_data(struct wl_data_source *wl_data_source)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source);
+}
+
+static inline void
+wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_source,
+			 WL_DATA_SOURCE_OFFER, mime_type);
+}
+
+static inline void
+wl_data_source_destroy(struct wl_data_source *wl_data_source)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_source,
+			 WL_DATA_SOURCE_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_data_source);
+}
+
+#ifndef WL_DATA_DEVICE_ERROR_ENUM
+#define WL_DATA_DEVICE_ERROR_ENUM
+enum wl_data_device_error {
+	WL_DATA_DEVICE_ERROR_ROLE = 0,
+};
+#endif /* WL_DATA_DEVICE_ERROR_ENUM */
+
+/**
+ * wl_data_device - data transfer device
+ * @data_offer: introduce a new wl_data_offer
+ * @enter: initiate drag-and-drop session
+ * @leave: end drag-and-drop session
+ * @motion: drag-and-drop session motion
+ * @drop: end drag-and-drag session successfully
+ * @selection: advertise new selection
+ *
+ * There is one wl_data_device per seat which can be obtained from the
+ * global wl_data_device_manager singleton.
+ *
+ * A wl_data_device provides access to inter-client data transfer
+ * mechanisms such as copy-and-paste and drag-and-drop.
+ */
+struct wl_data_device_listener {
+	/**
+	 * data_offer - introduce a new wl_data_offer
+	 * @id: (none)
+	 *
+	 * The data_offer event introduces a new wl_data_offer object,
+	 * which will subsequently be used in either the data_device.enter
+	 * event (for drag-and-drop) or the data_device.selection event
+	 * (for selections). Immediately following the
+	 * data_device_data_offer event, the new data_offer object will
+	 * send out data_offer.offer events to describe the mime types it
+	 * offers.
+	 */
+	void (*data_offer)(void *data,
+			   struct wl_data_device *wl_data_device,
+			   struct wl_data_offer *id);
+	/**
+	 * enter - initiate drag-and-drop session
+	 * @serial: (none)
+	 * @surface: (none)
+	 * @x: (none)
+	 * @y: (none)
+	 * @id: (none)
+	 *
+	 * This event is sent when an active drag-and-drop pointer enters
+	 * a surface owned by the client. The position of the pointer at
+	 * enter time is provided by the x and y arguments, in surface
+	 * local coordinates.
+	 */
+	void (*enter)(void *data,
+		      struct wl_data_device *wl_data_device,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      wl_fixed_t x,
+		      wl_fixed_t y,
+		      struct wl_data_offer *id);
+	/**
+	 * leave - end drag-and-drop session
+	 *
+	 * This event is sent when the drag-and-drop pointer leaves the
+	 * surface and the session ends. The client must destroy the
+	 * wl_data_offer introduced at enter time at this point.
+	 */
+	void (*leave)(void *data,
+		      struct wl_data_device *wl_data_device);
+	/**
+	 * motion - drag-and-drop session motion
+	 * @time: timestamp with millisecond granularity
+	 * @x: (none)
+	 * @y: (none)
+	 *
+	 * This event is sent when the drag-and-drop pointer moves within
+	 * the currently focused surface. The new position of the pointer
+	 * is provided by the x and y arguments, in surface local
+	 * coordinates.
+	 */
+	void (*motion)(void *data,
+		       struct wl_data_device *wl_data_device,
+		       uint32_t time,
+		       wl_fixed_t x,
+		       wl_fixed_t y);
+	/**
+	 * drop - end drag-and-drag session successfully
+	 *
+	 * The event is sent when a drag-and-drop operation is ended
+	 * because the implicit grab is removed.
+	 */
+	void (*drop)(void *data,
+		     struct wl_data_device *wl_data_device);
+	/**
+	 * selection - advertise new selection
+	 * @id: (none)
+	 *
+	 * The selection event is sent out to notify the client of a new
+	 * wl_data_offer for the selection for this device. The
+	 * data_device.data_offer and the data_offer.offer events are sent
+	 * out immediately before this event to introduce the data offer
+	 * object. The selection event is sent to a client immediately
+	 * before receiving keyboard focus and when a new selection is set
+	 * while the client has keyboard focus. The data_offer is valid
+	 * until a new data_offer or NULL is received or until the client
+	 * loses keyboard focus. The client must destroy the previous
+	 * selection data_offer, if any, upon receiving this event.
+	 */
+	void (*selection)(void *data,
+			  struct wl_data_device *wl_data_device,
+			  struct wl_data_offer *id);
+};
+
+static inline int
+wl_data_device_add_listener(struct wl_data_device *wl_data_device,
+			    const struct wl_data_device_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_device,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_DEVICE_START_DRAG	0
+#define WL_DATA_DEVICE_SET_SELECTION	1
+#define WL_DATA_DEVICE_RELEASE	2
+
+static inline void
+wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data);
+}
+
+static inline void *
+wl_data_device_get_user_data(struct wl_data_device *wl_data_device)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device);
+}
+
+static inline void
+wl_data_device_destroy(struct wl_data_device *wl_data_device)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_data_device);
+}
+
+static inline void
+wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_START_DRAG, source, origin, icon, serial);
+}
+
+static inline void
+wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_SET_SELECTION, source, serial);
+}
+
+static inline void
+wl_data_device_release(struct wl_data_device *wl_data_device)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_RELEASE);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_data_device);
+}
+
+#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE	0
+#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE	1
+
+static inline void
+wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data);
+}
+
+static inline void *
+wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager);
+}
+
+static inline void
+wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager);
+}
+
+static inline struct wl_data_source *
+wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager,
+			 WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, NULL);
+
+	return (struct wl_data_source *) id;
+}
+
+static inline struct wl_data_device *
+wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager,
+			 WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, NULL, seat);
+
+	return (struct wl_data_device *) id;
+}
+
+#ifndef WL_SHELL_ERROR_ENUM
+#define WL_SHELL_ERROR_ENUM
+enum wl_shell_error {
+	WL_SHELL_ERROR_ROLE = 0,
+};
+#endif /* WL_SHELL_ERROR_ENUM */
+
+#define WL_SHELL_GET_SHELL_SURFACE	0
+
+static inline void
+wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data);
+}
+
+static inline void *
+wl_shell_get_user_data(struct wl_shell *wl_shell)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shell);
+}
+
+static inline void
+wl_shell_destroy(struct wl_shell *wl_shell)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shell);
+}
+
+static inline struct wl_shell_surface *
+wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shell,
+			 WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, NULL, surface);
+
+	return (struct wl_shell_surface *) id;
+}
+
+#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
+#define WL_SHELL_SURFACE_RESIZE_ENUM
+/**
+ * wl_shell_surface_resize - edge values for resizing
+ * @WL_SHELL_SURFACE_RESIZE_NONE: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM: (none)
+ * @WL_SHELL_SURFACE_RESIZE_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_RIGHT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: (none)
+ *
+ * These values are used to indicate which edge of a surface is being
+ * dragged in a resize operation. The server may use this information to
+ * adapt its behavior, e.g. choose an appropriate cursor image.
+ */
+enum wl_shell_surface_resize {
+	WL_SHELL_SURFACE_RESIZE_NONE = 0,
+	WL_SHELL_SURFACE_RESIZE_TOP = 1,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
+	WL_SHELL_SURFACE_RESIZE_LEFT = 4,
+	WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
+	WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
+	WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
+};
+#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
+
+#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
+#define WL_SHELL_SURFACE_TRANSIENT_ENUM
+/**
+ * wl_shell_surface_transient - details of transient behaviour
+ * @WL_SHELL_SURFACE_TRANSIENT_INACTIVE: do not set keyboard focus
+ *
+ * These flags specify details of the expected behaviour of transient
+ * surfaces. Used in the set_transient request.
+ */
+enum wl_shell_surface_transient {
+	WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
+};
+#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
+
+#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+/**
+ * wl_shell_surface_fullscreen_method - different method to set the
+ *	surface fullscreen
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT: no preference, apply
+ *	default policy
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE: scale, preserve the
+ *	surface's aspect ratio and center on output
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: switch output mode to the
+ *	smallest mode that can fit the surface, add black borders to compensate
+ *	size mismatch
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: no upscaling, center on
+ *	output and add black borders to compensate size mismatch
+ *
+ * Hints to indicate to the compositor how to deal with a conflict
+ * between the dimensions of the surface and the dimensions of the output.
+ * The compositor is free to ignore this parameter.
+ */
+enum wl_shell_surface_fullscreen_method {
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
+};
+#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
+
+/**
+ * wl_shell_surface - desktop-style metadata interface
+ * @ping: ping client
+ * @configure: suggest resize
+ * @popup_done: popup interaction is done
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like toplevel, fullscreen or
+ * popup windows, move, resize or maximize them, associate metadata like
+ * title and class, etc.
+ *
+ * On the server side the object is automatically destroyed when the
+ * related wl_surface is destroyed. On client side,
+ * wl_shell_surface_destroy() must be called before destroying the
+ * wl_surface object.
+ */
+struct wl_shell_surface_listener {
+	/**
+	 * ping - ping client
+	 * @serial: (none)
+	 *
+	 * Ping a client to check if it is receiving events and sending
+	 * requests. A client is expected to reply with a pong request.
+	 */
+	void (*ping)(void *data,
+		     struct wl_shell_surface *wl_shell_surface,
+		     uint32_t serial);
+	/**
+	 * configure - suggest resize
+	 * @edges: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 *
+	 * The configure event asks the client to resize its surface.
+	 *
+	 * The size is a hint, in the sense that the client is free to
+	 * ignore it if it doesn't resize, pick a smaller size (to satisfy
+	 * aspect ratio or resize in steps of NxM pixels).
+	 *
+	 * The edges parameter provides a hint about how the surface was
+	 * resized. The client may use this information to decide how to
+	 * adjust its content to the new size (e.g. a scrolling area might
+	 * adjust its content position to leave the viewable content
+	 * unmoved).
+	 *
+	 * The client is free to dismiss all but the last configure event
+	 * it received.
+	 *
+	 * The width and height arguments specify the size of the window in
+	 * surface local coordinates.
+	 */
+	void (*configure)(void *data,
+			  struct wl_shell_surface *wl_shell_surface,
+			  uint32_t edges,
+			  int32_t width,
+			  int32_t height);
+	/**
+	 * popup_done - popup interaction is done
+	 *
+	 * The popup_done event is sent out when a popup grab is broken,
+	 * that is, when the user clicks a surface that doesn't belong to
+	 * the client owning the popup surface.
+	 */
+	void (*popup_done)(void *data,
+			   struct wl_shell_surface *wl_shell_surface);
+};
+
+static inline int
+wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface,
+			      const struct wl_shell_surface_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SHELL_SURFACE_PONG	0
+#define WL_SHELL_SURFACE_MOVE	1
+#define WL_SHELL_SURFACE_RESIZE	2
+#define WL_SHELL_SURFACE_SET_TOPLEVEL	3
+#define WL_SHELL_SURFACE_SET_TRANSIENT	4
+#define WL_SHELL_SURFACE_SET_FULLSCREEN	5
+#define WL_SHELL_SURFACE_SET_POPUP	6
+#define WL_SHELL_SURFACE_SET_MAXIMIZED	7
+#define WL_SHELL_SURFACE_SET_TITLE	8
+#define WL_SHELL_SURFACE_SET_CLASS	9
+
+static inline void
+wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data);
+}
+
+static inline void *
+wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface);
+}
+
+static inline void
+wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shell_surface);
+}
+
+static inline void
+wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_PONG, serial);
+}
+
+static inline void
+wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_MOVE, seat, serial);
+}
+
+static inline void
+wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_RESIZE, seat, serial, edges);
+}
+
+static inline void
+wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TOPLEVEL);
+}
+
+static inline void
+wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TRANSIENT, parent, x, y, flags);
+}
+
+static inline void
+wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_FULLSCREEN, method, framerate, output);
+}
+
+static inline void
+wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_POPUP, seat, serial, parent, x, y, flags);
+}
+
+static inline void
+wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_MAXIMIZED, output);
+}
+
+static inline void
+wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TITLE, title);
+}
+
+static inline void
+wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_CLASS, class_);
+}
+
+#ifndef WL_SURFACE_ERROR_ENUM
+#define WL_SURFACE_ERROR_ENUM
+/**
+ * wl_surface_error - wl_surface error values
+ * @WL_SURFACE_ERROR_INVALID_SCALE: buffer scale value is invalid
+ * @WL_SURFACE_ERROR_INVALID_TRANSFORM: buffer transform value is invalid
+ *
+ * These errors can be emitted in response to wl_surface requests.
+ */
+enum wl_surface_error {
+	WL_SURFACE_ERROR_INVALID_SCALE = 0,
+	WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
+};
+#endif /* WL_SURFACE_ERROR_ENUM */
+
+/**
+ * wl_surface - an onscreen surface
+ * @enter: surface enters an output
+ * @leave: surface leaves an output
+ *
+ * A surface is a rectangular area that is displayed on the screen. It
+ * has a location, size and pixel contents.
+ *
+ * The size of a surface (and relative positions on it) is described in
+ * surface local coordinates, which may differ from the buffer local
+ * coordinates of the pixel content, in case a buffer_transform or a
+ * buffer_scale is used.
+ *
+ * A surface without a "role" is fairly useless, a compositor does not know
+ * where, when or how to present it. The role is the purpose of a
+ * wl_surface. Examples of roles are a cursor for a pointer (as set by
+ * wl_pointer.set_cursor), a drag icon (wl_data_device.start_drag), a
+ * sub-surface (wl_subcompositor.get_subsurface), and a window as defined
+ * by a shell protocol (e.g. wl_shell.get_shell_surface).
+ *
+ * A surface can have only one role at a time. Initially a wl_surface does
+ * not have a role. Once a wl_surface is given a role, it is set
+ * permanently for the whole lifetime of the wl_surface object. Giving the
+ * current role again is allowed, unless explicitly forbidden by the
+ * relevant interface specification.
+ *
+ * Surface roles are given by requests in other interfaces such as
+ * wl_pointer.set_cursor. The request should explicitly mention that this
+ * request gives a role to a wl_surface. Often, this request also creates a
+ * new protocol object that represents the role and adds additional
+ * functionality to wl_surface. When a client wants to destroy a
+ * wl_surface, they must destroy this 'role object' before the wl_surface.
+ *
+ * Destroying the role object does not remove the role from the wl_surface,
+ * but it may stop the wl_surface from "playing the role". For instance, if
+ * a wl_subsurface object is destroyed, the wl_surface it was created for
+ * will be unmapped and forget its position and z-order. It is allowed to
+ * create a wl_subsurface for the same wl_surface again, but it is not
+ * allowed to use the wl_surface as a cursor (cursor is a different role
+ * than sub-surface, and role switching is not allowed).
+ */
+struct wl_surface_listener {
+	/**
+	 * enter - surface enters an output
+	 * @output: (none)
+	 *
+	 * This is emitted whenever a surface's creation, movement, or
+	 * resizing results in some part of it being within the scanout
+	 * region of an output.
+	 *
+	 * Note that a surface may be overlapping with zero or more
+	 * outputs.
+	 */
+	void (*enter)(void *data,
+		      struct wl_surface *wl_surface,
+		      struct wl_output *output);
+	/**
+	 * leave - surface leaves an output
+	 * @output: (none)
+	 *
+	 * This is emitted whenever a surface's creation, movement, or
+	 * resizing results in it no longer having any part of it within
+	 * the scanout region of an output.
+	 */
+	void (*leave)(void *data,
+		      struct wl_surface *wl_surface,
+		      struct wl_output *output);
+};
+
+static inline int
+wl_surface_add_listener(struct wl_surface *wl_surface,
+			const struct wl_surface_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_surface,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SURFACE_DESTROY	0
+#define WL_SURFACE_ATTACH	1
+#define WL_SURFACE_DAMAGE	2
+#define WL_SURFACE_FRAME	3
+#define WL_SURFACE_SET_OPAQUE_REGION	4
+#define WL_SURFACE_SET_INPUT_REGION	5
+#define WL_SURFACE_COMMIT	6
+#define WL_SURFACE_SET_BUFFER_TRANSFORM	7
+#define WL_SURFACE_SET_BUFFER_SCALE	8
+
+static inline void
+wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data);
+}
+
+static inline void *
+wl_surface_get_user_data(struct wl_surface *wl_surface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_surface);
+}
+
+static inline void
+wl_surface_destroy(struct wl_surface *wl_surface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_surface);
+}
+
+static inline void
+wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_ATTACH, buffer, x, y);
+}
+
+static inline void
+wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_DAMAGE, x, y, width, height);
+}
+
+static inline struct wl_callback *
+wl_surface_frame(struct wl_surface *wl_surface)
+{
+	struct wl_proxy *callback;
+
+	callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_FRAME, &wl_callback_interface, NULL);
+
+	return (struct wl_callback *) callback;
+}
+
+static inline void
+wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_OPAQUE_REGION, region);
+}
+
+static inline void
+wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_INPUT_REGION, region);
+}
+
+static inline void
+wl_surface_commit(struct wl_surface *wl_surface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_COMMIT);
+}
+
+static inline void
+wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_BUFFER_TRANSFORM, transform);
+}
+
+static inline void
+wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_BUFFER_SCALE, scale);
+}
+
+#ifndef WL_SEAT_CAPABILITY_ENUM
+#define WL_SEAT_CAPABILITY_ENUM
+/**
+ * wl_seat_capability - seat capability bitmask
+ * @WL_SEAT_CAPABILITY_POINTER: The seat has pointer devices
+ * @WL_SEAT_CAPABILITY_KEYBOARD: The seat has one or more keyboards
+ * @WL_SEAT_CAPABILITY_TOUCH: The seat has touch devices
+ *
+ * This is a bitmask of capabilities this seat has; if a member is set,
+ * then it is present on the seat.
+ */
+enum wl_seat_capability {
+	WL_SEAT_CAPABILITY_POINTER = 1,
+	WL_SEAT_CAPABILITY_KEYBOARD = 2,
+	WL_SEAT_CAPABILITY_TOUCH = 4,
+};
+#endif /* WL_SEAT_CAPABILITY_ENUM */
+
+/**
+ * wl_seat - group of input devices
+ * @capabilities: seat capabilities changed
+ * @name: unique identifier for this seat
+ *
+ * A seat is a group of keyboards, pointer and touch devices. This object
+ * is published as a global during start up, or when such a device is hot
+ * plugged. A seat typically has a pointer and maintains a keyboard focus
+ * and a pointer focus.
+ */
+struct wl_seat_listener {
+	/**
+	 * capabilities - seat capabilities changed
+	 * @capabilities: (none)
+	 *
+	 * This is emitted whenever a seat gains or loses the pointer,
+	 * keyboard or touch capabilities. The argument is a capability
+	 * enum containing the complete set of capabilities this seat has.
+	 */
+	void (*capabilities)(void *data,
+			     struct wl_seat *wl_seat,
+			     uint32_t capabilities);
+	/**
+	 * name - unique identifier for this seat
+	 * @name: (none)
+	 *
+	 * In a multiseat configuration this can be used by the client to
+	 * help identify which physical devices the seat represents. Based
+	 * on the seat configuration used by the compositor.
+	 * @since: 2
+	 */
+	void (*name)(void *data,
+		     struct wl_seat *wl_seat,
+		     const char *name);
+};
+
+static inline int
+wl_seat_add_listener(struct wl_seat *wl_seat,
+		     const struct wl_seat_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_seat,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SEAT_GET_POINTER	0
+#define WL_SEAT_GET_KEYBOARD	1
+#define WL_SEAT_GET_TOUCH	2
+
+static inline void
+wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data);
+}
+
+static inline void *
+wl_seat_get_user_data(struct wl_seat *wl_seat)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_seat);
+}
+
+static inline void
+wl_seat_destroy(struct wl_seat *wl_seat)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_seat);
+}
+
+static inline struct wl_pointer *
+wl_seat_get_pointer(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_POINTER, &wl_pointer_interface, NULL);
+
+	return (struct wl_pointer *) id;
+}
+
+static inline struct wl_keyboard *
+wl_seat_get_keyboard(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, NULL);
+
+	return (struct wl_keyboard *) id;
+}
+
+static inline struct wl_touch *
+wl_seat_get_touch(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_TOUCH, &wl_touch_interface, NULL);
+
+	return (struct wl_touch *) id;
+}
+
+#ifndef WL_POINTER_ERROR_ENUM
+#define WL_POINTER_ERROR_ENUM
+enum wl_pointer_error {
+	WL_POINTER_ERROR_ROLE = 0,
+};
+#endif /* WL_POINTER_ERROR_ENUM */
+
+#ifndef WL_POINTER_BUTTON_STATE_ENUM
+#define WL_POINTER_BUTTON_STATE_ENUM
+/**
+ * wl_pointer_button_state - physical button state
+ * @WL_POINTER_BUTTON_STATE_RELEASED: The button is not pressed
+ * @WL_POINTER_BUTTON_STATE_PRESSED: The button is pressed
+ *
+ * Describes the physical state of a button which provoked the button
+ * event.
+ */
+enum wl_pointer_button_state {
+	WL_POINTER_BUTTON_STATE_RELEASED = 0,
+	WL_POINTER_BUTTON_STATE_PRESSED = 1,
+};
+#endif /* WL_POINTER_BUTTON_STATE_ENUM */
+
+#ifndef WL_POINTER_AXIS_ENUM
+#define WL_POINTER_AXIS_ENUM
+/**
+ * wl_pointer_axis - axis types
+ * @WL_POINTER_AXIS_VERTICAL_SCROLL: (none)
+ * @WL_POINTER_AXIS_HORIZONTAL_SCROLL: (none)
+ *
+ * Describes the axis types of scroll events.
+ */
+enum wl_pointer_axis {
+	WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
+	WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
+};
+#endif /* WL_POINTER_AXIS_ENUM */
+
+/**
+ * wl_pointer - pointer input device
+ * @enter: enter event
+ * @leave: leave event
+ * @motion: pointer motion event
+ * @button: pointer button event
+ * @axis: axis event
+ *
+ * The wl_pointer interface represents one or more input devices, such as
+ * mice, which control the pointer location and pointer_focus of a seat.
+ *
+ * The wl_pointer interface generates motion, enter and leave events for
+ * the surfaces that the pointer is located over, and button and axis
+ * events for button presses, button releases and scrolling.
+ */
+struct wl_pointer_listener {
+	/**
+	 * enter - enter event
+	 * @serial: (none)
+	 * @surface: (none)
+	 * @surface_x: x coordinate in surface-relative coordinates
+	 * @surface_y: y coordinate in surface-relative coordinates
+	 *
+	 * Notification that this seat's pointer is focused on a certain
+	 * surface.
+	 *
+	 * When an seat's focus enters a surface, the pointer image is
+	 * undefined and a client should respond to this event by setting
+	 * an appropriate pointer image with the set_cursor request.
+	 */
+	void (*enter)(void *data,
+		      struct wl_pointer *wl_pointer,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      wl_fixed_t surface_x,
+		      wl_fixed_t surface_y);
+	/**
+	 * leave - leave event
+	 * @serial: (none)
+	 * @surface: (none)
+	 *
+	 * Notification that this seat's pointer is no longer focused on
+	 * a certain surface.
+	 *
+	 * The leave notification is sent before the enter notification for
+	 * the new focus.
+	 */
+	void (*leave)(void *data,
+		      struct wl_pointer *wl_pointer,
+		      uint32_t serial,
+		      struct wl_surface *surface);
+	/**
+	 * motion - pointer motion event
+	 * @time: timestamp with millisecond granularity
+	 * @surface_x: x coordinate in surface-relative coordinates
+	 * @surface_y: y coordinate in surface-relative coordinates
+	 *
+	 * Notification of pointer location change. The arguments
+	 * surface_x and surface_y are the location relative to the focused
+	 * surface.
+	 */
+	void (*motion)(void *data,
+		       struct wl_pointer *wl_pointer,
+		       uint32_t time,
+		       wl_fixed_t surface_x,
+		       wl_fixed_t surface_y);
+	/**
+	 * button - pointer button event
+	 * @serial: (none)
+	 * @time: timestamp with millisecond granularity
+	 * @button: (none)
+	 * @state: (none)
+	 *
+	 * Mouse button click and release notifications.
+	 *
+	 * The location of the click is given by the last motion or enter
+	 * event. The time argument is a timestamp with millisecond
+	 * granularity, with an undefined base.
+	 */
+	void (*button)(void *data,
+		       struct wl_pointer *wl_pointer,
+		       uint32_t serial,
+		       uint32_t time,
+		       uint32_t button,
+		       uint32_t state);
+	/**
+	 * axis - axis event
+	 * @time: timestamp with millisecond granularity
+	 * @axis: (none)
+	 * @value: (none)
+	 *
+	 * Scroll and other axis notifications.
+	 *
+	 * For scroll events (vertical and horizontal scroll axes), the
+	 * value parameter is the length of a vector along the specified
+	 * axis in a coordinate space identical to those of motion events,
+	 * representing a relative movement along the specified axis.
+	 *
+	 * For devices that support movements non-parallel to axes multiple
+	 * axis events will be emitted.
+	 *
+	 * When applicable, for example for touch pads, the server can
+	 * choose to emit scroll events where the motion vector is
+	 * equivalent to a motion event vector.
+	 *
+	 * When applicable, clients can transform its view relative to the
+	 * scroll distance.
+	 */
+	void (*axis)(void *data,
+		     struct wl_pointer *wl_pointer,
+		     uint32_t time,
+		     uint32_t axis,
+		     wl_fixed_t value);
+};
+
+static inline int
+wl_pointer_add_listener(struct wl_pointer *wl_pointer,
+			const struct wl_pointer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_pointer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_POINTER_SET_CURSOR	0
+#define WL_POINTER_RELEASE	1
+
+static inline void
+wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data);
+}
+
+static inline void *
+wl_pointer_get_user_data(struct wl_pointer *wl_pointer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer);
+}
+
+static inline void
+wl_pointer_destroy(struct wl_pointer *wl_pointer)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_pointer);
+}
+
+static inline void
+wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_pointer,
+			 WL_POINTER_SET_CURSOR, serial, surface, hotspot_x, hotspot_y);
+}
+
+static inline void
+wl_pointer_release(struct wl_pointer *wl_pointer)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_pointer,
+			 WL_POINTER_RELEASE);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_pointer);
+}
+
+#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+/**
+ * wl_keyboard_keymap_format - keyboard mapping format
+ * @WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP: no keymap; client must
+ *	understand how to interpret the raw keycode
+ * @WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1: libxkbcommon compatible; to
+ *	determine the xkb keycode, clients must add 8 to the key event keycode
+ *
+ * This specifies the format of the keymap provided to the client with
+ * the wl_keyboard.keymap event.
+ */
+enum wl_keyboard_keymap_format {
+	WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
+	WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
+};
+#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
+
+#ifndef WL_KEYBOARD_KEY_STATE_ENUM
+#define WL_KEYBOARD_KEY_STATE_ENUM
+/**
+ * wl_keyboard_key_state - physical key state
+ * @WL_KEYBOARD_KEY_STATE_RELEASED: key is not pressed
+ * @WL_KEYBOARD_KEY_STATE_PRESSED: key is pressed
+ *
+ * Describes the physical state of a key which provoked the key event.
+ */
+enum wl_keyboard_key_state {
+	WL_KEYBOARD_KEY_STATE_RELEASED = 0,
+	WL_KEYBOARD_KEY_STATE_PRESSED = 1,
+};
+#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
+
+/**
+ * wl_keyboard - keyboard input device
+ * @keymap: keyboard mapping
+ * @enter: enter event
+ * @leave: leave event
+ * @key: key event
+ * @modifiers: modifier and group state
+ * @repeat_info: repeat rate and delay
+ *
+ * The wl_keyboard interface represents one or more keyboards associated
+ * with a seat.
+ */
+struct wl_keyboard_listener {
+	/**
+	 * keymap - keyboard mapping
+	 * @format: (none)
+	 * @fd: (none)
+	 * @size: (none)
+	 *
+	 * This event provides a file descriptor to the client which can
+	 * be memory-mapped to provide a keyboard mapping description.
+	 */
+	void (*keymap)(void *data,
+		       struct wl_keyboard *wl_keyboard,
+		       uint32_t format,
+		       int32_t fd,
+		       uint32_t size);
+	/**
+	 * enter - enter event
+	 * @serial: (none)
+	 * @surface: (none)
+	 * @keys: the currently pressed keys
+	 *
+	 * Notification that this seat's keyboard focus is on a certain
+	 * surface.
+	 */
+	void (*enter)(void *data,
+		      struct wl_keyboard *wl_keyboard,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      struct wl_array *keys);
+	/**
+	 * leave - leave event
+	 * @serial: (none)
+	 * @surface: (none)
+	 *
+	 * Notification that this seat's keyboard focus is no longer on a
+	 * certain surface.
+	 *
+	 * The leave notification is sent before the enter notification for
+	 * the new focus.
+	 */
+	void (*leave)(void *data,
+		      struct wl_keyboard *wl_keyboard,
+		      uint32_t serial,
+		      struct wl_surface *surface);
+	/**
+	 * key - key event
+	 * @serial: (none)
+	 * @time: timestamp with millisecond granularity
+	 * @key: (none)
+	 * @state: (none)
+	 *
+	 * A key was pressed or released. The time argument is a
+	 * timestamp with millisecond granularity, with an undefined base.
+	 */
+	void (*key)(void *data,
+		    struct wl_keyboard *wl_keyboard,
+		    uint32_t serial,
+		    uint32_t time,
+		    uint32_t key,
+		    uint32_t state);
+	/**
+	 * modifiers - modifier and group state
+	 * @serial: (none)
+	 * @mods_depressed: (none)
+	 * @mods_latched: (none)
+	 * @mods_locked: (none)
+	 * @group: (none)
+	 *
+	 * Notifies clients that the modifier and/or group state has
+	 * changed, and it should update its local state.
+	 */
+	void (*modifiers)(void *data,
+			  struct wl_keyboard *wl_keyboard,
+			  uint32_t serial,
+			  uint32_t mods_depressed,
+			  uint32_t mods_latched,
+			  uint32_t mods_locked,
+			  uint32_t group);
+	/**
+	 * repeat_info - repeat rate and delay
+	 * @rate: the rate of repeating keys in characters per second
+	 * @delay: delay in milliseconds since key down until repeating
+	 *	starts
+	 *
+	 * Informs the client about the keyboard's repeat rate and delay.
+	 *
+	 * This event is sent as soon as the wl_keyboard object has been
+	 * created, and is guaranteed to be received by the client before
+	 * any key press event.
+	 *
+	 * Negative values for either rate or delay are illegal. A rate of
+	 * zero will disable any repeating (regardless of the value of
+	 * delay).
+	 *
+	 * This event can be sent later on as well with a new value if
+	 * necessary, so clients should continue listening for the event
+	 * past the creation of wl_keyboard.
+	 * @since: 4
+	 */
+	void (*repeat_info)(void *data,
+			    struct wl_keyboard *wl_keyboard,
+			    int32_t rate,
+			    int32_t delay);
+};
+
+static inline int
+wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard,
+			 const struct wl_keyboard_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_KEYBOARD_RELEASE	0
+
+static inline void
+wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data);
+}
+
+static inline void *
+wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard);
+}
+
+static inline void
+wl_keyboard_destroy(struct wl_keyboard *wl_keyboard)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_keyboard);
+}
+
+static inline void
+wl_keyboard_release(struct wl_keyboard *wl_keyboard)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_keyboard,
+			 WL_KEYBOARD_RELEASE);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_keyboard);
+}
+
+/**
+ * wl_touch - touchscreen input device
+ * @down: touch down event and beginning of a touch sequence
+ * @up: end of a touch event sequence
+ * @motion: update of touch point coordinates
+ * @frame: end of touch frame event
+ * @cancel: touch session cancelled
+ *
+ * The wl_touch interface represents a touchscreen associated with a
+ * seat.
+ *
+ * Touch interactions can consist of one or more contacts. For each
+ * contact, a series of events is generated, starting with a down event,
+ * followed by zero or more motion events, and ending with an up event.
+ * Events relating to the same contact point can be identified by the ID of
+ * the sequence.
+ */
+struct wl_touch_listener {
+	/**
+	 * down - touch down event and beginning of a touch sequence
+	 * @serial: (none)
+	 * @time: timestamp with millisecond granularity
+	 * @surface: (none)
+	 * @id: the unique ID of this touch point
+	 * @x: x coordinate in surface-relative coordinates
+	 * @y: y coordinate in surface-relative coordinates
+	 *
+	 * A new touch point has appeared on the surface. This touch
+	 * point is assigned a unique @id. Future events from this
+	 * touchpoint reference this ID. The ID ceases to be valid after a
+	 * touch up event and may be re-used in the future.
+	 */
+	void (*down)(void *data,
+		     struct wl_touch *wl_touch,
+		     uint32_t serial,
+		     uint32_t time,
+		     struct wl_surface *surface,
+		     int32_t id,
+		     wl_fixed_t x,
+		     wl_fixed_t y);
+	/**
+	 * up - end of a touch event sequence
+	 * @serial: (none)
+	 * @time: timestamp with millisecond granularity
+	 * @id: the unique ID of this touch point
+	 *
+	 * The touch point has disappeared. No further events will be
+	 * sent for this touchpoint and the touch point's ID is released
+	 * and may be re-used in a future touch down event.
+	 */
+	void (*up)(void *data,
+		   struct wl_touch *wl_touch,
+		   uint32_t serial,
+		   uint32_t time,
+		   int32_t id);
+	/**
+	 * motion - update of touch point coordinates
+	 * @time: timestamp with millisecond granularity
+	 * @id: the unique ID of this touch point
+	 * @x: x coordinate in surface-relative coordinates
+	 * @y: y coordinate in surface-relative coordinates
+	 *
+	 * A touchpoint has changed coordinates.
+	 */
+	void (*motion)(void *data,
+		       struct wl_touch *wl_touch,
+		       uint32_t time,
+		       int32_t id,
+		       wl_fixed_t x,
+		       wl_fixed_t y);
+	/**
+	 * frame - end of touch frame event
+	 *
+	 * Indicates the end of a contact point list.
+	 */
+	void (*frame)(void *data,
+		      struct wl_touch *wl_touch);
+	/**
+	 * cancel - touch session cancelled
+	 *
+	 * Sent if the compositor decides the touch stream is a global
+	 * gesture. No further events are sent to the clients from that
+	 * particular gesture. Touch cancellation applies to all touch
+	 * points currently active on this client's surface. The client is
+	 * responsible for finalizing the touch points, future touch points
+	 * on this surface may re-use the touch point ID.
+	 */
+	void (*cancel)(void *data,
+		       struct wl_touch *wl_touch);
+};
+
+static inline int
+wl_touch_add_listener(struct wl_touch *wl_touch,
+		      const struct wl_touch_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_touch,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_TOUCH_RELEASE	0
+
+static inline void
+wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data);
+}
+
+static inline void *
+wl_touch_get_user_data(struct wl_touch *wl_touch)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_touch);
+}
+
+static inline void
+wl_touch_destroy(struct wl_touch *wl_touch)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_touch);
+}
+
+static inline void
+wl_touch_release(struct wl_touch *wl_touch)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_touch,
+			 WL_TOUCH_RELEASE);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_touch);
+}
+
+#ifndef WL_OUTPUT_SUBPIXEL_ENUM
+#define WL_OUTPUT_SUBPIXEL_ENUM
+/**
+ * wl_output_subpixel - subpixel geometry information
+ * @WL_OUTPUT_SUBPIXEL_UNKNOWN: (none)
+ * @WL_OUTPUT_SUBPIXEL_NONE: (none)
+ * @WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: (none)
+ * @WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: (none)
+ * @WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: (none)
+ * @WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: (none)
+ *
+ * This enumeration describes how the physical pixels on an output are
+ * laid out.
+ */
+enum wl_output_subpixel {
+	WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
+	WL_OUTPUT_SUBPIXEL_NONE = 1,
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
+	WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
+	WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
+};
+#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
+
+#ifndef WL_OUTPUT_TRANSFORM_ENUM
+#define WL_OUTPUT_TRANSFORM_ENUM
+/**
+ * wl_output_transform - transform from framebuffer to output
+ * @WL_OUTPUT_TRANSFORM_NORMAL: (none)
+ * @WL_OUTPUT_TRANSFORM_90: (none)
+ * @WL_OUTPUT_TRANSFORM_180: (none)
+ * @WL_OUTPUT_TRANSFORM_270: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_90: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_180: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_270: (none)
+ *
+ * This describes the transform that a compositor will apply to a surface
+ * to compensate for the rotation or mirroring of an output device.
+ *
+ * The flipped values correspond to an initial flip around a vertical axis
+ * followed by rotation.
+ *
+ * The purpose is mainly to allow clients render accordingly and tell the
+ * compositor, so that for fullscreen surfaces, the compositor will still
+ * be able to scan out directly from client surfaces.
+ */
+enum wl_output_transform {
+	WL_OUTPUT_TRANSFORM_NORMAL = 0,
+	WL_OUTPUT_TRANSFORM_90 = 1,
+	WL_OUTPUT_TRANSFORM_180 = 2,
+	WL_OUTPUT_TRANSFORM_270 = 3,
+	WL_OUTPUT_TRANSFORM_FLIPPED = 4,
+	WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
+	WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
+	WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
+};
+#endif /* WL_OUTPUT_TRANSFORM_ENUM */
+
+#ifndef WL_OUTPUT_MODE_ENUM
+#define WL_OUTPUT_MODE_ENUM
+/**
+ * wl_output_mode - mode information
+ * @WL_OUTPUT_MODE_CURRENT: indicates this is the current mode
+ * @WL_OUTPUT_MODE_PREFERRED: indicates this is the preferred mode
+ *
+ * These flags describe properties of an output mode. They are used in
+ * the flags bitfield of the mode event.
+ */
+enum wl_output_mode {
+	WL_OUTPUT_MODE_CURRENT = 0x1,
+	WL_OUTPUT_MODE_PREFERRED = 0x2,
+};
+#endif /* WL_OUTPUT_MODE_ENUM */
+
+/**
+ * wl_output - compositor output region
+ * @geometry: properties of the output
+ * @mode: advertise available modes for the output
+ * @done: sent all information about output
+ * @scale: output scaling properties
+ *
+ * An output describes part of the compositor geometry. The compositor
+ * works in the 'compositor coordinate system' and an output corresponds to
+ * rectangular area in that space that is actually visible. This typically
+ * corresponds to a monitor that displays part of the compositor space.
+ * This object is published as global during start up, or when a monitor is
+ * hotplugged.
+ */
+struct wl_output_listener {
+	/**
+	 * geometry - properties of the output
+	 * @x: x position within the global compositor space
+	 * @y: y position within the global compositor space
+	 * @physical_width: width in millimeters of the output
+	 * @physical_height: height in millimeters of the output
+	 * @subpixel: subpixel orientation of the output
+	 * @make: textual description of the manufacturer
+	 * @model: textual description of the model
+	 * @transform: transform that maps framebuffer to output
+	 *
+	 * The geometry event describes geometric properties of the
+	 * output. The event is sent when binding to the output object and
+	 * whenever any of the properties change.
+	 */
+	void (*geometry)(void *data,
+			 struct wl_output *wl_output,
+			 int32_t x,
+			 int32_t y,
+			 int32_t physical_width,
+			 int32_t physical_height,
+			 int32_t subpixel,
+			 const char *make,
+			 const char *model,
+			 int32_t transform);
+	/**
+	 * mode - advertise available modes for the output
+	 * @flags: bitfield of mode flags
+	 * @width: width of the mode in hardware units
+	 * @height: height of the mode in hardware units
+	 * @refresh: vertical refresh rate in mHz
+	 *
+	 * The mode event describes an available mode for the output.
+	 *
+	 * The event is sent when binding to the output object and there
+	 * will always be one mode, the current mode. The event is sent
+	 * again if an output changes mode, for the mode that is now
+	 * current. In other words, the current mode is always the last
+	 * mode that was received with the current flag set.
+	 *
+	 * The size of a mode is given in physical hardware units of the
+	 * output device. This is not necessarily the same as the output
+	 * size in the global compositor space. For instance, the output
+	 * may be scaled, as described in wl_output.scale, or transformed ,
+	 * as described in wl_output.transform.
+	 */
+	void (*mode)(void *data,
+		     struct wl_output *wl_output,
+		     uint32_t flags,
+		     int32_t width,
+		     int32_t height,
+		     int32_t refresh);
+	/**
+	 * done - sent all information about output
+	 *
+	 * This event is sent after all other properties has been sent
+	 * after binding to the output object and after any other property
+	 * changes done after that. This allows changes to the output
+	 * properties to be seen as atomic, even if they happen via
+	 * multiple events.
+	 * @since: 2
+	 */
+	void (*done)(void *data,
+		     struct wl_output *wl_output);
+	/**
+	 * scale - output scaling properties
+	 * @factor: scaling factor of output
+	 *
+	 * This event contains scaling geometry information that is not
+	 * in the geometry event. It may be sent after binding the output
+	 * object or if the output scale changes later. If it is not sent,
+	 * the client should assume a scale of 1.
+	 *
+	 * A scale larger than 1 means that the compositor will
+	 * automatically scale surface buffers by this amount when
+	 * rendering. This is used for very high resolution displays where
+	 * applications rendering at the native resolution would be too
+	 * small to be legible.
+	 *
+	 * It is intended that scaling aware clients track the current
+	 * output of a surface, and if it is on a scaled output it should
+	 * use wl_surface.set_buffer_scale with the scale of the output.
+	 * That way the compositor can avoid scaling the surface, and the
+	 * client can supply a higher detail image.
+	 * @since: 2
+	 */
+	void (*scale)(void *data,
+		      struct wl_output *wl_output,
+		      int32_t factor);
+};
+
+static inline int
+wl_output_add_listener(struct wl_output *wl_output,
+		       const struct wl_output_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_output,
+				     (void (**)(void)) listener, data);
+}
+
+static inline void
+wl_output_set_user_data(struct wl_output *wl_output, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data);
+}
+
+static inline void *
+wl_output_get_user_data(struct wl_output *wl_output)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_output);
+}
+
+static inline void
+wl_output_destroy(struct wl_output *wl_output)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_output);
+}
+
+#define WL_REGION_DESTROY	0
+#define WL_REGION_ADD	1
+#define WL_REGION_SUBTRACT	2
+
+static inline void
+wl_region_set_user_data(struct wl_region *wl_region, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data);
+}
+
+static inline void *
+wl_region_get_user_data(struct wl_region *wl_region)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_region);
+}
+
+static inline void
+wl_region_destroy(struct wl_region *wl_region)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_region,
+			 WL_REGION_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_region);
+}
+
+static inline void
+wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_region,
+			 WL_REGION_ADD, x, y, width, height);
+}
+
+static inline void
+wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_region,
+			 WL_REGION_SUBTRACT, x, y, width, height);
+}
+
+#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
+#define WL_SUBCOMPOSITOR_ERROR_ENUM
+enum wl_subcompositor_error {
+	WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
+
+#define WL_SUBCOMPOSITOR_DESTROY	0
+#define WL_SUBCOMPOSITOR_GET_SUBSURFACE	1
+
+static inline void
+wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data);
+}
+
+static inline void *
+wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor);
+}
+
+static inline void
+wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subcompositor,
+			 WL_SUBCOMPOSITOR_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_subcompositor);
+}
+
+static inline struct wl_subsurface *
+wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_subcompositor,
+			 WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, NULL, surface, parent);
+
+	return (struct wl_subsurface *) id;
+}
+
+#ifndef WL_SUBSURFACE_ERROR_ENUM
+#define WL_SUBSURFACE_ERROR_ENUM
+enum wl_subsurface_error {
+	WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBSURFACE_ERROR_ENUM */
+
+#define WL_SUBSURFACE_DESTROY	0
+#define WL_SUBSURFACE_SET_POSITION	1
+#define WL_SUBSURFACE_PLACE_ABOVE	2
+#define WL_SUBSURFACE_PLACE_BELOW	3
+#define WL_SUBSURFACE_SET_SYNC	4
+#define WL_SUBSURFACE_SET_DESYNC	5
+
+static inline void
+wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data);
+}
+
+static inline void *
+wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface);
+}
+
+static inline void
+wl_subsurface_destroy(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_subsurface);
+}
+
+static inline void
+wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_POSITION, x, y);
+}
+
+static inline void
+wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_PLACE_ABOVE, sibling);
+}
+
+static inline void
+wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_PLACE_BELOW, sibling);
+}
+
+static inline void
+wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_SYNC);
+}
+
+static inline void
+wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_DESYNC);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/wayland/include/protocol/wayland-client-protocol.h b/third_party/wayland/include/protocol/wayland-client-protocol.h
new file mode 100644
index 0000000..8112d8d
--- /dev/null
+++ b/third_party/wayland/include/protocol/wayland-client-protocol.h
@@ -0,0 +1,2523 @@
+/* 
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ * 
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_CLIENT_PROTOCOL_H
+#define WAYLAND_CLIENT_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct wl_buffer;
+struct wl_callback;
+struct wl_compositor;
+struct wl_data_device;
+struct wl_data_device_manager;
+struct wl_data_offer;
+struct wl_data_source;
+struct wl_display;
+struct wl_keyboard;
+struct wl_output;
+struct wl_pointer;
+struct wl_region;
+struct wl_registry;
+struct wl_seat;
+struct wl_shell;
+struct wl_shell_surface;
+struct wl_shm;
+struct wl_shm_pool;
+struct wl_subcompositor;
+struct wl_subsurface;
+struct wl_surface;
+struct wl_touch;
+
+extern const struct wl_interface wl_display_interface;
+extern const struct wl_interface wl_registry_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_compositor_interface;
+extern const struct wl_interface wl_shm_pool_interface;
+extern const struct wl_interface wl_shm_interface;
+extern const struct wl_interface wl_buffer_interface;
+extern const struct wl_interface wl_data_offer_interface;
+extern const struct wl_interface wl_data_source_interface;
+extern const struct wl_interface wl_data_device_interface;
+extern const struct wl_interface wl_data_device_manager_interface;
+extern const struct wl_interface wl_shell_interface;
+extern const struct wl_interface wl_shell_surface_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_touch_interface;
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_region_interface;
+extern const struct wl_interface wl_subcompositor_interface;
+extern const struct wl_interface wl_subsurface_interface;
+
+#ifndef WL_DISPLAY_ERROR_ENUM
+#define WL_DISPLAY_ERROR_ENUM
+/**
+ * wl_display_error - global error values
+ * @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
+ * @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the
+ *	specified interface
+ * @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
+ *
+ * These errors are global and can be emitted in response to any server
+ * request.
+ */
+enum wl_display_error {
+	WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
+	WL_DISPLAY_ERROR_INVALID_METHOD = 1,
+	WL_DISPLAY_ERROR_NO_MEMORY = 2,
+};
+#endif /* WL_DISPLAY_ERROR_ENUM */
+
+/**
+ * wl_display - core global object
+ * @error: fatal error event
+ * @delete_id: acknowledge object ID deletion
+ *
+ * The core global object. This is a special singleton object. It is used
+ * for internal Wayland protocol features.
+ */
+struct wl_display_listener {
+	/**
+	 * error - fatal error event
+	 * @object_id: (none)
+	 * @code: (none)
+	 * @message: (none)
+	 *
+	 * The error event is sent out when a fatal (non-recoverable)
+	 * error has occurred. The object_id argument is the object where
+	 * the error occurred, most often in response to a request to that
+	 * object. The code identifies the error and is defined by the
+	 * object interface. As such, each interface defines its own set of
+	 * error codes. The message is an brief description of the error,
+	 * for (debugging) convenience.
+	 */
+	void (*error)(void *data,
+		      struct wl_display *wl_display,
+		      void *object_id,
+		      uint32_t code,
+		      const char *message);
+	/**
+	 * delete_id - acknowledge object ID deletion
+	 * @id: (none)
+	 *
+	 * This event is used internally by the object ID management
+	 * logic. When a client deletes an object, the server will send
+	 * this event to acknowledge that it has seen the delete request.
+	 * When the client receive this event, it will know that it can
+	 * safely reuse the object ID.
+	 */
+	void (*delete_id)(void *data,
+			  struct wl_display *wl_display,
+			  uint32_t id);
+};
+
+static inline int
+wl_display_add_listener(struct wl_display *wl_display,
+			const struct wl_display_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_display,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DISPLAY_SYNC	0
+#define WL_DISPLAY_GET_REGISTRY	1
+
+static inline void
+wl_display_set_user_data(struct wl_display *wl_display, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data);
+}
+
+static inline void *
+wl_display_get_user_data(struct wl_display *wl_display)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_display);
+}
+
+static inline struct wl_callback *
+wl_display_sync(struct wl_display *wl_display)
+{
+	struct wl_proxy *callback;
+
+	callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display,
+			 WL_DISPLAY_SYNC, &wl_callback_interface, NULL);
+
+	return (struct wl_callback *) callback;
+}
+
+static inline struct wl_registry *
+wl_display_get_registry(struct wl_display *wl_display)
+{
+	struct wl_proxy *registry;
+
+	registry = wl_proxy_marshal_constructor((struct wl_proxy *) wl_display,
+			 WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, NULL);
+
+	return (struct wl_registry *) registry;
+}
+
+/**
+ * wl_registry - global registry object
+ * @global: announce global object
+ * @global_remove: announce removal of global object
+ *
+ * The global registry object. The server has a number of global objects
+ * that are available to all clients. These objects typically represent an
+ * actual object in the server (for example, an input device) or they are
+ * singleton objects that provide extension functionality.
+ *
+ * When a client creates a registry object, the registry object will emit a
+ * global event for each global currently in the registry. Globals come and
+ * go as a result of device or monitor hotplugs, reconfiguration or other
+ * events, and the registry will send out global and global_remove events
+ * to keep the client up to date with the changes. To mark the end of the
+ * initial burst of events, the client can use the wl_display.sync request
+ * immediately after calling wl_display.get_registry.
+ *
+ * A client can bind to a global object by using the bind request. This
+ * creates a client-side handle that lets the object emit events to the
+ * client and lets the client invoke requests on the object.
+ */
+struct wl_registry_listener {
+	/**
+	 * global - announce global object
+	 * @name: (none)
+	 * @interface: (none)
+	 * @version: (none)
+	 *
+	 * Notify the client of global objects.
+	 *
+	 * The event notifies the client that a global object with the
+	 * given name is now available, and it implements the given version
+	 * of the given interface.
+	 */
+	void (*global)(void *data,
+		       struct wl_registry *wl_registry,
+		       uint32_t name,
+		       const char *interface,
+		       uint32_t version);
+	/**
+	 * global_remove - announce removal of global object
+	 * @name: (none)
+	 *
+	 * Notify the client of removed global objects.
+	 *
+	 * This event notifies the client that the global identified by
+	 * name is no longer available. If the client bound to the global
+	 * using the bind request, the client should now destroy that
+	 * object.
+	 *
+	 * The object remains valid and requests to the object will be
+	 * ignored until the client destroys it, to avoid races between the
+	 * global going away and a client sending a request to it.
+	 */
+	void (*global_remove)(void *data,
+			      struct wl_registry *wl_registry,
+			      uint32_t name);
+};
+
+static inline int
+wl_registry_add_listener(struct wl_registry *wl_registry,
+			 const struct wl_registry_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_registry,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_REGISTRY_BIND	0
+
+static inline void
+wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data);
+}
+
+static inline void *
+wl_registry_get_user_data(struct wl_registry *wl_registry)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_registry);
+}
+
+static inline void
+wl_registry_destroy(struct wl_registry *wl_registry)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_registry);
+}
+
+static inline void *
+wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_registry,
+			 WL_REGISTRY_BIND, interface, name, interface->name, version, NULL);
+
+	return (void *) id;
+}
+
+/**
+ * wl_callback - callback object
+ * @done: done event
+ *
+ * Clients can handle the 'done' event to get notified when the related
+ * request is done.
+ */
+struct wl_callback_listener {
+	/**
+	 * done - done event
+	 * @callback_data: request-specific data for the wl_callback
+	 *
+	 * Notify the client when the related request is done.
+	 */
+	void (*done)(void *data,
+		     struct wl_callback *wl_callback,
+		     uint32_t callback_data);
+};
+
+static inline int
+wl_callback_add_listener(struct wl_callback *wl_callback,
+			 const struct wl_callback_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_callback,
+				     (void (**)(void)) listener, data);
+}
+
+static inline void
+wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data);
+}
+
+static inline void *
+wl_callback_get_user_data(struct wl_callback *wl_callback)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_callback);
+}
+
+static inline void
+wl_callback_destroy(struct wl_callback *wl_callback)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_callback);
+}
+
+#define WL_COMPOSITOR_CREATE_SURFACE	0
+#define WL_COMPOSITOR_CREATE_REGION	1
+
+static inline void
+wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data);
+}
+
+static inline void *
+wl_compositor_get_user_data(struct wl_compositor *wl_compositor)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor);
+}
+
+static inline void
+wl_compositor_destroy(struct wl_compositor *wl_compositor)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_compositor);
+}
+
+static inline struct wl_surface *
+wl_compositor_create_surface(struct wl_compositor *wl_compositor)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
+			 WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, NULL);
+
+	return (struct wl_surface *) id;
+}
+
+static inline struct wl_region *
+wl_compositor_create_region(struct wl_compositor *wl_compositor)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_compositor,
+			 WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, NULL);
+
+	return (struct wl_region *) id;
+}
+
+#define WL_SHM_POOL_CREATE_BUFFER	0
+#define WL_SHM_POOL_DESTROY	1
+#define WL_SHM_POOL_RESIZE	2
+
+static inline void
+wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data);
+}
+
+static inline void *
+wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool);
+}
+
+static inline struct wl_buffer *
+wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, NULL, offset, width, height, stride, format);
+
+	return (struct wl_buffer *) id;
+}
+
+static inline void
+wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_shm_pool);
+}
+
+static inline void
+wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_RESIZE, size);
+}
+
+#ifndef WL_SHM_ERROR_ENUM
+#define WL_SHM_ERROR_ENUM
+/**
+ * wl_shm_error - wl_shm error values
+ * @WL_SHM_ERROR_INVALID_FORMAT: buffer format is not known
+ * @WL_SHM_ERROR_INVALID_STRIDE: invalid size or stride during pool or
+ *	buffer creation
+ * @WL_SHM_ERROR_INVALID_FD: mmapping the file descriptor failed
+ *
+ * These errors can be emitted in response to wl_shm requests.
+ */
+enum wl_shm_error {
+	WL_SHM_ERROR_INVALID_FORMAT = 0,
+	WL_SHM_ERROR_INVALID_STRIDE = 1,
+	WL_SHM_ERROR_INVALID_FD = 2,
+};
+#endif /* WL_SHM_ERROR_ENUM */
+
+#ifndef WL_SHM_FORMAT_ENUM
+#define WL_SHM_FORMAT_ENUM
+/**
+ * wl_shm_format - pixel formats
+ * @WL_SHM_FORMAT_ARGB8888: 32-bit ARGB format
+ * @WL_SHM_FORMAT_XRGB8888: 32-bit RGB format
+ * @WL_SHM_FORMAT_C8: (none)
+ * @WL_SHM_FORMAT_RGB332: (none)
+ * @WL_SHM_FORMAT_BGR233: (none)
+ * @WL_SHM_FORMAT_XRGB4444: (none)
+ * @WL_SHM_FORMAT_XBGR4444: (none)
+ * @WL_SHM_FORMAT_RGBX4444: (none)
+ * @WL_SHM_FORMAT_BGRX4444: (none)
+ * @WL_SHM_FORMAT_ARGB4444: (none)
+ * @WL_SHM_FORMAT_ABGR4444: (none)
+ * @WL_SHM_FORMAT_RGBA4444: (none)
+ * @WL_SHM_FORMAT_BGRA4444: (none)
+ * @WL_SHM_FORMAT_XRGB1555: (none)
+ * @WL_SHM_FORMAT_XBGR1555: (none)
+ * @WL_SHM_FORMAT_RGBX5551: (none)
+ * @WL_SHM_FORMAT_BGRX5551: (none)
+ * @WL_SHM_FORMAT_ARGB1555: (none)
+ * @WL_SHM_FORMAT_ABGR1555: (none)
+ * @WL_SHM_FORMAT_RGBA5551: (none)
+ * @WL_SHM_FORMAT_BGRA5551: (none)
+ * @WL_SHM_FORMAT_RGB565: (none)
+ * @WL_SHM_FORMAT_BGR565: (none)
+ * @WL_SHM_FORMAT_RGB888: (none)
+ * @WL_SHM_FORMAT_BGR888: (none)
+ * @WL_SHM_FORMAT_XBGR8888: (none)
+ * @WL_SHM_FORMAT_RGBX8888: (none)
+ * @WL_SHM_FORMAT_BGRX8888: (none)
+ * @WL_SHM_FORMAT_ABGR8888: (none)
+ * @WL_SHM_FORMAT_RGBA8888: (none)
+ * @WL_SHM_FORMAT_BGRA8888: (none)
+ * @WL_SHM_FORMAT_XRGB2101010: (none)
+ * @WL_SHM_FORMAT_XBGR2101010: (none)
+ * @WL_SHM_FORMAT_RGBX1010102: (none)
+ * @WL_SHM_FORMAT_BGRX1010102: (none)
+ * @WL_SHM_FORMAT_ARGB2101010: (none)
+ * @WL_SHM_FORMAT_ABGR2101010: (none)
+ * @WL_SHM_FORMAT_RGBA1010102: (none)
+ * @WL_SHM_FORMAT_BGRA1010102: (none)
+ * @WL_SHM_FORMAT_YUYV: (none)
+ * @WL_SHM_FORMAT_YVYU: (none)
+ * @WL_SHM_FORMAT_UYVY: (none)
+ * @WL_SHM_FORMAT_VYUY: (none)
+ * @WL_SHM_FORMAT_AYUV: (none)
+ * @WL_SHM_FORMAT_NV12: (none)
+ * @WL_SHM_FORMAT_NV21: (none)
+ * @WL_SHM_FORMAT_NV16: (none)
+ * @WL_SHM_FORMAT_NV61: (none)
+ * @WL_SHM_FORMAT_YUV410: (none)
+ * @WL_SHM_FORMAT_YVU410: (none)
+ * @WL_SHM_FORMAT_YUV411: (none)
+ * @WL_SHM_FORMAT_YVU411: (none)
+ * @WL_SHM_FORMAT_YUV420: (none)
+ * @WL_SHM_FORMAT_YVU420: (none)
+ * @WL_SHM_FORMAT_YUV422: (none)
+ * @WL_SHM_FORMAT_YVU422: (none)
+ * @WL_SHM_FORMAT_YUV444: (none)
+ * @WL_SHM_FORMAT_YVU444: (none)
+ *
+ * This describes the memory layout of an individual pixel.
+ *
+ * All renderers should support argb8888 and xrgb8888 but any other formats
+ * are optional and may not be supported by the particular renderer in use.
+ */
+enum wl_shm_format {
+	WL_SHM_FORMAT_ARGB8888 = 0,
+	WL_SHM_FORMAT_XRGB8888 = 1,
+	WL_SHM_FORMAT_C8 = 0x20203843,
+	WL_SHM_FORMAT_RGB332 = 0x38424752,
+	WL_SHM_FORMAT_BGR233 = 0x38524742,
+	WL_SHM_FORMAT_XRGB4444 = 0x32315258,
+	WL_SHM_FORMAT_XBGR4444 = 0x32314258,
+	WL_SHM_FORMAT_RGBX4444 = 0x32315852,
+	WL_SHM_FORMAT_BGRX4444 = 0x32315842,
+	WL_SHM_FORMAT_ARGB4444 = 0x32315241,
+	WL_SHM_FORMAT_ABGR4444 = 0x32314241,
+	WL_SHM_FORMAT_RGBA4444 = 0x32314152,
+	WL_SHM_FORMAT_BGRA4444 = 0x32314142,
+	WL_SHM_FORMAT_XRGB1555 = 0x35315258,
+	WL_SHM_FORMAT_XBGR1555 = 0x35314258,
+	WL_SHM_FORMAT_RGBX5551 = 0x35315852,
+	WL_SHM_FORMAT_BGRX5551 = 0x35315842,
+	WL_SHM_FORMAT_ARGB1555 = 0x35315241,
+	WL_SHM_FORMAT_ABGR1555 = 0x35314241,
+	WL_SHM_FORMAT_RGBA5551 = 0x35314152,
+	WL_SHM_FORMAT_BGRA5551 = 0x35314142,
+	WL_SHM_FORMAT_RGB565 = 0x36314752,
+	WL_SHM_FORMAT_BGR565 = 0x36314742,
+	WL_SHM_FORMAT_RGB888 = 0x34324752,
+	WL_SHM_FORMAT_BGR888 = 0x34324742,
+	WL_SHM_FORMAT_XBGR8888 = 0x34324258,
+	WL_SHM_FORMAT_RGBX8888 = 0x34325852,
+	WL_SHM_FORMAT_BGRX8888 = 0x34325842,
+	WL_SHM_FORMAT_ABGR8888 = 0x34324241,
+	WL_SHM_FORMAT_RGBA8888 = 0x34324152,
+	WL_SHM_FORMAT_BGRA8888 = 0x34324142,
+	WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
+	WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
+	WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
+	WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
+	WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
+	WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
+	WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
+	WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
+	WL_SHM_FORMAT_YUYV = 0x56595559,
+	WL_SHM_FORMAT_YVYU = 0x55595659,
+	WL_SHM_FORMAT_UYVY = 0x59565955,
+	WL_SHM_FORMAT_VYUY = 0x59555956,
+	WL_SHM_FORMAT_AYUV = 0x56555941,
+	WL_SHM_FORMAT_NV12 = 0x3231564e,
+	WL_SHM_FORMAT_NV21 = 0x3132564e,
+	WL_SHM_FORMAT_NV16 = 0x3631564e,
+	WL_SHM_FORMAT_NV61 = 0x3136564e,
+	WL_SHM_FORMAT_YUV410 = 0x39565559,
+	WL_SHM_FORMAT_YVU410 = 0x39555659,
+	WL_SHM_FORMAT_YUV411 = 0x31315559,
+	WL_SHM_FORMAT_YVU411 = 0x31315659,
+	WL_SHM_FORMAT_YUV420 = 0x32315559,
+	WL_SHM_FORMAT_YVU420 = 0x32315659,
+	WL_SHM_FORMAT_YUV422 = 0x36315559,
+	WL_SHM_FORMAT_YVU422 = 0x36315659,
+	WL_SHM_FORMAT_YUV444 = 0x34325559,
+	WL_SHM_FORMAT_YVU444 = 0x34325659,
+};
+#endif /* WL_SHM_FORMAT_ENUM */
+
+/**
+ * wl_shm - shared memory support
+ * @format: pixel format description
+ *
+ * A global singleton object that provides support for shared memory.
+ *
+ * Clients can create wl_shm_pool objects using the create_pool request.
+ *
+ * At connection setup time, the wl_shm object emits one or more format
+ * events to inform clients about the valid pixel formats that can be used
+ * for buffers.
+ */
+struct wl_shm_listener {
+	/**
+	 * format - pixel format description
+	 * @format: (none)
+	 *
+	 * Informs the client about a valid pixel format that can be used
+	 * for buffers. Known formats include argb8888 and xrgb8888.
+	 */
+	void (*format)(void *data,
+		       struct wl_shm *wl_shm,
+		       uint32_t format);
+};
+
+static inline int
+wl_shm_add_listener(struct wl_shm *wl_shm,
+		    const struct wl_shm_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_shm,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SHM_CREATE_POOL	0
+
+static inline void
+wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data);
+}
+
+static inline void *
+wl_shm_get_user_data(struct wl_shm *wl_shm)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shm);
+}
+
+static inline void
+wl_shm_destroy(struct wl_shm *wl_shm)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shm);
+}
+
+static inline struct wl_shm_pool *
+wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shm,
+			 WL_SHM_CREATE_POOL, &wl_shm_pool_interface, NULL, fd, size);
+
+	return (struct wl_shm_pool *) id;
+}
+
+/**
+ * wl_buffer - content for a wl_surface
+ * @release: compositor releases buffer
+ *
+ * A buffer provides the content for a wl_surface. Buffers are created
+ * through factory interfaces such as wl_drm, wl_shm or similar. It has a
+ * width and a height and can be attached to a wl_surface, but the
+ * mechanism by which a client provides and updates the contents is defined
+ * by the buffer factory interface.
+ */
+struct wl_buffer_listener {
+	/**
+	 * release - compositor releases buffer
+	 *
+	 * Sent when this wl_buffer is no longer used by the compositor.
+	 * The client is now free to re-use or destroy this buffer and its
+	 * backing storage.
+	 *
+	 * If a client receives a release event before the frame callback
+	 * requested in the same wl_surface.commit that attaches this
+	 * wl_buffer to a surface, then the client is immediately free to
+	 * re-use the buffer and its backing storage, and does not need a
+	 * second buffer for the next surface content update. Typically
+	 * this is possible, when the compositor maintains a copy of the
+	 * wl_surface contents, e.g. as a GL texture. This is an important
+	 * optimization for GL(ES) compositors with wl_shm clients.
+	 */
+	void (*release)(void *data,
+			struct wl_buffer *wl_buffer);
+};
+
+static inline int
+wl_buffer_add_listener(struct wl_buffer *wl_buffer,
+		       const struct wl_buffer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_buffer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_BUFFER_DESTROY	0
+
+static inline void
+wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data);
+}
+
+static inline void *
+wl_buffer_get_user_data(struct wl_buffer *wl_buffer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer);
+}
+
+static inline void
+wl_buffer_destroy(struct wl_buffer *wl_buffer)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_buffer,
+			 WL_BUFFER_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_buffer);
+}
+
+/**
+ * wl_data_offer - offer to transfer data
+ * @offer: advertise offered mime type
+ *
+ * A wl_data_offer represents a piece of data offered for transfer by
+ * another client (the source client). It is used by the copy-and-paste and
+ * drag-and-drop mechanisms. The offer describes the different mime types
+ * that the data can be converted to and provides the mechanism for
+ * transferring the data directly from the source client.
+ */
+struct wl_data_offer_listener {
+	/**
+	 * offer - advertise offered mime type
+	 * @mime_type: (none)
+	 *
+	 * Sent immediately after creating the wl_data_offer object. One
+	 * event per offered mime type.
+	 */
+	void (*offer)(void *data,
+		      struct wl_data_offer *wl_data_offer,
+		      const char *mime_type);
+};
+
+static inline int
+wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer,
+			   const struct wl_data_offer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_OFFER_ACCEPT	0
+#define WL_DATA_OFFER_RECEIVE	1
+#define WL_DATA_OFFER_DESTROY	2
+
+static inline void
+wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data);
+}
+
+static inline void *
+wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer);
+}
+
+static inline void
+wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_ACCEPT, serial, mime_type);
+}
+
+static inline void
+wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_RECEIVE, mime_type, fd);
+}
+
+static inline void
+wl_data_offer_destroy(struct wl_data_offer *wl_data_offer)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_data_offer);
+}
+
+/**
+ * wl_data_source - offer to transfer data
+ * @target: a target accepts an offered mime type
+ * @send: send the data
+ * @cancelled: selection was cancelled
+ *
+ * The wl_data_source object is the source side of a wl_data_offer. It is
+ * created by the source client in a data transfer and provides a way to
+ * describe the offered data and a way to respond to requests to transfer
+ * the data.
+ */
+struct wl_data_source_listener {
+	/**
+	 * target - a target accepts an offered mime type
+	 * @mime_type: (none)
+	 *
+	 * Sent when a target accepts pointer_focus or motion events. If
+	 * a target does not accept any of the offered types, type is NULL.
+	 *
+	 * Used for feedback during drag-and-drop.
+	 */
+	void (*target)(void *data,
+		       struct wl_data_source *wl_data_source,
+		       const char *mime_type);
+	/**
+	 * send - send the data
+	 * @mime_type: (none)
+	 * @fd: (none)
+	 *
+	 * Request for data from the client. Send the data as the
+	 * specified mime type over the passed file descriptor, then close
+	 * it.
+	 */
+	void (*send)(void *data,
+		     struct wl_data_source *wl_data_source,
+		     const char *mime_type,
+		     int32_t fd);
+	/**
+	 * cancelled - selection was cancelled
+	 *
+	 * This data source has been replaced by another data source. The
+	 * client should clean up and destroy this data source.
+	 */
+	void (*cancelled)(void *data,
+			  struct wl_data_source *wl_data_source);
+};
+
+static inline int
+wl_data_source_add_listener(struct wl_data_source *wl_data_source,
+			    const struct wl_data_source_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_source,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_SOURCE_OFFER	0
+#define WL_DATA_SOURCE_DESTROY	1
+
+static inline void
+wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data);
+}
+
+static inline void *
+wl_data_source_get_user_data(struct wl_data_source *wl_data_source)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source);
+}
+
+static inline void
+wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_source,
+			 WL_DATA_SOURCE_OFFER, mime_type);
+}
+
+static inline void
+wl_data_source_destroy(struct wl_data_source *wl_data_source)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_source,
+			 WL_DATA_SOURCE_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_data_source);
+}
+
+#ifndef WL_DATA_DEVICE_ERROR_ENUM
+#define WL_DATA_DEVICE_ERROR_ENUM
+enum wl_data_device_error {
+	WL_DATA_DEVICE_ERROR_ROLE = 0,
+};
+#endif /* WL_DATA_DEVICE_ERROR_ENUM */
+
+/**
+ * wl_data_device - data transfer device
+ * @data_offer: introduce a new wl_data_offer
+ * @enter: initiate drag-and-drop session
+ * @leave: end drag-and-drop session
+ * @motion: drag-and-drop session motion
+ * @drop: end drag-and-drag session successfully
+ * @selection: advertise new selection
+ *
+ * There is one wl_data_device per seat which can be obtained from the
+ * global wl_data_device_manager singleton.
+ *
+ * A wl_data_device provides access to inter-client data transfer
+ * mechanisms such as copy-and-paste and drag-and-drop.
+ */
+struct wl_data_device_listener {
+	/**
+	 * data_offer - introduce a new wl_data_offer
+	 * @id: (none)
+	 *
+	 * The data_offer event introduces a new wl_data_offer object,
+	 * which will subsequently be used in either the data_device.enter
+	 * event (for drag-and-drop) or the data_device.selection event
+	 * (for selections). Immediately following the
+	 * data_device_data_offer event, the new data_offer object will
+	 * send out data_offer.offer events to describe the mime types it
+	 * offers.
+	 */
+	void (*data_offer)(void *data,
+			   struct wl_data_device *wl_data_device,
+			   struct wl_data_offer *id);
+	/**
+	 * enter - initiate drag-and-drop session
+	 * @serial: (none)
+	 * @surface: (none)
+	 * @x: (none)
+	 * @y: (none)
+	 * @id: (none)
+	 *
+	 * This event is sent when an active drag-and-drop pointer enters
+	 * a surface owned by the client. The position of the pointer at
+	 * enter time is provided by the x and y arguments, in surface
+	 * local coordinates.
+	 */
+	void (*enter)(void *data,
+		      struct wl_data_device *wl_data_device,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      wl_fixed_t x,
+		      wl_fixed_t y,
+		      struct wl_data_offer *id);
+	/**
+	 * leave - end drag-and-drop session
+	 *
+	 * This event is sent when the drag-and-drop pointer leaves the
+	 * surface and the session ends. The client must destroy the
+	 * wl_data_offer introduced at enter time at this point.
+	 */
+	void (*leave)(void *data,
+		      struct wl_data_device *wl_data_device);
+	/**
+	 * motion - drag-and-drop session motion
+	 * @time: timestamp with millisecond granularity
+	 * @x: (none)
+	 * @y: (none)
+	 *
+	 * This event is sent when the drag-and-drop pointer moves within
+	 * the currently focused surface. The new position of the pointer
+	 * is provided by the x and y arguments, in surface local
+	 * coordinates.
+	 */
+	void (*motion)(void *data,
+		       struct wl_data_device *wl_data_device,
+		       uint32_t time,
+		       wl_fixed_t x,
+		       wl_fixed_t y);
+	/**
+	 * drop - end drag-and-drag session successfully
+	 *
+	 * The event is sent when a drag-and-drop operation is ended
+	 * because the implicit grab is removed.
+	 */
+	void (*drop)(void *data,
+		     struct wl_data_device *wl_data_device);
+	/**
+	 * selection - advertise new selection
+	 * @id: (none)
+	 *
+	 * The selection event is sent out to notify the client of a new
+	 * wl_data_offer for the selection for this device. The
+	 * data_device.data_offer and the data_offer.offer events are sent
+	 * out immediately before this event to introduce the data offer
+	 * object. The selection event is sent to a client immediately
+	 * before receiving keyboard focus and when a new selection is set
+	 * while the client has keyboard focus. The data_offer is valid
+	 * until a new data_offer or NULL is received or until the client
+	 * loses keyboard focus. The client must destroy the previous
+	 * selection data_offer, if any, upon receiving this event.
+	 */
+	void (*selection)(void *data,
+			  struct wl_data_device *wl_data_device,
+			  struct wl_data_offer *id);
+};
+
+static inline int
+wl_data_device_add_listener(struct wl_data_device *wl_data_device,
+			    const struct wl_data_device_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_device,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_DEVICE_START_DRAG	0
+#define WL_DATA_DEVICE_SET_SELECTION	1
+#define WL_DATA_DEVICE_RELEASE	2
+
+static inline void
+wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data);
+}
+
+static inline void *
+wl_data_device_get_user_data(struct wl_data_device *wl_data_device)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device);
+}
+
+static inline void
+wl_data_device_destroy(struct wl_data_device *wl_data_device)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_data_device);
+}
+
+static inline void
+wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_START_DRAG, source, origin, icon, serial);
+}
+
+static inline void
+wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_SET_SELECTION, source, serial);
+}
+
+static inline void
+wl_data_device_release(struct wl_data_device *wl_data_device)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_RELEASE);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_data_device);
+}
+
+#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE	0
+#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE	1
+
+static inline void
+wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data);
+}
+
+static inline void *
+wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager);
+}
+
+static inline void
+wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager);
+}
+
+static inline struct wl_data_source *
+wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager,
+			 WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, NULL);
+
+	return (struct wl_data_source *) id;
+}
+
+static inline struct wl_data_device *
+wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_data_device_manager,
+			 WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, NULL, seat);
+
+	return (struct wl_data_device *) id;
+}
+
+#ifndef WL_SHELL_ERROR_ENUM
+#define WL_SHELL_ERROR_ENUM
+enum wl_shell_error {
+	WL_SHELL_ERROR_ROLE = 0,
+};
+#endif /* WL_SHELL_ERROR_ENUM */
+
+#define WL_SHELL_GET_SHELL_SURFACE	0
+
+static inline void
+wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data);
+}
+
+static inline void *
+wl_shell_get_user_data(struct wl_shell *wl_shell)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shell);
+}
+
+static inline void
+wl_shell_destroy(struct wl_shell *wl_shell)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shell);
+}
+
+static inline struct wl_shell_surface *
+wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_shell,
+			 WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, NULL, surface);
+
+	return (struct wl_shell_surface *) id;
+}
+
+#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
+#define WL_SHELL_SURFACE_RESIZE_ENUM
+/**
+ * wl_shell_surface_resize - edge values for resizing
+ * @WL_SHELL_SURFACE_RESIZE_NONE: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM: (none)
+ * @WL_SHELL_SURFACE_RESIZE_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_RIGHT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: (none)
+ *
+ * These values are used to indicate which edge of a surface is being
+ * dragged in a resize operation. The server may use this information to
+ * adapt its behavior, e.g. choose an appropriate cursor image.
+ */
+enum wl_shell_surface_resize {
+	WL_SHELL_SURFACE_RESIZE_NONE = 0,
+	WL_SHELL_SURFACE_RESIZE_TOP = 1,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
+	WL_SHELL_SURFACE_RESIZE_LEFT = 4,
+	WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
+	WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
+	WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
+};
+#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
+
+#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
+#define WL_SHELL_SURFACE_TRANSIENT_ENUM
+/**
+ * wl_shell_surface_transient - details of transient behaviour
+ * @WL_SHELL_SURFACE_TRANSIENT_INACTIVE: do not set keyboard focus
+ *
+ * These flags specify details of the expected behaviour of transient
+ * surfaces. Used in the set_transient request.
+ */
+enum wl_shell_surface_transient {
+	WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
+};
+#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
+
+#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+/**
+ * wl_shell_surface_fullscreen_method - different method to set the
+ *	surface fullscreen
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT: no preference, apply
+ *	default policy
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE: scale, preserve the
+ *	surface's aspect ratio and center on output
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: switch output mode to the
+ *	smallest mode that can fit the surface, add black borders to compensate
+ *	size mismatch
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: no upscaling, center on
+ *	output and add black borders to compensate size mismatch
+ *
+ * Hints to indicate to the compositor how to deal with a conflict
+ * between the dimensions of the surface and the dimensions of the output.
+ * The compositor is free to ignore this parameter.
+ */
+enum wl_shell_surface_fullscreen_method {
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
+};
+#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
+
+/**
+ * wl_shell_surface - desktop-style metadata interface
+ * @ping: ping client
+ * @configure: suggest resize
+ * @popup_done: popup interaction is done
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like toplevel, fullscreen or
+ * popup windows, move, resize or maximize them, associate metadata like
+ * title and class, etc.
+ *
+ * On the server side the object is automatically destroyed when the
+ * related wl_surface is destroyed. On client side,
+ * wl_shell_surface_destroy() must be called before destroying the
+ * wl_surface object.
+ */
+struct wl_shell_surface_listener {
+	/**
+	 * ping - ping client
+	 * @serial: (none)
+	 *
+	 * Ping a client to check if it is receiving events and sending
+	 * requests. A client is expected to reply with a pong request.
+	 */
+	void (*ping)(void *data,
+		     struct wl_shell_surface *wl_shell_surface,
+		     uint32_t serial);
+	/**
+	 * configure - suggest resize
+	 * @edges: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 *
+	 * The configure event asks the client to resize its surface.
+	 *
+	 * The size is a hint, in the sense that the client is free to
+	 * ignore it if it doesn't resize, pick a smaller size (to satisfy
+	 * aspect ratio or resize in steps of NxM pixels).
+	 *
+	 * The edges parameter provides a hint about how the surface was
+	 * resized. The client may use this information to decide how to
+	 * adjust its content to the new size (e.g. a scrolling area might
+	 * adjust its content position to leave the viewable content
+	 * unmoved).
+	 *
+	 * The client is free to dismiss all but the last configure event
+	 * it received.
+	 *
+	 * The width and height arguments specify the size of the window in
+	 * surface local coordinates.
+	 */
+	void (*configure)(void *data,
+			  struct wl_shell_surface *wl_shell_surface,
+			  uint32_t edges,
+			  int32_t width,
+			  int32_t height);
+	/**
+	 * popup_done - popup interaction is done
+	 *
+	 * The popup_done event is sent out when a popup grab is broken,
+	 * that is, when the user clicks a surface that doesn't belong to
+	 * the client owning the popup surface.
+	 */
+	void (*popup_done)(void *data,
+			   struct wl_shell_surface *wl_shell_surface);
+};
+
+static inline int
+wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface,
+			      const struct wl_shell_surface_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SHELL_SURFACE_PONG	0
+#define WL_SHELL_SURFACE_MOVE	1
+#define WL_SHELL_SURFACE_RESIZE	2
+#define WL_SHELL_SURFACE_SET_TOPLEVEL	3
+#define WL_SHELL_SURFACE_SET_TRANSIENT	4
+#define WL_SHELL_SURFACE_SET_FULLSCREEN	5
+#define WL_SHELL_SURFACE_SET_POPUP	6
+#define WL_SHELL_SURFACE_SET_MAXIMIZED	7
+#define WL_SHELL_SURFACE_SET_TITLE	8
+#define WL_SHELL_SURFACE_SET_CLASS	9
+
+static inline void
+wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data);
+}
+
+static inline void *
+wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface);
+}
+
+static inline void
+wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shell_surface);
+}
+
+static inline void
+wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_PONG, serial);
+}
+
+static inline void
+wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_MOVE, seat, serial);
+}
+
+static inline void
+wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_RESIZE, seat, serial, edges);
+}
+
+static inline void
+wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TOPLEVEL);
+}
+
+static inline void
+wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TRANSIENT, parent, x, y, flags);
+}
+
+static inline void
+wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_FULLSCREEN, method, framerate, output);
+}
+
+static inline void
+wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_POPUP, seat, serial, parent, x, y, flags);
+}
+
+static inline void
+wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_MAXIMIZED, output);
+}
+
+static inline void
+wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TITLE, title);
+}
+
+static inline void
+wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_CLASS, class_);
+}
+
+#ifndef WL_SURFACE_ERROR_ENUM
+#define WL_SURFACE_ERROR_ENUM
+/**
+ * wl_surface_error - wl_surface error values
+ * @WL_SURFACE_ERROR_INVALID_SCALE: buffer scale value is invalid
+ * @WL_SURFACE_ERROR_INVALID_TRANSFORM: buffer transform value is invalid
+ *
+ * These errors can be emitted in response to wl_surface requests.
+ */
+enum wl_surface_error {
+	WL_SURFACE_ERROR_INVALID_SCALE = 0,
+	WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
+};
+#endif /* WL_SURFACE_ERROR_ENUM */
+
+/**
+ * wl_surface - an onscreen surface
+ * @enter: surface enters an output
+ * @leave: surface leaves an output
+ *
+ * A surface is a rectangular area that is displayed on the screen. It
+ * has a location, size and pixel contents.
+ *
+ * The size of a surface (and relative positions on it) is described in
+ * surface local coordinates, which may differ from the buffer local
+ * coordinates of the pixel content, in case a buffer_transform or a
+ * buffer_scale is used.
+ *
+ * A surface without a "role" is fairly useless, a compositor does not know
+ * where, when or how to present it. The role is the purpose of a
+ * wl_surface. Examples of roles are a cursor for a pointer (as set by
+ * wl_pointer.set_cursor), a drag icon (wl_data_device.start_drag), a
+ * sub-surface (wl_subcompositor.get_subsurface), and a window as defined
+ * by a shell protocol (e.g. wl_shell.get_shell_surface).
+ *
+ * A surface can have only one role at a time. Initially a wl_surface does
+ * not have a role. Once a wl_surface is given a role, it is set
+ * permanently for the whole lifetime of the wl_surface object. Giving the
+ * current role again is allowed, unless explicitly forbidden by the
+ * relevant interface specification.
+ *
+ * Surface roles are given by requests in other interfaces such as
+ * wl_pointer.set_cursor. The request should explicitly mention that this
+ * request gives a role to a wl_surface. Often, this request also creates a
+ * new protocol object that represents the role and adds additional
+ * functionality to wl_surface. When a client wants to destroy a
+ * wl_surface, they must destroy this 'role object' before the wl_surface.
+ *
+ * Destroying the role object does not remove the role from the wl_surface,
+ * but it may stop the wl_surface from "playing the role". For instance, if
+ * a wl_subsurface object is destroyed, the wl_surface it was created for
+ * will be unmapped and forget its position and z-order. It is allowed to
+ * create a wl_subsurface for the same wl_surface again, but it is not
+ * allowed to use the wl_surface as a cursor (cursor is a different role
+ * than sub-surface, and role switching is not allowed).
+ */
+struct wl_surface_listener {
+	/**
+	 * enter - surface enters an output
+	 * @output: (none)
+	 *
+	 * This is emitted whenever a surface's creation, movement, or
+	 * resizing results in some part of it being within the scanout
+	 * region of an output.
+	 *
+	 * Note that a surface may be overlapping with zero or more
+	 * outputs.
+	 */
+	void (*enter)(void *data,
+		      struct wl_surface *wl_surface,
+		      struct wl_output *output);
+	/**
+	 * leave - surface leaves an output
+	 * @output: (none)
+	 *
+	 * This is emitted whenever a surface's creation, movement, or
+	 * resizing results in it no longer having any part of it within
+	 * the scanout region of an output.
+	 */
+	void (*leave)(void *data,
+		      struct wl_surface *wl_surface,
+		      struct wl_output *output);
+};
+
+static inline int
+wl_surface_add_listener(struct wl_surface *wl_surface,
+			const struct wl_surface_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_surface,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SURFACE_DESTROY	0
+#define WL_SURFACE_ATTACH	1
+#define WL_SURFACE_DAMAGE	2
+#define WL_SURFACE_FRAME	3
+#define WL_SURFACE_SET_OPAQUE_REGION	4
+#define WL_SURFACE_SET_INPUT_REGION	5
+#define WL_SURFACE_COMMIT	6
+#define WL_SURFACE_SET_BUFFER_TRANSFORM	7
+#define WL_SURFACE_SET_BUFFER_SCALE	8
+
+static inline void
+wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data);
+}
+
+static inline void *
+wl_surface_get_user_data(struct wl_surface *wl_surface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_surface);
+}
+
+static inline void
+wl_surface_destroy(struct wl_surface *wl_surface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_surface);
+}
+
+static inline void
+wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_ATTACH, buffer, x, y);
+}
+
+static inline void
+wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_DAMAGE, x, y, width, height);
+}
+
+static inline struct wl_callback *
+wl_surface_frame(struct wl_surface *wl_surface)
+{
+	struct wl_proxy *callback;
+
+	callback = wl_proxy_marshal_constructor((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_FRAME, &wl_callback_interface, NULL);
+
+	return (struct wl_callback *) callback;
+}
+
+static inline void
+wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_OPAQUE_REGION, region);
+}
+
+static inline void
+wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_INPUT_REGION, region);
+}
+
+static inline void
+wl_surface_commit(struct wl_surface *wl_surface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_COMMIT);
+}
+
+static inline void
+wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_BUFFER_TRANSFORM, transform);
+}
+
+static inline void
+wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_BUFFER_SCALE, scale);
+}
+
+#ifndef WL_SEAT_CAPABILITY_ENUM
+#define WL_SEAT_CAPABILITY_ENUM
+/**
+ * wl_seat_capability - seat capability bitmask
+ * @WL_SEAT_CAPABILITY_POINTER: The seat has pointer devices
+ * @WL_SEAT_CAPABILITY_KEYBOARD: The seat has one or more keyboards
+ * @WL_SEAT_CAPABILITY_TOUCH: The seat has touch devices
+ *
+ * This is a bitmask of capabilities this seat has; if a member is set,
+ * then it is present on the seat.
+ */
+enum wl_seat_capability {
+	WL_SEAT_CAPABILITY_POINTER = 1,
+	WL_SEAT_CAPABILITY_KEYBOARD = 2,
+	WL_SEAT_CAPABILITY_TOUCH = 4,
+};
+#endif /* WL_SEAT_CAPABILITY_ENUM */
+
+/**
+ * wl_seat - group of input devices
+ * @capabilities: seat capabilities changed
+ * @name: unique identifier for this seat
+ *
+ * A seat is a group of keyboards, pointer and touch devices. This object
+ * is published as a global during start up, or when such a device is hot
+ * plugged. A seat typically has a pointer and maintains a keyboard focus
+ * and a pointer focus.
+ */
+struct wl_seat_listener {
+	/**
+	 * capabilities - seat capabilities changed
+	 * @capabilities: (none)
+	 *
+	 * This is emitted whenever a seat gains or loses the pointer,
+	 * keyboard or touch capabilities. The argument is a capability
+	 * enum containing the complete set of capabilities this seat has.
+	 */
+	void (*capabilities)(void *data,
+			     struct wl_seat *wl_seat,
+			     uint32_t capabilities);
+	/**
+	 * name - unique identifier for this seat
+	 * @name: (none)
+	 *
+	 * In a multiseat configuration this can be used by the client to
+	 * help identify which physical devices the seat represents. Based
+	 * on the seat configuration used by the compositor.
+	 * @since: 2
+	 */
+	void (*name)(void *data,
+		     struct wl_seat *wl_seat,
+		     const char *name);
+};
+
+static inline int
+wl_seat_add_listener(struct wl_seat *wl_seat,
+		     const struct wl_seat_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_seat,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SEAT_GET_POINTER	0
+#define WL_SEAT_GET_KEYBOARD	1
+#define WL_SEAT_GET_TOUCH	2
+
+static inline void
+wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data);
+}
+
+static inline void *
+wl_seat_get_user_data(struct wl_seat *wl_seat)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_seat);
+}
+
+static inline void
+wl_seat_destroy(struct wl_seat *wl_seat)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_seat);
+}
+
+static inline struct wl_pointer *
+wl_seat_get_pointer(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_POINTER, &wl_pointer_interface, NULL);
+
+	return (struct wl_pointer *) id;
+}
+
+static inline struct wl_keyboard *
+wl_seat_get_keyboard(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, NULL);
+
+	return (struct wl_keyboard *) id;
+}
+
+static inline struct wl_touch *
+wl_seat_get_touch(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_TOUCH, &wl_touch_interface, NULL);
+
+	return (struct wl_touch *) id;
+}
+
+#ifndef WL_POINTER_ERROR_ENUM
+#define WL_POINTER_ERROR_ENUM
+enum wl_pointer_error {
+	WL_POINTER_ERROR_ROLE = 0,
+};
+#endif /* WL_POINTER_ERROR_ENUM */
+
+#ifndef WL_POINTER_BUTTON_STATE_ENUM
+#define WL_POINTER_BUTTON_STATE_ENUM
+/**
+ * wl_pointer_button_state - physical button state
+ * @WL_POINTER_BUTTON_STATE_RELEASED: The button is not pressed
+ * @WL_POINTER_BUTTON_STATE_PRESSED: The button is pressed
+ *
+ * Describes the physical state of a button which provoked the button
+ * event.
+ */
+enum wl_pointer_button_state {
+	WL_POINTER_BUTTON_STATE_RELEASED = 0,
+	WL_POINTER_BUTTON_STATE_PRESSED = 1,
+};
+#endif /* WL_POINTER_BUTTON_STATE_ENUM */
+
+#ifndef WL_POINTER_AXIS_ENUM
+#define WL_POINTER_AXIS_ENUM
+/**
+ * wl_pointer_axis - axis types
+ * @WL_POINTER_AXIS_VERTICAL_SCROLL: (none)
+ * @WL_POINTER_AXIS_HORIZONTAL_SCROLL: (none)
+ *
+ * Describes the axis types of scroll events.
+ */
+enum wl_pointer_axis {
+	WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
+	WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
+};
+#endif /* WL_POINTER_AXIS_ENUM */
+
+/**
+ * wl_pointer - pointer input device
+ * @enter: enter event
+ * @leave: leave event
+ * @motion: pointer motion event
+ * @button: pointer button event
+ * @axis: axis event
+ *
+ * The wl_pointer interface represents one or more input devices, such as
+ * mice, which control the pointer location and pointer_focus of a seat.
+ *
+ * The wl_pointer interface generates motion, enter and leave events for
+ * the surfaces that the pointer is located over, and button and axis
+ * events for button presses, button releases and scrolling.
+ */
+struct wl_pointer_listener {
+	/**
+	 * enter - enter event
+	 * @serial: (none)
+	 * @surface: (none)
+	 * @surface_x: x coordinate in surface-relative coordinates
+	 * @surface_y: y coordinate in surface-relative coordinates
+	 *
+	 * Notification that this seat's pointer is focused on a certain
+	 * surface.
+	 *
+	 * When an seat's focus enters a surface, the pointer image is
+	 * undefined and a client should respond to this event by setting
+	 * an appropriate pointer image with the set_cursor request.
+	 */
+	void (*enter)(void *data,
+		      struct wl_pointer *wl_pointer,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      wl_fixed_t surface_x,
+		      wl_fixed_t surface_y);
+	/**
+	 * leave - leave event
+	 * @serial: (none)
+	 * @surface: (none)
+	 *
+	 * Notification that this seat's pointer is no longer focused on
+	 * a certain surface.
+	 *
+	 * The leave notification is sent before the enter notification for
+	 * the new focus.
+	 */
+	void (*leave)(void *data,
+		      struct wl_pointer *wl_pointer,
+		      uint32_t serial,
+		      struct wl_surface *surface);
+	/**
+	 * motion - pointer motion event
+	 * @time: timestamp with millisecond granularity
+	 * @surface_x: x coordinate in surface-relative coordinates
+	 * @surface_y: y coordinate in surface-relative coordinates
+	 *
+	 * Notification of pointer location change. The arguments
+	 * surface_x and surface_y are the location relative to the focused
+	 * surface.
+	 */
+	void (*motion)(void *data,
+		       struct wl_pointer *wl_pointer,
+		       uint32_t time,
+		       wl_fixed_t surface_x,
+		       wl_fixed_t surface_y);
+	/**
+	 * button - pointer button event
+	 * @serial: (none)
+	 * @time: timestamp with millisecond granularity
+	 * @button: (none)
+	 * @state: (none)
+	 *
+	 * Mouse button click and release notifications.
+	 *
+	 * The location of the click is given by the last motion or enter
+	 * event. The time argument is a timestamp with millisecond
+	 * granularity, with an undefined base.
+	 */
+	void (*button)(void *data,
+		       struct wl_pointer *wl_pointer,
+		       uint32_t serial,
+		       uint32_t time,
+		       uint32_t button,
+		       uint32_t state);
+	/**
+	 * axis - axis event
+	 * @time: timestamp with millisecond granularity
+	 * @axis: (none)
+	 * @value: (none)
+	 *
+	 * Scroll and other axis notifications.
+	 *
+	 * For scroll events (vertical and horizontal scroll axes), the
+	 * value parameter is the length of a vector along the specified
+	 * axis in a coordinate space identical to those of motion events,
+	 * representing a relative movement along the specified axis.
+	 *
+	 * For devices that support movements non-parallel to axes multiple
+	 * axis events will be emitted.
+	 *
+	 * When applicable, for example for touch pads, the server can
+	 * choose to emit scroll events where the motion vector is
+	 * equivalent to a motion event vector.
+	 *
+	 * When applicable, clients can transform its view relative to the
+	 * scroll distance.
+	 */
+	void (*axis)(void *data,
+		     struct wl_pointer *wl_pointer,
+		     uint32_t time,
+		     uint32_t axis,
+		     wl_fixed_t value);
+};
+
+static inline int
+wl_pointer_add_listener(struct wl_pointer *wl_pointer,
+			const struct wl_pointer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_pointer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_POINTER_SET_CURSOR	0
+#define WL_POINTER_RELEASE	1
+
+static inline void
+wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data);
+}
+
+static inline void *
+wl_pointer_get_user_data(struct wl_pointer *wl_pointer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer);
+}
+
+static inline void
+wl_pointer_destroy(struct wl_pointer *wl_pointer)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_pointer);
+}
+
+static inline void
+wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_pointer,
+			 WL_POINTER_SET_CURSOR, serial, surface, hotspot_x, hotspot_y);
+}
+
+static inline void
+wl_pointer_release(struct wl_pointer *wl_pointer)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_pointer,
+			 WL_POINTER_RELEASE);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_pointer);
+}
+
+#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+/**
+ * wl_keyboard_keymap_format - keyboard mapping format
+ * @WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP: no keymap; client must
+ *	understand how to interpret the raw keycode
+ * @WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1: libxkbcommon compatible; to
+ *	determine the xkb keycode, clients must add 8 to the key event keycode
+ *
+ * This specifies the format of the keymap provided to the client with
+ * the wl_keyboard.keymap event.
+ */
+enum wl_keyboard_keymap_format {
+	WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
+	WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
+};
+#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
+
+#ifndef WL_KEYBOARD_KEY_STATE_ENUM
+#define WL_KEYBOARD_KEY_STATE_ENUM
+/**
+ * wl_keyboard_key_state - physical key state
+ * @WL_KEYBOARD_KEY_STATE_RELEASED: key is not pressed
+ * @WL_KEYBOARD_KEY_STATE_PRESSED: key is pressed
+ *
+ * Describes the physical state of a key which provoked the key event.
+ */
+enum wl_keyboard_key_state {
+	WL_KEYBOARD_KEY_STATE_RELEASED = 0,
+	WL_KEYBOARD_KEY_STATE_PRESSED = 1,
+};
+#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
+
+/**
+ * wl_keyboard - keyboard input device
+ * @keymap: keyboard mapping
+ * @enter: enter event
+ * @leave: leave event
+ * @key: key event
+ * @modifiers: modifier and group state
+ * @repeat_info: repeat rate and delay
+ *
+ * The wl_keyboard interface represents one or more keyboards associated
+ * with a seat.
+ */
+struct wl_keyboard_listener {
+	/**
+	 * keymap - keyboard mapping
+	 * @format: (none)
+	 * @fd: (none)
+	 * @size: (none)
+	 *
+	 * This event provides a file descriptor to the client which can
+	 * be memory-mapped to provide a keyboard mapping description.
+	 */
+	void (*keymap)(void *data,
+		       struct wl_keyboard *wl_keyboard,
+		       uint32_t format,
+		       int32_t fd,
+		       uint32_t size);
+	/**
+	 * enter - enter event
+	 * @serial: (none)
+	 * @surface: (none)
+	 * @keys: the currently pressed keys
+	 *
+	 * Notification that this seat's keyboard focus is on a certain
+	 * surface.
+	 */
+	void (*enter)(void *data,
+		      struct wl_keyboard *wl_keyboard,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      struct wl_array *keys);
+	/**
+	 * leave - leave event
+	 * @serial: (none)
+	 * @surface: (none)
+	 *
+	 * Notification that this seat's keyboard focus is no longer on a
+	 * certain surface.
+	 *
+	 * The leave notification is sent before the enter notification for
+	 * the new focus.
+	 */
+	void (*leave)(void *data,
+		      struct wl_keyboard *wl_keyboard,
+		      uint32_t serial,
+		      struct wl_surface *surface);
+	/**
+	 * key - key event
+	 * @serial: (none)
+	 * @time: timestamp with millisecond granularity
+	 * @key: (none)
+	 * @state: (none)
+	 *
+	 * A key was pressed or released. The time argument is a
+	 * timestamp with millisecond granularity, with an undefined base.
+	 */
+	void (*key)(void *data,
+		    struct wl_keyboard *wl_keyboard,
+		    uint32_t serial,
+		    uint32_t time,
+		    uint32_t key,
+		    uint32_t state);
+	/**
+	 * modifiers - modifier and group state
+	 * @serial: (none)
+	 * @mods_depressed: (none)
+	 * @mods_latched: (none)
+	 * @mods_locked: (none)
+	 * @group: (none)
+	 *
+	 * Notifies clients that the modifier and/or group state has
+	 * changed, and it should update its local state.
+	 */
+	void (*modifiers)(void *data,
+			  struct wl_keyboard *wl_keyboard,
+			  uint32_t serial,
+			  uint32_t mods_depressed,
+			  uint32_t mods_latched,
+			  uint32_t mods_locked,
+			  uint32_t group);
+	/**
+	 * repeat_info - repeat rate and delay
+	 * @rate: the rate of repeating keys in characters per second
+	 * @delay: delay in milliseconds since key down until repeating
+	 *	starts
+	 *
+	 * Informs the client about the keyboard's repeat rate and delay.
+	 *
+	 * This event is sent as soon as the wl_keyboard object has been
+	 * created, and is guaranteed to be received by the client before
+	 * any key press event.
+	 *
+	 * Negative values for either rate or delay are illegal. A rate of
+	 * zero will disable any repeating (regardless of the value of
+	 * delay).
+	 *
+	 * This event can be sent later on as well with a new value if
+	 * necessary, so clients should continue listening for the event
+	 * past the creation of wl_keyboard.
+	 * @since: 4
+	 */
+	void (*repeat_info)(void *data,
+			    struct wl_keyboard *wl_keyboard,
+			    int32_t rate,
+			    int32_t delay);
+};
+
+static inline int
+wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard,
+			 const struct wl_keyboard_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_KEYBOARD_RELEASE	0
+
+static inline void
+wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data);
+}
+
+static inline void *
+wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard);
+}
+
+static inline void
+wl_keyboard_destroy(struct wl_keyboard *wl_keyboard)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_keyboard);
+}
+
+static inline void
+wl_keyboard_release(struct wl_keyboard *wl_keyboard)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_keyboard,
+			 WL_KEYBOARD_RELEASE);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_keyboard);
+}
+
+/**
+ * wl_touch - touchscreen input device
+ * @down: touch down event and beginning of a touch sequence
+ * @up: end of a touch event sequence
+ * @motion: update of touch point coordinates
+ * @frame: end of touch frame event
+ * @cancel: touch session cancelled
+ *
+ * The wl_touch interface represents a touchscreen associated with a
+ * seat.
+ *
+ * Touch interactions can consist of one or more contacts. For each
+ * contact, a series of events is generated, starting with a down event,
+ * followed by zero or more motion events, and ending with an up event.
+ * Events relating to the same contact point can be identified by the ID of
+ * the sequence.
+ */
+struct wl_touch_listener {
+	/**
+	 * down - touch down event and beginning of a touch sequence
+	 * @serial: (none)
+	 * @time: timestamp with millisecond granularity
+	 * @surface: (none)
+	 * @id: the unique ID of this touch point
+	 * @x: x coordinate in surface-relative coordinates
+	 * @y: y coordinate in surface-relative coordinates
+	 *
+	 * A new touch point has appeared on the surface. This touch
+	 * point is assigned a unique @id. Future events from this
+	 * touchpoint reference this ID. The ID ceases to be valid after a
+	 * touch up event and may be re-used in the future.
+	 */
+	void (*down)(void *data,
+		     struct wl_touch *wl_touch,
+		     uint32_t serial,
+		     uint32_t time,
+		     struct wl_surface *surface,
+		     int32_t id,
+		     wl_fixed_t x,
+		     wl_fixed_t y);
+	/**
+	 * up - end of a touch event sequence
+	 * @serial: (none)
+	 * @time: timestamp with millisecond granularity
+	 * @id: the unique ID of this touch point
+	 *
+	 * The touch point has disappeared. No further events will be
+	 * sent for this touchpoint and the touch point's ID is released
+	 * and may be re-used in a future touch down event.
+	 */
+	void (*up)(void *data,
+		   struct wl_touch *wl_touch,
+		   uint32_t serial,
+		   uint32_t time,
+		   int32_t id);
+	/**
+	 * motion - update of touch point coordinates
+	 * @time: timestamp with millisecond granularity
+	 * @id: the unique ID of this touch point
+	 * @x: x coordinate in surface-relative coordinates
+	 * @y: y coordinate in surface-relative coordinates
+	 *
+	 * A touchpoint has changed coordinates.
+	 */
+	void (*motion)(void *data,
+		       struct wl_touch *wl_touch,
+		       uint32_t time,
+		       int32_t id,
+		       wl_fixed_t x,
+		       wl_fixed_t y);
+	/**
+	 * frame - end of touch frame event
+	 *
+	 * Indicates the end of a contact point list.
+	 */
+	void (*frame)(void *data,
+		      struct wl_touch *wl_touch);
+	/**
+	 * cancel - touch session cancelled
+	 *
+	 * Sent if the compositor decides the touch stream is a global
+	 * gesture. No further events are sent to the clients from that
+	 * particular gesture. Touch cancellation applies to all touch
+	 * points currently active on this client's surface. The client is
+	 * responsible for finalizing the touch points, future touch points
+	 * on this surface may re-use the touch point ID.
+	 */
+	void (*cancel)(void *data,
+		       struct wl_touch *wl_touch);
+};
+
+static inline int
+wl_touch_add_listener(struct wl_touch *wl_touch,
+		      const struct wl_touch_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_touch,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_TOUCH_RELEASE	0
+
+static inline void
+wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data);
+}
+
+static inline void *
+wl_touch_get_user_data(struct wl_touch *wl_touch)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_touch);
+}
+
+static inline void
+wl_touch_destroy(struct wl_touch *wl_touch)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_touch);
+}
+
+static inline void
+wl_touch_release(struct wl_touch *wl_touch)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_touch,
+			 WL_TOUCH_RELEASE);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_touch);
+}
+
+#ifndef WL_OUTPUT_SUBPIXEL_ENUM
+#define WL_OUTPUT_SUBPIXEL_ENUM
+/**
+ * wl_output_subpixel - subpixel geometry information
+ * @WL_OUTPUT_SUBPIXEL_UNKNOWN: (none)
+ * @WL_OUTPUT_SUBPIXEL_NONE: (none)
+ * @WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: (none)
+ * @WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: (none)
+ * @WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: (none)
+ * @WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: (none)
+ *
+ * This enumeration describes how the physical pixels on an output are
+ * laid out.
+ */
+enum wl_output_subpixel {
+	WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
+	WL_OUTPUT_SUBPIXEL_NONE = 1,
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
+	WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
+	WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
+};
+#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
+
+#ifndef WL_OUTPUT_TRANSFORM_ENUM
+#define WL_OUTPUT_TRANSFORM_ENUM
+/**
+ * wl_output_transform - transform from framebuffer to output
+ * @WL_OUTPUT_TRANSFORM_NORMAL: (none)
+ * @WL_OUTPUT_TRANSFORM_90: (none)
+ * @WL_OUTPUT_TRANSFORM_180: (none)
+ * @WL_OUTPUT_TRANSFORM_270: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_90: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_180: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_270: (none)
+ *
+ * This describes the transform that a compositor will apply to a surface
+ * to compensate for the rotation or mirroring of an output device.
+ *
+ * The flipped values correspond to an initial flip around a vertical axis
+ * followed by rotation.
+ *
+ * The purpose is mainly to allow clients render accordingly and tell the
+ * compositor, so that for fullscreen surfaces, the compositor will still
+ * be able to scan out directly from client surfaces.
+ */
+enum wl_output_transform {
+	WL_OUTPUT_TRANSFORM_NORMAL = 0,
+	WL_OUTPUT_TRANSFORM_90 = 1,
+	WL_OUTPUT_TRANSFORM_180 = 2,
+	WL_OUTPUT_TRANSFORM_270 = 3,
+	WL_OUTPUT_TRANSFORM_FLIPPED = 4,
+	WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
+	WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
+	WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
+};
+#endif /* WL_OUTPUT_TRANSFORM_ENUM */
+
+#ifndef WL_OUTPUT_MODE_ENUM
+#define WL_OUTPUT_MODE_ENUM
+/**
+ * wl_output_mode - mode information
+ * @WL_OUTPUT_MODE_CURRENT: indicates this is the current mode
+ * @WL_OUTPUT_MODE_PREFERRED: indicates this is the preferred mode
+ *
+ * These flags describe properties of an output mode. They are used in
+ * the flags bitfield of the mode event.
+ */
+enum wl_output_mode {
+	WL_OUTPUT_MODE_CURRENT = 0x1,
+	WL_OUTPUT_MODE_PREFERRED = 0x2,
+};
+#endif /* WL_OUTPUT_MODE_ENUM */
+
+/**
+ * wl_output - compositor output region
+ * @geometry: properties of the output
+ * @mode: advertise available modes for the output
+ * @done: sent all information about output
+ * @scale: output scaling properties
+ *
+ * An output describes part of the compositor geometry. The compositor
+ * works in the 'compositor coordinate system' and an output corresponds to
+ * rectangular area in that space that is actually visible. This typically
+ * corresponds to a monitor that displays part of the compositor space.
+ * This object is published as global during start up, or when a monitor is
+ * hotplugged.
+ */
+struct wl_output_listener {
+	/**
+	 * geometry - properties of the output
+	 * @x: x position within the global compositor space
+	 * @y: y position within the global compositor space
+	 * @physical_width: width in millimeters of the output
+	 * @physical_height: height in millimeters of the output
+	 * @subpixel: subpixel orientation of the output
+	 * @make: textual description of the manufacturer
+	 * @model: textual description of the model
+	 * @transform: transform that maps framebuffer to output
+	 *
+	 * The geometry event describes geometric properties of the
+	 * output. The event is sent when binding to the output object and
+	 * whenever any of the properties change.
+	 */
+	void (*geometry)(void *data,
+			 struct wl_output *wl_output,
+			 int32_t x,
+			 int32_t y,
+			 int32_t physical_width,
+			 int32_t physical_height,
+			 int32_t subpixel,
+			 const char *make,
+			 const char *model,
+			 int32_t transform);
+	/**
+	 * mode - advertise available modes for the output
+	 * @flags: bitfield of mode flags
+	 * @width: width of the mode in hardware units
+	 * @height: height of the mode in hardware units
+	 * @refresh: vertical refresh rate in mHz
+	 *
+	 * The mode event describes an available mode for the output.
+	 *
+	 * The event is sent when binding to the output object and there
+	 * will always be one mode, the current mode. The event is sent
+	 * again if an output changes mode, for the mode that is now
+	 * current. In other words, the current mode is always the last
+	 * mode that was received with the current flag set.
+	 *
+	 * The size of a mode is given in physical hardware units of the
+	 * output device. This is not necessarily the same as the output
+	 * size in the global compositor space. For instance, the output
+	 * may be scaled, as described in wl_output.scale, or transformed ,
+	 * as described in wl_output.transform.
+	 */
+	void (*mode)(void *data,
+		     struct wl_output *wl_output,
+		     uint32_t flags,
+		     int32_t width,
+		     int32_t height,
+		     int32_t refresh);
+	/**
+	 * done - sent all information about output
+	 *
+	 * This event is sent after all other properties has been sent
+	 * after binding to the output object and after any other property
+	 * changes done after that. This allows changes to the output
+	 * properties to be seen as atomic, even if they happen via
+	 * multiple events.
+	 * @since: 2
+	 */
+	void (*done)(void *data,
+		     struct wl_output *wl_output);
+	/**
+	 * scale - output scaling properties
+	 * @factor: scaling factor of output
+	 *
+	 * This event contains scaling geometry information that is not
+	 * in the geometry event. It may be sent after binding the output
+	 * object or if the output scale changes later. If it is not sent,
+	 * the client should assume a scale of 1.
+	 *
+	 * A scale larger than 1 means that the compositor will
+	 * automatically scale surface buffers by this amount when
+	 * rendering. This is used for very high resolution displays where
+	 * applications rendering at the native resolution would be too
+	 * small to be legible.
+	 *
+	 * It is intended that scaling aware clients track the current
+	 * output of a surface, and if it is on a scaled output it should
+	 * use wl_surface.set_buffer_scale with the scale of the output.
+	 * That way the compositor can avoid scaling the surface, and the
+	 * client can supply a higher detail image.
+	 * @since: 2
+	 */
+	void (*scale)(void *data,
+		      struct wl_output *wl_output,
+		      int32_t factor);
+};
+
+static inline int
+wl_output_add_listener(struct wl_output *wl_output,
+		       const struct wl_output_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_output,
+				     (void (**)(void)) listener, data);
+}
+
+static inline void
+wl_output_set_user_data(struct wl_output *wl_output, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data);
+}
+
+static inline void *
+wl_output_get_user_data(struct wl_output *wl_output)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_output);
+}
+
+static inline void
+wl_output_destroy(struct wl_output *wl_output)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_output);
+}
+
+#define WL_REGION_DESTROY	0
+#define WL_REGION_ADD	1
+#define WL_REGION_SUBTRACT	2
+
+static inline void
+wl_region_set_user_data(struct wl_region *wl_region, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data);
+}
+
+static inline void *
+wl_region_get_user_data(struct wl_region *wl_region)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_region);
+}
+
+static inline void
+wl_region_destroy(struct wl_region *wl_region)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_region,
+			 WL_REGION_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_region);
+}
+
+static inline void
+wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_region,
+			 WL_REGION_ADD, x, y, width, height);
+}
+
+static inline void
+wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_region,
+			 WL_REGION_SUBTRACT, x, y, width, height);
+}
+
+#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
+#define WL_SUBCOMPOSITOR_ERROR_ENUM
+enum wl_subcompositor_error {
+	WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
+
+#define WL_SUBCOMPOSITOR_DESTROY	0
+#define WL_SUBCOMPOSITOR_GET_SUBSURFACE	1
+
+static inline void
+wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data);
+}
+
+static inline void *
+wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor);
+}
+
+static inline void
+wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subcompositor,
+			 WL_SUBCOMPOSITOR_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_subcompositor);
+}
+
+static inline struct wl_subsurface *
+wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor((struct wl_proxy *) wl_subcompositor,
+			 WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, NULL, surface, parent);
+
+	return (struct wl_subsurface *) id;
+}
+
+#ifndef WL_SUBSURFACE_ERROR_ENUM
+#define WL_SUBSURFACE_ERROR_ENUM
+enum wl_subsurface_error {
+	WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBSURFACE_ERROR_ENUM */
+
+#define WL_SUBSURFACE_DESTROY	0
+#define WL_SUBSURFACE_SET_POSITION	1
+#define WL_SUBSURFACE_PLACE_ABOVE	2
+#define WL_SUBSURFACE_PLACE_BELOW	3
+#define WL_SUBSURFACE_SET_SYNC	4
+#define WL_SUBSURFACE_SET_DESYNC	5
+
+static inline void
+wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data);
+}
+
+static inline void *
+wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface);
+}
+
+static inline void
+wl_subsurface_destroy(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_DESTROY);
+
+	wl_proxy_destroy((struct wl_proxy *) wl_subsurface);
+}
+
+static inline void
+wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_POSITION, x, y);
+}
+
+static inline void
+wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_PLACE_ABOVE, sibling);
+}
+
+static inline void
+wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_PLACE_BELOW, sibling);
+}
+
+static inline void
+wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_SYNC);
+}
+
+static inline void
+wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_DESYNC);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/wayland/include/protocol/wayland-server-protocol-core.h b/third_party/wayland/include/protocol/wayland-server-protocol-core.h
new file mode 100644
index 0000000..c5353c20
--- /dev/null
+++ b/third_party/wayland/include/protocol/wayland-server-protocol-core.h
@@ -0,0 +1,2404 @@
+/* 
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ * 
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_SERVER_PROTOCOL_H
+#define WAYLAND_SERVER_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server-core.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct wl_buffer;
+struct wl_callback;
+struct wl_compositor;
+struct wl_data_device;
+struct wl_data_device_manager;
+struct wl_data_offer;
+struct wl_data_source;
+struct wl_display;
+struct wl_keyboard;
+struct wl_output;
+struct wl_pointer;
+struct wl_region;
+struct wl_registry;
+struct wl_seat;
+struct wl_shell;
+struct wl_shell_surface;
+struct wl_shm;
+struct wl_shm_pool;
+struct wl_subcompositor;
+struct wl_subsurface;
+struct wl_surface;
+struct wl_touch;
+
+extern const struct wl_interface wl_display_interface;
+extern const struct wl_interface wl_registry_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_compositor_interface;
+extern const struct wl_interface wl_shm_pool_interface;
+extern const struct wl_interface wl_shm_interface;
+extern const struct wl_interface wl_buffer_interface;
+extern const struct wl_interface wl_data_offer_interface;
+extern const struct wl_interface wl_data_source_interface;
+extern const struct wl_interface wl_data_device_interface;
+extern const struct wl_interface wl_data_device_manager_interface;
+extern const struct wl_interface wl_shell_interface;
+extern const struct wl_interface wl_shell_surface_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_touch_interface;
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_region_interface;
+extern const struct wl_interface wl_subcompositor_interface;
+extern const struct wl_interface wl_subsurface_interface;
+
+#ifndef WL_DISPLAY_ERROR_ENUM
+#define WL_DISPLAY_ERROR_ENUM
+/**
+ * wl_display_error - global error values
+ * @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
+ * @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the
+ *	specified interface
+ * @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
+ *
+ * These errors are global and can be emitted in response to any server
+ * request.
+ */
+enum wl_display_error {
+	WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
+	WL_DISPLAY_ERROR_INVALID_METHOD = 1,
+	WL_DISPLAY_ERROR_NO_MEMORY = 2,
+};
+#endif /* WL_DISPLAY_ERROR_ENUM */
+
+/**
+ * wl_display - core global object
+ * @sync: asynchronous roundtrip
+ * @get_registry: get global registry object
+ *
+ * The core global object. This is a special singleton object. It is used
+ * for internal Wayland protocol features.
+ */
+struct wl_display_interface {
+	/**
+	 * sync - asynchronous roundtrip
+	 * @callback: (none)
+	 *
+	 * The sync request asks the server to emit the 'done' event on
+	 * the returned wl_callback object. Since requests are handled
+	 * in-order and events are delivered in-order, this can be used as
+	 * a barrier to ensure all previous requests and the resulting
+	 * events have been handled.
+	 *
+	 * The object returned by this request will be destroyed by the
+	 * compositor after the callback is fired and as such the client
+	 * must not attempt to use it after that point.
+	 *
+	 * The callback_data passed in the callback is the event serial.
+	 */
+	void (*sync)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t callback);
+	/**
+	 * get_registry - get global registry object
+	 * @registry: (none)
+	 *
+	 * This request creates a registry object that allows the client
+	 * to list and bind the global objects available from the
+	 * compositor.
+	 */
+	void (*get_registry)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t registry);
+};
+
+#define WL_DISPLAY_ERROR	0
+#define WL_DISPLAY_DELETE_ID	1
+
+#define WL_DISPLAY_ERROR_SINCE_VERSION	1
+#define WL_DISPLAY_DELETE_ID_SINCE_VERSION	1
+
+/**
+ * wl_registry - global registry object
+ * @bind: bind an object to the display
+ *
+ * The global registry object. The server has a number of global objects
+ * that are available to all clients. These objects typically represent an
+ * actual object in the server (for example, an input device) or they are
+ * singleton objects that provide extension functionality.
+ *
+ * When a client creates a registry object, the registry object will emit a
+ * global event for each global currently in the registry. Globals come and
+ * go as a result of device or monitor hotplugs, reconfiguration or other
+ * events, and the registry will send out global and global_remove events
+ * to keep the client up to date with the changes. To mark the end of the
+ * initial burst of events, the client can use the wl_display.sync request
+ * immediately after calling wl_display.get_registry.
+ *
+ * A client can bind to a global object by using the bind request. This
+ * creates a client-side handle that lets the object emit events to the
+ * client and lets the client invoke requests on the object.
+ */
+struct wl_registry_interface {
+	/**
+	 * bind - bind an object to the display
+	 * @name: unique name for the object
+	 * @interface: name of the objects interface
+	 * @version: version of the objects interface
+	 * @id: (none)
+	 *
+	 * Binds a new, client-created object to the server using the
+	 * specified name as the identifier.
+	 */
+	void (*bind)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t name,
+		     const char *interface, uint32_t version, uint32_t id);
+};
+
+#define WL_REGISTRY_GLOBAL	0
+#define WL_REGISTRY_GLOBAL_REMOVE	1
+
+#define WL_REGISTRY_GLOBAL_SINCE_VERSION	1
+#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION	1
+
+static inline void
+wl_registry_send_global(struct wl_resource *resource_, uint32_t name, const char *interface, uint32_t version)
+{
+	wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL, name, interface, version);
+}
+
+static inline void
+wl_registry_send_global_remove(struct wl_resource *resource_, uint32_t name)
+{
+	wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL_REMOVE, name);
+}
+
+#define WL_CALLBACK_DONE	0
+
+#define WL_CALLBACK_DONE_SINCE_VERSION	1
+
+static inline void
+wl_callback_send_done(struct wl_resource *resource_, uint32_t callback_data)
+{
+	wl_resource_post_event(resource_, WL_CALLBACK_DONE, callback_data);
+}
+
+/**
+ * wl_compositor - the compositor singleton
+ * @create_surface: create new surface
+ * @create_region: create new region
+ *
+ * A compositor. This object is a singleton global. The compositor is in
+ * charge of combining the contents of multiple surfaces into one
+ * displayable output.
+ */
+struct wl_compositor_interface {
+	/**
+	 * create_surface - create new surface
+	 * @id: (none)
+	 *
+	 * Ask the compositor to create a new surface.
+	 */
+	void (*create_surface)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t id);
+	/**
+	 * create_region - create new region
+	 * @id: (none)
+	 *
+	 * Ask the compositor to create a new region.
+	 */
+	void (*create_region)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      uint32_t id);
+};
+
+
+/**
+ * wl_shm_pool - a shared memory pool
+ * @create_buffer: create a buffer from the pool
+ * @destroy: destroy the pool
+ * @resize: change the size of the pool mapping
+ *
+ * The wl_shm_pool object encapsulates a piece of memory shared between
+ * the compositor and client. Through the wl_shm_pool object, the client
+ * can allocate shared memory wl_buffer objects. All objects created
+ * through the same pool share the same underlying mapped memory. Reusing
+ * the mapped memory avoids the setup/teardown overhead and is useful when
+ * interactively resizing a surface or for many small buffers.
+ */
+struct wl_shm_pool_interface {
+	/**
+	 * create_buffer - create a buffer from the pool
+	 * @id: (none)
+	 * @offset: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 * @stride: (none)
+	 * @format: (none)
+	 *
+	 * Create a wl_buffer object from the pool.
+	 *
+	 * The buffer is created offset bytes into the pool and has width
+	 * and height as specified. The stride arguments specifies the
+	 * number of bytes from beginning of one row to the beginning of
+	 * the next. The format is the pixel format of the buffer and must
+	 * be one of those advertised through the wl_shm.format event.
+	 *
+	 * A buffer will keep a reference to the pool it was created from
+	 * so it is valid to destroy the pool immediately after creating a
+	 * buffer from it.
+	 */
+	void (*create_buffer)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      uint32_t id,
+			      int32_t offset,
+			      int32_t width,
+			      int32_t height,
+			      int32_t stride,
+			      uint32_t format);
+	/**
+	 * destroy - destroy the pool
+	 *
+	 * Destroy the shared memory pool.
+	 *
+	 * The mmapped memory will be released when all buffers that have
+	 * been created from this pool are gone.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * resize - change the size of the pool mapping
+	 * @size: (none)
+	 *
+	 * This request will cause the server to remap the backing memory
+	 * for the pool from the file descriptor passed when the pool was
+	 * created, but using the new size. This request can only be used
+	 * to make the pool bigger.
+	 */
+	void (*resize)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       int32_t size);
+};
+
+
+#ifndef WL_SHM_ERROR_ENUM
+#define WL_SHM_ERROR_ENUM
+/**
+ * wl_shm_error - wl_shm error values
+ * @WL_SHM_ERROR_INVALID_FORMAT: buffer format is not known
+ * @WL_SHM_ERROR_INVALID_STRIDE: invalid size or stride during pool or
+ *	buffer creation
+ * @WL_SHM_ERROR_INVALID_FD: mmapping the file descriptor failed
+ *
+ * These errors can be emitted in response to wl_shm requests.
+ */
+enum wl_shm_error {
+	WL_SHM_ERROR_INVALID_FORMAT = 0,
+	WL_SHM_ERROR_INVALID_STRIDE = 1,
+	WL_SHM_ERROR_INVALID_FD = 2,
+};
+#endif /* WL_SHM_ERROR_ENUM */
+
+#ifndef WL_SHM_FORMAT_ENUM
+#define WL_SHM_FORMAT_ENUM
+/**
+ * wl_shm_format - pixel formats
+ * @WL_SHM_FORMAT_ARGB8888: 32-bit ARGB format
+ * @WL_SHM_FORMAT_XRGB8888: 32-bit RGB format
+ * @WL_SHM_FORMAT_C8: (none)
+ * @WL_SHM_FORMAT_RGB332: (none)
+ * @WL_SHM_FORMAT_BGR233: (none)
+ * @WL_SHM_FORMAT_XRGB4444: (none)
+ * @WL_SHM_FORMAT_XBGR4444: (none)
+ * @WL_SHM_FORMAT_RGBX4444: (none)
+ * @WL_SHM_FORMAT_BGRX4444: (none)
+ * @WL_SHM_FORMAT_ARGB4444: (none)
+ * @WL_SHM_FORMAT_ABGR4444: (none)
+ * @WL_SHM_FORMAT_RGBA4444: (none)
+ * @WL_SHM_FORMAT_BGRA4444: (none)
+ * @WL_SHM_FORMAT_XRGB1555: (none)
+ * @WL_SHM_FORMAT_XBGR1555: (none)
+ * @WL_SHM_FORMAT_RGBX5551: (none)
+ * @WL_SHM_FORMAT_BGRX5551: (none)
+ * @WL_SHM_FORMAT_ARGB1555: (none)
+ * @WL_SHM_FORMAT_ABGR1555: (none)
+ * @WL_SHM_FORMAT_RGBA5551: (none)
+ * @WL_SHM_FORMAT_BGRA5551: (none)
+ * @WL_SHM_FORMAT_RGB565: (none)
+ * @WL_SHM_FORMAT_BGR565: (none)
+ * @WL_SHM_FORMAT_RGB888: (none)
+ * @WL_SHM_FORMAT_BGR888: (none)
+ * @WL_SHM_FORMAT_XBGR8888: (none)
+ * @WL_SHM_FORMAT_RGBX8888: (none)
+ * @WL_SHM_FORMAT_BGRX8888: (none)
+ * @WL_SHM_FORMAT_ABGR8888: (none)
+ * @WL_SHM_FORMAT_RGBA8888: (none)
+ * @WL_SHM_FORMAT_BGRA8888: (none)
+ * @WL_SHM_FORMAT_XRGB2101010: (none)
+ * @WL_SHM_FORMAT_XBGR2101010: (none)
+ * @WL_SHM_FORMAT_RGBX1010102: (none)
+ * @WL_SHM_FORMAT_BGRX1010102: (none)
+ * @WL_SHM_FORMAT_ARGB2101010: (none)
+ * @WL_SHM_FORMAT_ABGR2101010: (none)
+ * @WL_SHM_FORMAT_RGBA1010102: (none)
+ * @WL_SHM_FORMAT_BGRA1010102: (none)
+ * @WL_SHM_FORMAT_YUYV: (none)
+ * @WL_SHM_FORMAT_YVYU: (none)
+ * @WL_SHM_FORMAT_UYVY: (none)
+ * @WL_SHM_FORMAT_VYUY: (none)
+ * @WL_SHM_FORMAT_AYUV: (none)
+ * @WL_SHM_FORMAT_NV12: (none)
+ * @WL_SHM_FORMAT_NV21: (none)
+ * @WL_SHM_FORMAT_NV16: (none)
+ * @WL_SHM_FORMAT_NV61: (none)
+ * @WL_SHM_FORMAT_YUV410: (none)
+ * @WL_SHM_FORMAT_YVU410: (none)
+ * @WL_SHM_FORMAT_YUV411: (none)
+ * @WL_SHM_FORMAT_YVU411: (none)
+ * @WL_SHM_FORMAT_YUV420: (none)
+ * @WL_SHM_FORMAT_YVU420: (none)
+ * @WL_SHM_FORMAT_YUV422: (none)
+ * @WL_SHM_FORMAT_YVU422: (none)
+ * @WL_SHM_FORMAT_YUV444: (none)
+ * @WL_SHM_FORMAT_YVU444: (none)
+ *
+ * This describes the memory layout of an individual pixel.
+ *
+ * All renderers should support argb8888 and xrgb8888 but any other formats
+ * are optional and may not be supported by the particular renderer in use.
+ */
+enum wl_shm_format {
+	WL_SHM_FORMAT_ARGB8888 = 0,
+	WL_SHM_FORMAT_XRGB8888 = 1,
+	WL_SHM_FORMAT_C8 = 0x20203843,
+	WL_SHM_FORMAT_RGB332 = 0x38424752,
+	WL_SHM_FORMAT_BGR233 = 0x38524742,
+	WL_SHM_FORMAT_XRGB4444 = 0x32315258,
+	WL_SHM_FORMAT_XBGR4444 = 0x32314258,
+	WL_SHM_FORMAT_RGBX4444 = 0x32315852,
+	WL_SHM_FORMAT_BGRX4444 = 0x32315842,
+	WL_SHM_FORMAT_ARGB4444 = 0x32315241,
+	WL_SHM_FORMAT_ABGR4444 = 0x32314241,
+	WL_SHM_FORMAT_RGBA4444 = 0x32314152,
+	WL_SHM_FORMAT_BGRA4444 = 0x32314142,
+	WL_SHM_FORMAT_XRGB1555 = 0x35315258,
+	WL_SHM_FORMAT_XBGR1555 = 0x35314258,
+	WL_SHM_FORMAT_RGBX5551 = 0x35315852,
+	WL_SHM_FORMAT_BGRX5551 = 0x35315842,
+	WL_SHM_FORMAT_ARGB1555 = 0x35315241,
+	WL_SHM_FORMAT_ABGR1555 = 0x35314241,
+	WL_SHM_FORMAT_RGBA5551 = 0x35314152,
+	WL_SHM_FORMAT_BGRA5551 = 0x35314142,
+	WL_SHM_FORMAT_RGB565 = 0x36314752,
+	WL_SHM_FORMAT_BGR565 = 0x36314742,
+	WL_SHM_FORMAT_RGB888 = 0x34324752,
+	WL_SHM_FORMAT_BGR888 = 0x34324742,
+	WL_SHM_FORMAT_XBGR8888 = 0x34324258,
+	WL_SHM_FORMAT_RGBX8888 = 0x34325852,
+	WL_SHM_FORMAT_BGRX8888 = 0x34325842,
+	WL_SHM_FORMAT_ABGR8888 = 0x34324241,
+	WL_SHM_FORMAT_RGBA8888 = 0x34324152,
+	WL_SHM_FORMAT_BGRA8888 = 0x34324142,
+	WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
+	WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
+	WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
+	WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
+	WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
+	WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
+	WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
+	WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
+	WL_SHM_FORMAT_YUYV = 0x56595559,
+	WL_SHM_FORMAT_YVYU = 0x55595659,
+	WL_SHM_FORMAT_UYVY = 0x59565955,
+	WL_SHM_FORMAT_VYUY = 0x59555956,
+	WL_SHM_FORMAT_AYUV = 0x56555941,
+	WL_SHM_FORMAT_NV12 = 0x3231564e,
+	WL_SHM_FORMAT_NV21 = 0x3132564e,
+	WL_SHM_FORMAT_NV16 = 0x3631564e,
+	WL_SHM_FORMAT_NV61 = 0x3136564e,
+	WL_SHM_FORMAT_YUV410 = 0x39565559,
+	WL_SHM_FORMAT_YVU410 = 0x39555659,
+	WL_SHM_FORMAT_YUV411 = 0x31315559,
+	WL_SHM_FORMAT_YVU411 = 0x31315659,
+	WL_SHM_FORMAT_YUV420 = 0x32315559,
+	WL_SHM_FORMAT_YVU420 = 0x32315659,
+	WL_SHM_FORMAT_YUV422 = 0x36315559,
+	WL_SHM_FORMAT_YVU422 = 0x36315659,
+	WL_SHM_FORMAT_YUV444 = 0x34325559,
+	WL_SHM_FORMAT_YVU444 = 0x34325659,
+};
+#endif /* WL_SHM_FORMAT_ENUM */
+
+/**
+ * wl_shm - shared memory support
+ * @create_pool: create a shm pool
+ *
+ * A global singleton object that provides support for shared memory.
+ *
+ * Clients can create wl_shm_pool objects using the create_pool request.
+ *
+ * At connection setup time, the wl_shm object emits one or more format
+ * events to inform clients about the valid pixel formats that can be used
+ * for buffers.
+ */
+struct wl_shm_interface {
+	/**
+	 * create_pool - create a shm pool
+	 * @id: (none)
+	 * @fd: (none)
+	 * @size: (none)
+	 *
+	 * Create a new wl_shm_pool object.
+	 *
+	 * The pool can be used to create shared memory based buffer
+	 * objects. The server will mmap size bytes of the passed file
+	 * descriptor, to use as backing memory for the pool.
+	 */
+	void (*create_pool)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    uint32_t id,
+			    int32_t fd,
+			    int32_t size);
+};
+
+#define WL_SHM_FORMAT	0
+
+#define WL_SHM_FORMAT_SINCE_VERSION	1
+
+static inline void
+wl_shm_send_format(struct wl_resource *resource_, uint32_t format)
+{
+	wl_resource_post_event(resource_, WL_SHM_FORMAT, format);
+}
+
+/**
+ * wl_buffer - content for a wl_surface
+ * @destroy: destroy a buffer
+ *
+ * A buffer provides the content for a wl_surface. Buffers are created
+ * through factory interfaces such as wl_drm, wl_shm or similar. It has a
+ * width and a height and can be attached to a wl_surface, but the
+ * mechanism by which a client provides and updates the contents is defined
+ * by the buffer factory interface.
+ */
+struct wl_buffer_interface {
+	/**
+	 * destroy - destroy a buffer
+	 *
+	 * Destroy a buffer. If and how you need to release the backing
+	 * storage is defined by the buffer factory interface.
+	 *
+	 * For possible side-effects to a surface, see wl_surface.attach.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_BUFFER_RELEASE	0
+
+#define WL_BUFFER_RELEASE_SINCE_VERSION	1
+
+static inline void
+wl_buffer_send_release(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_BUFFER_RELEASE);
+}
+
+/**
+ * wl_data_offer - offer to transfer data
+ * @accept: accept one of the offered mime types
+ * @receive: request that the data is transferred
+ * @destroy: destroy data offer
+ *
+ * A wl_data_offer represents a piece of data offered for transfer by
+ * another client (the source client). It is used by the copy-and-paste and
+ * drag-and-drop mechanisms. The offer describes the different mime types
+ * that the data can be converted to and provides the mechanism for
+ * transferring the data directly from the source client.
+ */
+struct wl_data_offer_interface {
+	/**
+	 * accept - accept one of the offered mime types
+	 * @serial: (none)
+	 * @mime_type: (none)
+	 *
+	 * Indicate that the client can accept the given mime type, or
+	 * NULL for not accepted.
+	 *
+	 * Used for feedback during drag-and-drop.
+	 */
+	void (*accept)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       uint32_t serial,
+		       const char *mime_type);
+	/**
+	 * receive - request that the data is transferred
+	 * @mime_type: (none)
+	 * @fd: (none)
+	 *
+	 * To transfer the offered data, the client issues this request
+	 * and indicates the mime type it wants to receive. The transfer
+	 * happens through the passed file descriptor (typically created
+	 * with the pipe system call). The source client writes the data in
+	 * the mime type representation requested and then closes the file
+	 * descriptor.
+	 *
+	 * The receiving client reads from the read end of the pipe until
+	 * EOF and then closes its end, at which point the transfer is
+	 * complete.
+	 */
+	void (*receive)(struct wl_client *client,
+			struct wl_resource *resource,
+			const char *mime_type,
+			int32_t fd);
+	/**
+	 * destroy - destroy data offer
+	 *
+	 * Destroy the data offer.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_DATA_OFFER_OFFER	0
+
+#define WL_DATA_OFFER_OFFER_SINCE_VERSION	1
+
+static inline void
+wl_data_offer_send_offer(struct wl_resource *resource_, const char *mime_type)
+{
+	wl_resource_post_event(resource_, WL_DATA_OFFER_OFFER, mime_type);
+}
+
+/**
+ * wl_data_source - offer to transfer data
+ * @offer: add an offered mime type
+ * @destroy: destroy the data source
+ *
+ * The wl_data_source object is the source side of a wl_data_offer. It is
+ * created by the source client in a data transfer and provides a way to
+ * describe the offered data and a way to respond to requests to transfer
+ * the data.
+ */
+struct wl_data_source_interface {
+	/**
+	 * offer - add an offered mime type
+	 * @mime_type: (none)
+	 *
+	 * This request adds a mime type to the set of mime types
+	 * advertised to targets. Can be called several times to offer
+	 * multiple types.
+	 */
+	void (*offer)(struct wl_client *client,
+		      struct wl_resource *resource,
+		      const char *mime_type);
+	/**
+	 * destroy - destroy the data source
+	 *
+	 * Destroy the data source.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_DATA_SOURCE_TARGET	0
+#define WL_DATA_SOURCE_SEND	1
+#define WL_DATA_SOURCE_CANCELLED	2
+
+#define WL_DATA_SOURCE_TARGET_SINCE_VERSION	1
+#define WL_DATA_SOURCE_SEND_SINCE_VERSION	1
+#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION	1
+
+static inline void
+wl_data_source_send_target(struct wl_resource *resource_, const char *mime_type)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_TARGET, mime_type);
+}
+
+static inline void
+wl_data_source_send_send(struct wl_resource *resource_, const char *mime_type, int32_t fd)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_SEND, mime_type, fd);
+}
+
+static inline void
+wl_data_source_send_cancelled(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_CANCELLED);
+}
+
+#ifndef WL_DATA_DEVICE_ERROR_ENUM
+#define WL_DATA_DEVICE_ERROR_ENUM
+enum wl_data_device_error {
+	WL_DATA_DEVICE_ERROR_ROLE = 0,
+};
+#endif /* WL_DATA_DEVICE_ERROR_ENUM */
+
+/**
+ * wl_data_device - data transfer device
+ * @start_drag: start drag-and-drop operation
+ * @set_selection: copy data to the selection
+ * @release: destroy data device
+ *
+ * There is one wl_data_device per seat which can be obtained from the
+ * global wl_data_device_manager singleton.
+ *
+ * A wl_data_device provides access to inter-client data transfer
+ * mechanisms such as copy-and-paste and drag-and-drop.
+ */
+struct wl_data_device_interface {
+	/**
+	 * start_drag - start drag-and-drop operation
+	 * @source: (none)
+	 * @origin: (none)
+	 * @icon: (none)
+	 * @serial: serial of the implicit grab on the origin
+	 *
+	 * This request asks the compositor to start a drag-and-drop
+	 * operation on behalf of the client.
+	 *
+	 * The source argument is the data source that provides the data
+	 * for the eventual data transfer. If source is NULL, enter, leave
+	 * and motion events are sent only to the client that initiated the
+	 * drag and the client is expected to handle the data passing
+	 * internally.
+	 *
+	 * The origin surface is the surface where the drag originates and
+	 * the client must have an active implicit grab that matches the
+	 * serial.
+	 *
+	 * The icon surface is an optional (can be NULL) surface that
+	 * provides an icon to be moved around with the cursor. Initially,
+	 * the top-left corner of the icon surface is placed at the cursor
+	 * hotspot, but subsequent wl_surface.attach request can move the
+	 * relative position. Attach requests must be confirmed with
+	 * wl_surface.commit as usual. The icon surface is given the role
+	 * of a drag-and-drop icon. If the icon surface already has another
+	 * role, it raises a protocol error.
+	 *
+	 * The current and pending input regions of the icon wl_surface are
+	 * cleared, and wl_surface.set_input_region is ignored until the
+	 * wl_surface is no longer used as the icon surface. When the use
+	 * as an icon ends, the current and pending input regions become
+	 * undefined, and the wl_surface is unmapped.
+	 */
+	void (*start_drag)(struct wl_client *client,
+			   struct wl_resource *resource,
+			   struct wl_resource *source,
+			   struct wl_resource *origin,
+			   struct wl_resource *icon,
+			   uint32_t serial);
+	/**
+	 * set_selection - copy data to the selection
+	 * @source: (none)
+	 * @serial: serial of the event that triggered this request
+	 *
+	 * This request asks the compositor to set the selection to the
+	 * data from the source on behalf of the client.
+	 *
+	 * To unset the selection, set the source to NULL.
+	 */
+	void (*set_selection)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *source,
+			      uint32_t serial);
+	/**
+	 * release - destroy data device
+	 *
+	 * This request destroys the data device.
+	 * @since: 2
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_DATA_DEVICE_DATA_OFFER	0
+#define WL_DATA_DEVICE_ENTER	1
+#define WL_DATA_DEVICE_LEAVE	2
+#define WL_DATA_DEVICE_MOTION	3
+#define WL_DATA_DEVICE_DROP	4
+#define WL_DATA_DEVICE_SELECTION	5
+
+#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION	1
+#define WL_DATA_DEVICE_ENTER_SINCE_VERSION	1
+#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION	1
+#define WL_DATA_DEVICE_MOTION_SINCE_VERSION	1
+#define WL_DATA_DEVICE_DROP_SINCE_VERSION	1
+#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION	1
+
+static inline void
+wl_data_device_send_data_offer(struct wl_resource *resource_, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_DATA_OFFER, id);
+}
+
+static inline void
+wl_data_device_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_ENTER, serial, surface, x, y, id);
+}
+
+static inline void
+wl_data_device_send_leave(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_LEAVE);
+}
+
+static inline void
+wl_data_device_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_MOTION, time, x, y);
+}
+
+static inline void
+wl_data_device_send_drop(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_DROP);
+}
+
+static inline void
+wl_data_device_send_selection(struct wl_resource *resource_, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_SELECTION, id);
+}
+
+/**
+ * wl_data_device_manager - data transfer interface
+ * @create_data_source: create a new data source
+ * @get_data_device: create a new data device
+ *
+ * The wl_data_device_manager is a singleton global object that provides
+ * access to inter-client data transfer mechanisms such as copy-and-paste
+ * and drag-and-drop. These mechanisms are tied to a wl_seat and this
+ * interface lets a client get a wl_data_device corresponding to a wl_seat.
+ */
+struct wl_data_device_manager_interface {
+	/**
+	 * create_data_source - create a new data source
+	 * @id: (none)
+	 *
+	 * Create a new data source.
+	 */
+	void (*create_data_source)(struct wl_client *client,
+				   struct wl_resource *resource,
+				   uint32_t id);
+	/**
+	 * get_data_device - create a new data device
+	 * @id: (none)
+	 * @seat: (none)
+	 *
+	 * Create a new data device for a given seat.
+	 */
+	void (*get_data_device)(struct wl_client *client,
+				struct wl_resource *resource,
+				uint32_t id,
+				struct wl_resource *seat);
+};
+
+
+#ifndef WL_SHELL_ERROR_ENUM
+#define WL_SHELL_ERROR_ENUM
+enum wl_shell_error {
+	WL_SHELL_ERROR_ROLE = 0,
+};
+#endif /* WL_SHELL_ERROR_ENUM */
+
+/**
+ * wl_shell - create desktop-style surfaces
+ * @get_shell_surface: create a shell surface from a surface
+ *
+ * This interface is implemented by servers that provide desktop-style
+ * user interfaces.
+ *
+ * It allows clients to associate a wl_shell_surface with a basic surface.
+ */
+struct wl_shell_interface {
+	/**
+	 * get_shell_surface - create a shell surface from a surface
+	 * @id: (none)
+	 * @surface: (none)
+	 *
+	 * Create a shell surface for an existing surface. This gives the
+	 * wl_surface the role of a shell surface. If the wl_surface
+	 * already has another role, it raises a protocol error.
+	 *
+	 * Only one shell surface can be associated with a given surface.
+	 */
+	void (*get_shell_surface)(struct wl_client *client,
+				  struct wl_resource *resource,
+				  uint32_t id,
+				  struct wl_resource *surface);
+};
+
+
+#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
+#define WL_SHELL_SURFACE_RESIZE_ENUM
+/**
+ * wl_shell_surface_resize - edge values for resizing
+ * @WL_SHELL_SURFACE_RESIZE_NONE: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM: (none)
+ * @WL_SHELL_SURFACE_RESIZE_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_RIGHT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: (none)
+ *
+ * These values are used to indicate which edge of a surface is being
+ * dragged in a resize operation. The server may use this information to
+ * adapt its behavior, e.g. choose an appropriate cursor image.
+ */
+enum wl_shell_surface_resize {
+	WL_SHELL_SURFACE_RESIZE_NONE = 0,
+	WL_SHELL_SURFACE_RESIZE_TOP = 1,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
+	WL_SHELL_SURFACE_RESIZE_LEFT = 4,
+	WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
+	WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
+	WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
+};
+#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
+
+#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
+#define WL_SHELL_SURFACE_TRANSIENT_ENUM
+/**
+ * wl_shell_surface_transient - details of transient behaviour
+ * @WL_SHELL_SURFACE_TRANSIENT_INACTIVE: do not set keyboard focus
+ *
+ * These flags specify details of the expected behaviour of transient
+ * surfaces. Used in the set_transient request.
+ */
+enum wl_shell_surface_transient {
+	WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
+};
+#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
+
+#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+/**
+ * wl_shell_surface_fullscreen_method - different method to set the
+ *	surface fullscreen
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT: no preference, apply
+ *	default policy
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE: scale, preserve the
+ *	surface's aspect ratio and center on output
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: switch output mode to the
+ *	smallest mode that can fit the surface, add black borders to compensate
+ *	size mismatch
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: no upscaling, center on
+ *	output and add black borders to compensate size mismatch
+ *
+ * Hints to indicate to the compositor how to deal with a conflict
+ * between the dimensions of the surface and the dimensions of the output.
+ * The compositor is free to ignore this parameter.
+ */
+enum wl_shell_surface_fullscreen_method {
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
+};
+#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
+
+/**
+ * wl_shell_surface - desktop-style metadata interface
+ * @pong: respond to a ping event
+ * @move: start an interactive move
+ * @resize: start an interactive resize
+ * @set_toplevel: make the surface a toplevel surface
+ * @set_transient: make the surface a transient surface
+ * @set_fullscreen: make the surface a fullscreen surface
+ * @set_popup: make the surface a popup surface
+ * @set_maximized: make the surface a maximized surface
+ * @set_title: set surface title
+ * @set_class: set surface class
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like toplevel, fullscreen or
+ * popup windows, move, resize or maximize them, associate metadata like
+ * title and class, etc.
+ *
+ * On the server side the object is automatically destroyed when the
+ * related wl_surface is destroyed. On client side,
+ * wl_shell_surface_destroy() must be called before destroying the
+ * wl_surface object.
+ */
+struct wl_shell_surface_interface {
+	/**
+	 * pong - respond to a ping event
+	 * @serial: serial of the ping event
+	 *
+	 * A client must respond to a ping event with a pong request or
+	 * the client may be deemed unresponsive.
+	 */
+	void (*pong)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t serial);
+	/**
+	 * move - start an interactive move
+	 * @seat: the wl_seat whose pointer is used
+	 * @serial: serial of the implicit grab on the pointer
+	 *
+	 * Start a pointer-driven move of the surface.
+	 *
+	 * This request must be used in response to a button press event.
+	 * The server may ignore move requests depending on the state of
+	 * the surface (e.g. fullscreen or maximized).
+	 */
+	void (*move)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     struct wl_resource *seat,
+		     uint32_t serial);
+	/**
+	 * resize - start an interactive resize
+	 * @seat: the wl_seat whose pointer is used
+	 * @serial: serial of the implicit grab on the pointer
+	 * @edges: which edge or corner is being dragged
+	 *
+	 * Start a pointer-driven resizing of the surface.
+	 *
+	 * This request must be used in response to a button press event.
+	 * The server may ignore resize requests depending on the state of
+	 * the surface (e.g. fullscreen or maximized).
+	 */
+	void (*resize)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       struct wl_resource *seat,
+		       uint32_t serial,
+		       uint32_t edges);
+	/**
+	 * set_toplevel - make the surface a toplevel surface
+	 *
+	 * Map the surface as a toplevel surface.
+	 *
+	 * A toplevel surface is not fullscreen, maximized or transient.
+	 */
+	void (*set_toplevel)(struct wl_client *client,
+			     struct wl_resource *resource);
+	/**
+	 * set_transient - make the surface a transient surface
+	 * @parent: (none)
+	 * @x: (none)
+	 * @y: (none)
+	 * @flags: (none)
+	 *
+	 * Map the surface relative to an existing surface.
+	 *
+	 * The x and y arguments specify the locations of the upper left
+	 * corner of the surface relative to the upper left corner of the
+	 * parent surface, in surface local coordinates.
+	 *
+	 * The flags argument controls details of the transient behaviour.
+	 */
+	void (*set_transient)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *parent,
+			      int32_t x,
+			      int32_t y,
+			      uint32_t flags);
+	/**
+	 * set_fullscreen - make the surface a fullscreen surface
+	 * @method: (none)
+	 * @framerate: (none)
+	 * @output: (none)
+	 *
+	 * Map the surface as a fullscreen surface.
+	 *
+	 * If an output parameter is given then the surface will be made
+	 * fullscreen on that output. If the client does not specify the
+	 * output then the compositor will apply its policy - usually
+	 * choosing the output on which the surface has the biggest surface
+	 * area.
+	 *
+	 * The client may specify a method to resolve a size conflict
+	 * between the output size and the surface size - this is provided
+	 * through the method parameter.
+	 *
+	 * The framerate parameter is used only when the method is set to
+	 * "driver", to indicate the preferred framerate. A value of 0
+	 * indicates that the app does not care about framerate. The
+	 * framerate is specified in mHz, that is framerate of 60000 is
+	 * 60Hz.
+	 *
+	 * A method of "scale" or "driver" implies a scaling operation of
+	 * the surface, either via a direct scaling operation or a change
+	 * of the output mode. This will override any kind of output
+	 * scaling, so that mapping a surface with a buffer size equal to
+	 * the mode can fill the screen independent of buffer_scale.
+	 *
+	 * A method of "fill" means we don't scale up the buffer, however
+	 * any output scale is applied. This means that you may run into an
+	 * edge case where the application maps a buffer with the same size
+	 * of the output mode but buffer_scale 1 (thus making a surface
+	 * larger than the output). In this case it is allowed to downscale
+	 * the results to fit the screen.
+	 *
+	 * The compositor must reply to this request with a configure event
+	 * with the dimensions for the output on which the surface will be
+	 * made fullscreen.
+	 */
+	void (*set_fullscreen)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t method,
+			       uint32_t framerate,
+			       struct wl_resource *output);
+	/**
+	 * set_popup - make the surface a popup surface
+	 * @seat: the wl_seat whose pointer is used
+	 * @serial: serial of the implicit grab on the pointer
+	 * @parent: (none)
+	 * @x: (none)
+	 * @y: (none)
+	 * @flags: (none)
+	 *
+	 * Map the surface as a popup.
+	 *
+	 * A popup surface is a transient surface with an added pointer
+	 * grab.
+	 *
+	 * An existing implicit grab will be changed to owner-events mode,
+	 * and the popup grab will continue after the implicit grab ends
+	 * (i.e. releasing the mouse button does not cause the popup to be
+	 * unmapped).
+	 *
+	 * The popup grab continues until the window is destroyed or a
+	 * mouse button is pressed in any other clients window. A click in
+	 * any of the clients surfaces is reported as normal, however,
+	 * clicks in other clients surfaces will be discarded and trigger
+	 * the callback.
+	 *
+	 * The x and y arguments specify the locations of the upper left
+	 * corner of the surface relative to the upper left corner of the
+	 * parent surface, in surface local coordinates.
+	 */
+	void (*set_popup)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  struct wl_resource *seat,
+			  uint32_t serial,
+			  struct wl_resource *parent,
+			  int32_t x,
+			  int32_t y,
+			  uint32_t flags);
+	/**
+	 * set_maximized - make the surface a maximized surface
+	 * @output: (none)
+	 *
+	 * Map the surface as a maximized surface.
+	 *
+	 * If an output parameter is given then the surface will be
+	 * maximized on that output. If the client does not specify the
+	 * output then the compositor will apply its policy - usually
+	 * choosing the output on which the surface has the biggest surface
+	 * area.
+	 *
+	 * The compositor will reply with a configure event telling the
+	 * expected new surface size. The operation is completed on the
+	 * next buffer attach to this surface.
+	 *
+	 * A maximized surface typically fills the entire output it is
+	 * bound to, except for desktop element such as panels. This is the
+	 * main difference between a maximized shell surface and a
+	 * fullscreen shell surface.
+	 *
+	 * The details depend on the compositor implementation.
+	 */
+	void (*set_maximized)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *output);
+	/**
+	 * set_title - set surface title
+	 * @title: (none)
+	 *
+	 * Set a short title for the surface.
+	 *
+	 * This string may be used to identify the surface in a task bar,
+	 * window list, or other user interface elements provided by the
+	 * compositor.
+	 *
+	 * The string must be encoded in UTF-8.
+	 */
+	void (*set_title)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  const char *title);
+	/**
+	 * set_class - set surface class
+	 * @class_: (none)
+	 *
+	 * Set a class for the surface.
+	 *
+	 * The surface class identifies the general class of applications
+	 * to which the surface belongs. A common convention is to use the
+	 * file name (or the full path if it is a non-standard location) of
+	 * the application's .desktop file as the class.
+	 */
+	void (*set_class)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  const char *class_);
+};
+
+#define WL_SHELL_SURFACE_PING	0
+#define WL_SHELL_SURFACE_CONFIGURE	1
+#define WL_SHELL_SURFACE_POPUP_DONE	2
+
+#define WL_SHELL_SURFACE_PING_SINCE_VERSION	1
+#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION	1
+#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION	1
+
+static inline void
+wl_shell_surface_send_ping(struct wl_resource *resource_, uint32_t serial)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_PING, serial);
+}
+
+static inline void
+wl_shell_surface_send_configure(struct wl_resource *resource_, uint32_t edges, int32_t width, int32_t height)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_CONFIGURE, edges, width, height);
+}
+
+static inline void
+wl_shell_surface_send_popup_done(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_POPUP_DONE);
+}
+
+#ifndef WL_SURFACE_ERROR_ENUM
+#define WL_SURFACE_ERROR_ENUM
+/**
+ * wl_surface_error - wl_surface error values
+ * @WL_SURFACE_ERROR_INVALID_SCALE: buffer scale value is invalid
+ * @WL_SURFACE_ERROR_INVALID_TRANSFORM: buffer transform value is invalid
+ *
+ * These errors can be emitted in response to wl_surface requests.
+ */
+enum wl_surface_error {
+	WL_SURFACE_ERROR_INVALID_SCALE = 0,
+	WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
+};
+#endif /* WL_SURFACE_ERROR_ENUM */
+
+/**
+ * wl_surface - an onscreen surface
+ * @destroy: delete surface
+ * @attach: set the surface contents
+ * @damage: mark part of the surface damaged
+ * @frame: request a frame throttling hint
+ * @set_opaque_region: set opaque region
+ * @set_input_region: set input region
+ * @commit: commit pending surface state
+ * @set_buffer_transform: sets the buffer transformation
+ * @set_buffer_scale: sets the buffer scaling factor
+ *
+ * A surface is a rectangular area that is displayed on the screen. It
+ * has a location, size and pixel contents.
+ *
+ * The size of a surface (and relative positions on it) is described in
+ * surface local coordinates, which may differ from the buffer local
+ * coordinates of the pixel content, in case a buffer_transform or a
+ * buffer_scale is used.
+ *
+ * A surface without a "role" is fairly useless, a compositor does not know
+ * where, when or how to present it. The role is the purpose of a
+ * wl_surface. Examples of roles are a cursor for a pointer (as set by
+ * wl_pointer.set_cursor), a drag icon (wl_data_device.start_drag), a
+ * sub-surface (wl_subcompositor.get_subsurface), and a window as defined
+ * by a shell protocol (e.g. wl_shell.get_shell_surface).
+ *
+ * A surface can have only one role at a time. Initially a wl_surface does
+ * not have a role. Once a wl_surface is given a role, it is set
+ * permanently for the whole lifetime of the wl_surface object. Giving the
+ * current role again is allowed, unless explicitly forbidden by the
+ * relevant interface specification.
+ *
+ * Surface roles are given by requests in other interfaces such as
+ * wl_pointer.set_cursor. The request should explicitly mention that this
+ * request gives a role to a wl_surface. Often, this request also creates a
+ * new protocol object that represents the role and adds additional
+ * functionality to wl_surface. When a client wants to destroy a
+ * wl_surface, they must destroy this 'role object' before the wl_surface.
+ *
+ * Destroying the role object does not remove the role from the wl_surface,
+ * but it may stop the wl_surface from "playing the role". For instance, if
+ * a wl_subsurface object is destroyed, the wl_surface it was created for
+ * will be unmapped and forget its position and z-order. It is allowed to
+ * create a wl_subsurface for the same wl_surface again, but it is not
+ * allowed to use the wl_surface as a cursor (cursor is a different role
+ * than sub-surface, and role switching is not allowed).
+ */
+struct wl_surface_interface {
+	/**
+	 * destroy - delete surface
+	 *
+	 * Deletes the surface and invalidates its object ID.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * attach - set the surface contents
+	 * @buffer: (none)
+	 * @x: (none)
+	 * @y: (none)
+	 *
+	 * Set a buffer as the content of this surface.
+	 *
+	 * The new size of the surface is calculated based on the buffer
+	 * size transformed by the inverse buffer_transform and the inverse
+	 * buffer_scale. This means that the supplied buffer must be an
+	 * integer multiple of the buffer_scale.
+	 *
+	 * The x and y arguments specify the location of the new pending
+	 * buffer's upper left corner, relative to the current buffer's
+	 * upper left corner, in surface local coordinates. In other words,
+	 * the x and y, combined with the new surface size define in which
+	 * directions the surface's size changes.
+	 *
+	 * Surface contents are double-buffered state, see
+	 * wl_surface.commit.
+	 *
+	 * The initial surface contents are void; there is no content.
+	 * wl_surface.attach assigns the given wl_buffer as the pending
+	 * wl_buffer. wl_surface.commit makes the pending wl_buffer the new
+	 * surface contents, and the size of the surface becomes the size
+	 * calculated from the wl_buffer, as described above. After commit,
+	 * there is no pending buffer until the next attach.
+	 *
+	 * Committing a pending wl_buffer allows the compositor to read the
+	 * pixels in the wl_buffer. The compositor may access the pixels at
+	 * any time after the wl_surface.commit request. When the
+	 * compositor will not access the pixels anymore, it will send the
+	 * wl_buffer.release event. Only after receiving wl_buffer.release,
+	 * the client may re-use the wl_buffer. A wl_buffer that has been
+	 * attached and then replaced by another attach instead of
+	 * committed will not receive a release event, and is not used by
+	 * the compositor.
+	 *
+	 * Destroying the wl_buffer after wl_buffer.release does not change
+	 * the surface contents. However, if the client destroys the
+	 * wl_buffer before receiving the wl_buffer.release event, the
+	 * surface contents become undefined immediately.
+	 *
+	 * If wl_surface.attach is sent with a NULL wl_buffer, the
+	 * following wl_surface.commit will remove the surface content.
+	 */
+	void (*attach)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       struct wl_resource *buffer,
+		       int32_t x,
+		       int32_t y);
+	/**
+	 * damage - mark part of the surface damaged
+	 * @x: (none)
+	 * @y: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 *
+	 * This request is used to describe the regions where the pending
+	 * buffer is different from the current surface contents, and where
+	 * the surface therefore needs to be repainted. The pending buffer
+	 * must be set by wl_surface.attach before sending damage. The
+	 * compositor ignores the parts of the damage that fall outside of
+	 * the surface.
+	 *
+	 * Damage is double-buffered state, see wl_surface.commit.
+	 *
+	 * The damage rectangle is specified in surface local coordinates.
+	 *
+	 * The initial value for pending damage is empty: no damage.
+	 * wl_surface.damage adds pending damage: the new pending damage is
+	 * the union of old pending damage and the given rectangle.
+	 *
+	 * wl_surface.commit assigns pending damage as the current damage,
+	 * and clears pending damage. The server will clear the current
+	 * damage as it repaints the surface.
+	 */
+	void (*damage)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       int32_t x,
+		       int32_t y,
+		       int32_t width,
+		       int32_t height);
+	/**
+	 * frame - request a frame throttling hint
+	 * @callback: (none)
+	 *
+	 * Request a notification when it is a good time start drawing a
+	 * new frame, by creating a frame callback. This is useful for
+	 * throttling redrawing operations, and driving animations.
+	 *
+	 * When a client is animating on a wl_surface, it can use the
+	 * 'frame' request to get notified when it is a good time to draw
+	 * and commit the next frame of animation. If the client commits an
+	 * update earlier than that, it is likely that some updates will
+	 * not make it to the display, and the client is wasting resources
+	 * by drawing too often.
+	 *
+	 * The frame request will take effect on the next
+	 * wl_surface.commit. The notification will only be posted for one
+	 * frame unless requested again. For a wl_surface, the
+	 * notifications are posted in the order the frame requests were
+	 * committed.
+	 *
+	 * The server must send the notifications so that a client will not
+	 * send excessive updates, while still allowing the highest
+	 * possible update rate for clients that wait for the reply before
+	 * drawing again. The server should give some time for the client
+	 * to draw and commit after sending the frame callback events to
+	 * let them hit the next output refresh.
+	 *
+	 * A server should avoid signalling the frame callbacks if the
+	 * surface is not visible in any way, e.g. the surface is
+	 * off-screen, or completely obscured by other opaque surfaces.
+	 *
+	 * The object returned by this request will be destroyed by the
+	 * compositor after the callback is fired and as such the client
+	 * must not attempt to use it after that point.
+	 *
+	 * The callback_data passed in the callback is the current time, in
+	 * milliseconds, with an undefined base.
+	 */
+	void (*frame)(struct wl_client *client,
+		      struct wl_resource *resource,
+		      uint32_t callback);
+	/**
+	 * set_opaque_region - set opaque region
+	 * @region: (none)
+	 *
+	 * This request sets the region of the surface that contains
+	 * opaque content.
+	 *
+	 * The opaque region is an optimization hint for the compositor
+	 * that lets it optimize out redrawing of content behind opaque
+	 * regions. Setting an opaque region is not required for correct
+	 * behaviour, but marking transparent content as opaque will result
+	 * in repaint artifacts.
+	 *
+	 * The opaque region is specified in surface local coordinates.
+	 *
+	 * The compositor ignores the parts of the opaque region that fall
+	 * outside of the surface.
+	 *
+	 * Opaque region is double-buffered state, see wl_surface.commit.
+	 *
+	 * wl_surface.set_opaque_region changes the pending opaque region.
+	 * wl_surface.commit copies the pending region to the current
+	 * region. Otherwise, the pending and current regions are never
+	 * changed.
+	 *
+	 * The initial value for opaque region is empty. Setting the
+	 * pending opaque region has copy semantics, and the wl_region
+	 * object can be destroyed immediately. A NULL wl_region causes the
+	 * pending opaque region to be set to empty.
+	 */
+	void (*set_opaque_region)(struct wl_client *client,
+				  struct wl_resource *resource,
+				  struct wl_resource *region);
+	/**
+	 * set_input_region - set input region
+	 * @region: (none)
+	 *
+	 * This request sets the region of the surface that can receive
+	 * pointer and touch events.
+	 *
+	 * Input events happening outside of this region will try the next
+	 * surface in the server surface stack. The compositor ignores the
+	 * parts of the input region that fall outside of the surface.
+	 *
+	 * The input region is specified in surface local coordinates.
+	 *
+	 * Input region is double-buffered state, see wl_surface.commit.
+	 *
+	 * wl_surface.set_input_region changes the pending input region.
+	 * wl_surface.commit copies the pending region to the current
+	 * region. Otherwise the pending and current regions are never
+	 * changed, except cursor and icon surfaces are special cases, see
+	 * wl_pointer.set_cursor and wl_data_device.start_drag.
+	 *
+	 * The initial value for input region is infinite. That means the
+	 * whole surface will accept input. Setting the pending input
+	 * region has copy semantics, and the wl_region object can be
+	 * destroyed immediately. A NULL wl_region causes the input region
+	 * to be set to infinite.
+	 */
+	void (*set_input_region)(struct wl_client *client,
+				 struct wl_resource *resource,
+				 struct wl_resource *region);
+	/**
+	 * commit - commit pending surface state
+	 *
+	 * Surface state (input, opaque, and damage regions, attached
+	 * buffers, etc.) is double-buffered. Protocol requests modify the
+	 * pending state, as opposed to current state in use by the
+	 * compositor. Commit request atomically applies all pending state,
+	 * replacing the current state. After commit, the new pending state
+	 * is as documented for each related request.
+	 *
+	 * On commit, a pending wl_buffer is applied first, all other state
+	 * second. This means that all coordinates in double-buffered state
+	 * are relative to the new wl_buffer coming into use, except for
+	 * wl_surface.attach itself. If there is no pending wl_buffer, the
+	 * coordinates are relative to the current surface contents.
+	 *
+	 * All requests that need a commit to become effective are
+	 * documented to affect double-buffered state.
+	 *
+	 * Other interfaces may add further double-buffered surface state.
+	 */
+	void (*commit)(struct wl_client *client,
+		       struct wl_resource *resource);
+	/**
+	 * set_buffer_transform - sets the buffer transformation
+	 * @transform: (none)
+	 *
+	 * This request sets an optional transformation on how the
+	 * compositor interprets the contents of the buffer attached to the
+	 * surface. The accepted values for the transform parameter are the
+	 * values for wl_output.transform.
+	 *
+	 * Buffer transform is double-buffered state, see
+	 * wl_surface.commit.
+	 *
+	 * A newly created surface has its buffer transformation set to
+	 * normal.
+	 *
+	 * wl_surface.set_buffer_transform changes the pending buffer
+	 * transformation. wl_surface.commit copies the pending buffer
+	 * transformation to the current one. Otherwise, the pending and
+	 * current values are never changed.
+	 *
+	 * The purpose of this request is to allow clients to render
+	 * content according to the output transform, thus permiting the
+	 * compositor to use certain optimizations even if the display is
+	 * rotated. Using hardware overlays and scanning out a client
+	 * buffer for fullscreen surfaces are examples of such
+	 * optimizations. Those optimizations are highly dependent on the
+	 * compositor implementation, so the use of this request should be
+	 * considered on a case-by-case basis.
+	 *
+	 * Note that if the transform value includes 90 or 270 degree
+	 * rotation, the width of the buffer will become the surface height
+	 * and the height of the buffer will become the surface width.
+	 *
+	 * If transform is not one of the values from the
+	 * wl_output.transform enum the invalid_transform protocol error is
+	 * raised.
+	 * @since: 2
+	 */
+	void (*set_buffer_transform)(struct wl_client *client,
+				     struct wl_resource *resource,
+				     int32_t transform);
+	/**
+	 * set_buffer_scale - sets the buffer scaling factor
+	 * @scale: (none)
+	 *
+	 * This request sets an optional scaling factor on how the
+	 * compositor interprets the contents of the buffer attached to the
+	 * window.
+	 *
+	 * Buffer scale is double-buffered state, see wl_surface.commit.
+	 *
+	 * A newly created surface has its buffer scale set to 1.
+	 *
+	 * wl_surface.set_buffer_scale changes the pending buffer scale.
+	 * wl_surface.commit copies the pending buffer scale to the current
+	 * one. Otherwise, the pending and current values are never
+	 * changed.
+	 *
+	 * The purpose of this request is to allow clients to supply higher
+	 * resolution buffer data for use on high resolution outputs. Its
+	 * intended that you pick the same buffer scale as the scale of the
+	 * output that the surface is displayed on.This means the
+	 * compositor can avoid scaling when rendering the surface on that
+	 * output.
+	 *
+	 * Note that if the scale is larger than 1, then you have to attach
+	 * a buffer that is larger (by a factor of scale in each dimension)
+	 * than the desired surface size.
+	 *
+	 * If scale is not positive the invalid_scale protocol error is
+	 * raised.
+	 * @since: 3
+	 */
+	void (*set_buffer_scale)(struct wl_client *client,
+				 struct wl_resource *resource,
+				 int32_t scale);
+};
+
+#define WL_SURFACE_ENTER	0
+#define WL_SURFACE_LEAVE	1
+
+#define WL_SURFACE_ENTER_SINCE_VERSION	1
+#define WL_SURFACE_LEAVE_SINCE_VERSION	1
+
+static inline void
+wl_surface_send_enter(struct wl_resource *resource_, struct wl_resource *output)
+{
+	wl_resource_post_event(resource_, WL_SURFACE_ENTER, output);
+}
+
+static inline void
+wl_surface_send_leave(struct wl_resource *resource_, struct wl_resource *output)
+{
+	wl_resource_post_event(resource_, WL_SURFACE_LEAVE, output);
+}
+
+#ifndef WL_SEAT_CAPABILITY_ENUM
+#define WL_SEAT_CAPABILITY_ENUM
+/**
+ * wl_seat_capability - seat capability bitmask
+ * @WL_SEAT_CAPABILITY_POINTER: The seat has pointer devices
+ * @WL_SEAT_CAPABILITY_KEYBOARD: The seat has one or more keyboards
+ * @WL_SEAT_CAPABILITY_TOUCH: The seat has touch devices
+ *
+ * This is a bitmask of capabilities this seat has; if a member is set,
+ * then it is present on the seat.
+ */
+enum wl_seat_capability {
+	WL_SEAT_CAPABILITY_POINTER = 1,
+	WL_SEAT_CAPABILITY_KEYBOARD = 2,
+	WL_SEAT_CAPABILITY_TOUCH = 4,
+};
+#endif /* WL_SEAT_CAPABILITY_ENUM */
+
+/**
+ * wl_seat - group of input devices
+ * @get_pointer: return pointer object
+ * @get_keyboard: return keyboard object
+ * @get_touch: return touch object
+ *
+ * A seat is a group of keyboards, pointer and touch devices. This object
+ * is published as a global during start up, or when such a device is hot
+ * plugged. A seat typically has a pointer and maintains a keyboard focus
+ * and a pointer focus.
+ */
+struct wl_seat_interface {
+	/**
+	 * get_pointer - return pointer object
+	 * @id: (none)
+	 *
+	 * The ID provided will be initialized to the wl_pointer
+	 * interface for this seat.
+	 *
+	 * This request only takes effect if the seat has the pointer
+	 * capability.
+	 */
+	void (*get_pointer)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    uint32_t id);
+	/**
+	 * get_keyboard - return keyboard object
+	 * @id: (none)
+	 *
+	 * The ID provided will be initialized to the wl_keyboard
+	 * interface for this seat.
+	 *
+	 * This request only takes effect if the seat has the keyboard
+	 * capability.
+	 */
+	void (*get_keyboard)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t id);
+	/**
+	 * get_touch - return touch object
+	 * @id: (none)
+	 *
+	 * The ID provided will be initialized to the wl_touch interface
+	 * for this seat.
+	 *
+	 * This request only takes effect if the seat has the touch
+	 * capability.
+	 */
+	void (*get_touch)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  uint32_t id);
+};
+
+#define WL_SEAT_CAPABILITIES	0
+#define WL_SEAT_NAME	1
+
+#define WL_SEAT_CAPABILITIES_SINCE_VERSION	1
+#define WL_SEAT_NAME_SINCE_VERSION	2
+
+static inline void
+wl_seat_send_capabilities(struct wl_resource *resource_, uint32_t capabilities)
+{
+	wl_resource_post_event(resource_, WL_SEAT_CAPABILITIES, capabilities);
+}
+
+static inline void
+wl_seat_send_name(struct wl_resource *resource_, const char *name)
+{
+	wl_resource_post_event(resource_, WL_SEAT_NAME, name);
+}
+
+#ifndef WL_POINTER_ERROR_ENUM
+#define WL_POINTER_ERROR_ENUM
+enum wl_pointer_error {
+	WL_POINTER_ERROR_ROLE = 0,
+};
+#endif /* WL_POINTER_ERROR_ENUM */
+
+#ifndef WL_POINTER_BUTTON_STATE_ENUM
+#define WL_POINTER_BUTTON_STATE_ENUM
+/**
+ * wl_pointer_button_state - physical button state
+ * @WL_POINTER_BUTTON_STATE_RELEASED: The button is not pressed
+ * @WL_POINTER_BUTTON_STATE_PRESSED: The button is pressed
+ *
+ * Describes the physical state of a button which provoked the button
+ * event.
+ */
+enum wl_pointer_button_state {
+	WL_POINTER_BUTTON_STATE_RELEASED = 0,
+	WL_POINTER_BUTTON_STATE_PRESSED = 1,
+};
+#endif /* WL_POINTER_BUTTON_STATE_ENUM */
+
+#ifndef WL_POINTER_AXIS_ENUM
+#define WL_POINTER_AXIS_ENUM
+/**
+ * wl_pointer_axis - axis types
+ * @WL_POINTER_AXIS_VERTICAL_SCROLL: (none)
+ * @WL_POINTER_AXIS_HORIZONTAL_SCROLL: (none)
+ *
+ * Describes the axis types of scroll events.
+ */
+enum wl_pointer_axis {
+	WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
+	WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
+};
+#endif /* WL_POINTER_AXIS_ENUM */
+
+/**
+ * wl_pointer - pointer input device
+ * @set_cursor: set the pointer surface
+ * @release: release the pointer object
+ *
+ * The wl_pointer interface represents one or more input devices, such as
+ * mice, which control the pointer location and pointer_focus of a seat.
+ *
+ * The wl_pointer interface generates motion, enter and leave events for
+ * the surfaces that the pointer is located over, and button and axis
+ * events for button presses, button releases and scrolling.
+ */
+struct wl_pointer_interface {
+	/**
+	 * set_cursor - set the pointer surface
+	 * @serial: serial of the enter event
+	 * @surface: (none)
+	 * @hotspot_x: x coordinate in surface-relative coordinates
+	 * @hotspot_y: y coordinate in surface-relative coordinates
+	 *
+	 * Set the pointer surface, i.e., the surface that contains the
+	 * pointer image (cursor). This request gives the surface the role
+	 * of a cursor. If the surface already has another role, it raises
+	 * a protocol error.
+	 *
+	 * The cursor actually changes only if the pointer focus for this
+	 * device is one of the requesting client's surfaces or the surface
+	 * parameter is the current pointer surface. If there was a
+	 * previous surface set with this request it is replaced. If
+	 * surface is NULL, the pointer image is hidden.
+	 *
+	 * The parameters hotspot_x and hotspot_y define the position of
+	 * the pointer surface relative to the pointer location. Its
+	 * top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
+	 * where (x, y) are the coordinates of the pointer location, in
+	 * surface local coordinates.
+	 *
+	 * On surface.attach requests to the pointer surface, hotspot_x and
+	 * hotspot_y are decremented by the x and y parameters passed to
+	 * the request. Attach must be confirmed by wl_surface.commit as
+	 * usual.
+	 *
+	 * The hotspot can also be updated by passing the currently set
+	 * pointer surface to this request with new values for hotspot_x
+	 * and hotspot_y.
+	 *
+	 * The current and pending input regions of the wl_surface are
+	 * cleared, and wl_surface.set_input_region is ignored until the
+	 * wl_surface is no longer used as the cursor. When the use as a
+	 * cursor ends, the current and pending input regions become
+	 * undefined, and the wl_surface is unmapped.
+	 */
+	void (*set_cursor)(struct wl_client *client,
+			   struct wl_resource *resource,
+			   uint32_t serial,
+			   struct wl_resource *surface,
+			   int32_t hotspot_x,
+			   int32_t hotspot_y);
+	/**
+	 * release - release the pointer object
+	 *
+	 * Using this request client can tell the server that it is not
+	 * going to use the pointer object anymore.
+	 *
+	 * This request destroys the pointer proxy object, so user must not
+	 * call wl_pointer_destroy() after using this request.
+	 * @since: 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_POINTER_ENTER	0
+#define WL_POINTER_LEAVE	1
+#define WL_POINTER_MOTION	2
+#define WL_POINTER_BUTTON	3
+#define WL_POINTER_AXIS	4
+
+#define WL_POINTER_ENTER_SINCE_VERSION	1
+#define WL_POINTER_LEAVE_SINCE_VERSION	1
+#define WL_POINTER_MOTION_SINCE_VERSION	1
+#define WL_POINTER_BUTTON_SINCE_VERSION	1
+#define WL_POINTER_AXIS_SINCE_VERSION	1
+
+static inline void
+wl_pointer_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+	wl_resource_post_event(resource_, WL_POINTER_ENTER, serial, surface, surface_x, surface_y);
+}
+
+static inline void
+wl_pointer_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface)
+{
+	wl_resource_post_event(resource_, WL_POINTER_LEAVE, serial, surface);
+}
+
+static inline void
+wl_pointer_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+	wl_resource_post_event(resource_, WL_POINTER_MOTION, time, surface_x, surface_y);
+}
+
+static inline void
+wl_pointer_send_button(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
+{
+	wl_resource_post_event(resource_, WL_POINTER_BUTTON, serial, time, button, state);
+}
+
+static inline void
+wl_pointer_send_axis(struct wl_resource *resource_, uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+	wl_resource_post_event(resource_, WL_POINTER_AXIS, time, axis, value);
+}
+
+#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+/**
+ * wl_keyboard_keymap_format - keyboard mapping format
+ * @WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP: no keymap; client must
+ *	understand how to interpret the raw keycode
+ * @WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1: libxkbcommon compatible; to
+ *	determine the xkb keycode, clients must add 8 to the key event keycode
+ *
+ * This specifies the format of the keymap provided to the client with
+ * the wl_keyboard.keymap event.
+ */
+enum wl_keyboard_keymap_format {
+	WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
+	WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
+};
+#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
+
+#ifndef WL_KEYBOARD_KEY_STATE_ENUM
+#define WL_KEYBOARD_KEY_STATE_ENUM
+/**
+ * wl_keyboard_key_state - physical key state
+ * @WL_KEYBOARD_KEY_STATE_RELEASED: key is not pressed
+ * @WL_KEYBOARD_KEY_STATE_PRESSED: key is pressed
+ *
+ * Describes the physical state of a key which provoked the key event.
+ */
+enum wl_keyboard_key_state {
+	WL_KEYBOARD_KEY_STATE_RELEASED = 0,
+	WL_KEYBOARD_KEY_STATE_PRESSED = 1,
+};
+#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
+
+/**
+ * wl_keyboard - keyboard input device
+ * @release: release the keyboard object
+ *
+ * The wl_keyboard interface represents one or more keyboards associated
+ * with a seat.
+ */
+struct wl_keyboard_interface {
+	/**
+	 * release - release the keyboard object
+	 *
+	 * 
+	 * @since: 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_KEYBOARD_KEYMAP	0
+#define WL_KEYBOARD_ENTER	1
+#define WL_KEYBOARD_LEAVE	2
+#define WL_KEYBOARD_KEY	3
+#define WL_KEYBOARD_MODIFIERS	4
+#define WL_KEYBOARD_REPEAT_INFO	5
+
+#define WL_KEYBOARD_KEYMAP_SINCE_VERSION	1
+#define WL_KEYBOARD_ENTER_SINCE_VERSION	1
+#define WL_KEYBOARD_LEAVE_SINCE_VERSION	1
+#define WL_KEYBOARD_KEY_SINCE_VERSION	1
+#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION	1
+#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION	4
+
+static inline void
+wl_keyboard_send_keymap(struct wl_resource *resource_, uint32_t format, int32_t fd, uint32_t size)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_KEYMAP, format, fd, size);
+}
+
+static inline void
+wl_keyboard_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, struct wl_array *keys)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_ENTER, serial, surface, keys);
+}
+
+static inline void
+wl_keyboard_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_LEAVE, serial, surface);
+}
+
+static inline void
+wl_keyboard_send_key(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_KEY, serial, time, key, state);
+}
+
+static inline void
+wl_keyboard_send_modifiers(struct wl_resource *resource_, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_MODIFIERS, serial, mods_depressed, mods_latched, mods_locked, group);
+}
+
+static inline void
+wl_keyboard_send_repeat_info(struct wl_resource *resource_, int32_t rate, int32_t delay)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_REPEAT_INFO, rate, delay);
+}
+
+/**
+ * wl_touch - touchscreen input device
+ * @release: release the touch object
+ *
+ * The wl_touch interface represents a touchscreen associated with a
+ * seat.
+ *
+ * Touch interactions can consist of one or more contacts. For each
+ * contact, a series of events is generated, starting with a down event,
+ * followed by zero or more motion events, and ending with an up event.
+ * Events relating to the same contact point can be identified by the ID of
+ * the sequence.
+ */
+struct wl_touch_interface {
+	/**
+	 * release - release the touch object
+	 *
+	 * 
+	 * @since: 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_TOUCH_DOWN	0
+#define WL_TOUCH_UP	1
+#define WL_TOUCH_MOTION	2
+#define WL_TOUCH_FRAME	3
+#define WL_TOUCH_CANCEL	4
+
+#define WL_TOUCH_DOWN_SINCE_VERSION	1
+#define WL_TOUCH_UP_SINCE_VERSION	1
+#define WL_TOUCH_MOTION_SINCE_VERSION	1
+#define WL_TOUCH_FRAME_SINCE_VERSION	1
+#define WL_TOUCH_CANCEL_SINCE_VERSION	1
+
+static inline void
+wl_touch_send_down(struct wl_resource *resource_, uint32_t serial, uint32_t time, struct wl_resource *surface, int32_t id, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_DOWN, serial, time, surface, id, x, y);
+}
+
+static inline void
+wl_touch_send_up(struct wl_resource *resource_, uint32_t serial, uint32_t time, int32_t id)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_UP, serial, time, id);
+}
+
+static inline void
+wl_touch_send_motion(struct wl_resource *resource_, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_MOTION, time, id, x, y);
+}
+
+static inline void
+wl_touch_send_frame(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_FRAME);
+}
+
+static inline void
+wl_touch_send_cancel(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_CANCEL);
+}
+
+#ifndef WL_OUTPUT_SUBPIXEL_ENUM
+#define WL_OUTPUT_SUBPIXEL_ENUM
+/**
+ * wl_output_subpixel - subpixel geometry information
+ * @WL_OUTPUT_SUBPIXEL_UNKNOWN: (none)
+ * @WL_OUTPUT_SUBPIXEL_NONE: (none)
+ * @WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: (none)
+ * @WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: (none)
+ * @WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: (none)
+ * @WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: (none)
+ *
+ * This enumeration describes how the physical pixels on an output are
+ * laid out.
+ */
+enum wl_output_subpixel {
+	WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
+	WL_OUTPUT_SUBPIXEL_NONE = 1,
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
+	WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
+	WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
+};
+#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
+
+#ifndef WL_OUTPUT_TRANSFORM_ENUM
+#define WL_OUTPUT_TRANSFORM_ENUM
+/**
+ * wl_output_transform - transform from framebuffer to output
+ * @WL_OUTPUT_TRANSFORM_NORMAL: (none)
+ * @WL_OUTPUT_TRANSFORM_90: (none)
+ * @WL_OUTPUT_TRANSFORM_180: (none)
+ * @WL_OUTPUT_TRANSFORM_270: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_90: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_180: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_270: (none)
+ *
+ * This describes the transform that a compositor will apply to a surface
+ * to compensate for the rotation or mirroring of an output device.
+ *
+ * The flipped values correspond to an initial flip around a vertical axis
+ * followed by rotation.
+ *
+ * The purpose is mainly to allow clients render accordingly and tell the
+ * compositor, so that for fullscreen surfaces, the compositor will still
+ * be able to scan out directly from client surfaces.
+ */
+enum wl_output_transform {
+	WL_OUTPUT_TRANSFORM_NORMAL = 0,
+	WL_OUTPUT_TRANSFORM_90 = 1,
+	WL_OUTPUT_TRANSFORM_180 = 2,
+	WL_OUTPUT_TRANSFORM_270 = 3,
+	WL_OUTPUT_TRANSFORM_FLIPPED = 4,
+	WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
+	WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
+	WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
+};
+#endif /* WL_OUTPUT_TRANSFORM_ENUM */
+
+#ifndef WL_OUTPUT_MODE_ENUM
+#define WL_OUTPUT_MODE_ENUM
+/**
+ * wl_output_mode - mode information
+ * @WL_OUTPUT_MODE_CURRENT: indicates this is the current mode
+ * @WL_OUTPUT_MODE_PREFERRED: indicates this is the preferred mode
+ *
+ * These flags describe properties of an output mode. They are used in
+ * the flags bitfield of the mode event.
+ */
+enum wl_output_mode {
+	WL_OUTPUT_MODE_CURRENT = 0x1,
+	WL_OUTPUT_MODE_PREFERRED = 0x2,
+};
+#endif /* WL_OUTPUT_MODE_ENUM */
+
+#define WL_OUTPUT_GEOMETRY	0
+#define WL_OUTPUT_MODE	1
+#define WL_OUTPUT_DONE	2
+#define WL_OUTPUT_SCALE	3
+
+#define WL_OUTPUT_GEOMETRY_SINCE_VERSION	1
+#define WL_OUTPUT_MODE_SINCE_VERSION	1
+#define WL_OUTPUT_DONE_SINCE_VERSION	2
+#define WL_OUTPUT_SCALE_SINCE_VERSION	2
+
+static inline void
+wl_output_send_geometry(struct wl_resource *resource_, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_GEOMETRY, x, y, physical_width, physical_height, subpixel, make, model, transform);
+}
+
+static inline void
+wl_output_send_mode(struct wl_resource *resource_, uint32_t flags, int32_t width, int32_t height, int32_t refresh)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_MODE, flags, width, height, refresh);
+}
+
+static inline void
+wl_output_send_done(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_DONE);
+}
+
+static inline void
+wl_output_send_scale(struct wl_resource *resource_, int32_t factor)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_SCALE, factor);
+}
+
+/**
+ * wl_region - region interface
+ * @destroy: destroy region
+ * @add: add rectangle to region
+ * @subtract: subtract rectangle from region
+ *
+ * A region object describes an area.
+ *
+ * Region objects are used to describe the opaque and input regions of a
+ * surface.
+ */
+struct wl_region_interface {
+	/**
+	 * destroy - destroy region
+	 *
+	 * Destroy the region. This will invalidate the object ID.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * add - add rectangle to region
+	 * @x: (none)
+	 * @y: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 *
+	 * Add the specified rectangle to the region.
+	 */
+	void (*add)(struct wl_client *client,
+		    struct wl_resource *resource,
+		    int32_t x,
+		    int32_t y,
+		    int32_t width,
+		    int32_t height);
+	/**
+	 * subtract - subtract rectangle from region
+	 * @x: (none)
+	 * @y: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 *
+	 * Subtract the specified rectangle from the region.
+	 */
+	void (*subtract)(struct wl_client *client,
+			 struct wl_resource *resource,
+			 int32_t x,
+			 int32_t y,
+			 int32_t width,
+			 int32_t height);
+};
+
+
+#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
+#define WL_SUBCOMPOSITOR_ERROR_ENUM
+enum wl_subcompositor_error {
+	WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
+
+/**
+ * wl_subcompositor - sub-surface compositing
+ * @destroy: unbind from the subcompositor interface
+ * @get_subsurface: give a surface the role sub-surface
+ *
+ * The global interface exposing sub-surface compositing capabilities. A
+ * wl_surface, that has sub-surfaces associated, is called the parent
+ * surface. Sub-surfaces can be arbitrarily nested and create a tree of
+ * sub-surfaces.
+ *
+ * The root surface in a tree of sub-surfaces is the main surface. The main
+ * surface cannot be a sub-surface, because sub-surfaces must always have a
+ * parent.
+ *
+ * A main surface with its sub-surfaces forms a (compound) window. For
+ * window management purposes, this set of wl_surface objects is to be
+ * considered as a single window, and it should also behave as such.
+ *
+ * The aim of sub-surfaces is to offload some of the compositing work
+ * within a window from clients to the compositor. A prime example is a
+ * video player with decorations and video in separate wl_surface objects.
+ * This should allow the compositor to pass YUV video buffer processing to
+ * dedicated overlay hardware when possible.
+ */
+struct wl_subcompositor_interface {
+	/**
+	 * destroy - unbind from the subcompositor interface
+	 *
+	 * Informs the server that the client will not be using this
+	 * protocol object anymore. This does not affect any other objects,
+	 * wl_subsurface objects included.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * get_subsurface - give a surface the role sub-surface
+	 * @id: the new subsurface object id
+	 * @surface: the surface to be turned into a sub-surface
+	 * @parent: the parent surface
+	 *
+	 * Create a sub-surface interface for the given surface, and
+	 * associate it with the given parent surface. This turns a plain
+	 * wl_surface into a sub-surface.
+	 *
+	 * The to-be sub-surface must not already have another role, and it
+	 * must not have an existing wl_subsurface object. Otherwise a
+	 * protocol error is raised.
+	 */
+	void (*get_subsurface)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t id,
+			       struct wl_resource *surface,
+			       struct wl_resource *parent);
+};
+
+
+#ifndef WL_SUBSURFACE_ERROR_ENUM
+#define WL_SUBSURFACE_ERROR_ENUM
+enum wl_subsurface_error {
+	WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBSURFACE_ERROR_ENUM */
+
+/**
+ * wl_subsurface - sub-surface interface to a wl_surface
+ * @destroy: remove sub-surface interface
+ * @set_position: reposition the sub-surface
+ * @place_above: restack the sub-surface
+ * @place_below: restack the sub-surface
+ * @set_sync: set sub-surface to synchronized mode
+ * @set_desync: set sub-surface to desynchronized mode
+ *
+ * An additional interface to a wl_surface object, which has been made a
+ * sub-surface. A sub-surface has one parent surface. A sub-surface's size
+ * and position are not limited to that of the parent. Particularly, a
+ * sub-surface is not automatically clipped to its parent's area.
+ *
+ * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and
+ * the parent surface is mapped. The order of which one happens first is
+ * irrelevant. A sub-surface is hidden if the parent becomes hidden, or if
+ * a NULL wl_buffer is applied. These rules apply recursively through the
+ * tree of surfaces.
+ *
+ * The behaviour of wl_surface.commit request on a sub-surface depends on
+ * the sub-surface's mode. The possible modes are synchronized and
+ * desynchronized, see methods wl_subsurface.set_sync and
+ * wl_subsurface.set_desync. Synchronized mode caches the wl_surface state
+ * to be applied when the parent's state gets applied, and desynchronized
+ * mode applies the pending wl_surface state directly. A sub-surface is
+ * initially in the synchronized mode.
+ *
+ * Sub-surfaces have also other kind of state, which is managed by
+ * wl_subsurface requests, as opposed to wl_surface requests. This state
+ * includes the sub-surface position relative to the parent surface
+ * (wl_subsurface.set_position), and the stacking order of the parent and
+ * its sub-surfaces (wl_subsurface.place_above and .place_below). This
+ * state is applied when the parent surface's wl_surface state is applied,
+ * regardless of the sub-surface's mode. As the exception, set_sync and
+ * set_desync are effective immediately.
+ *
+ * The main surface can be thought to be always in desynchronized mode,
+ * since it does not have a parent in the sub-surfaces sense.
+ *
+ * Even if a sub-surface is in desynchronized mode, it will behave as in
+ * synchronized mode, if its parent surface behaves as in synchronized
+ * mode. This rule is applied recursively throughout the tree of surfaces.
+ * This means, that one can set a sub-surface into synchronized mode, and
+ * then assume that all its child and grand-child sub-surfaces are
+ * synchronized, too, without explicitly setting them.
+ *
+ * If the wl_surface associated with the wl_subsurface is destroyed, the
+ * wl_subsurface object becomes inert. Note, that destroying either object
+ * takes effect immediately. If you need to synchronize the removal of a
+ * sub-surface to the parent surface update, unmap the sub-surface first by
+ * attaching a NULL wl_buffer, update parent, and then destroy the
+ * sub-surface.
+ *
+ * If the parent wl_surface object is destroyed, the sub-surface is
+ * unmapped.
+ */
+struct wl_subsurface_interface {
+	/**
+	 * destroy - remove sub-surface interface
+	 *
+	 * The sub-surface interface is removed from the wl_surface
+	 * object that was turned into a sub-surface with
+	 * wl_subcompositor.get_subsurface request. The wl_surface's
+	 * association to the parent is deleted, and the wl_surface loses
+	 * its role as a sub-surface. The wl_surface is unmapped.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * set_position - reposition the sub-surface
+	 * @x: coordinate in the parent surface
+	 * @y: coordinate in the parent surface
+	 *
+	 * This schedules a sub-surface position change. The sub-surface
+	 * will be moved so, that its origin (top-left corner pixel) will
+	 * be at the location x, y of the parent surface coordinate system.
+	 * The coordinates are not restricted to the parent surface area.
+	 * Negative values are allowed.
+	 *
+	 * The scheduled coordinates will take effect whenever the state of
+	 * the parent surface is applied. When this happens depends on
+	 * whether the parent surface is in synchronized mode or not. See
+	 * wl_subsurface.set_sync and wl_subsurface.set_desync for details.
+	 *
+	 * If more than one set_position request is invoked by the client
+	 * before the commit of the parent surface, the position of a new
+	 * request always replaces the scheduled position from any previous
+	 * request.
+	 *
+	 * The initial position is 0, 0.
+	 */
+	void (*set_position)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     int32_t x,
+			     int32_t y);
+	/**
+	 * place_above - restack the sub-surface
+	 * @sibling: the reference surface
+	 *
+	 * This sub-surface is taken from the stack, and put back just
+	 * above the reference surface, changing the z-order of the
+	 * sub-surfaces. The reference surface must be one of the sibling
+	 * surfaces, or the parent surface. Using any other surface,
+	 * including this sub-surface, will cause a protocol error.
+	 *
+	 * The z-order is double-buffered. Requests are handled in order
+	 * and applied immediately to a pending state. The final pending
+	 * state is copied to the active state the next time the state of
+	 * the parent surface is applied. When this happens depends on
+	 * whether the parent surface is in synchronized mode or not. See
+	 * wl_subsurface.set_sync and wl_subsurface.set_desync for details.
+	 *
+	 * A new sub-surface is initially added as the top-most in the
+	 * stack of its siblings and parent.
+	 */
+	void (*place_above)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    struct wl_resource *sibling);
+	/**
+	 * place_below - restack the sub-surface
+	 * @sibling: the reference surface
+	 *
+	 * The sub-surface is placed just below of the reference surface.
+	 * See wl_subsurface.place_above.
+	 */
+	void (*place_below)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    struct wl_resource *sibling);
+	/**
+	 * set_sync - set sub-surface to synchronized mode
+	 *
+	 * Change the commit behaviour of the sub-surface to synchronized
+	 * mode, also described as the parent dependent mode.
+	 *
+	 * In synchronized mode, wl_surface.commit on a sub-surface will
+	 * accumulate the committed state in a cache, but the state will
+	 * not be applied and hence will not change the compositor output.
+	 * The cached state is applied to the sub-surface immediately after
+	 * the parent surface's state is applied. This ensures atomic
+	 * updates of the parent and all its synchronized sub-surfaces.
+	 * Applying the cached state will invalidate the cache, so further
+	 * parent surface commits do not (re-)apply old state.
+	 *
+	 * See wl_subsurface for the recursive effect of this mode.
+	 */
+	void (*set_sync)(struct wl_client *client,
+			 struct wl_resource *resource);
+	/**
+	 * set_desync - set sub-surface to desynchronized mode
+	 *
+	 * Change the commit behaviour of the sub-surface to
+	 * desynchronized mode, also described as independent or freely
+	 * running mode.
+	 *
+	 * In desynchronized mode, wl_surface.commit on a sub-surface will
+	 * apply the pending state directly, without caching, as happens
+	 * normally with a wl_surface. Calling wl_surface.commit on the
+	 * parent surface has no effect on the sub-surface's wl_surface
+	 * state. This mode allows a sub-surface to be updated on its own.
+	 *
+	 * If cached state exists when wl_surface.commit is called in
+	 * desynchronized mode, the pending state is added to the cached
+	 * state, and applied as whole. This invalidates the cache.
+	 *
+	 * Note: even if a sub-surface is set to desynchronized, a parent
+	 * sub-surface may override it to behave as synchronized. For
+	 * details, see wl_subsurface.
+	 *
+	 * If a surface's parent surface behaves as desynchronized, then
+	 * the cached state is applied on set_desync.
+	 */
+	void (*set_desync)(struct wl_client *client,
+			   struct wl_resource *resource);
+};
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/wayland/include/protocol/wayland-server-protocol.h b/third_party/wayland/include/protocol/wayland-server-protocol.h
new file mode 100644
index 0000000..16e3d271
--- /dev/null
+++ b/third_party/wayland/include/protocol/wayland-server-protocol.h
@@ -0,0 +1,2404 @@
+/* 
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ * 
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_SERVER_PROTOCOL_H
+#define WAYLAND_SERVER_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+struct wl_client;
+struct wl_resource;
+
+struct wl_buffer;
+struct wl_callback;
+struct wl_compositor;
+struct wl_data_device;
+struct wl_data_device_manager;
+struct wl_data_offer;
+struct wl_data_source;
+struct wl_display;
+struct wl_keyboard;
+struct wl_output;
+struct wl_pointer;
+struct wl_region;
+struct wl_registry;
+struct wl_seat;
+struct wl_shell;
+struct wl_shell_surface;
+struct wl_shm;
+struct wl_shm_pool;
+struct wl_subcompositor;
+struct wl_subsurface;
+struct wl_surface;
+struct wl_touch;
+
+extern const struct wl_interface wl_display_interface;
+extern const struct wl_interface wl_registry_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_compositor_interface;
+extern const struct wl_interface wl_shm_pool_interface;
+extern const struct wl_interface wl_shm_interface;
+extern const struct wl_interface wl_buffer_interface;
+extern const struct wl_interface wl_data_offer_interface;
+extern const struct wl_interface wl_data_source_interface;
+extern const struct wl_interface wl_data_device_interface;
+extern const struct wl_interface wl_data_device_manager_interface;
+extern const struct wl_interface wl_shell_interface;
+extern const struct wl_interface wl_shell_surface_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_touch_interface;
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_region_interface;
+extern const struct wl_interface wl_subcompositor_interface;
+extern const struct wl_interface wl_subsurface_interface;
+
+#ifndef WL_DISPLAY_ERROR_ENUM
+#define WL_DISPLAY_ERROR_ENUM
+/**
+ * wl_display_error - global error values
+ * @WL_DISPLAY_ERROR_INVALID_OBJECT: server couldn't find object
+ * @WL_DISPLAY_ERROR_INVALID_METHOD: method doesn't exist on the
+ *	specified interface
+ * @WL_DISPLAY_ERROR_NO_MEMORY: server is out of memory
+ *
+ * These errors are global and can be emitted in response to any server
+ * request.
+ */
+enum wl_display_error {
+	WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
+	WL_DISPLAY_ERROR_INVALID_METHOD = 1,
+	WL_DISPLAY_ERROR_NO_MEMORY = 2,
+};
+#endif /* WL_DISPLAY_ERROR_ENUM */
+
+/**
+ * wl_display - core global object
+ * @sync: asynchronous roundtrip
+ * @get_registry: get global registry object
+ *
+ * The core global object. This is a special singleton object. It is used
+ * for internal Wayland protocol features.
+ */
+struct wl_display_interface {
+	/**
+	 * sync - asynchronous roundtrip
+	 * @callback: (none)
+	 *
+	 * The sync request asks the server to emit the 'done' event on
+	 * the returned wl_callback object. Since requests are handled
+	 * in-order and events are delivered in-order, this can be used as
+	 * a barrier to ensure all previous requests and the resulting
+	 * events have been handled.
+	 *
+	 * The object returned by this request will be destroyed by the
+	 * compositor after the callback is fired and as such the client
+	 * must not attempt to use it after that point.
+	 *
+	 * The callback_data passed in the callback is the event serial.
+	 */
+	void (*sync)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t callback);
+	/**
+	 * get_registry - get global registry object
+	 * @registry: (none)
+	 *
+	 * This request creates a registry object that allows the client
+	 * to list and bind the global objects available from the
+	 * compositor.
+	 */
+	void (*get_registry)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t registry);
+};
+
+#define WL_DISPLAY_ERROR	0
+#define WL_DISPLAY_DELETE_ID	1
+
+#define WL_DISPLAY_ERROR_SINCE_VERSION	1
+#define WL_DISPLAY_DELETE_ID_SINCE_VERSION	1
+
+/**
+ * wl_registry - global registry object
+ * @bind: bind an object to the display
+ *
+ * The global registry object. The server has a number of global objects
+ * that are available to all clients. These objects typically represent an
+ * actual object in the server (for example, an input device) or they are
+ * singleton objects that provide extension functionality.
+ *
+ * When a client creates a registry object, the registry object will emit a
+ * global event for each global currently in the registry. Globals come and
+ * go as a result of device or monitor hotplugs, reconfiguration or other
+ * events, and the registry will send out global and global_remove events
+ * to keep the client up to date with the changes. To mark the end of the
+ * initial burst of events, the client can use the wl_display.sync request
+ * immediately after calling wl_display.get_registry.
+ *
+ * A client can bind to a global object by using the bind request. This
+ * creates a client-side handle that lets the object emit events to the
+ * client and lets the client invoke requests on the object.
+ */
+struct wl_registry_interface {
+	/**
+	 * bind - bind an object to the display
+	 * @name: unique name for the object
+	 * @interface: name of the objects interface
+	 * @version: version of the objects interface
+	 * @id: (none)
+	 *
+	 * Binds a new, client-created object to the server using the
+	 * specified name as the identifier.
+	 */
+	void (*bind)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t name,
+		     const char *interface, uint32_t version, uint32_t id);
+};
+
+#define WL_REGISTRY_GLOBAL	0
+#define WL_REGISTRY_GLOBAL_REMOVE	1
+
+#define WL_REGISTRY_GLOBAL_SINCE_VERSION	1
+#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION	1
+
+static inline void
+wl_registry_send_global(struct wl_resource *resource_, uint32_t name, const char *interface, uint32_t version)
+{
+	wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL, name, interface, version);
+}
+
+static inline void
+wl_registry_send_global_remove(struct wl_resource *resource_, uint32_t name)
+{
+	wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL_REMOVE, name);
+}
+
+#define WL_CALLBACK_DONE	0
+
+#define WL_CALLBACK_DONE_SINCE_VERSION	1
+
+static inline void
+wl_callback_send_done(struct wl_resource *resource_, uint32_t callback_data)
+{
+	wl_resource_post_event(resource_, WL_CALLBACK_DONE, callback_data);
+}
+
+/**
+ * wl_compositor - the compositor singleton
+ * @create_surface: create new surface
+ * @create_region: create new region
+ *
+ * A compositor. This object is a singleton global. The compositor is in
+ * charge of combining the contents of multiple surfaces into one
+ * displayable output.
+ */
+struct wl_compositor_interface {
+	/**
+	 * create_surface - create new surface
+	 * @id: (none)
+	 *
+	 * Ask the compositor to create a new surface.
+	 */
+	void (*create_surface)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t id);
+	/**
+	 * create_region - create new region
+	 * @id: (none)
+	 *
+	 * Ask the compositor to create a new region.
+	 */
+	void (*create_region)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      uint32_t id);
+};
+
+
+/**
+ * wl_shm_pool - a shared memory pool
+ * @create_buffer: create a buffer from the pool
+ * @destroy: destroy the pool
+ * @resize: change the size of the pool mapping
+ *
+ * The wl_shm_pool object encapsulates a piece of memory shared between
+ * the compositor and client. Through the wl_shm_pool object, the client
+ * can allocate shared memory wl_buffer objects. All objects created
+ * through the same pool share the same underlying mapped memory. Reusing
+ * the mapped memory avoids the setup/teardown overhead and is useful when
+ * interactively resizing a surface or for many small buffers.
+ */
+struct wl_shm_pool_interface {
+	/**
+	 * create_buffer - create a buffer from the pool
+	 * @id: (none)
+	 * @offset: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 * @stride: (none)
+	 * @format: (none)
+	 *
+	 * Create a wl_buffer object from the pool.
+	 *
+	 * The buffer is created offset bytes into the pool and has width
+	 * and height as specified. The stride arguments specifies the
+	 * number of bytes from beginning of one row to the beginning of
+	 * the next. The format is the pixel format of the buffer and must
+	 * be one of those advertised through the wl_shm.format event.
+	 *
+	 * A buffer will keep a reference to the pool it was created from
+	 * so it is valid to destroy the pool immediately after creating a
+	 * buffer from it.
+	 */
+	void (*create_buffer)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      uint32_t id,
+			      int32_t offset,
+			      int32_t width,
+			      int32_t height,
+			      int32_t stride,
+			      uint32_t format);
+	/**
+	 * destroy - destroy the pool
+	 *
+	 * Destroy the shared memory pool.
+	 *
+	 * The mmapped memory will be released when all buffers that have
+	 * been created from this pool are gone.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * resize - change the size of the pool mapping
+	 * @size: (none)
+	 *
+	 * This request will cause the server to remap the backing memory
+	 * for the pool from the file descriptor passed when the pool was
+	 * created, but using the new size. This request can only be used
+	 * to make the pool bigger.
+	 */
+	void (*resize)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       int32_t size);
+};
+
+
+#ifndef WL_SHM_ERROR_ENUM
+#define WL_SHM_ERROR_ENUM
+/**
+ * wl_shm_error - wl_shm error values
+ * @WL_SHM_ERROR_INVALID_FORMAT: buffer format is not known
+ * @WL_SHM_ERROR_INVALID_STRIDE: invalid size or stride during pool or
+ *	buffer creation
+ * @WL_SHM_ERROR_INVALID_FD: mmapping the file descriptor failed
+ *
+ * These errors can be emitted in response to wl_shm requests.
+ */
+enum wl_shm_error {
+	WL_SHM_ERROR_INVALID_FORMAT = 0,
+	WL_SHM_ERROR_INVALID_STRIDE = 1,
+	WL_SHM_ERROR_INVALID_FD = 2,
+};
+#endif /* WL_SHM_ERROR_ENUM */
+
+#ifndef WL_SHM_FORMAT_ENUM
+#define WL_SHM_FORMAT_ENUM
+/**
+ * wl_shm_format - pixel formats
+ * @WL_SHM_FORMAT_ARGB8888: 32-bit ARGB format
+ * @WL_SHM_FORMAT_XRGB8888: 32-bit RGB format
+ * @WL_SHM_FORMAT_C8: (none)
+ * @WL_SHM_FORMAT_RGB332: (none)
+ * @WL_SHM_FORMAT_BGR233: (none)
+ * @WL_SHM_FORMAT_XRGB4444: (none)
+ * @WL_SHM_FORMAT_XBGR4444: (none)
+ * @WL_SHM_FORMAT_RGBX4444: (none)
+ * @WL_SHM_FORMAT_BGRX4444: (none)
+ * @WL_SHM_FORMAT_ARGB4444: (none)
+ * @WL_SHM_FORMAT_ABGR4444: (none)
+ * @WL_SHM_FORMAT_RGBA4444: (none)
+ * @WL_SHM_FORMAT_BGRA4444: (none)
+ * @WL_SHM_FORMAT_XRGB1555: (none)
+ * @WL_SHM_FORMAT_XBGR1555: (none)
+ * @WL_SHM_FORMAT_RGBX5551: (none)
+ * @WL_SHM_FORMAT_BGRX5551: (none)
+ * @WL_SHM_FORMAT_ARGB1555: (none)
+ * @WL_SHM_FORMAT_ABGR1555: (none)
+ * @WL_SHM_FORMAT_RGBA5551: (none)
+ * @WL_SHM_FORMAT_BGRA5551: (none)
+ * @WL_SHM_FORMAT_RGB565: (none)
+ * @WL_SHM_FORMAT_BGR565: (none)
+ * @WL_SHM_FORMAT_RGB888: (none)
+ * @WL_SHM_FORMAT_BGR888: (none)
+ * @WL_SHM_FORMAT_XBGR8888: (none)
+ * @WL_SHM_FORMAT_RGBX8888: (none)
+ * @WL_SHM_FORMAT_BGRX8888: (none)
+ * @WL_SHM_FORMAT_ABGR8888: (none)
+ * @WL_SHM_FORMAT_RGBA8888: (none)
+ * @WL_SHM_FORMAT_BGRA8888: (none)
+ * @WL_SHM_FORMAT_XRGB2101010: (none)
+ * @WL_SHM_FORMAT_XBGR2101010: (none)
+ * @WL_SHM_FORMAT_RGBX1010102: (none)
+ * @WL_SHM_FORMAT_BGRX1010102: (none)
+ * @WL_SHM_FORMAT_ARGB2101010: (none)
+ * @WL_SHM_FORMAT_ABGR2101010: (none)
+ * @WL_SHM_FORMAT_RGBA1010102: (none)
+ * @WL_SHM_FORMAT_BGRA1010102: (none)
+ * @WL_SHM_FORMAT_YUYV: (none)
+ * @WL_SHM_FORMAT_YVYU: (none)
+ * @WL_SHM_FORMAT_UYVY: (none)
+ * @WL_SHM_FORMAT_VYUY: (none)
+ * @WL_SHM_FORMAT_AYUV: (none)
+ * @WL_SHM_FORMAT_NV12: (none)
+ * @WL_SHM_FORMAT_NV21: (none)
+ * @WL_SHM_FORMAT_NV16: (none)
+ * @WL_SHM_FORMAT_NV61: (none)
+ * @WL_SHM_FORMAT_YUV410: (none)
+ * @WL_SHM_FORMAT_YVU410: (none)
+ * @WL_SHM_FORMAT_YUV411: (none)
+ * @WL_SHM_FORMAT_YVU411: (none)
+ * @WL_SHM_FORMAT_YUV420: (none)
+ * @WL_SHM_FORMAT_YVU420: (none)
+ * @WL_SHM_FORMAT_YUV422: (none)
+ * @WL_SHM_FORMAT_YVU422: (none)
+ * @WL_SHM_FORMAT_YUV444: (none)
+ * @WL_SHM_FORMAT_YVU444: (none)
+ *
+ * This describes the memory layout of an individual pixel.
+ *
+ * All renderers should support argb8888 and xrgb8888 but any other formats
+ * are optional and may not be supported by the particular renderer in use.
+ */
+enum wl_shm_format {
+	WL_SHM_FORMAT_ARGB8888 = 0,
+	WL_SHM_FORMAT_XRGB8888 = 1,
+	WL_SHM_FORMAT_C8 = 0x20203843,
+	WL_SHM_FORMAT_RGB332 = 0x38424752,
+	WL_SHM_FORMAT_BGR233 = 0x38524742,
+	WL_SHM_FORMAT_XRGB4444 = 0x32315258,
+	WL_SHM_FORMAT_XBGR4444 = 0x32314258,
+	WL_SHM_FORMAT_RGBX4444 = 0x32315852,
+	WL_SHM_FORMAT_BGRX4444 = 0x32315842,
+	WL_SHM_FORMAT_ARGB4444 = 0x32315241,
+	WL_SHM_FORMAT_ABGR4444 = 0x32314241,
+	WL_SHM_FORMAT_RGBA4444 = 0x32314152,
+	WL_SHM_FORMAT_BGRA4444 = 0x32314142,
+	WL_SHM_FORMAT_XRGB1555 = 0x35315258,
+	WL_SHM_FORMAT_XBGR1555 = 0x35314258,
+	WL_SHM_FORMAT_RGBX5551 = 0x35315852,
+	WL_SHM_FORMAT_BGRX5551 = 0x35315842,
+	WL_SHM_FORMAT_ARGB1555 = 0x35315241,
+	WL_SHM_FORMAT_ABGR1555 = 0x35314241,
+	WL_SHM_FORMAT_RGBA5551 = 0x35314152,
+	WL_SHM_FORMAT_BGRA5551 = 0x35314142,
+	WL_SHM_FORMAT_RGB565 = 0x36314752,
+	WL_SHM_FORMAT_BGR565 = 0x36314742,
+	WL_SHM_FORMAT_RGB888 = 0x34324752,
+	WL_SHM_FORMAT_BGR888 = 0x34324742,
+	WL_SHM_FORMAT_XBGR8888 = 0x34324258,
+	WL_SHM_FORMAT_RGBX8888 = 0x34325852,
+	WL_SHM_FORMAT_BGRX8888 = 0x34325842,
+	WL_SHM_FORMAT_ABGR8888 = 0x34324241,
+	WL_SHM_FORMAT_RGBA8888 = 0x34324152,
+	WL_SHM_FORMAT_BGRA8888 = 0x34324142,
+	WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
+	WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
+	WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
+	WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
+	WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
+	WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
+	WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
+	WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
+	WL_SHM_FORMAT_YUYV = 0x56595559,
+	WL_SHM_FORMAT_YVYU = 0x55595659,
+	WL_SHM_FORMAT_UYVY = 0x59565955,
+	WL_SHM_FORMAT_VYUY = 0x59555956,
+	WL_SHM_FORMAT_AYUV = 0x56555941,
+	WL_SHM_FORMAT_NV12 = 0x3231564e,
+	WL_SHM_FORMAT_NV21 = 0x3132564e,
+	WL_SHM_FORMAT_NV16 = 0x3631564e,
+	WL_SHM_FORMAT_NV61 = 0x3136564e,
+	WL_SHM_FORMAT_YUV410 = 0x39565559,
+	WL_SHM_FORMAT_YVU410 = 0x39555659,
+	WL_SHM_FORMAT_YUV411 = 0x31315559,
+	WL_SHM_FORMAT_YVU411 = 0x31315659,
+	WL_SHM_FORMAT_YUV420 = 0x32315559,
+	WL_SHM_FORMAT_YVU420 = 0x32315659,
+	WL_SHM_FORMAT_YUV422 = 0x36315559,
+	WL_SHM_FORMAT_YVU422 = 0x36315659,
+	WL_SHM_FORMAT_YUV444 = 0x34325559,
+	WL_SHM_FORMAT_YVU444 = 0x34325659,
+};
+#endif /* WL_SHM_FORMAT_ENUM */
+
+/**
+ * wl_shm - shared memory support
+ * @create_pool: create a shm pool
+ *
+ * A global singleton object that provides support for shared memory.
+ *
+ * Clients can create wl_shm_pool objects using the create_pool request.
+ *
+ * At connection setup time, the wl_shm object emits one or more format
+ * events to inform clients about the valid pixel formats that can be used
+ * for buffers.
+ */
+struct wl_shm_interface {
+	/**
+	 * create_pool - create a shm pool
+	 * @id: (none)
+	 * @fd: (none)
+	 * @size: (none)
+	 *
+	 * Create a new wl_shm_pool object.
+	 *
+	 * The pool can be used to create shared memory based buffer
+	 * objects. The server will mmap size bytes of the passed file
+	 * descriptor, to use as backing memory for the pool.
+	 */
+	void (*create_pool)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    uint32_t id,
+			    int32_t fd,
+			    int32_t size);
+};
+
+#define WL_SHM_FORMAT	0
+
+#define WL_SHM_FORMAT_SINCE_VERSION	1
+
+static inline void
+wl_shm_send_format(struct wl_resource *resource_, uint32_t format)
+{
+	wl_resource_post_event(resource_, WL_SHM_FORMAT, format);
+}
+
+/**
+ * wl_buffer - content for a wl_surface
+ * @destroy: destroy a buffer
+ *
+ * A buffer provides the content for a wl_surface. Buffers are created
+ * through factory interfaces such as wl_drm, wl_shm or similar. It has a
+ * width and a height and can be attached to a wl_surface, but the
+ * mechanism by which a client provides and updates the contents is defined
+ * by the buffer factory interface.
+ */
+struct wl_buffer_interface {
+	/**
+	 * destroy - destroy a buffer
+	 *
+	 * Destroy a buffer. If and how you need to release the backing
+	 * storage is defined by the buffer factory interface.
+	 *
+	 * For possible side-effects to a surface, see wl_surface.attach.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_BUFFER_RELEASE	0
+
+#define WL_BUFFER_RELEASE_SINCE_VERSION	1
+
+static inline void
+wl_buffer_send_release(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_BUFFER_RELEASE);
+}
+
+/**
+ * wl_data_offer - offer to transfer data
+ * @accept: accept one of the offered mime types
+ * @receive: request that the data is transferred
+ * @destroy: destroy data offer
+ *
+ * A wl_data_offer represents a piece of data offered for transfer by
+ * another client (the source client). It is used by the copy-and-paste and
+ * drag-and-drop mechanisms. The offer describes the different mime types
+ * that the data can be converted to and provides the mechanism for
+ * transferring the data directly from the source client.
+ */
+struct wl_data_offer_interface {
+	/**
+	 * accept - accept one of the offered mime types
+	 * @serial: (none)
+	 * @mime_type: (none)
+	 *
+	 * Indicate that the client can accept the given mime type, or
+	 * NULL for not accepted.
+	 *
+	 * Used for feedback during drag-and-drop.
+	 */
+	void (*accept)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       uint32_t serial,
+		       const char *mime_type);
+	/**
+	 * receive - request that the data is transferred
+	 * @mime_type: (none)
+	 * @fd: (none)
+	 *
+	 * To transfer the offered data, the client issues this request
+	 * and indicates the mime type it wants to receive. The transfer
+	 * happens through the passed file descriptor (typically created
+	 * with the pipe system call). The source client writes the data in
+	 * the mime type representation requested and then closes the file
+	 * descriptor.
+	 *
+	 * The receiving client reads from the read end of the pipe until
+	 * EOF and then closes its end, at which point the transfer is
+	 * complete.
+	 */
+	void (*receive)(struct wl_client *client,
+			struct wl_resource *resource,
+			const char *mime_type,
+			int32_t fd);
+	/**
+	 * destroy - destroy data offer
+	 *
+	 * Destroy the data offer.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_DATA_OFFER_OFFER	0
+
+#define WL_DATA_OFFER_OFFER_SINCE_VERSION	1
+
+static inline void
+wl_data_offer_send_offer(struct wl_resource *resource_, const char *mime_type)
+{
+	wl_resource_post_event(resource_, WL_DATA_OFFER_OFFER, mime_type);
+}
+
+/**
+ * wl_data_source - offer to transfer data
+ * @offer: add an offered mime type
+ * @destroy: destroy the data source
+ *
+ * The wl_data_source object is the source side of a wl_data_offer. It is
+ * created by the source client in a data transfer and provides a way to
+ * describe the offered data and a way to respond to requests to transfer
+ * the data.
+ */
+struct wl_data_source_interface {
+	/**
+	 * offer - add an offered mime type
+	 * @mime_type: (none)
+	 *
+	 * This request adds a mime type to the set of mime types
+	 * advertised to targets. Can be called several times to offer
+	 * multiple types.
+	 */
+	void (*offer)(struct wl_client *client,
+		      struct wl_resource *resource,
+		      const char *mime_type);
+	/**
+	 * destroy - destroy the data source
+	 *
+	 * Destroy the data source.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_DATA_SOURCE_TARGET	0
+#define WL_DATA_SOURCE_SEND	1
+#define WL_DATA_SOURCE_CANCELLED	2
+
+#define WL_DATA_SOURCE_TARGET_SINCE_VERSION	1
+#define WL_DATA_SOURCE_SEND_SINCE_VERSION	1
+#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION	1
+
+static inline void
+wl_data_source_send_target(struct wl_resource *resource_, const char *mime_type)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_TARGET, mime_type);
+}
+
+static inline void
+wl_data_source_send_send(struct wl_resource *resource_, const char *mime_type, int32_t fd)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_SEND, mime_type, fd);
+}
+
+static inline void
+wl_data_source_send_cancelled(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_CANCELLED);
+}
+
+#ifndef WL_DATA_DEVICE_ERROR_ENUM
+#define WL_DATA_DEVICE_ERROR_ENUM
+enum wl_data_device_error {
+	WL_DATA_DEVICE_ERROR_ROLE = 0,
+};
+#endif /* WL_DATA_DEVICE_ERROR_ENUM */
+
+/**
+ * wl_data_device - data transfer device
+ * @start_drag: start drag-and-drop operation
+ * @set_selection: copy data to the selection
+ * @release: destroy data device
+ *
+ * There is one wl_data_device per seat which can be obtained from the
+ * global wl_data_device_manager singleton.
+ *
+ * A wl_data_device provides access to inter-client data transfer
+ * mechanisms such as copy-and-paste and drag-and-drop.
+ */
+struct wl_data_device_interface {
+	/**
+	 * start_drag - start drag-and-drop operation
+	 * @source: (none)
+	 * @origin: (none)
+	 * @icon: (none)
+	 * @serial: serial of the implicit grab on the origin
+	 *
+	 * This request asks the compositor to start a drag-and-drop
+	 * operation on behalf of the client.
+	 *
+	 * The source argument is the data source that provides the data
+	 * for the eventual data transfer. If source is NULL, enter, leave
+	 * and motion events are sent only to the client that initiated the
+	 * drag and the client is expected to handle the data passing
+	 * internally.
+	 *
+	 * The origin surface is the surface where the drag originates and
+	 * the client must have an active implicit grab that matches the
+	 * serial.
+	 *
+	 * The icon surface is an optional (can be NULL) surface that
+	 * provides an icon to be moved around with the cursor. Initially,
+	 * the top-left corner of the icon surface is placed at the cursor
+	 * hotspot, but subsequent wl_surface.attach request can move the
+	 * relative position. Attach requests must be confirmed with
+	 * wl_surface.commit as usual. The icon surface is given the role
+	 * of a drag-and-drop icon. If the icon surface already has another
+	 * role, it raises a protocol error.
+	 *
+	 * The current and pending input regions of the icon wl_surface are
+	 * cleared, and wl_surface.set_input_region is ignored until the
+	 * wl_surface is no longer used as the icon surface. When the use
+	 * as an icon ends, the current and pending input regions become
+	 * undefined, and the wl_surface is unmapped.
+	 */
+	void (*start_drag)(struct wl_client *client,
+			   struct wl_resource *resource,
+			   struct wl_resource *source,
+			   struct wl_resource *origin,
+			   struct wl_resource *icon,
+			   uint32_t serial);
+	/**
+	 * set_selection - copy data to the selection
+	 * @source: (none)
+	 * @serial: serial of the event that triggered this request
+	 *
+	 * This request asks the compositor to set the selection to the
+	 * data from the source on behalf of the client.
+	 *
+	 * To unset the selection, set the source to NULL.
+	 */
+	void (*set_selection)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *source,
+			      uint32_t serial);
+	/**
+	 * release - destroy data device
+	 *
+	 * This request destroys the data device.
+	 * @since: 2
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_DATA_DEVICE_DATA_OFFER	0
+#define WL_DATA_DEVICE_ENTER	1
+#define WL_DATA_DEVICE_LEAVE	2
+#define WL_DATA_DEVICE_MOTION	3
+#define WL_DATA_DEVICE_DROP	4
+#define WL_DATA_DEVICE_SELECTION	5
+
+#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION	1
+#define WL_DATA_DEVICE_ENTER_SINCE_VERSION	1
+#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION	1
+#define WL_DATA_DEVICE_MOTION_SINCE_VERSION	1
+#define WL_DATA_DEVICE_DROP_SINCE_VERSION	1
+#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION	1
+
+static inline void
+wl_data_device_send_data_offer(struct wl_resource *resource_, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_DATA_OFFER, id);
+}
+
+static inline void
+wl_data_device_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_ENTER, serial, surface, x, y, id);
+}
+
+static inline void
+wl_data_device_send_leave(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_LEAVE);
+}
+
+static inline void
+wl_data_device_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_MOTION, time, x, y);
+}
+
+static inline void
+wl_data_device_send_drop(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_DROP);
+}
+
+static inline void
+wl_data_device_send_selection(struct wl_resource *resource_, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_SELECTION, id);
+}
+
+/**
+ * wl_data_device_manager - data transfer interface
+ * @create_data_source: create a new data source
+ * @get_data_device: create a new data device
+ *
+ * The wl_data_device_manager is a singleton global object that provides
+ * access to inter-client data transfer mechanisms such as copy-and-paste
+ * and drag-and-drop. These mechanisms are tied to a wl_seat and this
+ * interface lets a client get a wl_data_device corresponding to a wl_seat.
+ */
+struct wl_data_device_manager_interface {
+	/**
+	 * create_data_source - create a new data source
+	 * @id: (none)
+	 *
+	 * Create a new data source.
+	 */
+	void (*create_data_source)(struct wl_client *client,
+				   struct wl_resource *resource,
+				   uint32_t id);
+	/**
+	 * get_data_device - create a new data device
+	 * @id: (none)
+	 * @seat: (none)
+	 *
+	 * Create a new data device for a given seat.
+	 */
+	void (*get_data_device)(struct wl_client *client,
+				struct wl_resource *resource,
+				uint32_t id,
+				struct wl_resource *seat);
+};
+
+
+#ifndef WL_SHELL_ERROR_ENUM
+#define WL_SHELL_ERROR_ENUM
+enum wl_shell_error {
+	WL_SHELL_ERROR_ROLE = 0,
+};
+#endif /* WL_SHELL_ERROR_ENUM */
+
+/**
+ * wl_shell - create desktop-style surfaces
+ * @get_shell_surface: create a shell surface from a surface
+ *
+ * This interface is implemented by servers that provide desktop-style
+ * user interfaces.
+ *
+ * It allows clients to associate a wl_shell_surface with a basic surface.
+ */
+struct wl_shell_interface {
+	/**
+	 * get_shell_surface - create a shell surface from a surface
+	 * @id: (none)
+	 * @surface: (none)
+	 *
+	 * Create a shell surface for an existing surface. This gives the
+	 * wl_surface the role of a shell surface. If the wl_surface
+	 * already has another role, it raises a protocol error.
+	 *
+	 * Only one shell surface can be associated with a given surface.
+	 */
+	void (*get_shell_surface)(struct wl_client *client,
+				  struct wl_resource *resource,
+				  uint32_t id,
+				  struct wl_resource *surface);
+};
+
+
+#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
+#define WL_SHELL_SURFACE_RESIZE_ENUM
+/**
+ * wl_shell_surface_resize - edge values for resizing
+ * @WL_SHELL_SURFACE_RESIZE_NONE: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM: (none)
+ * @WL_SHELL_SURFACE_RESIZE_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_RIGHT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_TOP_RIGHT: (none)
+ * @WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT: (none)
+ *
+ * These values are used to indicate which edge of a surface is being
+ * dragged in a resize operation. The server may use this information to
+ * adapt its behavior, e.g. choose an appropriate cursor image.
+ */
+enum wl_shell_surface_resize {
+	WL_SHELL_SURFACE_RESIZE_NONE = 0,
+	WL_SHELL_SURFACE_RESIZE_TOP = 1,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
+	WL_SHELL_SURFACE_RESIZE_LEFT = 4,
+	WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
+	WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
+	WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
+};
+#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
+
+#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
+#define WL_SHELL_SURFACE_TRANSIENT_ENUM
+/**
+ * wl_shell_surface_transient - details of transient behaviour
+ * @WL_SHELL_SURFACE_TRANSIENT_INACTIVE: do not set keyboard focus
+ *
+ * These flags specify details of the expected behaviour of transient
+ * surfaces. Used in the set_transient request.
+ */
+enum wl_shell_surface_transient {
+	WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
+};
+#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
+
+#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+/**
+ * wl_shell_surface_fullscreen_method - different method to set the
+ *	surface fullscreen
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT: no preference, apply
+ *	default policy
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE: scale, preserve the
+ *	surface's aspect ratio and center on output
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: switch output mode to the
+ *	smallest mode that can fit the surface, add black borders to compensate
+ *	size mismatch
+ * @WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: no upscaling, center on
+ *	output and add black borders to compensate size mismatch
+ *
+ * Hints to indicate to the compositor how to deal with a conflict
+ * between the dimensions of the surface and the dimensions of the output.
+ * The compositor is free to ignore this parameter.
+ */
+enum wl_shell_surface_fullscreen_method {
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
+};
+#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
+
+/**
+ * wl_shell_surface - desktop-style metadata interface
+ * @pong: respond to a ping event
+ * @move: start an interactive move
+ * @resize: start an interactive resize
+ * @set_toplevel: make the surface a toplevel surface
+ * @set_transient: make the surface a transient surface
+ * @set_fullscreen: make the surface a fullscreen surface
+ * @set_popup: make the surface a popup surface
+ * @set_maximized: make the surface a maximized surface
+ * @set_title: set surface title
+ * @set_class: set surface class
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like toplevel, fullscreen or
+ * popup windows, move, resize or maximize them, associate metadata like
+ * title and class, etc.
+ *
+ * On the server side the object is automatically destroyed when the
+ * related wl_surface is destroyed. On client side,
+ * wl_shell_surface_destroy() must be called before destroying the
+ * wl_surface object.
+ */
+struct wl_shell_surface_interface {
+	/**
+	 * pong - respond to a ping event
+	 * @serial: serial of the ping event
+	 *
+	 * A client must respond to a ping event with a pong request or
+	 * the client may be deemed unresponsive.
+	 */
+	void (*pong)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t serial);
+	/**
+	 * move - start an interactive move
+	 * @seat: the wl_seat whose pointer is used
+	 * @serial: serial of the implicit grab on the pointer
+	 *
+	 * Start a pointer-driven move of the surface.
+	 *
+	 * This request must be used in response to a button press event.
+	 * The server may ignore move requests depending on the state of
+	 * the surface (e.g. fullscreen or maximized).
+	 */
+	void (*move)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     struct wl_resource *seat,
+		     uint32_t serial);
+	/**
+	 * resize - start an interactive resize
+	 * @seat: the wl_seat whose pointer is used
+	 * @serial: serial of the implicit grab on the pointer
+	 * @edges: which edge or corner is being dragged
+	 *
+	 * Start a pointer-driven resizing of the surface.
+	 *
+	 * This request must be used in response to a button press event.
+	 * The server may ignore resize requests depending on the state of
+	 * the surface (e.g. fullscreen or maximized).
+	 */
+	void (*resize)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       struct wl_resource *seat,
+		       uint32_t serial,
+		       uint32_t edges);
+	/**
+	 * set_toplevel - make the surface a toplevel surface
+	 *
+	 * Map the surface as a toplevel surface.
+	 *
+	 * A toplevel surface is not fullscreen, maximized or transient.
+	 */
+	void (*set_toplevel)(struct wl_client *client,
+			     struct wl_resource *resource);
+	/**
+	 * set_transient - make the surface a transient surface
+	 * @parent: (none)
+	 * @x: (none)
+	 * @y: (none)
+	 * @flags: (none)
+	 *
+	 * Map the surface relative to an existing surface.
+	 *
+	 * The x and y arguments specify the locations of the upper left
+	 * corner of the surface relative to the upper left corner of the
+	 * parent surface, in surface local coordinates.
+	 *
+	 * The flags argument controls details of the transient behaviour.
+	 */
+	void (*set_transient)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *parent,
+			      int32_t x,
+			      int32_t y,
+			      uint32_t flags);
+	/**
+	 * set_fullscreen - make the surface a fullscreen surface
+	 * @method: (none)
+	 * @framerate: (none)
+	 * @output: (none)
+	 *
+	 * Map the surface as a fullscreen surface.
+	 *
+	 * If an output parameter is given then the surface will be made
+	 * fullscreen on that output. If the client does not specify the
+	 * output then the compositor will apply its policy - usually
+	 * choosing the output on which the surface has the biggest surface
+	 * area.
+	 *
+	 * The client may specify a method to resolve a size conflict
+	 * between the output size and the surface size - this is provided
+	 * through the method parameter.
+	 *
+	 * The framerate parameter is used only when the method is set to
+	 * "driver", to indicate the preferred framerate. A value of 0
+	 * indicates that the app does not care about framerate. The
+	 * framerate is specified in mHz, that is framerate of 60000 is
+	 * 60Hz.
+	 *
+	 * A method of "scale" or "driver" implies a scaling operation of
+	 * the surface, either via a direct scaling operation or a change
+	 * of the output mode. This will override any kind of output
+	 * scaling, so that mapping a surface with a buffer size equal to
+	 * the mode can fill the screen independent of buffer_scale.
+	 *
+	 * A method of "fill" means we don't scale up the buffer, however
+	 * any output scale is applied. This means that you may run into an
+	 * edge case where the application maps a buffer with the same size
+	 * of the output mode but buffer_scale 1 (thus making a surface
+	 * larger than the output). In this case it is allowed to downscale
+	 * the results to fit the screen.
+	 *
+	 * The compositor must reply to this request with a configure event
+	 * with the dimensions for the output on which the surface will be
+	 * made fullscreen.
+	 */
+	void (*set_fullscreen)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t method,
+			       uint32_t framerate,
+			       struct wl_resource *output);
+	/**
+	 * set_popup - make the surface a popup surface
+	 * @seat: the wl_seat whose pointer is used
+	 * @serial: serial of the implicit grab on the pointer
+	 * @parent: (none)
+	 * @x: (none)
+	 * @y: (none)
+	 * @flags: (none)
+	 *
+	 * Map the surface as a popup.
+	 *
+	 * A popup surface is a transient surface with an added pointer
+	 * grab.
+	 *
+	 * An existing implicit grab will be changed to owner-events mode,
+	 * and the popup grab will continue after the implicit grab ends
+	 * (i.e. releasing the mouse button does not cause the popup to be
+	 * unmapped).
+	 *
+	 * The popup grab continues until the window is destroyed or a
+	 * mouse button is pressed in any other clients window. A click in
+	 * any of the clients surfaces is reported as normal, however,
+	 * clicks in other clients surfaces will be discarded and trigger
+	 * the callback.
+	 *
+	 * The x and y arguments specify the locations of the upper left
+	 * corner of the surface relative to the upper left corner of the
+	 * parent surface, in surface local coordinates.
+	 */
+	void (*set_popup)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  struct wl_resource *seat,
+			  uint32_t serial,
+			  struct wl_resource *parent,
+			  int32_t x,
+			  int32_t y,
+			  uint32_t flags);
+	/**
+	 * set_maximized - make the surface a maximized surface
+	 * @output: (none)
+	 *
+	 * Map the surface as a maximized surface.
+	 *
+	 * If an output parameter is given then the surface will be
+	 * maximized on that output. If the client does not specify the
+	 * output then the compositor will apply its policy - usually
+	 * choosing the output on which the surface has the biggest surface
+	 * area.
+	 *
+	 * The compositor will reply with a configure event telling the
+	 * expected new surface size. The operation is completed on the
+	 * next buffer attach to this surface.
+	 *
+	 * A maximized surface typically fills the entire output it is
+	 * bound to, except for desktop element such as panels. This is the
+	 * main difference between a maximized shell surface and a
+	 * fullscreen shell surface.
+	 *
+	 * The details depend on the compositor implementation.
+	 */
+	void (*set_maximized)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *output);
+	/**
+	 * set_title - set surface title
+	 * @title: (none)
+	 *
+	 * Set a short title for the surface.
+	 *
+	 * This string may be used to identify the surface in a task bar,
+	 * window list, or other user interface elements provided by the
+	 * compositor.
+	 *
+	 * The string must be encoded in UTF-8.
+	 */
+	void (*set_title)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  const char *title);
+	/**
+	 * set_class - set surface class
+	 * @class_: (none)
+	 *
+	 * Set a class for the surface.
+	 *
+	 * The surface class identifies the general class of applications
+	 * to which the surface belongs. A common convention is to use the
+	 * file name (or the full path if it is a non-standard location) of
+	 * the application's .desktop file as the class.
+	 */
+	void (*set_class)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  const char *class_);
+};
+
+#define WL_SHELL_SURFACE_PING	0
+#define WL_SHELL_SURFACE_CONFIGURE	1
+#define WL_SHELL_SURFACE_POPUP_DONE	2
+
+#define WL_SHELL_SURFACE_PING_SINCE_VERSION	1
+#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION	1
+#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION	1
+
+static inline void
+wl_shell_surface_send_ping(struct wl_resource *resource_, uint32_t serial)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_PING, serial);
+}
+
+static inline void
+wl_shell_surface_send_configure(struct wl_resource *resource_, uint32_t edges, int32_t width, int32_t height)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_CONFIGURE, edges, width, height);
+}
+
+static inline void
+wl_shell_surface_send_popup_done(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_POPUP_DONE);
+}
+
+#ifndef WL_SURFACE_ERROR_ENUM
+#define WL_SURFACE_ERROR_ENUM
+/**
+ * wl_surface_error - wl_surface error values
+ * @WL_SURFACE_ERROR_INVALID_SCALE: buffer scale value is invalid
+ * @WL_SURFACE_ERROR_INVALID_TRANSFORM: buffer transform value is invalid
+ *
+ * These errors can be emitted in response to wl_surface requests.
+ */
+enum wl_surface_error {
+	WL_SURFACE_ERROR_INVALID_SCALE = 0,
+	WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
+};
+#endif /* WL_SURFACE_ERROR_ENUM */
+
+/**
+ * wl_surface - an onscreen surface
+ * @destroy: delete surface
+ * @attach: set the surface contents
+ * @damage: mark part of the surface damaged
+ * @frame: request a frame throttling hint
+ * @set_opaque_region: set opaque region
+ * @set_input_region: set input region
+ * @commit: commit pending surface state
+ * @set_buffer_transform: sets the buffer transformation
+ * @set_buffer_scale: sets the buffer scaling factor
+ *
+ * A surface is a rectangular area that is displayed on the screen. It
+ * has a location, size and pixel contents.
+ *
+ * The size of a surface (and relative positions on it) is described in
+ * surface local coordinates, which may differ from the buffer local
+ * coordinates of the pixel content, in case a buffer_transform or a
+ * buffer_scale is used.
+ *
+ * A surface without a "role" is fairly useless, a compositor does not know
+ * where, when or how to present it. The role is the purpose of a
+ * wl_surface. Examples of roles are a cursor for a pointer (as set by
+ * wl_pointer.set_cursor), a drag icon (wl_data_device.start_drag), a
+ * sub-surface (wl_subcompositor.get_subsurface), and a window as defined
+ * by a shell protocol (e.g. wl_shell.get_shell_surface).
+ *
+ * A surface can have only one role at a time. Initially a wl_surface does
+ * not have a role. Once a wl_surface is given a role, it is set
+ * permanently for the whole lifetime of the wl_surface object. Giving the
+ * current role again is allowed, unless explicitly forbidden by the
+ * relevant interface specification.
+ *
+ * Surface roles are given by requests in other interfaces such as
+ * wl_pointer.set_cursor. The request should explicitly mention that this
+ * request gives a role to a wl_surface. Often, this request also creates a
+ * new protocol object that represents the role and adds additional
+ * functionality to wl_surface. When a client wants to destroy a
+ * wl_surface, they must destroy this 'role object' before the wl_surface.
+ *
+ * Destroying the role object does not remove the role from the wl_surface,
+ * but it may stop the wl_surface from "playing the role". For instance, if
+ * a wl_subsurface object is destroyed, the wl_surface it was created for
+ * will be unmapped and forget its position and z-order. It is allowed to
+ * create a wl_subsurface for the same wl_surface again, but it is not
+ * allowed to use the wl_surface as a cursor (cursor is a different role
+ * than sub-surface, and role switching is not allowed).
+ */
+struct wl_surface_interface {
+	/**
+	 * destroy - delete surface
+	 *
+	 * Deletes the surface and invalidates its object ID.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * attach - set the surface contents
+	 * @buffer: (none)
+	 * @x: (none)
+	 * @y: (none)
+	 *
+	 * Set a buffer as the content of this surface.
+	 *
+	 * The new size of the surface is calculated based on the buffer
+	 * size transformed by the inverse buffer_transform and the inverse
+	 * buffer_scale. This means that the supplied buffer must be an
+	 * integer multiple of the buffer_scale.
+	 *
+	 * The x and y arguments specify the location of the new pending
+	 * buffer's upper left corner, relative to the current buffer's
+	 * upper left corner, in surface local coordinates. In other words,
+	 * the x and y, combined with the new surface size define in which
+	 * directions the surface's size changes.
+	 *
+	 * Surface contents are double-buffered state, see
+	 * wl_surface.commit.
+	 *
+	 * The initial surface contents are void; there is no content.
+	 * wl_surface.attach assigns the given wl_buffer as the pending
+	 * wl_buffer. wl_surface.commit makes the pending wl_buffer the new
+	 * surface contents, and the size of the surface becomes the size
+	 * calculated from the wl_buffer, as described above. After commit,
+	 * there is no pending buffer until the next attach.
+	 *
+	 * Committing a pending wl_buffer allows the compositor to read the
+	 * pixels in the wl_buffer. The compositor may access the pixels at
+	 * any time after the wl_surface.commit request. When the
+	 * compositor will not access the pixels anymore, it will send the
+	 * wl_buffer.release event. Only after receiving wl_buffer.release,
+	 * the client may re-use the wl_buffer. A wl_buffer that has been
+	 * attached and then replaced by another attach instead of
+	 * committed will not receive a release event, and is not used by
+	 * the compositor.
+	 *
+	 * Destroying the wl_buffer after wl_buffer.release does not change
+	 * the surface contents. However, if the client destroys the
+	 * wl_buffer before receiving the wl_buffer.release event, the
+	 * surface contents become undefined immediately.
+	 *
+	 * If wl_surface.attach is sent with a NULL wl_buffer, the
+	 * following wl_surface.commit will remove the surface content.
+	 */
+	void (*attach)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       struct wl_resource *buffer,
+		       int32_t x,
+		       int32_t y);
+	/**
+	 * damage - mark part of the surface damaged
+	 * @x: (none)
+	 * @y: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 *
+	 * This request is used to describe the regions where the pending
+	 * buffer is different from the current surface contents, and where
+	 * the surface therefore needs to be repainted. The pending buffer
+	 * must be set by wl_surface.attach before sending damage. The
+	 * compositor ignores the parts of the damage that fall outside of
+	 * the surface.
+	 *
+	 * Damage is double-buffered state, see wl_surface.commit.
+	 *
+	 * The damage rectangle is specified in surface local coordinates.
+	 *
+	 * The initial value for pending damage is empty: no damage.
+	 * wl_surface.damage adds pending damage: the new pending damage is
+	 * the union of old pending damage and the given rectangle.
+	 *
+	 * wl_surface.commit assigns pending damage as the current damage,
+	 * and clears pending damage. The server will clear the current
+	 * damage as it repaints the surface.
+	 */
+	void (*damage)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       int32_t x,
+		       int32_t y,
+		       int32_t width,
+		       int32_t height);
+	/**
+	 * frame - request a frame throttling hint
+	 * @callback: (none)
+	 *
+	 * Request a notification when it is a good time start drawing a
+	 * new frame, by creating a frame callback. This is useful for
+	 * throttling redrawing operations, and driving animations.
+	 *
+	 * When a client is animating on a wl_surface, it can use the
+	 * 'frame' request to get notified when it is a good time to draw
+	 * and commit the next frame of animation. If the client commits an
+	 * update earlier than that, it is likely that some updates will
+	 * not make it to the display, and the client is wasting resources
+	 * by drawing too often.
+	 *
+	 * The frame request will take effect on the next
+	 * wl_surface.commit. The notification will only be posted for one
+	 * frame unless requested again. For a wl_surface, the
+	 * notifications are posted in the order the frame requests were
+	 * committed.
+	 *
+	 * The server must send the notifications so that a client will not
+	 * send excessive updates, while still allowing the highest
+	 * possible update rate for clients that wait for the reply before
+	 * drawing again. The server should give some time for the client
+	 * to draw and commit after sending the frame callback events to
+	 * let them hit the next output refresh.
+	 *
+	 * A server should avoid signalling the frame callbacks if the
+	 * surface is not visible in any way, e.g. the surface is
+	 * off-screen, or completely obscured by other opaque surfaces.
+	 *
+	 * The object returned by this request will be destroyed by the
+	 * compositor after the callback is fired and as such the client
+	 * must not attempt to use it after that point.
+	 *
+	 * The callback_data passed in the callback is the current time, in
+	 * milliseconds, with an undefined base.
+	 */
+	void (*frame)(struct wl_client *client,
+		      struct wl_resource *resource,
+		      uint32_t callback);
+	/**
+	 * set_opaque_region - set opaque region
+	 * @region: (none)
+	 *
+	 * This request sets the region of the surface that contains
+	 * opaque content.
+	 *
+	 * The opaque region is an optimization hint for the compositor
+	 * that lets it optimize out redrawing of content behind opaque
+	 * regions. Setting an opaque region is not required for correct
+	 * behaviour, but marking transparent content as opaque will result
+	 * in repaint artifacts.
+	 *
+	 * The opaque region is specified in surface local coordinates.
+	 *
+	 * The compositor ignores the parts of the opaque region that fall
+	 * outside of the surface.
+	 *
+	 * Opaque region is double-buffered state, see wl_surface.commit.
+	 *
+	 * wl_surface.set_opaque_region changes the pending opaque region.
+	 * wl_surface.commit copies the pending region to the current
+	 * region. Otherwise, the pending and current regions are never
+	 * changed.
+	 *
+	 * The initial value for opaque region is empty. Setting the
+	 * pending opaque region has copy semantics, and the wl_region
+	 * object can be destroyed immediately. A NULL wl_region causes the
+	 * pending opaque region to be set to empty.
+	 */
+	void (*set_opaque_region)(struct wl_client *client,
+				  struct wl_resource *resource,
+				  struct wl_resource *region);
+	/**
+	 * set_input_region - set input region
+	 * @region: (none)
+	 *
+	 * This request sets the region of the surface that can receive
+	 * pointer and touch events.
+	 *
+	 * Input events happening outside of this region will try the next
+	 * surface in the server surface stack. The compositor ignores the
+	 * parts of the input region that fall outside of the surface.
+	 *
+	 * The input region is specified in surface local coordinates.
+	 *
+	 * Input region is double-buffered state, see wl_surface.commit.
+	 *
+	 * wl_surface.set_input_region changes the pending input region.
+	 * wl_surface.commit copies the pending region to the current
+	 * region. Otherwise the pending and current regions are never
+	 * changed, except cursor and icon surfaces are special cases, see
+	 * wl_pointer.set_cursor and wl_data_device.start_drag.
+	 *
+	 * The initial value for input region is infinite. That means the
+	 * whole surface will accept input. Setting the pending input
+	 * region has copy semantics, and the wl_region object can be
+	 * destroyed immediately. A NULL wl_region causes the input region
+	 * to be set to infinite.
+	 */
+	void (*set_input_region)(struct wl_client *client,
+				 struct wl_resource *resource,
+				 struct wl_resource *region);
+	/**
+	 * commit - commit pending surface state
+	 *
+	 * Surface state (input, opaque, and damage regions, attached
+	 * buffers, etc.) is double-buffered. Protocol requests modify the
+	 * pending state, as opposed to current state in use by the
+	 * compositor. Commit request atomically applies all pending state,
+	 * replacing the current state. After commit, the new pending state
+	 * is as documented for each related request.
+	 *
+	 * On commit, a pending wl_buffer is applied first, all other state
+	 * second. This means that all coordinates in double-buffered state
+	 * are relative to the new wl_buffer coming into use, except for
+	 * wl_surface.attach itself. If there is no pending wl_buffer, the
+	 * coordinates are relative to the current surface contents.
+	 *
+	 * All requests that need a commit to become effective are
+	 * documented to affect double-buffered state.
+	 *
+	 * Other interfaces may add further double-buffered surface state.
+	 */
+	void (*commit)(struct wl_client *client,
+		       struct wl_resource *resource);
+	/**
+	 * set_buffer_transform - sets the buffer transformation
+	 * @transform: (none)
+	 *
+	 * This request sets an optional transformation on how the
+	 * compositor interprets the contents of the buffer attached to the
+	 * surface. The accepted values for the transform parameter are the
+	 * values for wl_output.transform.
+	 *
+	 * Buffer transform is double-buffered state, see
+	 * wl_surface.commit.
+	 *
+	 * A newly created surface has its buffer transformation set to
+	 * normal.
+	 *
+	 * wl_surface.set_buffer_transform changes the pending buffer
+	 * transformation. wl_surface.commit copies the pending buffer
+	 * transformation to the current one. Otherwise, the pending and
+	 * current values are never changed.
+	 *
+	 * The purpose of this request is to allow clients to render
+	 * content according to the output transform, thus permiting the
+	 * compositor to use certain optimizations even if the display is
+	 * rotated. Using hardware overlays and scanning out a client
+	 * buffer for fullscreen surfaces are examples of such
+	 * optimizations. Those optimizations are highly dependent on the
+	 * compositor implementation, so the use of this request should be
+	 * considered on a case-by-case basis.
+	 *
+	 * Note that if the transform value includes 90 or 270 degree
+	 * rotation, the width of the buffer will become the surface height
+	 * and the height of the buffer will become the surface width.
+	 *
+	 * If transform is not one of the values from the
+	 * wl_output.transform enum the invalid_transform protocol error is
+	 * raised.
+	 * @since: 2
+	 */
+	void (*set_buffer_transform)(struct wl_client *client,
+				     struct wl_resource *resource,
+				     int32_t transform);
+	/**
+	 * set_buffer_scale - sets the buffer scaling factor
+	 * @scale: (none)
+	 *
+	 * This request sets an optional scaling factor on how the
+	 * compositor interprets the contents of the buffer attached to the
+	 * window.
+	 *
+	 * Buffer scale is double-buffered state, see wl_surface.commit.
+	 *
+	 * A newly created surface has its buffer scale set to 1.
+	 *
+	 * wl_surface.set_buffer_scale changes the pending buffer scale.
+	 * wl_surface.commit copies the pending buffer scale to the current
+	 * one. Otherwise, the pending and current values are never
+	 * changed.
+	 *
+	 * The purpose of this request is to allow clients to supply higher
+	 * resolution buffer data for use on high resolution outputs. Its
+	 * intended that you pick the same buffer scale as the scale of the
+	 * output that the surface is displayed on.This means the
+	 * compositor can avoid scaling when rendering the surface on that
+	 * output.
+	 *
+	 * Note that if the scale is larger than 1, then you have to attach
+	 * a buffer that is larger (by a factor of scale in each dimension)
+	 * than the desired surface size.
+	 *
+	 * If scale is not positive the invalid_scale protocol error is
+	 * raised.
+	 * @since: 3
+	 */
+	void (*set_buffer_scale)(struct wl_client *client,
+				 struct wl_resource *resource,
+				 int32_t scale);
+};
+
+#define WL_SURFACE_ENTER	0
+#define WL_SURFACE_LEAVE	1
+
+#define WL_SURFACE_ENTER_SINCE_VERSION	1
+#define WL_SURFACE_LEAVE_SINCE_VERSION	1
+
+static inline void
+wl_surface_send_enter(struct wl_resource *resource_, struct wl_resource *output)
+{
+	wl_resource_post_event(resource_, WL_SURFACE_ENTER, output);
+}
+
+static inline void
+wl_surface_send_leave(struct wl_resource *resource_, struct wl_resource *output)
+{
+	wl_resource_post_event(resource_, WL_SURFACE_LEAVE, output);
+}
+
+#ifndef WL_SEAT_CAPABILITY_ENUM
+#define WL_SEAT_CAPABILITY_ENUM
+/**
+ * wl_seat_capability - seat capability bitmask
+ * @WL_SEAT_CAPABILITY_POINTER: The seat has pointer devices
+ * @WL_SEAT_CAPABILITY_KEYBOARD: The seat has one or more keyboards
+ * @WL_SEAT_CAPABILITY_TOUCH: The seat has touch devices
+ *
+ * This is a bitmask of capabilities this seat has; if a member is set,
+ * then it is present on the seat.
+ */
+enum wl_seat_capability {
+	WL_SEAT_CAPABILITY_POINTER = 1,
+	WL_SEAT_CAPABILITY_KEYBOARD = 2,
+	WL_SEAT_CAPABILITY_TOUCH = 4,
+};
+#endif /* WL_SEAT_CAPABILITY_ENUM */
+
+/**
+ * wl_seat - group of input devices
+ * @get_pointer: return pointer object
+ * @get_keyboard: return keyboard object
+ * @get_touch: return touch object
+ *
+ * A seat is a group of keyboards, pointer and touch devices. This object
+ * is published as a global during start up, or when such a device is hot
+ * plugged. A seat typically has a pointer and maintains a keyboard focus
+ * and a pointer focus.
+ */
+struct wl_seat_interface {
+	/**
+	 * get_pointer - return pointer object
+	 * @id: (none)
+	 *
+	 * The ID provided will be initialized to the wl_pointer
+	 * interface for this seat.
+	 *
+	 * This request only takes effect if the seat has the pointer
+	 * capability.
+	 */
+	void (*get_pointer)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    uint32_t id);
+	/**
+	 * get_keyboard - return keyboard object
+	 * @id: (none)
+	 *
+	 * The ID provided will be initialized to the wl_keyboard
+	 * interface for this seat.
+	 *
+	 * This request only takes effect if the seat has the keyboard
+	 * capability.
+	 */
+	void (*get_keyboard)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t id);
+	/**
+	 * get_touch - return touch object
+	 * @id: (none)
+	 *
+	 * The ID provided will be initialized to the wl_touch interface
+	 * for this seat.
+	 *
+	 * This request only takes effect if the seat has the touch
+	 * capability.
+	 */
+	void (*get_touch)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  uint32_t id);
+};
+
+#define WL_SEAT_CAPABILITIES	0
+#define WL_SEAT_NAME	1
+
+#define WL_SEAT_CAPABILITIES_SINCE_VERSION	1
+#define WL_SEAT_NAME_SINCE_VERSION	2
+
+static inline void
+wl_seat_send_capabilities(struct wl_resource *resource_, uint32_t capabilities)
+{
+	wl_resource_post_event(resource_, WL_SEAT_CAPABILITIES, capabilities);
+}
+
+static inline void
+wl_seat_send_name(struct wl_resource *resource_, const char *name)
+{
+	wl_resource_post_event(resource_, WL_SEAT_NAME, name);
+}
+
+#ifndef WL_POINTER_ERROR_ENUM
+#define WL_POINTER_ERROR_ENUM
+enum wl_pointer_error {
+	WL_POINTER_ERROR_ROLE = 0,
+};
+#endif /* WL_POINTER_ERROR_ENUM */
+
+#ifndef WL_POINTER_BUTTON_STATE_ENUM
+#define WL_POINTER_BUTTON_STATE_ENUM
+/**
+ * wl_pointer_button_state - physical button state
+ * @WL_POINTER_BUTTON_STATE_RELEASED: The button is not pressed
+ * @WL_POINTER_BUTTON_STATE_PRESSED: The button is pressed
+ *
+ * Describes the physical state of a button which provoked the button
+ * event.
+ */
+enum wl_pointer_button_state {
+	WL_POINTER_BUTTON_STATE_RELEASED = 0,
+	WL_POINTER_BUTTON_STATE_PRESSED = 1,
+};
+#endif /* WL_POINTER_BUTTON_STATE_ENUM */
+
+#ifndef WL_POINTER_AXIS_ENUM
+#define WL_POINTER_AXIS_ENUM
+/**
+ * wl_pointer_axis - axis types
+ * @WL_POINTER_AXIS_VERTICAL_SCROLL: (none)
+ * @WL_POINTER_AXIS_HORIZONTAL_SCROLL: (none)
+ *
+ * Describes the axis types of scroll events.
+ */
+enum wl_pointer_axis {
+	WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
+	WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
+};
+#endif /* WL_POINTER_AXIS_ENUM */
+
+/**
+ * wl_pointer - pointer input device
+ * @set_cursor: set the pointer surface
+ * @release: release the pointer object
+ *
+ * The wl_pointer interface represents one or more input devices, such as
+ * mice, which control the pointer location and pointer_focus of a seat.
+ *
+ * The wl_pointer interface generates motion, enter and leave events for
+ * the surfaces that the pointer is located over, and button and axis
+ * events for button presses, button releases and scrolling.
+ */
+struct wl_pointer_interface {
+	/**
+	 * set_cursor - set the pointer surface
+	 * @serial: serial of the enter event
+	 * @surface: (none)
+	 * @hotspot_x: x coordinate in surface-relative coordinates
+	 * @hotspot_y: y coordinate in surface-relative coordinates
+	 *
+	 * Set the pointer surface, i.e., the surface that contains the
+	 * pointer image (cursor). This request gives the surface the role
+	 * of a cursor. If the surface already has another role, it raises
+	 * a protocol error.
+	 *
+	 * The cursor actually changes only if the pointer focus for this
+	 * device is one of the requesting client's surfaces or the surface
+	 * parameter is the current pointer surface. If there was a
+	 * previous surface set with this request it is replaced. If
+	 * surface is NULL, the pointer image is hidden.
+	 *
+	 * The parameters hotspot_x and hotspot_y define the position of
+	 * the pointer surface relative to the pointer location. Its
+	 * top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
+	 * where (x, y) are the coordinates of the pointer location, in
+	 * surface local coordinates.
+	 *
+	 * On surface.attach requests to the pointer surface, hotspot_x and
+	 * hotspot_y are decremented by the x and y parameters passed to
+	 * the request. Attach must be confirmed by wl_surface.commit as
+	 * usual.
+	 *
+	 * The hotspot can also be updated by passing the currently set
+	 * pointer surface to this request with new values for hotspot_x
+	 * and hotspot_y.
+	 *
+	 * The current and pending input regions of the wl_surface are
+	 * cleared, and wl_surface.set_input_region is ignored until the
+	 * wl_surface is no longer used as the cursor. When the use as a
+	 * cursor ends, the current and pending input regions become
+	 * undefined, and the wl_surface is unmapped.
+	 */
+	void (*set_cursor)(struct wl_client *client,
+			   struct wl_resource *resource,
+			   uint32_t serial,
+			   struct wl_resource *surface,
+			   int32_t hotspot_x,
+			   int32_t hotspot_y);
+	/**
+	 * release - release the pointer object
+	 *
+	 * Using this request client can tell the server that it is not
+	 * going to use the pointer object anymore.
+	 *
+	 * This request destroys the pointer proxy object, so user must not
+	 * call wl_pointer_destroy() after using this request.
+	 * @since: 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_POINTER_ENTER	0
+#define WL_POINTER_LEAVE	1
+#define WL_POINTER_MOTION	2
+#define WL_POINTER_BUTTON	3
+#define WL_POINTER_AXIS	4
+
+#define WL_POINTER_ENTER_SINCE_VERSION	1
+#define WL_POINTER_LEAVE_SINCE_VERSION	1
+#define WL_POINTER_MOTION_SINCE_VERSION	1
+#define WL_POINTER_BUTTON_SINCE_VERSION	1
+#define WL_POINTER_AXIS_SINCE_VERSION	1
+
+static inline void
+wl_pointer_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+	wl_resource_post_event(resource_, WL_POINTER_ENTER, serial, surface, surface_x, surface_y);
+}
+
+static inline void
+wl_pointer_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface)
+{
+	wl_resource_post_event(resource_, WL_POINTER_LEAVE, serial, surface);
+}
+
+static inline void
+wl_pointer_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+	wl_resource_post_event(resource_, WL_POINTER_MOTION, time, surface_x, surface_y);
+}
+
+static inline void
+wl_pointer_send_button(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
+{
+	wl_resource_post_event(resource_, WL_POINTER_BUTTON, serial, time, button, state);
+}
+
+static inline void
+wl_pointer_send_axis(struct wl_resource *resource_, uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+	wl_resource_post_event(resource_, WL_POINTER_AXIS, time, axis, value);
+}
+
+#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+/**
+ * wl_keyboard_keymap_format - keyboard mapping format
+ * @WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP: no keymap; client must
+ *	understand how to interpret the raw keycode
+ * @WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1: libxkbcommon compatible; to
+ *	determine the xkb keycode, clients must add 8 to the key event keycode
+ *
+ * This specifies the format of the keymap provided to the client with
+ * the wl_keyboard.keymap event.
+ */
+enum wl_keyboard_keymap_format {
+	WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
+	WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
+};
+#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
+
+#ifndef WL_KEYBOARD_KEY_STATE_ENUM
+#define WL_KEYBOARD_KEY_STATE_ENUM
+/**
+ * wl_keyboard_key_state - physical key state
+ * @WL_KEYBOARD_KEY_STATE_RELEASED: key is not pressed
+ * @WL_KEYBOARD_KEY_STATE_PRESSED: key is pressed
+ *
+ * Describes the physical state of a key which provoked the key event.
+ */
+enum wl_keyboard_key_state {
+	WL_KEYBOARD_KEY_STATE_RELEASED = 0,
+	WL_KEYBOARD_KEY_STATE_PRESSED = 1,
+};
+#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
+
+/**
+ * wl_keyboard - keyboard input device
+ * @release: release the keyboard object
+ *
+ * The wl_keyboard interface represents one or more keyboards associated
+ * with a seat.
+ */
+struct wl_keyboard_interface {
+	/**
+	 * release - release the keyboard object
+	 *
+	 * 
+	 * @since: 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_KEYBOARD_KEYMAP	0
+#define WL_KEYBOARD_ENTER	1
+#define WL_KEYBOARD_LEAVE	2
+#define WL_KEYBOARD_KEY	3
+#define WL_KEYBOARD_MODIFIERS	4
+#define WL_KEYBOARD_REPEAT_INFO	5
+
+#define WL_KEYBOARD_KEYMAP_SINCE_VERSION	1
+#define WL_KEYBOARD_ENTER_SINCE_VERSION	1
+#define WL_KEYBOARD_LEAVE_SINCE_VERSION	1
+#define WL_KEYBOARD_KEY_SINCE_VERSION	1
+#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION	1
+#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION	4
+
+static inline void
+wl_keyboard_send_keymap(struct wl_resource *resource_, uint32_t format, int32_t fd, uint32_t size)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_KEYMAP, format, fd, size);
+}
+
+static inline void
+wl_keyboard_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, struct wl_array *keys)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_ENTER, serial, surface, keys);
+}
+
+static inline void
+wl_keyboard_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_LEAVE, serial, surface);
+}
+
+static inline void
+wl_keyboard_send_key(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_KEY, serial, time, key, state);
+}
+
+static inline void
+wl_keyboard_send_modifiers(struct wl_resource *resource_, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_MODIFIERS, serial, mods_depressed, mods_latched, mods_locked, group);
+}
+
+static inline void
+wl_keyboard_send_repeat_info(struct wl_resource *resource_, int32_t rate, int32_t delay)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_REPEAT_INFO, rate, delay);
+}
+
+/**
+ * wl_touch - touchscreen input device
+ * @release: release the touch object
+ *
+ * The wl_touch interface represents a touchscreen associated with a
+ * seat.
+ *
+ * Touch interactions can consist of one or more contacts. For each
+ * contact, a series of events is generated, starting with a down event,
+ * followed by zero or more motion events, and ending with an up event.
+ * Events relating to the same contact point can be identified by the ID of
+ * the sequence.
+ */
+struct wl_touch_interface {
+	/**
+	 * release - release the touch object
+	 *
+	 * 
+	 * @since: 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_TOUCH_DOWN	0
+#define WL_TOUCH_UP	1
+#define WL_TOUCH_MOTION	2
+#define WL_TOUCH_FRAME	3
+#define WL_TOUCH_CANCEL	4
+
+#define WL_TOUCH_DOWN_SINCE_VERSION	1
+#define WL_TOUCH_UP_SINCE_VERSION	1
+#define WL_TOUCH_MOTION_SINCE_VERSION	1
+#define WL_TOUCH_FRAME_SINCE_VERSION	1
+#define WL_TOUCH_CANCEL_SINCE_VERSION	1
+
+static inline void
+wl_touch_send_down(struct wl_resource *resource_, uint32_t serial, uint32_t time, struct wl_resource *surface, int32_t id, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_DOWN, serial, time, surface, id, x, y);
+}
+
+static inline void
+wl_touch_send_up(struct wl_resource *resource_, uint32_t serial, uint32_t time, int32_t id)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_UP, serial, time, id);
+}
+
+static inline void
+wl_touch_send_motion(struct wl_resource *resource_, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_MOTION, time, id, x, y);
+}
+
+static inline void
+wl_touch_send_frame(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_FRAME);
+}
+
+static inline void
+wl_touch_send_cancel(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_CANCEL);
+}
+
+#ifndef WL_OUTPUT_SUBPIXEL_ENUM
+#define WL_OUTPUT_SUBPIXEL_ENUM
+/**
+ * wl_output_subpixel - subpixel geometry information
+ * @WL_OUTPUT_SUBPIXEL_UNKNOWN: (none)
+ * @WL_OUTPUT_SUBPIXEL_NONE: (none)
+ * @WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB: (none)
+ * @WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR: (none)
+ * @WL_OUTPUT_SUBPIXEL_VERTICAL_RGB: (none)
+ * @WL_OUTPUT_SUBPIXEL_VERTICAL_BGR: (none)
+ *
+ * This enumeration describes how the physical pixels on an output are
+ * laid out.
+ */
+enum wl_output_subpixel {
+	WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
+	WL_OUTPUT_SUBPIXEL_NONE = 1,
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
+	WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
+	WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
+};
+#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
+
+#ifndef WL_OUTPUT_TRANSFORM_ENUM
+#define WL_OUTPUT_TRANSFORM_ENUM
+/**
+ * wl_output_transform - transform from framebuffer to output
+ * @WL_OUTPUT_TRANSFORM_NORMAL: (none)
+ * @WL_OUTPUT_TRANSFORM_90: (none)
+ * @WL_OUTPUT_TRANSFORM_180: (none)
+ * @WL_OUTPUT_TRANSFORM_270: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_90: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_180: (none)
+ * @WL_OUTPUT_TRANSFORM_FLIPPED_270: (none)
+ *
+ * This describes the transform that a compositor will apply to a surface
+ * to compensate for the rotation or mirroring of an output device.
+ *
+ * The flipped values correspond to an initial flip around a vertical axis
+ * followed by rotation.
+ *
+ * The purpose is mainly to allow clients render accordingly and tell the
+ * compositor, so that for fullscreen surfaces, the compositor will still
+ * be able to scan out directly from client surfaces.
+ */
+enum wl_output_transform {
+	WL_OUTPUT_TRANSFORM_NORMAL = 0,
+	WL_OUTPUT_TRANSFORM_90 = 1,
+	WL_OUTPUT_TRANSFORM_180 = 2,
+	WL_OUTPUT_TRANSFORM_270 = 3,
+	WL_OUTPUT_TRANSFORM_FLIPPED = 4,
+	WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
+	WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
+	WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
+};
+#endif /* WL_OUTPUT_TRANSFORM_ENUM */
+
+#ifndef WL_OUTPUT_MODE_ENUM
+#define WL_OUTPUT_MODE_ENUM
+/**
+ * wl_output_mode - mode information
+ * @WL_OUTPUT_MODE_CURRENT: indicates this is the current mode
+ * @WL_OUTPUT_MODE_PREFERRED: indicates this is the preferred mode
+ *
+ * These flags describe properties of an output mode. They are used in
+ * the flags bitfield of the mode event.
+ */
+enum wl_output_mode {
+	WL_OUTPUT_MODE_CURRENT = 0x1,
+	WL_OUTPUT_MODE_PREFERRED = 0x2,
+};
+#endif /* WL_OUTPUT_MODE_ENUM */
+
+#define WL_OUTPUT_GEOMETRY	0
+#define WL_OUTPUT_MODE	1
+#define WL_OUTPUT_DONE	2
+#define WL_OUTPUT_SCALE	3
+
+#define WL_OUTPUT_GEOMETRY_SINCE_VERSION	1
+#define WL_OUTPUT_MODE_SINCE_VERSION	1
+#define WL_OUTPUT_DONE_SINCE_VERSION	2
+#define WL_OUTPUT_SCALE_SINCE_VERSION	2
+
+static inline void
+wl_output_send_geometry(struct wl_resource *resource_, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_GEOMETRY, x, y, physical_width, physical_height, subpixel, make, model, transform);
+}
+
+static inline void
+wl_output_send_mode(struct wl_resource *resource_, uint32_t flags, int32_t width, int32_t height, int32_t refresh)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_MODE, flags, width, height, refresh);
+}
+
+static inline void
+wl_output_send_done(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_DONE);
+}
+
+static inline void
+wl_output_send_scale(struct wl_resource *resource_, int32_t factor)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_SCALE, factor);
+}
+
+/**
+ * wl_region - region interface
+ * @destroy: destroy region
+ * @add: add rectangle to region
+ * @subtract: subtract rectangle from region
+ *
+ * A region object describes an area.
+ *
+ * Region objects are used to describe the opaque and input regions of a
+ * surface.
+ */
+struct wl_region_interface {
+	/**
+	 * destroy - destroy region
+	 *
+	 * Destroy the region. This will invalidate the object ID.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * add - add rectangle to region
+	 * @x: (none)
+	 * @y: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 *
+	 * Add the specified rectangle to the region.
+	 */
+	void (*add)(struct wl_client *client,
+		    struct wl_resource *resource,
+		    int32_t x,
+		    int32_t y,
+		    int32_t width,
+		    int32_t height);
+	/**
+	 * subtract - subtract rectangle from region
+	 * @x: (none)
+	 * @y: (none)
+	 * @width: (none)
+	 * @height: (none)
+	 *
+	 * Subtract the specified rectangle from the region.
+	 */
+	void (*subtract)(struct wl_client *client,
+			 struct wl_resource *resource,
+			 int32_t x,
+			 int32_t y,
+			 int32_t width,
+			 int32_t height);
+};
+
+
+#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
+#define WL_SUBCOMPOSITOR_ERROR_ENUM
+enum wl_subcompositor_error {
+	WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
+
+/**
+ * wl_subcompositor - sub-surface compositing
+ * @destroy: unbind from the subcompositor interface
+ * @get_subsurface: give a surface the role sub-surface
+ *
+ * The global interface exposing sub-surface compositing capabilities. A
+ * wl_surface, that has sub-surfaces associated, is called the parent
+ * surface. Sub-surfaces can be arbitrarily nested and create a tree of
+ * sub-surfaces.
+ *
+ * The root surface in a tree of sub-surfaces is the main surface. The main
+ * surface cannot be a sub-surface, because sub-surfaces must always have a
+ * parent.
+ *
+ * A main surface with its sub-surfaces forms a (compound) window. For
+ * window management purposes, this set of wl_surface objects is to be
+ * considered as a single window, and it should also behave as such.
+ *
+ * The aim of sub-surfaces is to offload some of the compositing work
+ * within a window from clients to the compositor. A prime example is a
+ * video player with decorations and video in separate wl_surface objects.
+ * This should allow the compositor to pass YUV video buffer processing to
+ * dedicated overlay hardware when possible.
+ */
+struct wl_subcompositor_interface {
+	/**
+	 * destroy - unbind from the subcompositor interface
+	 *
+	 * Informs the server that the client will not be using this
+	 * protocol object anymore. This does not affect any other objects,
+	 * wl_subsurface objects included.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * get_subsurface - give a surface the role sub-surface
+	 * @id: the new subsurface object id
+	 * @surface: the surface to be turned into a sub-surface
+	 * @parent: the parent surface
+	 *
+	 * Create a sub-surface interface for the given surface, and
+	 * associate it with the given parent surface. This turns a plain
+	 * wl_surface into a sub-surface.
+	 *
+	 * The to-be sub-surface must not already have another role, and it
+	 * must not have an existing wl_subsurface object. Otherwise a
+	 * protocol error is raised.
+	 */
+	void (*get_subsurface)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t id,
+			       struct wl_resource *surface,
+			       struct wl_resource *parent);
+};
+
+
+#ifndef WL_SUBSURFACE_ERROR_ENUM
+#define WL_SUBSURFACE_ERROR_ENUM
+enum wl_subsurface_error {
+	WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBSURFACE_ERROR_ENUM */
+
+/**
+ * wl_subsurface - sub-surface interface to a wl_surface
+ * @destroy: remove sub-surface interface
+ * @set_position: reposition the sub-surface
+ * @place_above: restack the sub-surface
+ * @place_below: restack the sub-surface
+ * @set_sync: set sub-surface to synchronized mode
+ * @set_desync: set sub-surface to desynchronized mode
+ *
+ * An additional interface to a wl_surface object, which has been made a
+ * sub-surface. A sub-surface has one parent surface. A sub-surface's size
+ * and position are not limited to that of the parent. Particularly, a
+ * sub-surface is not automatically clipped to its parent's area.
+ *
+ * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and
+ * the parent surface is mapped. The order of which one happens first is
+ * irrelevant. A sub-surface is hidden if the parent becomes hidden, or if
+ * a NULL wl_buffer is applied. These rules apply recursively through the
+ * tree of surfaces.
+ *
+ * The behaviour of wl_surface.commit request on a sub-surface depends on
+ * the sub-surface's mode. The possible modes are synchronized and
+ * desynchronized, see methods wl_subsurface.set_sync and
+ * wl_subsurface.set_desync. Synchronized mode caches the wl_surface state
+ * to be applied when the parent's state gets applied, and desynchronized
+ * mode applies the pending wl_surface state directly. A sub-surface is
+ * initially in the synchronized mode.
+ *
+ * Sub-surfaces have also other kind of state, which is managed by
+ * wl_subsurface requests, as opposed to wl_surface requests. This state
+ * includes the sub-surface position relative to the parent surface
+ * (wl_subsurface.set_position), and the stacking order of the parent and
+ * its sub-surfaces (wl_subsurface.place_above and .place_below). This
+ * state is applied when the parent surface's wl_surface state is applied,
+ * regardless of the sub-surface's mode. As the exception, set_sync and
+ * set_desync are effective immediately.
+ *
+ * The main surface can be thought to be always in desynchronized mode,
+ * since it does not have a parent in the sub-surfaces sense.
+ *
+ * Even if a sub-surface is in desynchronized mode, it will behave as in
+ * synchronized mode, if its parent surface behaves as in synchronized
+ * mode. This rule is applied recursively throughout the tree of surfaces.
+ * This means, that one can set a sub-surface into synchronized mode, and
+ * then assume that all its child and grand-child sub-surfaces are
+ * synchronized, too, without explicitly setting them.
+ *
+ * If the wl_surface associated with the wl_subsurface is destroyed, the
+ * wl_subsurface object becomes inert. Note, that destroying either object
+ * takes effect immediately. If you need to synchronize the removal of a
+ * sub-surface to the parent surface update, unmap the sub-surface first by
+ * attaching a NULL wl_buffer, update parent, and then destroy the
+ * sub-surface.
+ *
+ * If the parent wl_surface object is destroyed, the sub-surface is
+ * unmapped.
+ */
+struct wl_subsurface_interface {
+	/**
+	 * destroy - remove sub-surface interface
+	 *
+	 * The sub-surface interface is removed from the wl_surface
+	 * object that was turned into a sub-surface with
+	 * wl_subcompositor.get_subsurface request. The wl_surface's
+	 * association to the parent is deleted, and the wl_surface loses
+	 * its role as a sub-surface. The wl_surface is unmapped.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * set_position - reposition the sub-surface
+	 * @x: coordinate in the parent surface
+	 * @y: coordinate in the parent surface
+	 *
+	 * This schedules a sub-surface position change. The sub-surface
+	 * will be moved so, that its origin (top-left corner pixel) will
+	 * be at the location x, y of the parent surface coordinate system.
+	 * The coordinates are not restricted to the parent surface area.
+	 * Negative values are allowed.
+	 *
+	 * The scheduled coordinates will take effect whenever the state of
+	 * the parent surface is applied. When this happens depends on
+	 * whether the parent surface is in synchronized mode or not. See
+	 * wl_subsurface.set_sync and wl_subsurface.set_desync for details.
+	 *
+	 * If more than one set_position request is invoked by the client
+	 * before the commit of the parent surface, the position of a new
+	 * request always replaces the scheduled position from any previous
+	 * request.
+	 *
+	 * The initial position is 0, 0.
+	 */
+	void (*set_position)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     int32_t x,
+			     int32_t y);
+	/**
+	 * place_above - restack the sub-surface
+	 * @sibling: the reference surface
+	 *
+	 * This sub-surface is taken from the stack, and put back just
+	 * above the reference surface, changing the z-order of the
+	 * sub-surfaces. The reference surface must be one of the sibling
+	 * surfaces, or the parent surface. Using any other surface,
+	 * including this sub-surface, will cause a protocol error.
+	 *
+	 * The z-order is double-buffered. Requests are handled in order
+	 * and applied immediately to a pending state. The final pending
+	 * state is copied to the active state the next time the state of
+	 * the parent surface is applied. When this happens depends on
+	 * whether the parent surface is in synchronized mode or not. See
+	 * wl_subsurface.set_sync and wl_subsurface.set_desync for details.
+	 *
+	 * A new sub-surface is initially added as the top-most in the
+	 * stack of its siblings and parent.
+	 */
+	void (*place_above)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    struct wl_resource *sibling);
+	/**
+	 * place_below - restack the sub-surface
+	 * @sibling: the reference surface
+	 *
+	 * The sub-surface is placed just below of the reference surface.
+	 * See wl_subsurface.place_above.
+	 */
+	void (*place_below)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    struct wl_resource *sibling);
+	/**
+	 * set_sync - set sub-surface to synchronized mode
+	 *
+	 * Change the commit behaviour of the sub-surface to synchronized
+	 * mode, also described as the parent dependent mode.
+	 *
+	 * In synchronized mode, wl_surface.commit on a sub-surface will
+	 * accumulate the committed state in a cache, but the state will
+	 * not be applied and hence will not change the compositor output.
+	 * The cached state is applied to the sub-surface immediately after
+	 * the parent surface's state is applied. This ensures atomic
+	 * updates of the parent and all its synchronized sub-surfaces.
+	 * Applying the cached state will invalidate the cache, so further
+	 * parent surface commits do not (re-)apply old state.
+	 *
+	 * See wl_subsurface for the recursive effect of this mode.
+	 */
+	void (*set_sync)(struct wl_client *client,
+			 struct wl_resource *resource);
+	/**
+	 * set_desync - set sub-surface to desynchronized mode
+	 *
+	 * Change the commit behaviour of the sub-surface to
+	 * desynchronized mode, also described as independent or freely
+	 * running mode.
+	 *
+	 * In desynchronized mode, wl_surface.commit on a sub-surface will
+	 * apply the pending state directly, without caching, as happens
+	 * normally with a wl_surface. Calling wl_surface.commit on the
+	 * parent surface has no effect on the sub-surface's wl_surface
+	 * state. This mode allows a sub-surface to be updated on its own.
+	 *
+	 * If cached state exists when wl_surface.commit is called in
+	 * desynchronized mode, the pending state is added to the cached
+	 * state, and applied as whole. This invalidates the cache.
+	 *
+	 * Note: even if a sub-surface is set to desynchronized, a parent
+	 * sub-surface may override it to behave as synchronized. For
+	 * details, see wl_subsurface.
+	 *
+	 * If a surface's parent surface behaves as desynchronized, then
+	 * the cached state is applied on set_desync.
+	 */
+	void (*set_desync)(struct wl_client *client,
+			   struct wl_resource *resource);
+};
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/third_party/wayland/include/src/wayland-version.h b/third_party/wayland/include/src/wayland-version.h
new file mode 100644
index 0000000..34aeaf6
--- /dev/null
+++ b/third_party/wayland/include/src/wayland-version.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_VERSION_H
+#define WAYLAND_VERSION_H
+
+#define WAYLAND_VERSION_MAJOR 1
+#define WAYLAND_VERSION_MINOR 9
+#define WAYLAND_VERSION_MICRO 0
+#define WAYLAND_VERSION "1.9.0"
+
+#endif
diff --git a/third_party/wayland/protocol/wayland-protocol.c b/third_party/wayland/protocol/wayland-protocol.c
new file mode 100644
index 0000000..5ce57be
--- /dev/null
+++ b/third_party/wayland/protocol/wayland-protocol.c
@@ -0,0 +1,485 @@
+/* 
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ * 
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+extern const struct wl_interface wl_buffer_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_data_device_interface;
+extern const struct wl_interface wl_data_offer_interface;
+extern const struct wl_interface wl_data_source_interface;
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_region_interface;
+extern const struct wl_interface wl_registry_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_shell_surface_interface;
+extern const struct wl_interface wl_shm_pool_interface;
+extern const struct wl_interface wl_subsurface_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wl_touch_interface;
+
+static const struct wl_interface *types[] = {
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&wl_callback_interface,
+	&wl_registry_interface,
+	&wl_surface_interface,
+	&wl_region_interface,
+	&wl_buffer_interface,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&wl_shm_pool_interface,
+	NULL,
+	NULL,
+	&wl_data_source_interface,
+	&wl_surface_interface,
+	&wl_surface_interface,
+	NULL,
+	&wl_data_source_interface,
+	NULL,
+	&wl_data_offer_interface,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	&wl_data_offer_interface,
+	&wl_data_offer_interface,
+	&wl_data_source_interface,
+	&wl_data_device_interface,
+	&wl_seat_interface,
+	&wl_shell_surface_interface,
+	&wl_surface_interface,
+	&wl_seat_interface,
+	NULL,
+	&wl_seat_interface,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&wl_output_interface,
+	&wl_seat_interface,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	&wl_output_interface,
+	&wl_buffer_interface,
+	NULL,
+	NULL,
+	&wl_callback_interface,
+	&wl_region_interface,
+	&wl_region_interface,
+	&wl_output_interface,
+	&wl_output_interface,
+	&wl_pointer_interface,
+	&wl_keyboard_interface,
+	&wl_touch_interface,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	&wl_subsurface_interface,
+	&wl_surface_interface,
+	&wl_surface_interface,
+	&wl_surface_interface,
+	&wl_surface_interface,
+};
+
+static const struct wl_message wl_display_requests[] = {
+	{ "sync", "n", types + 8 },
+	{ "get_registry", "n", types + 9 },
+};
+
+static const struct wl_message wl_display_events[] = {
+	{ "error", "ous", types + 0 },
+	{ "delete_id", "u", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_display_interface = {
+	"wl_display", 1,
+	2, wl_display_requests,
+	2, wl_display_events,
+};
+
+static const struct wl_message wl_registry_requests[] = {
+	{ "bind", "usun", types + 0 },
+};
+
+static const struct wl_message wl_registry_events[] = {
+	{ "global", "usu", types + 0 },
+	{ "global_remove", "u", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_registry_interface = {
+	"wl_registry", 1,
+	1, wl_registry_requests,
+	2, wl_registry_events,
+};
+
+static const struct wl_message wl_callback_events[] = {
+	{ "done", "u", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_callback_interface = {
+	"wl_callback", 1,
+	0, NULL,
+	1, wl_callback_events,
+};
+
+static const struct wl_message wl_compositor_requests[] = {
+	{ "create_surface", "n", types + 10 },
+	{ "create_region", "n", types + 11 },
+};
+
+WL_EXPORT const struct wl_interface wl_compositor_interface = {
+	"wl_compositor", 3,
+	2, wl_compositor_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_shm_pool_requests[] = {
+	{ "create_buffer", "niiiiu", types + 12 },
+	{ "destroy", "", types + 0 },
+	{ "resize", "i", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_shm_pool_interface = {
+	"wl_shm_pool", 1,
+	3, wl_shm_pool_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_shm_requests[] = {
+	{ "create_pool", "nhi", types + 18 },
+};
+
+static const struct wl_message wl_shm_events[] = {
+	{ "format", "u", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_shm_interface = {
+	"wl_shm", 1,
+	1, wl_shm_requests,
+	1, wl_shm_events,
+};
+
+static const struct wl_message wl_buffer_requests[] = {
+	{ "destroy", "", types + 0 },
+};
+
+static const struct wl_message wl_buffer_events[] = {
+	{ "release", "", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_buffer_interface = {
+	"wl_buffer", 1,
+	1, wl_buffer_requests,
+	1, wl_buffer_events,
+};
+
+static const struct wl_message wl_data_offer_requests[] = {
+	{ "accept", "u?s", types + 0 },
+	{ "receive", "sh", types + 0 },
+	{ "destroy", "", types + 0 },
+};
+
+static const struct wl_message wl_data_offer_events[] = {
+	{ "offer", "s", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_data_offer_interface = {
+	"wl_data_offer", 1,
+	3, wl_data_offer_requests,
+	1, wl_data_offer_events,
+};
+
+static const struct wl_message wl_data_source_requests[] = {
+	{ "offer", "s", types + 0 },
+	{ "destroy", "", types + 0 },
+};
+
+static const struct wl_message wl_data_source_events[] = {
+	{ "target", "?s", types + 0 },
+	{ "send", "sh", types + 0 },
+	{ "cancelled", "", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_data_source_interface = {
+	"wl_data_source", 1,
+	2, wl_data_source_requests,
+	3, wl_data_source_events,
+};
+
+static const struct wl_message wl_data_device_requests[] = {
+	{ "start_drag", "?oo?ou", types + 21 },
+	{ "set_selection", "?ou", types + 25 },
+	{ "release", "2", types + 0 },
+};
+
+static const struct wl_message wl_data_device_events[] = {
+	{ "data_offer", "n", types + 27 },
+	{ "enter", "uoff?o", types + 28 },
+	{ "leave", "", types + 0 },
+	{ "motion", "uff", types + 0 },
+	{ "drop", "", types + 0 },
+	{ "selection", "?o", types + 33 },
+};
+
+WL_EXPORT const struct wl_interface wl_data_device_interface = {
+	"wl_data_device", 2,
+	3, wl_data_device_requests,
+	6, wl_data_device_events,
+};
+
+static const struct wl_message wl_data_device_manager_requests[] = {
+	{ "create_data_source", "n", types + 34 },
+	{ "get_data_device", "no", types + 35 },
+};
+
+WL_EXPORT const struct wl_interface wl_data_device_manager_interface = {
+	"wl_data_device_manager", 2,
+	2, wl_data_device_manager_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_shell_requests[] = {
+	{ "get_shell_surface", "no", types + 37 },
+};
+
+WL_EXPORT const struct wl_interface wl_shell_interface = {
+	"wl_shell", 1,
+	1, wl_shell_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_shell_surface_requests[] = {
+	{ "pong", "u", types + 0 },
+	{ "move", "ou", types + 39 },
+	{ "resize", "ouu", types + 41 },
+	{ "set_toplevel", "", types + 0 },
+	{ "set_transient", "oiiu", types + 44 },
+	{ "set_fullscreen", "uu?o", types + 48 },
+	{ "set_popup", "ouoiiu", types + 51 },
+	{ "set_maximized", "?o", types + 57 },
+	{ "set_title", "s", types + 0 },
+	{ "set_class", "s", types + 0 },
+};
+
+static const struct wl_message wl_shell_surface_events[] = {
+	{ "ping", "u", types + 0 },
+	{ "configure", "uii", types + 0 },
+	{ "popup_done", "", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_shell_surface_interface = {
+	"wl_shell_surface", 1,
+	10, wl_shell_surface_requests,
+	3, wl_shell_surface_events,
+};
+
+static const struct wl_message wl_surface_requests[] = {
+	{ "destroy", "", types + 0 },
+	{ "attach", "?oii", types + 58 },
+	{ "damage", "iiii", types + 0 },
+	{ "frame", "n", types + 61 },
+	{ "set_opaque_region", "?o", types + 62 },
+	{ "set_input_region", "?o", types + 63 },
+	{ "commit", "", types + 0 },
+	{ "set_buffer_transform", "2i", types + 0 },
+	{ "set_buffer_scale", "3i", types + 0 },
+};
+
+static const struct wl_message wl_surface_events[] = {
+	{ "enter", "o", types + 64 },
+	{ "leave", "o", types + 65 },
+};
+
+WL_EXPORT const struct wl_interface wl_surface_interface = {
+	"wl_surface", 3,
+	9, wl_surface_requests,
+	2, wl_surface_events,
+};
+
+static const struct wl_message wl_seat_requests[] = {
+	{ "get_pointer", "n", types + 66 },
+	{ "get_keyboard", "n", types + 67 },
+	{ "get_touch", "n", types + 68 },
+};
+
+static const struct wl_message wl_seat_events[] = {
+	{ "capabilities", "u", types + 0 },
+	{ "name", "2s", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_seat_interface = {
+	"wl_seat", 4,
+	3, wl_seat_requests,
+	2, wl_seat_events,
+};
+
+static const struct wl_message wl_pointer_requests[] = {
+	{ "set_cursor", "u?oii", types + 69 },
+	{ "release", "3", types + 0 },
+};
+
+static const struct wl_message wl_pointer_events[] = {
+	{ "enter", "uoff", types + 73 },
+	{ "leave", "uo", types + 77 },
+	{ "motion", "uff", types + 0 },
+	{ "button", "uuuu", types + 0 },
+	{ "axis", "uuf", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_pointer_interface = {
+	"wl_pointer", 3,
+	2, wl_pointer_requests,
+	5, wl_pointer_events,
+};
+
+static const struct wl_message wl_keyboard_requests[] = {
+	{ "release", "3", types + 0 },
+};
+
+static const struct wl_message wl_keyboard_events[] = {
+	{ "keymap", "uhu", types + 0 },
+	{ "enter", "uoa", types + 79 },
+	{ "leave", "uo", types + 82 },
+	{ "key", "uuuu", types + 0 },
+	{ "modifiers", "uuuuu", types + 0 },
+	{ "repeat_info", "4ii", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_keyboard_interface = {
+	"wl_keyboard", 4,
+	1, wl_keyboard_requests,
+	6, wl_keyboard_events,
+};
+
+static const struct wl_message wl_touch_requests[] = {
+	{ "release", "3", types + 0 },
+};
+
+static const struct wl_message wl_touch_events[] = {
+	{ "down", "uuoiff", types + 84 },
+	{ "up", "uui", types + 0 },
+	{ "motion", "uiff", types + 0 },
+	{ "frame", "", types + 0 },
+	{ "cancel", "", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_touch_interface = {
+	"wl_touch", 3,
+	1, wl_touch_requests,
+	5, wl_touch_events,
+};
+
+static const struct wl_message wl_output_events[] = {
+	{ "geometry", "iiiiissi", types + 0 },
+	{ "mode", "uiii", types + 0 },
+	{ "done", "2", types + 0 },
+	{ "scale", "2i", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_output_interface = {
+	"wl_output", 2,
+	0, NULL,
+	4, wl_output_events,
+};
+
+static const struct wl_message wl_region_requests[] = {
+	{ "destroy", "", types + 0 },
+	{ "add", "iiii", types + 0 },
+	{ "subtract", "iiii", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_region_interface = {
+	"wl_region", 1,
+	3, wl_region_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_subcompositor_requests[] = {
+	{ "destroy", "", types + 0 },
+	{ "get_subsurface", "noo", types + 90 },
+};
+
+WL_EXPORT const struct wl_interface wl_subcompositor_interface = {
+	"wl_subcompositor", 1,
+	2, wl_subcompositor_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_subsurface_requests[] = {
+	{ "destroy", "", types + 0 },
+	{ "set_position", "ii", types + 0 },
+	{ "place_above", "o", types + 93 },
+	{ "place_below", "o", types + 94 },
+	{ "set_sync", "", types + 0 },
+	{ "set_desync", "", types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_subsurface_interface = {
+	"wl_subsurface", 1,
+	6, wl_subsurface_requests,
+	0, NULL,
+};
+
diff --git a/third_party/wayland/wayland.gyp b/third_party/wayland/wayland.gyp
new file mode 100644
index 0000000..7bb4c79c
--- /dev/null
+++ b/third_party/wayland/wayland.gyp
@@ -0,0 +1,74 @@
+# Copyright 2015 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.
+
+{
+  'targets': [
+    {
+      'target_name': 'wayland_util',
+      'type': 'static_library',
+      'sources': [
+        'src/src/wayland-util.c',
+        'src/src/wayland-util.h',
+      ],
+      'include_dirs': [
+        'include/src',
+        'include/protocol',
+        'src/src',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          'include/src',
+          'include/protocol',
+          'src/src',
+        ],
+      },
+    },
+    {
+      'target_name': 'wayland_private',
+      'type': 'static_library',
+      'dependencies' : [
+        '../../build/linux/system.gyp:libffi',
+      ],
+      'sources': [
+        'src/src/connection.c',
+        'src/src/wayland-os.c',
+        'src/src/wayland-os.h',
+        'src/src/wayland-private.h',
+      ],
+      'include_dirs': [
+        'include/src',
+        'include/protocol',
+        'src/src',
+      ],
+    },
+    {
+      'target_name': 'wayland_server',
+      'type': 'static_library',
+      'dependencies' : [
+        '../../build/linux/system.gyp:libffi',
+        'wayland_private',
+        'wayland_util',
+      ],
+      'sources': [
+        'include/protocol/wayland-server-protocol.h',
+        'protocol/wayland-protocol.c',
+        'src/src/event-loop.c',
+        'src/src/wayland-server.c',
+        'src/src/wayland-shm.c',
+      ],
+      'include_dirs': [
+        'include/src',
+        'include/protocol',
+        'src/src',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          'include/src',
+          'include/protocol',
+          'src/src',
+        ],
+      },
+    },
+  ],
+}
diff --git a/tools/battor_agent/battor_agent.cc b/tools/battor_agent/battor_agent.cc
index 97fa13e..f9ef824c 100644
--- a/tools/battor_agent/battor_agent.cc
+++ b/tools/battor_agent/battor_agent.cc
@@ -22,29 +22,26 @@
   // TODO(charliea): Close the serial connection with the BattOr.
 }
 
-void BattOrAgent::StartTracing(const SendCallback& callback) {
+BattOrAgent::BattOrError BattOrAgent::StartTracing() {
   // TODO(charliea): Tell the BattOr to start tracing.
-  callback.Run(device::serial::SEND_ERROR_NONE);
+  return BATTOR_ERROR_NONE;
 }
 
-void BattOrAgent::StopTracing(std::string* trace_output,
-                              const SendReceiveCallback& callback) {
+BattOrAgent::BattOrError BattOrAgent::StopTracing(std::string* trace_output) {
   // TODO(charliea): Tell the BattOr to stop tracing.
   *trace_output = "battor trace output";
-  callback.Run(device::serial::SEND_ERROR_NONE,
-               device::serial::RECEIVE_ERROR_NONE);
+  return BATTOR_ERROR_NONE;
 }
 
-void BattOrAgent::RecordClockSyncMarker(const std::string& marker,
-                                        const SendReceiveCallback& callback) {
+BattOrAgent::BattOrError BattOrAgent::RecordClockSyncMarker(
+    const std::string& marker) {
   // TODO(charliea): Tell the BattOr to record the specified clock sync marker.
-  callback.Run(device::serial::SEND_ERROR_NONE,
-               device::serial::RECEIVE_ERROR_NONE);
+  return BATTOR_ERROR_NONE;
 }
 
-void BattOrAgent::IssueClockSyncMarker(const SendCallback& callback) {
+BattOrAgent::BattOrError BattOrAgent::IssueClockSyncMarker() {
   // TODO(charliea): Tell atrace to issue a clock sync marker.
-  callback.Run(device::serial::SEND_ERROR_NONE);
+  return BATTOR_ERROR_NONE;
 }
 
 }  // namespace battor
diff --git a/tools/battor_agent/battor_agent.h b/tools/battor_agent/battor_agent.h
index 139fe1e..d37ef6e 100644
--- a/tools/battor_agent/battor_agent.h
+++ b/tools/battor_agent/battor_agent.h
@@ -10,32 +10,35 @@
 
 namespace battor {
 
+// A BattOrAgent is a class used to synchronously communicate with a BattOr for
+// the purpose of collecting power samples. A BattOr is an external USB device
+// that's capable of recording accurate, high-frequency (2000Hz) power samples.
+//
+// Because the communication is synchronous and passes over a serial connection,
+// callers wishing to avoid blocking the thread (like the Chromium tracing
+// controller) should issue these commands in a separate thread.
 class BattOrAgent {
  public:
-  typedef base::Callback<void(device::serial::SendError)> SendCallback;
-  typedef base::Callback<void(device::serial::SendError,
-                              device::serial::ReceiveError)>
-      SendReceiveCallback;
+  enum BattOrError {
+    BATTOR_ERROR_NONE,
+  };
 
   explicit BattOrAgent(const std::string& path);
   virtual ~BattOrAgent();
 
-  // Tells the BattOr to start tracing and calls the callback when complete.
-  void StartTracing(const SendCallback& callback);
+  // Tells the BattOr to start tracing.
+  BattOrError StartTracing();
 
   // Tells the BattOr to stop tracing and write the trace output to the
-  // specified string and calls the callback when complete.
-  void StopTracing(std::string* trace_output,
-                   const SendReceiveCallback& callback);
+  // specified string.
+  BattOrError StopTracing(std::string* trace_output);
 
-  // Tells the BattOr to record a clock sync marker in its own trace log and
-  // calls the callback when complete.
-  void RecordClockSyncMarker(const std::string& marker,
-                             const SendReceiveCallback& callback);
+  // Tells the BattOr to record a clock sync marker in its own trace log.
+  BattOrError RecordClockSyncMarker(const std::string& marker);
 
   // Tells the BattOr to issue clock sync markers to all other tracing agents
-  // that it's connected to and calls the callback when complete.
-  void IssueClockSyncMarker(const SendCallback& callback);
+  // to which it's connected.
+  BattOrError IssueClockSyncMarker();
 
   // Returns whether the BattOr is able to record clock sync markers in its own
   // trace log.
diff --git a/tools/battor_agent/battor_agent_bin.cc b/tools/battor_agent/battor_agent_bin.cc
index 491e9c52..f490d0e 100644
--- a/tools/battor_agent/battor_agent_bin.cc
+++ b/tools/battor_agent/battor_agent_bin.cc
@@ -15,6 +15,7 @@
 #include "device/serial/serial.mojom.h"
 #include "tools/battor_agent/battor_agent.h"
 
+using std::cerr;
 using std::cout;
 using std::endl;
 using std::string;
@@ -28,7 +29,7 @@
 static const base::TimeDelta COMMAND_TIMEOUT = base::TimeDelta::FromSeconds(10);
 
 void PrintUsage() {
-  cout << "Usage: battor_agent <command> <arguments>" << endl
+  cerr << "Usage: battor_agent <command> <arguments>" << endl
        << endl
        << "Commands:" << endl
        << endl
@@ -51,78 +52,28 @@
   return argv[argnum];
 }
 
-// Checks if a send error occurred and, if it did, prints the error and exits
+// Checks if an error occurred and, if it did, prints the error and exits
 // with an error code.
-void CheckSendError(SendError error) {
-  if (error != device::serial::SEND_ERROR_NONE) {
-    printf("Error occured while sending: %d", error);
+void CheckError(battor::BattOrAgent::BattOrError error) {
+  if (error != battor::BattOrAgent::BATTOR_ERROR_NONE) {
+    cerr << "Error when communicating with the BattOr: " << error << endl;
     exit(1);
   }
 }
 
-// Checks if a receive error occurred and, if it did, prints the error and exits
-// with an error code.
-void CheckReceiveError(ReceiveError error) {
-  if (error != device::serial::RECEIVE_ERROR_NONE) {
-    cout << "Error occured while receiving: " << error << endl;
-    exit(1);
-  }
-}
-
-void OnStartTracingComplete(base::WaitableEvent* complete_event,
-                            SendError error) {
-  CheckSendError(error);
-  cout << "Tracing successfully started." << endl;
-  complete_event->Signal();
-}
-
-void OnStopTracingComplete(string* trace_output,
-                           base::WaitableEvent* complete_event,
-                           SendError send_error,
-                           ReceiveError receive_error) {
-  CheckSendError(send_error);
-  CheckReceiveError(receive_error);
-  cout << *trace_output << endl;
-  complete_event->Signal();
-}
-
-void OnRecordClockSyncMarkerComplete(base::WaitableEvent* complete_event,
-                                     SendError send_error,
-                                     ReceiveError receive_error) {
-  CheckSendError(send_error);
-  CheckReceiveError(receive_error);
-  // TODO(charliea): Write time to STDOUT.
-  cout << "Successfully recorded clock sync marker." << endl;
-  complete_event->Signal();
-}
-
-void OnIssueClockSyncMarkerComplete(base::WaitableEvent* complete_event,
-                                    SendError error) {
-  CheckSendError(error);
-  cout << "Successfully issued clock sync marker." << endl;
-  complete_event->Signal();
-}
-
 void StartTracing(int argc, char* argv[]) {
   string path = GetArg(2, argc, argv);
   battor::BattOrAgent agent(path);
-  base::WaitableEvent command_complete_event(false, false);
 
-  agent.StartTracing(
-      base::Bind(&OnStartTracingComplete, &command_complete_event));
-  command_complete_event.TimedWait(COMMAND_TIMEOUT);
+  CheckError(agent.StartTracing());
 }
 
 void StopTracing(int argc, char* argv[]) {
   string path = GetArg(2, argc, argv);
   string trace_output;
   battor::BattOrAgent agent(path);
-  base::WaitableEvent command_complete_event(false, false);
 
-  agent.StopTracing(&trace_output,
-                    base::Bind(&OnStopTracingComplete, &trace_output,
-                               &command_complete_event));
-  command_complete_event.TimedWait(COMMAND_TIMEOUT);
+  CheckError(agent.StopTracing(&trace_output));
 }
 
 void SupportsExplicitClockSync() {
@@ -132,24 +83,18 @@
 void RecordClockSyncMarker(int argc, char* argv[]) {
   string path = GetArg(2, argc, argv);
   string marker = GetArg(3, argc, argv);
-  base::WaitableEvent command_complete_event(false, false);
   battor::BattOrAgent agent(path);
 
   // TODO(charliea): Write time to STDOUT.
-  agent.RecordClockSyncMarker(
-      marker,
-      base::Bind(&OnRecordClockSyncMarkerComplete, &command_complete_event));
-  command_complete_event.TimedWait(COMMAND_TIMEOUT);
+  CheckError(agent.RecordClockSyncMarker(marker));
+  // TODO(charliea): Write time to STDOUT.
 }
 
 void IssueClockSyncMarker(int argc, char* argv[]) {
   string path = GetArg(2, argc, argv);
-  base::WaitableEvent command_complete_event(false, false);
   battor::BattOrAgent agent(path);
 
-  agent.IssueClockSyncMarker(
-      base::Bind(&OnIssueClockSyncMarkerComplete, &command_complete_event));
-  command_complete_event.TimedWait(COMMAND_TIMEOUT);
+  CheckError(agent.IssueClockSyncMarker());
 }
 
 }  // namespace
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py
index fe08d70..143dedc 100755
--- a/tools/checklicenses/checklicenses.py
+++ b/tools/checklicenses/checklicenses.py
@@ -458,6 +458,10 @@
     'third_party/modp_b64': [
         'UNKNOWN',
     ],
+    # Missing license headers in openh264 sources: https://github.com/cisco/openh264/issues/2233
+    'third_party/openh264/src': [
+        'UNKNOWN',
+    ],
     'third_party/openmax_dl/dl' : [
         'Khronos Group',
     ],
@@ -556,6 +560,11 @@
     'third_party/tlslite': [
         'UNKNOWN',
     ],
+    # MIT license but some files contain no licensing info. e.g. autogen.sh.
+    # Files missing licensing info are not shipped.
+    'third_party/wayland': [  #  http://crbug.com/553573
+        'UNKNOWN',
+    ],
     'third_party/webdriver': [  # http://crbug.com/98590
         'UNKNOWN',
     ],
diff --git a/tools/copyright_scanner/third_party_files_whitelist.txt b/tools/copyright_scanner/third_party_files_whitelist.txt
index d451228..a8eee6aed 100644
--- a/tools/copyright_scanner/third_party_files_whitelist.txt
+++ b/tools/copyright_scanner/third_party_files_whitelist.txt
@@ -208,6 +208,3 @@
 # Bundles of existing code.
 chrome/browser/resources/md_downloads/crisper.js
 chrome/browser/resources/md_downloads/vulcanized.html
-# Contains "copyright" in a test string.
-# TODO(thakis): Change the test string and remove this entry again.
-tools/grit/grit/tclib_unittest.py
diff --git a/tools/gn/action_target_generator.cc b/tools/gn/action_target_generator.cc
index b2d7e27..6f962b6d 100644
--- a/tools/gn/action_target_generator.cc
+++ b/tools/gn/action_target_generator.cc
@@ -85,9 +85,9 @@
     return;
   }
   if (!target_->action_values().uses_rsp_file() && has_rsp_file_name) {
-    *err_ = Err(function_call_, "Missing response_file_content definition.",
+    *err_ = Err(function_call_, "Missing response_file_contents definition.",
         "This target uses {{response_file_name}} in the args, but does not\n"
-        "define response_file_content which means the response file\n"
+        "define response_file_contents which means the response file\n"
         "will be empty.");
     return;
   }
diff --git a/tools/gn/docs/reference.md b/tools/gn/docs/reference.md
index a3bb57b..a180d88 100644
--- a/tools/gn/docs/reference.md
+++ b/tools/gn/docs/reference.md
@@ -437,7 +437,7 @@
           Prints the label of the target.
       output
           Prints the first output file for the target relative to the
-          current directory.
+          root build directory.
 
   --testonly=(true|false)
       Restrict outputs to targets with the testonly flag set
@@ -581,7 +581,7 @@
           Prints the label of the target.
       output
           Prints the first output file for the target relative to the
-          current directory.
+          root build directory.
 
   --all-toolchains
       Matches all toolchains. When set, if the label pattern does not
@@ -636,9 +636,12 @@
   The two targets can appear in either order: paths will be found going
   in either direction.
 
-  Each dependency will be annotated with its type. By default, only the
-  first path encountered will be printed, which is not necessarily the
-  shortest path.
+  By default, a single path will be printed. If there is a path with
+  only public dependencies, the shortest public path will be printed.
+  Otherwise, the shortest path using either public or private
+  dependencies will be printed. If --with-data is specified, data deps
+  will also be considered. If there are multiple shortest paths, an
+  arbitrary one will be selected.
 
 ```
 
@@ -646,7 +649,16 @@
 
 ```
   --all
-     Prints all paths found rather than just the first one.
+     Prints all paths found rather than just the first one. Public paths
+     will be printed first in order of increasing length, followed by
+     non-public paths in order of increasing length.
+
+  --public
+     Considers only public paths. Can't be used with --with-data.
+
+  --with-data
+     Additionally follows data deps. Without this flag, only public and
+     private linked deps will be followed. Can't be used with --public.
 
 ```
 
@@ -719,7 +731,7 @@
           Prints the label of the target.
       output
           Prints the first output file for the target relative to the
-          current directory.
+          root build directory.
 
   -q
      Quiet. If nothing matches, don't print any output. Without this
@@ -817,6 +829,9 @@
   if an input file changes) by writing a depfile when the script is run
   (see "gn help depfile"). This is more flexible than "inputs".
 
+  If the command line length is very long, you can use response files
+  to pass args to your script. See "gn help response_file_contents".
+
   It is recommended you put inputs to your script in the "sources"
   variable, and stuff like other Python files required to run your
   script in the "inputs" variable.
@@ -858,8 +873,8 @@
 ### **Variables**
 
 ```
-  args, console, data, data_deps, depfile, deps, outputs*, script*,
-  inputs, sources
+  args, console, data, data_deps, depfile, deps, inputs, outputs*,
+  response_file_contents, script*, sources
   * = required
 
 ```
@@ -907,6 +922,9 @@
   listed in the "inputs" variable. These files are treated as
   dependencies of each script invocation.
 
+  If the command line length is very long, you can use response files
+  to pass args to your script. See "gn help response_file_contents".
+
   You can dynamically write input dependencies (for incremental rebuilds
   if an input file changes) by writing a depfile when the script is run
   (see "gn help depfile"). This is more flexible than "inputs".
@@ -945,8 +963,8 @@
 ### **Variables**
 
 ```
-  args, console, data, data_deps, depfile, deps, outputs*, script*,
-  inputs, sources*
+  args, console, data, data_deps, depfile, deps, inputs, outputs*,
+  response_file_contents, script*, sources*
   * = required
 
 ```
@@ -2553,6 +2571,13 @@
         omitted from the label for targets in the default toolchain, and
         will be included for targets in other toolchains.
 
+    {{label_name}}
+        The short name of the label of the target. This is the part
+        after the colon. For "//foo/bar:baz" this will be "baz".
+        Unlike {{target_output_name}}, this is not affected by the
+        "output_prefix" in the tool or the "output_name" set
+        on the target.
+
     {{output}}
         The relative path and name of the output(s) of the current
         build step. If there is more than one output, this will expand
@@ -2570,6 +2595,7 @@
         The short name of the current target with no path information,
         or the value of the "output_name" variable if one is specified
         in the target. This will include the "output_prefix" if any.
+        See also {{label_name}}.
         Example: "libfoo" for the target named "foo" and an
         output prefix for the linker tool of "lib".
 
@@ -2868,12 +2894,17 @@
   written, the file will not be updated. This will prevent unnecessary
   rebuilds of targets that depend on this file.
 
+  One use for write_file is to write a list of inputs to an script
+  that might be too long for the command line. However, it is
+  preferrable to use response files for this purpose. See
+  "gn help response_file_contents".
+
   TODO(brettw) we probably need an optional third argument to control
   list formatting.
 
 ```
 
-### **Arguments**:
+### **Arguments**
 
 ```
   filename
@@ -3789,14 +3820,34 @@
 ```
   A list of target labels.
 
-  Specifies private dependencies of a target. Shared and dynamic
-  libraries will be linked into the current target.
+  Specifies private dependencies of a target. Private dependencies are
+  propagated up the dependency tree and linked to dependant targets, but
+  do not grant the ability to include headers from the dependency.
+  Public configs are not forwarded.
 
-  These dependencies are private in that it does not grant dependent
-  targets the ability to include headers from the dependency, and direct
-  dependent configs are not forwarded.
+```
 
-  See also "public_deps" and "data_deps".
+### **Details of dependency propagation**
+
+```
+  Source sets, shared libraries, and non-complete static libraries
+  will be propagated up the dependency tree across groups, non-complete
+  static libraries and source sets.
+
+  Executables, shared libraries, and complete static libraries will
+  link all propagated targets and stop propagation. Actions and copy
+  steps also stop propagation, allowing them to take a library as an
+  input but not force dependants to link to it.
+
+  Propagation of all_dependent_configs and public_configs happens
+  independently of target type. all_dependent_configs are always
+  propagated across all types of targets, and public_configs
+  are always propagated across public deps of all types of targets.
+
+  Data dependencies are propagated differently. See
+  "gn help data_deps" and "gn help runtime_deps".
+
+  See also "public_deps".
 
 
 ```
@@ -4011,9 +4062,12 @@
   When constructing the linker command, the "lib_prefix" attribute of
   the linker tool in the current toolchain will be prepended to each
   library. So your BUILD file should not specify the switch prefix
-  (like "-l"). On Mac, libraries ending in ".framework" will be
-  special-cased: the switch "-framework" will be prepended instead of
-  the lib_prefix, and the ".framework" suffix will be trimmed.
+  (like "-l").
+
+  Libraries ending in ".framework" will be special-cased: the switch
+  "-framework" will be prepended instead of the lib_prefix, and the
+  ".framework" suffix will be trimmed. This is to support the way Mac
+  links framework dependencies.
 
   libs and lib_dirs work differently than other flags in two respects.
   First, then are inherited across static library boundaries until a
@@ -4298,9 +4352,9 @@
 ## **public_deps**: Declare public dependencies.
 
 ```
-  Public dependencies are like private dependencies ("deps") but
-  additionally express that the current target exposes the listed deps
-  as part of its public API.
+  Public dependencies are like private dependencies (see
+  "gn help deps") but additionally express that the current target
+  exposes the listed deps as part of its public API.
 
   This has several ramifications:
 
@@ -4351,6 +4405,47 @@
 
 
 ```
+## **response_file_contents**: Contents of a response file for actions.
+
+```
+  Sometimes the arguments passed to a script can be too long for the
+  system's command-line capabilities. This is especially the case on
+  Windows where the maximum command-line length is less than 8K. A
+  response file allows you to pass an unlimited amount of data to a
+  script in a temporary file for an action or action_foreach target.
+
+  If the response_file_contents variable is defined and non-empty, the
+  list will be treated as script args (including possibly substitution
+  patterns) that will be written to a temporary file at build time.
+  The name of the temporary file will be substituted for
+  "{{response_file_name}}" in the script args.
+
+  The response file contents will always be quoted and escaped
+  according to Unix shell rules. To parse the response file, the Python
+  script should use "shlex.split(file_contents)".
+
+```
+
+### **Example**
+
+```
+  action("process_lots_of_files") {
+    script = "process.py",
+    inputs = [ ... huge list of files ... ]
+
+    # Write all the inputs to a response file for the script. Also,
+    # make the paths relative to the script working directory.
+    response_file_contents = rebase_path(inputs, root_build_dir)
+
+    # The script expects the name of the response file in --file-list.
+    args = [
+      "--enable-foo",
+      "--file-list={{response_file_name}}",
+    ]
+  }
+
+
+```
 ## **script**: Script file for actions.
 
 ```
diff --git a/tools/gn/exec_process.cc b/tools/gn/exec_process.cc
index 1079657..8a66307 100644
--- a/tools/gn/exec_process.cc
+++ b/tools/gn/exec_process.cc
@@ -2,12 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "tools/gn/exec_process.h"
+
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/process/process.h"
+#include "build/build_config.h"
 
 #if defined(OS_WIN)
 #include <windows.h>
diff --git a/tools/gn/exec_process_unittest.cc b/tools/gn/exec_process_unittest.cc
index a5697b0..70a208c9 100644
--- a/tools/gn/exec_process_unittest.cc
+++ b/tools/gn/exec_process_unittest.cc
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "tools/gn/exec_process.h"
+
 #include "base/command_line.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/strings/string_util.h"
+#include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "tools/gn/exec_process.h"
 
 #if defined(OS_WIN)
 #include "base/strings/utf_string_conversions.h"
diff --git a/tools/gn/target.cc b/tools/gn/target.cc
index 94cc2e06..3655982 100644
--- a/tools/gn/target.cc
+++ b/tools/gn/target.cc
@@ -198,6 +198,9 @@
   return output_type_ == EXECUTABLE ||
          output_type_ == SHARED_LIBRARY ||
          output_type_ == LOADABLE_MODULE ||
+         output_type_ == ACTION ||
+         output_type_ == ACTION_FOREACH ||
+         output_type_ == COPY_FILES ||
          (output_type_ == STATIC_LIBRARY && complete_static_lib_);
 }
 
@@ -322,17 +325,13 @@
 
 void Target::PullRecursiveHardDeps() {
   for (const auto& pair : GetDeps(DEPS_LINKED)) {
+    // Direct hard dependencies.
     if (pair.ptr->hard_dep())
       recursive_hard_deps_.insert(pair.ptr);
 
-    // Android STL doesn't like insert(begin, end) so do it manually.
-    // TODO(brettw) this can be changed to
-    // insert(iter.target()->begin(), iter.target()->end())
-    // when Android uses a better STL.
-    for (std::set<const Target*>::const_iterator cur =
-             pair.ptr->recursive_hard_deps().begin();
-         cur != pair.ptr->recursive_hard_deps().end(); ++cur)
-      recursive_hard_deps_.insert(*cur);
+    // Recursive hard dependencies of all dependencies.
+    recursive_hard_deps_.insert(pair.ptr->recursive_hard_deps().begin(),
+                                pair.ptr->recursive_hard_deps().end());
   }
 }
 
diff --git a/tools/gn/target.h b/tools/gn/target.h
index 383a2af..10d3b05 100644
--- a/tools/gn/target.h
+++ b/tools/gn/target.h
@@ -68,7 +68,9 @@
   // Can be linked into other targets.
   bool IsLinkable() const;
 
-  // Can have dependencies linked in.
+  // True if the target links dependencies rather than propogated up the graph.
+  // This is also true of action and copy steps even though they don't link
+  // dependencies, because they also don't propogate libraries up.
   bool IsFinal() const;
 
   // Will be the empty string to use the target label as the output name.
diff --git a/tools/gn/target_unittest.cc b/tools/gn/target_unittest.cc
index f4acaca..426243e 100644
--- a/tools/gn/target_unittest.cc
+++ b/tools/gn/target_unittest.cc
@@ -234,6 +234,31 @@
   ASSERT_FALSE(a.OnResolved(&err));
 }
 
+TEST(Target, NoActionDepPropgation) {
+  TestWithScope setup;
+  Err err;
+
+  // Create a dependency chain:
+  //   A (exe) -> B (action) -> C (source_set)
+  {
+    TestTarget a(setup, "//foo:a", Target::EXECUTABLE);
+    TestTarget b(setup, "//foo:b", Target::ACTION);
+    TestTarget c(setup, "//foo:c", Target::SOURCE_SET);
+
+    a.private_deps().push_back(LabelTargetPair(&b));
+    b.private_deps().push_back(LabelTargetPair(&c));
+
+    ASSERT_TRUE(c.OnResolved(&err));
+    ASSERT_TRUE(b.OnResolved(&err));
+    ASSERT_TRUE(a.OnResolved(&err));
+
+    // The executable should not have inherited the source set across the
+    // action.
+    std::vector<const Target*> libs = a.inherited_libraries().GetOrdered();
+    ASSERT_TRUE(libs.empty());
+  }
+}
+
 TEST(Target, GetComputedOutputName) {
   TestWithScope setup;
   Err err;
diff --git a/tools/gn/variables.cc b/tools/gn/variables.cc
index aa4de36..7898273 100644
--- a/tools/gn/variables.cc
+++ b/tools/gn/variables.cc
@@ -722,14 +722,31 @@
     "\n"
     "  A list of target labels.\n"
     "\n"
-    "  Specifies private dependencies of a target. Shared and dynamic\n"
-    "  libraries will be linked into the current target.\n"
+    "  Specifies private dependencies of a target. Private dependencies are\n"
+    "  propagated up the dependency tree and linked to dependant targets, but\n"
+    "  do not grant the ability to include headers from the dependency.\n"
+    "  Public configs are not forwarded.\n"
     "\n"
-    "  These dependencies are private in that it does not grant dependent\n"
-    "  targets the ability to include headers from the dependency, and direct\n"
-    "  dependent configs are not forwarded.\n"
+    "Details of dependency propagation\n"
     "\n"
-    "  See also \"public_deps\" and \"data_deps\".\n";
+    "  Source sets, shared libraries, and non-complete static libraries\n"
+    "  will be propagated up the dependency tree across groups, non-complete\n"
+    "  static libraries and source sets.\n"
+    "\n"
+    "  Executables, shared libraries, and complete static libraries will\n"
+    "  link all propagated targets and stop propagation. Actions and copy\n"
+    "  steps also stop propagation, allowing them to take a library as an\n"
+    "  input but not force dependants to link to it.\n"
+    "\n"
+    "  Propagation of all_dependent_configs and public_configs happens\n"
+    "  independently of target type. all_dependent_configs are always\n"
+    "  propagated across all types of targets, and public_configs\n"
+    "  are always propagated across public deps of all types of targets.\n"
+    "\n"
+    "  Data dependencies are propagated differently. See\n"
+    "  \"gn help data_deps\" and \"gn help runtime_deps\".\n"
+    "\n"
+    "  See also \"public_deps\".\n";
 
 const char kIncludeDirs[] = "include_dirs";
 const char kIncludeDirs_HelpShort[] =
@@ -1122,9 +1139,9 @@
 const char kPublicDeps_Help[] =
     "public_deps: Declare public dependencies.\n"
     "\n"
-    "  Public dependencies are like private dependencies (\"deps\") but\n"
-    "  additionally express that the current target exposes the listed deps\n"
-    "  as part of its public API.\n"
+    "  Public dependencies are like private dependencies (see\n"
+    "  \"gn help deps\") but additionally express that the current target\n"
+    "  exposes the listed deps as part of its public API.\n"
     "\n"
     "  This has several ramifications:\n"
     "\n"
diff --git a/build/secondary/tools/grit/BUILD.gn b/tools/grit/BUILD.gn
similarity index 92%
rename from build/secondary/tools/grit/BUILD.gn
rename to tools/grit/BUILD.gn
index 660bf1b1..edcff62 100644
--- a/build/secondary/tools/grit/BUILD.gn
+++ b/tools/grit/BUILD.gn
@@ -7,7 +7,7 @@
 # grit itself changes.
 action("grit_sources") {
   depfile = "$target_out_dir/grit_sources.d"
-  script = "//build/secondary/tools/grit/stamp_grit_sources.py"
+  script = "stamp_grit_sources.py"
 
   inputs = [
     "grit.py",
diff --git a/tools/grit/LICENSE b/tools/grit/LICENSE
deleted file mode 100644
index 2aa3944..0000000
--- a/tools/grit/LICENSE
+++ /dev/null
@@ -1,25 +0,0 @@
-Copyright (c) 2012 The Chromium Authors.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-Redistributions of source code must retain the above copyright notice,
-this list of conditions and the following disclaimer.
-
-Redistributions in binary form must reproduce the above copyright
-notice, this list of conditions and the following disclaimer in the
-documentation and/or other materials provided with the distribution.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tools/grit/README b/tools/grit/README
index 8fcdafe..aa7d946 100644
--- a/tools/grit/README
+++ b/tools/grit/README
@@ -1,2 +1,8 @@
 GRIT (Google Resource and Internationalization Tool) is a tool for Windows
 projects to manage resources and simplify the localization workflow.
+
+This code previously used to live at
+https://code.google.com/p/grit-i18n/source/checkout which still contains the
+project's history.  https://chromium.googlesource.com/external/grit-i18n/ is
+a git mirror of the SVN repository that's identical except for the last two
+commits.
diff --git a/tools/grit/codereview.settings b/tools/grit/codereview.settings
deleted file mode 100644
index 4535052e..0000000
--- a/tools/grit/codereview.settings
+++ /dev/null
@@ -1,6 +0,0 @@
-# This file is used by gcl to get repository specific information.
-CODE_REVIEW_SERVER: codereview.chromium.org
-CC_LIST: grit-developer@googlegroups.com
-VIEW_VC: http://code.google.com/p/grit-i18n/source/detail?r=
-TRY_ON_UPLOAD: False
-
diff --git a/tools/grit/grit/clique.py b/tools/grit/grit/clique.py
index 3a979890..7d920a8 100755
--- a/tools/grit/grit/clique.py
+++ b/tools/grit/grit/clique.py
@@ -275,8 +275,8 @@
 class OneOffCustomType(CustomType):
   '''A very simple custom type that performs the validation expressed by
   the input expression on all languages including the source language.
-  The expression can access the variables 'lang', 'msg' and 'text()' where 'lang'
-  is the language of 'msg', 'msg' is the message or translation being
+  The expression can access the variables 'lang', 'msg' and 'text()' where
+  'lang' is the language of 'msg', 'msg' is the message or translation being
   validated and 'text()' returns the real contents of 'msg' (for shorthand).
   '''
   def __init__(self, expression):
@@ -308,7 +308,8 @@
   # A pattern to match messages that are empty or whitespace only.
   WHITESPACE_MESSAGE = lazy_re.compile(u'^\s*$')
 
-  def __init__(self, uber_clique, message, translateable=True, custom_type=None):
+  def __init__(self, uber_clique, message, translateable=True,
+               custom_type=None):
     '''Create a new clique initialized with just a message.
 
     Note that messages with a body comprised only of whitespace will implicitly
@@ -365,7 +366,8 @@
     if custom_type and not custom_type.Validate(self.GetMessage()):
       raise exception.InvalidMessage(self.GetMessage().GetRealContent())
 
-  def MessageForLanguage(self, lang, pseudo_if_no_match=True, fallback_to_english=False):
+  def MessageForLanguage(self, lang, pseudo_if_no_match=True,
+                         fallback_to_english=False):
     '''Returns the message/translation for the specified language, providing
     a pseudotranslation if there is no available translation and a pseudo-
     translation is requested.
@@ -475,7 +477,8 @@
                                    text=translation.GetPresentableContent(),
                                    placeholders=original.GetPlaceholders())
 
-    if self.custom_type and not self.custom_type.ValidateAndModify(language, transl_msg):
+    if (self.custom_type and
+        not self.custom_type.ValidateAndModify(language, transl_msg)):
       print "WARNING: %s translation failed validation: %s" % (
         language, transl_msg.GetId())
 
diff --git a/tools/grit/grit/clique_unittest.py b/tools/grit/grit/clique_unittest.py
index faf54833..ff2c3a3 100755
--- a/tools/grit/grit/clique_unittest.py
+++ b/tools/grit/grit/clique_unittest.py
@@ -59,7 +59,8 @@
 
     rex = re.compile('fr|de|bingo')
     self.failUnless(len(c.AllMessagesThatMatch(rex, False)) == 2)
-    self.failUnless(c.AllMessagesThatMatch(rex, True)[pseudo.PSEUDO_LANG] != None)
+    self.failUnless(
+        c.AllMessagesThatMatch(rex, True)[pseudo.PSEUDO_LANG] is not None)
 
   def testBestClique(self):
     factory = clique.UberClique()
diff --git a/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py b/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py
index cfa5dc2..8d7a7f24 100755
--- a/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py
+++ b/tools/grit/grit/format/policy_templates/writers/xml_writer_base_unittest.py
@@ -28,7 +28,7 @@
     # function which produces new lines around string literals. This has been
     # fixed in Precise which has Python 2.7.3 but we have to keep compatibility
     # with both for now.
-    text_re = re.compile('>\n\s+([^<>\s].*?)\n\s*</', re.DOTALL)    
+    text_re = re.compile('>\n\s+([^<>\s].*?)\n\s*</', re.DOTALL)
     return text_re.sub('>\g<1></', raw_pretty_xml)
 
   def AssertXMLEquals(self, output, expected_output):
diff --git a/tools/grit/grit/tclib_unittest.py b/tools/grit/grit/tclib_unittest.py
index e85bb946..87849c5 100755
--- a/tools/grit/grit/tclib_unittest.py
+++ b/tools/grit/grit/tclib_unittest.py
@@ -70,7 +70,6 @@
     # This has Windows line endings.  That is on purpose.
     id = grit.extern.tclib.GenerateMessageId(
       'Google Desktop for Enterprise\r\n'
-      'Copyright (C) 2006 Google Inc.\r\n'
       'All Rights Reserved\r\n'
       '\r\n'
       '---------\r\n'
@@ -155,7 +154,7 @@
       'you can get to the preferences, add the following line to your \r\n'
       'notes.ini file:\r\n'
       'GDSNoIndexHistory=1\r\n')
-    self.failUnless(id == '8961534701379422820')
+    self.failUnless(id == '3138901326664699350')
 
   def testPlaceholderNameChecking(self):
     try:
diff --git a/tools/grit/grit/tool/build_unittest.py b/tools/grit/grit/tool/build_unittest.py
index bf657249..952eff9 100755
--- a/tools/grit/grit/tool/build_unittest.py
+++ b/tools/grit/grit/tool/build_unittest.py
@@ -57,7 +57,7 @@
       self.failUnlessEqual(1, len(deps))
       self.failUnlessEqual(deps[0],
           util.PathFromRoot('grit/testdata/substitute.xmb'))
-      
+
   def testGenerateDepFileWithResourceIds(self):
     output_dir = tempfile.mkdtemp()
     builder = build.RcBuilder()
@@ -67,11 +67,11 @@
         self.verbose = False
         self.extra_verbose = False
     expected_dep_file = os.path.join(output_dir, 'substitute_no_ids.grd.d')
-    builder.Run(DummyOpts(), 
-		['-f', util.PathFromRoot('grit/testdata/resource_ids'),
-		'-o', output_dir,
-		'--depdir', output_dir,
-		'--depfile', expected_dep_file])
+    builder.Run(DummyOpts(),
+        ['-f', util.PathFromRoot('grit/testdata/resource_ids'),
+        '-o', output_dir,
+        '--depdir', output_dir,
+        '--depfile', expected_dep_file])
 
     self.failUnless(os.path.isfile(expected_dep_file))
     with open(expected_dep_file) as f:
diff --git a/tools/grit/grit/tool/resize.py b/tools/grit/grit/tool/resize.py
index 8b9bdb94..3daffa43 100755
--- a/tools/grit/grit/tool/resize.py
+++ b/tools/grit/grit/tool/resize.py
@@ -22,38 +22,38 @@
 PROJECT_TEMPLATE = '''\
 <?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject
-	ProjectType="Visual C++"
-	Version="7.10"
-	Name="[[DIALOG_NAME]]"
-	ProjectGUID="[[PROJECT_GUID]]"
-	Keyword="Win32Proj">
-	<Platforms>
-		<Platform
-			Name="Win32"/>
-	</Platforms>
-	<Configurations>
-		<Configuration
-			Name="Debug|Win32"
-			OutputDirectory="Debug"
-			IntermediateDirectory="Debug"
-			ConfigurationType="1"
-			CharacterSet="2">
-		</Configuration>
-	</Configurations>
-	<References>
-	</References>
-	<Files>
-		<Filter
-			Name="Resource Files"
-			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
-			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
-			<File
-				RelativePath=".\[[DIALOG_NAME]].rc">
-			</File>
-		</Filter>
-	</Files>
-	<Globals>
-	</Globals>
+  ProjectType="Visual C++"
+  Version="7.10"
+  Name="[[DIALOG_NAME]]"
+  ProjectGUID="[[PROJECT_GUID]]"
+  Keyword="Win32Proj">
+  <Platforms>
+    <Platform
+      Name="Win32"/>
+  </Platforms>
+  <Configurations>
+    <Configuration
+      Name="Debug|Win32"
+      OutputDirectory="Debug"
+      IntermediateDirectory="Debug"
+      ConfigurationType="1"
+      CharacterSet="2">
+    </Configuration>
+  </Configurations>
+  <References>
+  </References>
+  <Files>
+    <Filter
+      Name="Resource Files"
+      Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+      UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+      <File
+        RelativePath=".\[[DIALOG_NAME]].rc">
+      </File>
+    </Filter>
+  </Files>
+  <Globals>
+  </Globals>
 </VisualStudioProject>'''
 
 
diff --git a/tools/grit/grit/tool/xmb.py b/tools/grit/grit/tool/xmb.py
index aaefeeca..0e7950cc 100755
--- a/tools/grit/grit/tool/xmb.py
+++ b/tools/grit/grit/tool/xmb.py
@@ -28,8 +28,10 @@
     u"'":  u'&apos;',
     u'"':  u'&quot;',
 }
+# See http://www.w3.org/TR/xml/#charsets
 _XML_BAD_CHAR_REGEX = lazy_re.compile(u'[^\u0009\u000A\u000D'
-                                      u'\u0020-\uD7FF\uE000-\uFFFD]')
+                                      u'\u0020-\uD7FF\uE000-\uFFFD'
+                                      u'\U00010000-\U0010FFFF]')
 
 
 def _XmlEscape(s):
@@ -40,7 +42,11 @@
   if not type(s) == unicode:
     s = unicode(s)
   result = saxutils.escape(s, _XML_QUOTE_ESCAPES)
-  return _XML_BAD_CHAR_REGEX.sub(u'', result).encode('utf-8')
+  illegal_chars = _XML_BAD_CHAR_REGEX.search(result)
+  if illegal_chars:
+    raise Exception('String contains characters disallowed in XML: %s' %
+                    repr(result))
+  return result.encode('utf-8')
 
 
 def _WriteAttribute(file, name, value):
diff --git a/tools/grit/grit/tool/xmb_unittest.py b/tools/grit/grit/tool/xmb_unittest.py
index 10f81d7..df8e84b 100755
--- a/tools/grit/grit/tool/xmb_unittest.py
+++ b/tools/grit/grit/tool/xmb_unittest.py
@@ -37,18 +37,23 @@
             <message name="IDS_BONGOBINGO">
               Yibbee
             </message>
+            <message name="IDS_UNICODE">
+              Ol\xe1, \u4eca\u65e5\u306f! \U0001F60A
+            </message>
           </messages>
           <structures>
             <structure type="dialog" name="IDD_SPACYBOX" encoding="utf-16" file="grit/testdata/klonk.rc" />
           </structures>
         </release>
-      </grit>'''), '.')
+      </grit>'''.encode('utf-8')), '.')
     self.xmb_file = StringIO.StringIO()
 
   def testNormalOutput(self):
     xmb.OutputXmb().Process(self.res_tree, self.xmb_file)
-    output = self.xmb_file.getvalue()
-    self.failUnless(output.count('Joi') and output.count('Yibbee'))
+    output = self.xmb_file.getvalue().decode('utf-8')
+    self.failUnless(output.count('Joi'))
+    self.failUnless(output.count('Yibbee'))
+    self.failUnless(output.count(u'Ol\xe1, \u4eca\u65e5\u306f! \U0001F60A'))
 
   def testLimitList(self):
     limit_file = StringIO.StringIO(
diff --git a/build/secondary/tools/grit/grit_rule.gni b/tools/grit/grit_rule.gni
similarity index 100%
rename from build/secondary/tools/grit/grit_rule.gni
rename to tools/grit/grit_rule.gni
diff --git a/build/secondary/tools/grit/repack.gni b/tools/grit/repack.gni
similarity index 100%
rename from build/secondary/tools/grit/repack.gni
rename to tools/grit/repack.gni
diff --git a/build/secondary/tools/grit/stamp_grit_sources.py b/tools/grit/stamp_grit_sources.py
similarity index 100%
rename from build/secondary/tools/grit/stamp_grit_sources.py
rename to tools/grit/stamp_grit_sources.py
diff --git a/tools/mb/docs/design_spec.md b/tools/mb/docs/design_spec.md
index 55f8c79..525a02b0 100644
--- a/tools/mb/docs/design_spec.md
+++ b/tools/mb/docs/design_spec.md
@@ -187,8 +187,11 @@
 
 Any of the three inputs may be an empty list:
 
-* It doesn't make sense to call analyze at all if no files were modified,
-  so this should probably return an error.
+* It normally doesn't make sense to call analyze at all if no files
+  were modified, but in rare cases we can hit a race where we try to
+  test a patch after it has already been committed, in which case
+  the list of modified files is empty. We should return 'no dependency'
+  in that case.
 
 * Passing an empty list for one or the other of test_targets and
   additional_compile_targets is perfectly sensible: in the former case,
diff --git a/tools/mb/mb.py b/tools/mb/mb.py
index c3be5d7..2d142cd 100755
--- a/tools/mb/mb.py
+++ b/tools/mb/mb.py
@@ -773,24 +773,43 @@
     if ret:
       return ret
 
-    inp = self.ReadInputJSON(['files', 'targets'])
+    # TODO(dpranke): add 'test_targets' and 'additional_compile_targets'
+    # as required keys once the recipe has been converted over.
+    # See crbug.com/552146.
+    inp = self.ReadInputJSON(['files'])
     if self.args.verbose:
       self.Print()
       self.Print('analyze input:')
       self.PrintJSON(inp)
       self.Print()
 
+    use_new_logic = ('test_targets' in inp and
+                     'additional_compile_targets' in inp)
+    if use_new_logic:
+      # TODO(crbug.com/555273) - currently GN treats targets and
+      # additional_compile_targets identically since we can't tell the
+      # difference between a target that is a group in GN and one that isn't.
+      # We should eventually fix this and treat the two types differently.
+      targets = (set(inp['test_targets']) |
+                 set(inp['additional_compile_targets']))
+    else:
+      targets = set(inp['targets'])
+
     output_path = self.args.output_path[0]
 
     # Bail out early if a GN file was modified, since 'gn refs' won't know
-    # what to do about it.
-    if any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']):
-      self.WriteJSON({'status': 'Found dependency (all)'}, output_path)
-      return 0
-
-    # Bail out early if 'all' was asked for, since 'gn refs' won't recognize it.
-    if 'all' in inp['targets']:
-      self.WriteJSON({'status': 'Found dependency (all)'}, output_path)
+    # what to do about it. Also, bail out early if 'all' was asked for,
+    # since we can't deal with it yet.
+    if (any(f.endswith('.gn') or f.endswith('.gni') for f in inp['files']) or
+        'all' in targets):
+      if use_new_logic:
+        self.WriteJSON({
+              'status': 'Found dependency (all)',
+              'compile_targets': sorted(targets),
+              'test_targets': sorted(targets & set(inp['test_targets'])),
+            }, output_path)
+      else:
+        self.WriteJSON({'status': 'Found dependency (all)'}, output_path)
       return 0
 
     # This shouldn't normally happen, but could due to unusual race conditions,
@@ -798,9 +817,18 @@
     # the patch has landed.
     if not inp['files']:
       self.Print('Warning: No files modified in patch, bailing out early.')
-      self.WriteJSON({'targets': [],
-                      'build_targets': [],
-                      'status': 'No dependency'}, output_path)
+      if use_new_logic:
+        self.WriteJSON({
+              'status': 'No dependency',
+              'compile_targets': [],
+              'test_targets': [],
+            }, output_path)
+      else:
+        self.WriteJSON({
+              'status': 'No dependency',
+              'targets': [],
+              'build_targets': [],
+            }, output_path)
       return 0
 
     ret = 0
@@ -808,7 +836,7 @@
     response_file.write('\n'.join(inp['files']) + '\n')
     response_file.close()
 
-    matching_targets = []
+    matching_targets = set()
     try:
       cmd = self.GNCmd('refs', self.args.path[0]) + [
           '@%s' % response_file.name, '--all', '--as=output']
@@ -819,8 +847,8 @@
       build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep
       for output in out.splitlines():
         build_output = output.replace(build_dir, '')
-        if build_output in inp['targets']:
-          matching_targets.append(build_output)
+        if build_output in targets:
+          matching_targets.add(build_output)
 
       cmd = self.GNCmd('refs', self.args.path[0]) + [
           '@%s' % response_file.name, '--all']
@@ -833,25 +861,40 @@
         # We want to accept 'chrome/android:chrome_public_apk' and
         # just 'chrome_public_apk'. This may result in too many targets
         # getting built, but we can adjust that later if need be.
-        for input_target in inp['targets']:
+        for input_target in targets:
           if (input_target == build_target or
               build_target.endswith(':' + input_target)):
-            matching_targets.append(input_target)
+            matching_targets.add(input_target)
     finally:
       self.RemoveFile(response_file.name)
 
     if matching_targets:
-      # TODO: it could be that a target X might depend on a target Y
-      # and both would be listed in the input, but we would only need
-      # to specify target X as a build_target (whereas both X and Y are
-      # targets). I'm not sure if that optimization is generally worth it.
-      self.WriteJSON({'targets': sorted(set(matching_targets)),
-                      'build_targets': sorted(set(matching_targets)),
-                      'status': 'Found dependency'}, output_path)
+      if use_new_logic:
+        self.WriteJSON({
+              'status': 'Found dependency',
+              'compile_targets': sorted(matching_targets),
+              'test_targets': sorted(matching_targets &
+                                     set(inp['test_targets'])),
+            }, output_path)
+      else:
+        self.WriteJSON({
+            'status': 'Found dependency',
+            'targets': sorted(matching_targets),
+            'build_targets': sorted(matching_targets),
+        }, output_path)
     else:
-      self.WriteJSON({'targets': [],
-                      'build_targets': [],
-                      'status': 'No dependency'}, output_path)
+      if use_new_logic:
+        self.WriteJSON({
+            'status': 'No dependency',
+            'compile_targets': [],
+            'test_targets': [],
+        }, output_path)
+      else:
+        self.WriteJSON({
+            'status': 'No dependency',
+            'targets': [],
+            'build_targets': [],
+        }, output_path)
 
     if self.args.verbose:
       outp = json.loads(self.ReadFile(output_path))
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index db82afa..76c34a5 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -350,6 +350,9 @@
     'chrome': {
       'precise64': 'gn_official',
     },
+    'chrome.continuous': {
+      'precise64 trunk': 'gn_official',
+    },
     'chromium': {
       'Win': 'noswarming_gyp_release_bot',
       'Mac': 'noswarming_gyp_release_bot_mac_strip',
@@ -445,11 +448,10 @@
       'Win GN (dbg)': 'gn_debug_bot_minimal_symbols_x86',
     },
     'client.skia': {
-      'Linux Builder': 'swarming_gyp_release_bot',
-      'Linux Builder-Trybot': 'swarming_gyp_release_bot',
-      'Linux Tests': 'swarming_gyp_release_bot',
+      'Linux Builder': 'swarming_gn_release_bot',
+      'Linux Builder-Trybot': 'swarming_gn_release_bot',
+      'Linux Tests': 'swarming_gn_release_bot',
     },
-
     'client.v8.fyi': {
       'Linux Debug Builder': 'gn_debug_bot',
       'V8 Linux GN': 'gn_release_bot',
@@ -458,6 +460,9 @@
     'official.desktop': {
       'precise64': 'gn_official',
     },
+    'official.desktop.continuous': {
+      'precise64 trunk': 'gn_official',
+    },
     'tryserver.blink': {
       'android_blink_compile_dbg': 'android_gyp_debug_bot',
       'android_blink_compile_rel': 'android_gyp_release_trybot',
diff --git a/tools/mb/mb_unittest.py b/tools/mb/mb_unittest.py
index 23b3ee08..1a0f901f 100755
--- a/tools/mb/mb_unittest.py
+++ b/tools/mb/mb_unittest.py
@@ -220,6 +220,26 @@
       'build_targets': ['foo_unittests']
     })
 
+  def test_gn_analyze_new_logic(self):
+    files = {'/tmp/in.json': """{\
+               "files": ["foo/foo_unittest.cc"],
+               "test_targets": ["foo_unittests", "bar_unittests"],
+               "additional_compile_targets": []
+             }"""}
+
+    mbw = self.fake_mbw(files)
+    mbw.Call = lambda cmd, env=None, buffer_output=True: (
+        0, 'out/Default/foo_unittests\n', '')
+
+    self.check(['analyze', '-c', 'gn_debug', '//out/Default',
+                '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
+    out = json.loads(mbw.files['/tmp/out.json'])
+    self.assertEqual(out, {
+      'status': 'Found dependency',
+      'compile_targets': ['foo_unittests'],
+      'test_targets': ['foo_unittests']
+    })
+
   def test_gn_analyze_all(self):
     files = {'/tmp/in.json': """{\
                "files": ["foo/foo_unittest.cc"],
@@ -235,6 +255,24 @@
       'status': 'Found dependency (all)',
     })
 
+  def test_gn_analyze_all_new_logic(self):
+    files = {'/tmp/in.json': """{\
+               "files": ["foo/foo_unittest.cc"],
+               "test_targets": ["bar_unittests"],
+               "additional_compile_targets": ["all"]
+             }"""}
+    mbw = self.fake_mbw(files)
+    mbw.Call = lambda cmd, env=None, buffer_output=True: (
+        0, 'out/Default/foo_unittests\n', '')
+    self.check(['analyze', '-c', 'gn_debug', '//out/Default',
+                '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
+    out = json.loads(mbw.files['/tmp/out.json'])
+    self.assertEqual(out, {
+      'status': 'Found dependency (all)',
+      'compile_targets': ['all', 'bar_unittests'],
+      'test_targets': ['bar_unittests'],
+    })
+
   def test_gn_analyze_missing_file(self):
     files = {'/tmp/in.json': """{\
                "files": ["foo/foo_unittest.cc"],
@@ -256,6 +294,28 @@
       'status': 'No dependency',
     })
 
+  def test_gn_analyze_missing_file_new_logic(self):
+    files = {'/tmp/in.json': """{\
+               "files": ["foo/foo_unittest.cc"],
+               "test_targets": ["bar_unittests"],
+               "additional_compile_targets": []
+             }"""}
+    mbw = self.fake_mbw(files)
+    mbw.cmds = [
+        (0, '', ''),
+        (1, 'The input matches no targets, configs, or files\n', ''),
+        (1, 'The input matches no targets, configs, or files\n', ''),
+    ]
+
+    self.check(['analyze', '-c', 'gn_debug', '//out/Default',
+                '/tmp/in.json', '/tmp/out.json'], mbw=mbw, ret=0)
+    out = json.loads(mbw.files['/tmp/out.json'])
+    self.assertEqual(out, {
+      'status': 'No dependency',
+      'compile_targets': [],
+      'test_targets': [],
+    })
+
   def test_gn_gen(self):
     self.check(['gen', '-c', 'gn_debug', '//out/Default', '-g', '/goma'],
                ret=0,
diff --git a/tools/metrics/actions/actions.xml b/tools/metrics/actions/actions.xml
index 979dd73..8837add129 100644
--- a/tools/metrics/actions/actions.xml
+++ b/tools/metrics/actions/actions.xml
@@ -3004,6 +3004,24 @@
   <description>Please enter the description of this user action.</description>
 </action>
 
+<action name="EnhancedBookmarks.EditAfterCreateButtonClicked">
+  <owner>kkimlabs@chromium.org</owner>
+  <owner>ianwen@chromium.org</owner>
+  <owner>fgorski@chromium.org</owner>
+  <description>
+    User clicked the Edit button on a snackbar after a bookmark was created.
+  </description>
+</action>
+
+<action name="EnhancedBookmarks.EditAfterCreateButtonNotClicked">
+  <owner>kkimlabs@chromium.org</owner>
+  <owner>ianwen@chromium.org</owner>
+  <owner>fgorski@chromium.org</owner>
+  <description>
+    User ignored the Edit button on a snackbar after a bookmark was created.
+  </description>
+</action>
+
 <action name="EnterFullScreenWithWrenchMenu">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <description>Please enter the description of this user action.</description>
@@ -8694,6 +8712,14 @@
   </description>
 </action>
 
+<action name="Notifications.Persistent.ClickedWithoutPermission">
+  <owner>peter@chromium.org</owner>
+  <description>
+    Recorded when a persistent notification gets clicked on by the user, but the
+    user has revoked notification permission for the origin since it was shown.
+  </description>
+</action>
+
 <action name="Notifications.Persistent.Closed">
   <owner>peter@chromium.org</owner>
   <description>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 77ffd4bd..e4c9971 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -9428,6 +9428,12 @@
   </summary>
 </histogram>
 
+<histogram name="EnhancedBookmarks.AllBookmarksCount">
+  <owner>ianwen@chromium.org</owner>
+  <owner>kkimlabs@chromium.org</owner>
+  <summary>Number of bookmarks the user has. Android only.</summary>
+</histogram>
+
 <histogram name="EnhancedBookmarks.SyncExperimentState"
     enum="BookmarksExperimentState">
   <obsolete>
@@ -12302,16 +12308,14 @@
 
 <histogram name="Extensions.LoadAll">
   <owner>kalman@chromium.org</owner>
-  <summary>
-    The number of extensions and themes loaded at browser startup.
-  </summary>
+  <summary>The number of extensions and themes loaded at profile open.</summary>
 </histogram>
 
 <histogram name="Extensions.LoadAllComponentTime" units="milliseconds">
   <owner>kalman@chromium.org</owner>
   <summary>
-    Time taken to load all component extensions at browser startup. This happens
-    as part of the total initialization time of ExtensionService, measured in
+    Time taken to load all component extensions at profile open. This happens as
+    part of the total initialization time of ExtensionService, measured in
     Extensions.ExtensionServiceInitTime.
   </summary>
 </histogram>
@@ -12319,7 +12323,7 @@
 <histogram name="Extensions.LoadAllTime" units="milliseconds">
   <owner>kalman@chromium.org</owner>
   <summary>
-    Time taken to load all non-component extensions at browser startup. This
+    Time taken to load all non-component extensions at profile open. This
     happens as part of the total initialization time of ExtensionService,
     measured in Extensions.ExtensionServiceInitTime.
   </summary>
@@ -12328,35 +12332,35 @@
 <histogram name="Extensions.LoadAllTime2" units="milliseconds">
   <owner>kalman@chromium.org</owner>
   <summary>
-    Time taken to load all non-component extensions at browser startup and
-    record metrics. This happens as part of the total initialization time of
+    Time taken to load all non-component extensions at profile open and record
+    metrics. This happens as part of the total initialization time of
     ExtensionService, measured in Extensions.ExtensionServiceInitTime.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadApp">
   <owner>kalman@chromium.org</owner>
-  <summary>The number of apps loaded by each user at startup time.</summary>
+  <summary>The number of apps loaded by each user at profile open.</summary>
 </histogram>
 
 <histogram name="Extensions.LoadAppExternal">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of externally managed apps loaded by each user at startup time.
+    The number of externally managed apps loaded by each user at profile open.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadAppUser">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of user-installed apps loaded by each user at startup time.
+    The number of user-installed apps loaded by each user at profile open.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadBrowserAction">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of browser action extensions loaded at browser startup.
+    The number of browser action extensions loaded at profile open.
   </summary>
 </histogram>
 
@@ -12366,73 +12370,80 @@
     Deprecated as of 4/2015. Replaced by ManagedUsers.Whitelist.Count.
   </obsolete>
   <summary>
-    The number of content-pack extensions loaded at browser startup.
+    The number of content-pack extensions loaded at profile open.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadCreationFlags" enum="ExtensionCreationFlags">
   <owner>calamity@chromium.org</owner>
   <summary>
-    The creation flags of all extensions loaded at startup time grouped by
+    The creation flags of all extensions loaded at profile open grouped by
     Extension::InitFromValueFlags.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadExtension">
   <owner>kalman@chromium.org</owner>
-  <summary>The number of extensions loaded at browser startup.</summary>
+  <summary>The number of extensions loaded at profile open.</summary>
 </histogram>
 
 <histogram name="Extensions.LoadExtensionExternal">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of externally managed extensions loaded at browser startup.
+    The number of externally managed extensions loaded at profile open.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadExtensionUser">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of user-installed extensions loaded at browser startup.
+    The number of user-installed extensions loaded at profile open.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadExternal">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of externally managed extensions and apps loaded at browser
-    startup.
+    The number of externally managed extensions and apps loaded at profile open.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadHostedApp">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of hosted apps loaded by each user at startup time.
+    The number of hosted apps loaded by each user at profile open.
+  </summary>
+</histogram>
+
+<histogram name="Extensions.LoadNoExtensionAction">
+  <owner>rdevlin.cronin@chromium.org</owner>
+  <summary>
+    The number of extensions that had neither a page nor browser action
+    specified in their manifest. Recorded at profile open.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadPackagedApp">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of legacy packaged apps loaded by each user at startup time.
+    The number of legacy packaged apps loaded by each user at profile open.
   </summary>
 </histogram>
 
 <histogram name="Extensions.LoadPlatformApp">
   <owner>kalman@chromium.org</owner>
-  <summary>The number of platform apps loaded at browser startup.</summary>
+  <summary>The number of platform apps loaded at profile open.</summary>
 </histogram>
 
 <histogram name="Extensions.LoadTheme">
   <owner>kalman@chromium.org</owner>
-  <summary>The number of themes loaded at browser startup.</summary>
+  <summary>The number of themes loaded at profile open.</summary>
 </histogram>
 
 <histogram name="Extensions.LoadType" enum="ExtensionType">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of extensions loaded at startup time grouped by
+    The number of extensions loaded at profile open grouped by
     Extension::HistogramType.
   </summary>
 </histogram>
@@ -12440,7 +12451,7 @@
 <histogram name="Extensions.LoadUserScript">
   <owner>kalman@chromium.org</owner>
   <summary>
-    The number of converted user scripts loaded at browser startup.
+    The number of converted user scripts loaded at profile open.
   </summary>
 </histogram>
 
@@ -15671,8 +15682,9 @@
   <owner>shuchen@chromium.org</owner>
   <summary>
     The number of active input methods. Recorded when the user logs in to Chrome
-    OS. The active input methods are selected by user in the language settings
-    page.
+    OS or each cold start of Chrome on Android. The active input methods are
+    selected by user in the language settings page on Chrome OS and in system
+    language settings on Android.
   </summary>
 </histogram>
 
@@ -15743,6 +15755,14 @@
   <summary>The trigger type of input method switches by user.</summary>
 </histogram>
 
+<histogram name="InputMethod.MatchesSystemLanguage" enum="BooleanMatched">
+  <owner>aurimas@chromium.org</owner>
+  <summary>
+    Whether the currently selected keyboard language matches the system
+    language. Recorded once with every cold start of Chrome for Android.
+  </summary>
+</histogram>
+
 <histogram name="InputMethod.PkCommit.Index">
   <owner>shuchen@chromium.org</owner>
   <summary>
@@ -29808,11 +29828,31 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.BatchDelete.Count">
+  <owner>jianli@chromium.org</owner>
+  <summary>Number of offline pages that are deleted in a batch.</summary>
+</histogram>
+
+<histogram name="OfflinePages.BatchDelete.TotalPageSize" units="KB">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Total size, in kilobytes, of all offline pages that are deleted in a batch.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.ClearAllStatus" enum="OfflinePagesClearAllStatus">
   <owner>jianli@chromium.org</owner>
   <summary>Status code of wiping out the offline page data.</summary>
 </histogram>
 
+<histogram name="OfflinePages.DeletePage.AccessCount">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Number of accesses to the offline page since its creation. This is reported
+    when the offline page was deleted.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.DeletePage.FreeSpaceMB" units="MB">
   <owner>jianli@chromium.org</owner>
   <summary>
@@ -29829,12 +29869,65 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.DeletePage.TotalPageSizeAsPercentageOfFreeSpace"
+    units="%">
+  <owner>fgorski@chromium.org</owner>
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    The percentage of space taken by offline pages from the free space that
+    could be available, if the feature was not present. I.e. considering
+    situation where the user has: Free Space, Offline content, other apps and
+    data. This is a percentage of: Offline content / (Offline content + Free
+    Space).
+
+    The value will be recorded after user deletes a single or multiple offline
+    pages. In case pages are removed in bulk, this value will be reported once.
+    This value is only reported with deleting, as we are trying to infer if lack
+    of free space might have caused the user to delete.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.DeletePage.LastOpenToCreated" units="minutes">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Length of time between when an offline page was created and was opened last
+    time. This is reported when the page was deleted.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.DeletePage.PageSize" units="KB">
+  <owner>jianli@chromium.org</owner>
+  <summary>Size of the offline page, in kilobytes, that was deleted.</summary>
+</histogram>
+
+<histogram name="OfflinePages.DeletePage.TimeSinceLastOpen" units="minutes">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Length of time between when an offline page was last opened and was deleted.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.DeletePageResult"
     enum="OfflinePagesDeletePageResult">
   <owner>jianli@chromium.org</owner>
   <summary>Result of removing an offline copy for a page.</summary>
 </histogram>
 
+<histogram name="OfflinePages.FirstOpenSinceCreated" units="minutes">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    The time elapsed between creation of the offline page and the first time it
+    was opened.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.IncognitoSave" enum="Boolean">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Whether the page that was being saved offline was in incognito mode.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePages.LoadStatus" enum="OfflinePagesLoadStatus">
   <owner>jianli@chromium.org</owner>
   <summary>
@@ -29852,6 +29945,24 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.OfflinePageCount">
+  <owner>fgorski@chromium.org</owner>
+  <owner>jianli@chromium.org</owner>
+  <summary>Number of offline pages the user has. Android only.</summary>
+</histogram>
+
+<histogram name="OfflinePages.OnlineOnOpen" enum="Boolean">
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Whether the user was online when a saved page with offline copy was opened.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.OpenSinceLastOpen" units="minutes">
+  <owner>jianli@chromium.org</owner>
+  <summary>Length of time between two consecutive opens.</summary>
+</histogram>
+
 <histogram name="OfflinePages.PageLifetime" units="minutes">
   <owner>jianli@chromium.org</owner>
   <summary>
@@ -29900,6 +30011,30 @@
   </summary>
 </histogram>
 
+<histogram name="OfflinePages.TotalPageSize" units="MB">
+  <owner>fgorski@chromium.org</owner>
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Total size of all the offline pages saved by the user.
+
+    This value is recorded whenever the number of pages change, meaning after a
+    page is added or removed. If pages are removed in bulk, this value will be
+    reported only once.
+  </summary>
+</histogram>
+
+<histogram name="OfflinePages.TotalPageSizePercentage" units="%">
+  <owner>fgorski@chromium.org</owner>
+  <owner>jianli@chromium.org</owner>
+  <summary>
+    Total size of all the offline pages saved by the user as a percentage of
+    total storage size.
+
+    This value is recorded whenever the number of pages change, meaning after a
+    page is added or removed.
+  </summary>
+</histogram>
+
 <histogram name="OfflinePolicy.SuccessfulResourceLoadPercentage" units="%">
   <owner>Please list the metric's owners. Add more owner tags as needed.</owner>
   <summary>
@@ -40269,6 +40404,14 @@
   </summary>
 </histogram>
 
+<histogram name="SBClientDownload.ZipFileSuccess" enum="BooleanSuccess">
+  <owner>nparker@chromium.org</owner>
+  <summary>
+    For each zip file analyzed by the SafeBrowsing download service, records if
+    the unpacking was 100% successful.
+  </summary>
+</histogram>
+
 <histogram name="SBClientMalware.ClassificationStart" enum="BooleanHit">
   <owner>noelutz@chromium.org</owner>
   <summary>
@@ -41519,6 +41662,71 @@
   </summary>
 </histogram>
 
+<histogram name="Search.ContextualSearchIconSpriteAnimated"
+    enum="ContextualSearchIconSpriteAnimated">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Whether search results were seen, whether the search provider icon sprite
+    was animated when the panel first appeared, and the triggering gesture. If
+    animation is disabled due to a field trial, we still log
+    &quot;animated&quot; if the animation would have run otherwise.
+  </summary>
+</histogram>
+
+<histogram name="Search.ContextualSearchPeekPromoCount" units="count">
+  <owner>donnd@chromium.org</owner>
+  <owner>pedrosimonetti@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The number of times the Peek Promo was seen. This histogram will be emitted
+    when the Panel closes. The panel is always visible when the Peek Promo is
+    shown, so this histogram will always be emitted after a Promo is shown
+    (except in the case of a crash). This histogram does not care whether the
+    Panel was opened.
+  </summary>
+</histogram>
+
+<histogram name="Search.ContextualSearchPeekPromoCountUntilOpened"
+    units="count">
+  <owner>donnd@chromium.org</owner>
+  <owner>pedrosimonetti@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The number of times the Peek Promo was seen until the Panel was opened. This
+    histogram will be emitted when the Panel closes, if the Panel was opened
+    with the Peek Promo visible. If the Panel is not opened, nothing will be
+    emitted.
+  </summary>
+</histogram>
+
+<histogram name="Search.ContextualSearchPeekPromoOutcome"
+    enum="ContextualSearchPeekPromoOutcome">
+  <owner>donnd@chromium.org</owner>
+  <owner>pedrosimonetti@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    The outcome of the Contextual Search Peek Promo for those who have seen the
+    promo and for those who would have seen the promo if it was enabled, so we
+    can compare the effect of the promo on users opening the Panel. This
+    histogram will be emitted when the Panel closes, if the conditions to
+    display the Peek Promo are met, regardless of whether the Peek Promo was
+    actually visible (the Promo is controlled by Finch) and regardless of
+    whether the Panel was opened.
+  </summary>
+</histogram>
+
+<histogram name="Search.ContextualSearchShouldTranslate"
+    enum="ContextualSearchShouldTranslate">
+  <owner>donnd@chromium.org</owner>
+  <owner>twellington@chromium.org</owner>
+  <summary>
+    Emitted when a translate one-box should be forced, to indicate if it
+    actually was forced or simply would have been forced if not disabled by a
+    flag in the variations_service.
+  </summary>
+</histogram>
+
 <histogram name="Search.DefaultSearchChangeOrigin"
     enum="DefaultSearchChangeOrigin">
   <owner>mathp@chromium.org</owner>
@@ -46347,6 +46555,15 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.ExtraSyncDataCount" units="entries">
+  <owner>gangwu@chromium.org</owner>
+  <summary>
+    Counts the total number of extra copies of sync data in memory. This count
+    is emitted once, after loading Sync Directory. The count will indicate how
+    many Directory entities fail to share client and server specifics.
+  </summary>
+</histogram>
+
 <histogram name="Sync.FaviconCacheLookupSucceeded" enum="BooleanSuccess">
   <owner>zea@chromium.org</owner>
   <summary>Whether a sync favicon cache lookup succeeded or not.</summary>
@@ -54316,8 +54533,8 @@
 <enum name="AutoLaunchState" type="int">
   <int value="0" label="AUTO_LAUNCH_NONE"/>
   <int value="1" label="AUTO_LAUNCH_BACKGROUND"/>
-  <int value="2" label="AUTO_LAUNCH_FOREGROUND"/>
-  <int value="3" label="AUTO_LAUNCH_FOREGROUND_USELESS"/>
+  <int value="2" label="[Deprecated] AUTO_LAUNCH_FOREGROUND"/>
+  <int value="3" label="[Deprecated] AUTO_LAUNCH_FOREGROUND_USELESS"/>
 </enum>
 
 <enum name="BackgroundModeMenuItem" type="int">
@@ -55991,6 +56208,33 @@
   <int value="19" label="Share image"/>
 </enum>
 
+<enum name="ContextualSearchIconSpriteAnimated" type="int">
+  <int value="0" label="Animated, seen, from tap"/>
+  <int value="1" label="Animated, not seen, from tap"/>
+  <int value="2" label="Not animated, seen, from tap"/>
+  <int value="3" label="Not animated, not seen, from tap"/>
+  <int value="4" label="Animated, seen, from long press"/>
+  <int value="5" label="Animated, not seen, from long press"/>
+  <int value="6" label="Not animated, seen, from long press"/>
+  <int value="7" label="Not animated, not seen, from long press"/>
+</enum>
+
+<enum name="ContextualSearchPeekPromoOutcome" type="int">
+  <summary>The outcome of the Contextual Search Peek Promo.</summary>
+  <int value="0" label="Peek Promo was seen, Panel was opened"/>
+  <int value="1" label="Peek Promo was seen, Panel was not opened"/>
+  <int value="2" label="Peek Promo was not seen, Panel was opened"/>
+  <int value="3" label="Peek Promo was not seen, Panel was not opened"/>
+</enum>
+
+<enum name="ContextualSearchShouldTranslate" type="int">
+  <summary>
+    Notes when a translation one-box should be forced by Contextual Search.
+  </summary>
+  <int value="0" label="Did force a translation"/>
+  <int value="1" label="Would force a translation (if not disabled)"/>
+</enum>
+
 <enum name="CookieDeletionCause" type="int">
   <summary>Reason why a cookie was removed from the cookie store</summary>
   <int value="0" label="explicit">
@@ -61773,7 +62017,7 @@
   <int value="930" label="PresentationRequestReconnect"/>
   <int value="931" label="PresentationRequestGetAvailability"/>
   <int value="932" label="PresentationRequestConnectionAvailableEventListener"/>
-  <int value="933" label="PresentationConnectionClose"/>
+  <int value="933" label="PresentationConnectionTerminate"/>
   <int value="934" label="PresentationConnectionSend"/>
   <int value="935" label="PresentationConnectionStateChangeEventListener"/>
   <int value="936" label="PresentationConnectionMessageEventListener"/>
@@ -61837,6 +62081,34 @@
   <int value="994" label="MeterElementWithNoneAppearance"/>
   <int value="995" label="MeterElementWithRatingAppearance"/>
   <int value="996" label="MeterElementWithRelevancyAppearance"/>
+  <int value="997" label="SelectionAnchorNode"/>
+  <int value="998" label="SelectionAnchorOffset"/>
+  <int value="999" label="SelectionFocusNode"/>
+  <int value="1000" label="SelectionFocusOffset"/>
+  <int value="1001" label="SelectionIsCollapsed"/>
+  <int value="1002" label="SelectionRangeCount"/>
+  <int value="1003" label="SelectionGetRangeAt"/>
+  <int value="1004" label="SelectionAddRange"/>
+  <int value="1005" label="SelectionRemoveAllRanges"/>
+  <int value="1006" label="SelectionCollapse"/>
+  <int value="1007" label="SelectionCollapseToStart"/>
+  <int value="1008" label="SelectionCollapseToEnd"/>
+  <int value="1009" label="SelectionExtend"/>
+  <int value="1010" label="SelectionSelectAllChildren"/>
+  <int value="1011" label="SelectionDeleteDromDocument"/>
+  <int value="1012" label="SelectionDOMString"/>
+  <int value="1013" label="InputTypeRangeVerticalAppearance"/>
+  <int value="1014" label="CSSFilterReference"/>
+  <int value="1015" label="CSSFilterGrayscale"/>
+  <int value="1016" label="CSSFilterSepia"/>
+  <int value="1017" label="CSSFilterSaturate"/>
+  <int value="1018" label="CSSFilterHueRotate"/>
+  <int value="1019" label="CSSFilterInvert"/>
+  <int value="1020" label="CSSFilterOpacity"/>
+  <int value="1021" label="CSSFilterBrightness"/>
+  <int value="1022" label="CSSFilterContrast"/>
+  <int value="1023" label="CSSFilterBlur"/>
+  <int value="1024" label="CSSFilterDropShadow"/>
 </enum>
 
 <enum name="FetchRequestMode" type="int">
@@ -65883,6 +66155,7 @@
   <int value="-867087281" label="enable-virtual-keyboard"/>
   <int value="-864266073" label="cros-regions-mode"/>
   <int value="-864205629" label="enable-offline-load-stale-cache"/>
+  <int value="-861678473" label="disable-offer-upload-credit-cards"/>
   <int value="-853594220" label="disable-new-avatar-menu"/>
   <int value="-836123854" label="wallet-service-use-sandbox"/>
   <int value="-820041355" label="enable-transition-compositing"/>
@@ -66246,6 +66519,7 @@
   <int value="2122876605" label="enable-bleeding-edge-rendering-fast-paths"/>
   <int value="2137347307" label="enable-drive-apps-in-app-list"/>
   <int value="2137599770" label="enable-win32k-renderer-lockdown"/>
+  <int value="2141463681" label="enable-offer-upload-credit-cards"/>
 </enum>
 
 <enum name="LoginDatabaseInitError" type="int">
@@ -76502,6 +76776,7 @@
   <int value="7" label="Transparency viewer opened"/>
   <int value="8" label="Connection help opened"/>
   <int value="9" label="Site settings opened"/>
+  <int value="10" label="Security details opened"/>
 </enum>
 
 <enum name="WebSocketHandshakeResult" type="int">
diff --git a/tools/perf/benchmarks/dromaeo.py b/tools/perf/benchmarks/dromaeo.py
index 3a34543..a0e688c 100644
--- a/tools/perf/benchmarks/dromaeo.py
+++ b/tools/perf/benchmarks/dromaeo.py
@@ -234,10 +234,9 @@
 
 # xp: crbug.com/389731
 # win7: http://crbug.com/479796
-# linux: http://crbug.com/513853
 # android: http://crbug.com/503138
 # win8: crbug.com/529330
-@benchmark.Disabled('xp', 'win7', 'linux', 'android', 'win8')
+@benchmark.Disabled('xp', 'win7', 'android', 'win8')
 class DromaeoJslibModifyJquery(_DromaeoBenchmark):
   """Dromaeo JSLib modify jquery JavaScript benchmark.
 
diff --git a/tools/perf/benchmarks/dummy_benchmark.py b/tools/perf/benchmarks/dummy_benchmark.py
index ef6c04c7..60ba2802 100644
--- a/tools/perf/benchmarks/dummy_benchmark.py
+++ b/tools/perf/benchmarks/dummy_benchmark.py
@@ -5,6 +5,8 @@
 Benchmarks in this file is created for the purpose of testing telemetry
 integration with perf dashboard and bisect bot. The number they produce aren't
 meant to represent any actual performance data of the browser.
+
+For more information about these dummy benchmarks, see: https://goo.gl/WvZiiW
 """
 
 import random
diff --git a/tools/perf/page_sets/story_set_unittest.py b/tools/perf/page_sets/story_set_unittest.py
index 9cf753d..35247c6 100644
--- a/tools/perf/page_sets/story_set_unittest.py
+++ b/tools/perf/page_sets/story_set_unittest.py
@@ -3,7 +3,6 @@
 # found in the LICENSE file.
 
 import os
-import logging
 
 import page_sets
 
@@ -11,8 +10,6 @@
 from telemetry import page
 from telemetry.testing import story_set_smoke_test
 
-from catapult_base import cloud_storage
-
 
 class StorySetUnitTest(story_set_smoke_test.StorySetSmokeTest):
 
@@ -23,33 +20,21 @@
   # TODO(tbarzic): crbug.com/386416.
   @decorators.Disabled('chromeos')
   def testSmoke(self):
-    try:
-      self.RunSmokeTest(self.story_sets_dir, self.top_level_dir)
-    # Swallow cloud_storage.CredentialsError due to http://crbug.com/513086.
-    # TODO(nednguyen): remove the try except block once that bug is fixed.
-    except cloud_storage.CredentialsError:
-      logging.warning(
-          'CredentialsError was ignored for StorySetUnitTest.testSmoke')
+    self.RunSmokeTest(self.story_sets_dir, self.top_level_dir)
 
   # TODO(nednguyen): Remove this test once crbug.com/508538 is fixed.
-  # http://crbug.com/513086
-  @decorators.Disabled('all')
+  # TODO(tbarzic): crbug.com/386416.
+  @decorators.Disabled('chromeos')
   def testNoPageDefinedSyntheticDelay(self):
     for story_set_class in self.GetAllStorySetClasses(self.story_sets_dir,
                                                       self.top_level_dir):
       if story_set_class is page_sets.ToughSchedulingCasesPageSet:
         continue
-      try:
-        story_set = story_set_class()
-        for story in story_set:
-          if isinstance(story, page.Page):
-            self.assertFalse(
-              story.synthetic_delays,
-              'Page %s in page set %s has non empty synthetic delay. '
-              'Synthetic delay is no longer supported. See crbug.com/508538.' %
-              (story.display_name, story_set.Name()))
-      # Swallow cloud_storage.CredentialsError due to http://crbug.com/513086.
-      # TODO(nednguyen): remove the try except block once that bug is fixed.
-      except cloud_storage.CredentialsError:
-        logging.warning('CredentialsError was ignored for '
-                        'StorySetUnitTest.testNoPageDefinedSyntheticDelay')
+      story_set = story_set_class()
+      for story in story_set:
+        if isinstance(story, page.Page):
+          self.assertFalse(
+            story.synthetic_delays,
+            'Page %s in page set %s has non empty synthetic delay. '
+            'Synthetic delay is no longer supported. See crbug.com/508538.' %
+            (story.display_name, story_set.Name()))
diff --git a/tools/strict_enum_value_checker/OWNERS b/tools/strict_enum_value_checker/OWNERS
new file mode 100644
index 0000000..0d6b206
--- /dev/null
+++ b/tools/strict_enum_value_checker/OWNERS
@@ -0,0 +1,3 @@
+rdevlin.cronin@chromium.org
+rockot@chromium.org
+
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/__init__.py b/tools/telemetry/telemetry/internal/platform/power_monitor/__init__.py
index 7a13fa91d..4c3cf45 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/__init__.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/__init__.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import logging
+
 from telemetry.core import exceptions
 
 
@@ -10,6 +12,9 @@
 
   Provides an interface to register power consumption during a test.
   """
+  def __init__(self):
+    self._monitoring = False
+
   def CanMonitorPower(self):
     """Returns True iff power can be monitored asynchronously via
     StartMonitoringPower() and StopMonitoringPower().
@@ -22,6 +27,14 @@
     energy consumption."""
     return False
 
+  def _CheckStart(self):
+    assert not self._monitoring, "Already monitoring power."
+    self._monitoring = True
+
+  def _CheckStop(self):
+    assert self._monitoring, "Not monitoring power."
+    self._monitoring = False
+
   def StartMonitoringPower(self, browser):
     """Starts monitoring power utilization statistics.
 
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/android_dumpsys_power_monitor.py b/tools/telemetry/telemetry/internal/platform/power_monitor/android_dumpsys_power_monitor.py
index 6e363bb..eefdae88 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/android_dumpsys_power_monitor.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/android_dumpsys_power_monitor.py
@@ -5,10 +5,9 @@
 import csv
 import logging
 
-from telemetry.internal.platform import power_monitor
+from telemetry.internal.platform.power_monitor import android_power_monitor_base
 
-
-class DumpsysPowerMonitor(power_monitor.PowerMonitor):
+class DumpsysPowerMonitor(android_power_monitor_base.AndroidPowerMonitorBase):
   """PowerMonitor that relies on the dumpsys batterystats to monitor the power
   consumption of a single android application. This measure uses a heuristic
   and is the same information end-users see with the battery application.
@@ -29,57 +28,42 @@
   def CanMonitorPower(self):
     result = self._platform.RunCommand('dumpsys batterystats -c')
     DUMP_VERSION_INDEX = 0
-    csvreader = csv.reader(result)
     # Dumpsys power data is present in dumpsys versions 8 and 9
     # which is found on L+ devices.
-    if csvreader.next()[DUMP_VERSION_INDEX] in ['8', '9']:
-      return True
-    return False
+    return (csv.reader(result).next()[DUMP_VERSION_INDEX] in ['8', '9'])
 
   def StartMonitoringPower(self, browser):
+    self._CheckStart()
+    assert browser
     self._browser = browser
     # Disable the charging of the device over USB. This is necessary because the
     # device only collects information about power usage when the device is not
     # charging.
-    self._battery.SetCharging(False)
+    self._ChargingOff(self._battery)
 
   def StopMonitoringPower(self):
-    self._battery.SetCharging(True)
-    if self._browser:
-      package = self._browser._browser_backend.package
-      self._browser = None
+    self._CheckStop()
+    assert self._browser
+    self._ChargingOn(self._battery)
+    package = self._browser._browser_backend.package
+    self._browser = None
 
+    voltage = self._ParseVoltage(self._battery.GetBatteryInfo().get('voltage'))
     power_data = self._battery.GetPowerData()
-    battery_info = self._battery.GetBatteryInfo()
-    voltage = battery_info.get('voltage')
-    if voltage is None:
-      # Converting at a nominal voltage of 4.0V, as those values are obtained by
-      # a heuristic, and 4.0V is the voltage we set when using a monsoon device.
-      voltage = 4.0
-      logging.warning('Unable to get device voltage. Using %s.', voltage)
-    else:
-      voltage = float(voltage) / 1000
-      logging.info('Device voltage at %s', voltage)
     power_results = self.ProcessPowerData(power_data, voltage, package)
-    if power_results['energy_consumption_mwh'] == 0:
-      logging.warning('Power data is returning 0 for system total usage. %s'
-                      % (power_data))
-    if power_results['application_energy_consumption_mwh'] == 0:
-      logging.warning('Power data is returning 0 usage for %s. %s'
-                      % (package, power_data))
+    self._LogPowerAnomalies(power_results, package)
     return power_results
 
   @staticmethod
   def ProcessPowerData(power_data, voltage, package):
-    power_results = {'identifier': 'dumpsys', 'power_samples_mw': []}
-    system_power = power_data['system_total']
-    package_power = power_data['per_package'].get(package)
-    if not package_power:
+    package_power_data = power_data['per_package'].get(package)
+    if not package_power_data:
       logging.warning('No power data for %s in dumpsys output.' % package)
-      package_consumption_mwh = 0
+      package_power = 0
     else:
-      package_consumption_mwh = sum(package_power['data']) * voltage
-    power_results['application_energy_consumption_mwh'] = \
-        package_consumption_mwh
-    power_results['energy_consumption_mwh'] = system_power * voltage
-    return power_results
+      package_power = sum(package_power_data['data'])
+
+    return {'identifier': 'dumpsys',
+            'power_samples_mw': [],
+            'energy_consumption_mwh': power_data['system_total'] * voltage,
+            'application_energy_consumption_mwh': package_power * voltage}
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/android_dumpsys_power_monitor_unittest.py b/tools/telemetry/telemetry/internal/platform/power_monitor/android_dumpsys_power_monitor_unittest.py
index 1b21386..d532b04 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/android_dumpsys_power_monitor_unittest.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/android_dumpsys_power_monitor_unittest.py
@@ -5,21 +5,32 @@
 import unittest
 
 from telemetry.internal.platform.power_monitor import android_dumpsys_power_monitor
+from telemetry.internal.platform.power_monitor import pm_mock
+
+
+_PACKAGE = 'com.google.android.apps.chrome'
+
+_TYPICAL_POWER_DATA = {
+      'system_total': 2000.0,
+      'per_package': {
+        _PACKAGE: {'data': [23.9], 'uid': '12345'}
+      }
+    }
+
+_TYPICAL_POWER_DATA_MULTISAMPLE = {
+      'system_total': 2000.0,
+      'per_package': {
+        _PACKAGE: {'data': [23.9, 26.1], 'uid': '12345'}
+      }
+    }
 
 
 class DumpsysPowerMonitorMonitorTest(unittest.TestCase):
 
   def testApplicationEnergyConsumption(self):
-    package = 'com.google.android.apps.chrome'
-    power_data = {
-      'system_total': 2000.0,
-      'per_package': {
-        package: {'data': [23.9], 'uid': '12345'}
-      }
-    }
     results = (
         android_dumpsys_power_monitor.DumpsysPowerMonitor.ProcessPowerData(
-            power_data, 4.0, package))
+            _TYPICAL_POWER_DATA, 4.0, _PACKAGE))
     self.assertEqual(results['identifier'], 'dumpsys')
     self.assertAlmostEqual(results['application_energy_consumption_mwh'], 95.6)
 
@@ -35,6 +46,37 @@
     self.assertEqual(results['application_energy_consumption_mwh'], 0)
     self.assertEqual(results['energy_consumption_mwh'], 8000.0)
 
+  def testMonitorCycle(self):
+    browser = pm_mock.MockBrowser(_PACKAGE)
+    battery = pm_mock.MockBattery(_TYPICAL_POWER_DATA_MULTISAMPLE, voltage=5.0)
+    backend = pm_mock.MockPlatformBackend()
+    pm = android_dumpsys_power_monitor.DumpsysPowerMonitor(battery, backend)
+    pm.StartMonitoringPower(browser)
+    result = pm.StopMonitoringPower()
+    self.assertEqual(result['identifier'], 'dumpsys')
+    self.assertEqual(result['power_samples_mw'], [])
+    self.assertAlmostEqual(result['application_energy_consumption_mwh'], 250.0)
+    self.assertAlmostEqual(result['energy_consumption_mwh'], 10000.0)
+
+  def testDoubleStop(self):
+    browser = pm_mock.MockBrowser(_PACKAGE)
+    battery = pm_mock.MockBattery(_TYPICAL_POWER_DATA_MULTISAMPLE, voltage=5.0)
+    backend = pm_mock.MockPlatformBackend()
+    pm = android_dumpsys_power_monitor.DumpsysPowerMonitor(battery, backend)
+    pm.StartMonitoringPower(browser)
+    pm.StopMonitoringPower()
+    with self.assertRaises(AssertionError):
+      pm.StopMonitoringPower()
+
+  def testDoubleStart(self):
+    browser = pm_mock.MockBrowser(_PACKAGE)
+    battery = pm_mock.MockBattery(_TYPICAL_POWER_DATA_MULTISAMPLE, voltage=5.0)
+    backend = pm_mock.MockPlatformBackend()
+    pm = android_dumpsys_power_monitor.DumpsysPowerMonitor(battery, backend)
+    pm.StartMonitoringPower(browser)
+    with self.assertRaises(AssertionError):
+      pm.StartMonitoringPower(browser)
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/android_fuelgauge_power_monitor.py b/tools/telemetry/telemetry/internal/platform/power_monitor/android_fuelgauge_power_monitor.py
index 8b219e00..0e7fe306 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/android_fuelgauge_power_monitor.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/android_fuelgauge_power_monitor.py
@@ -2,12 +2,10 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import logging
-
-from telemetry.internal.platform import power_monitor
+from telemetry.internal.platform.power_monitor import android_power_monitor_base
 
 
-class FuelGaugePowerMonitor(power_monitor.PowerMonitor):
+class FuelGaugePowerMonitor(android_power_monitor_base.AndroidPowerMonitorBase):
   """PowerMonitor that relies on the fuel gauge chips to monitor the power
   consumption of a android device.
   """
@@ -26,30 +24,21 @@
     return self._battery.SupportsFuelGauge()
 
   def StartMonitoringPower(self, browser):
-    self._battery.SetCharging(False)
+    self._CheckStart()
+    self._ChargingOff(self._battery)
     self._starting_fuel_gauge = self._battery.GetFuelGaugeChargeCounter()
 
   def StopMonitoringPower(self):
+    self._CheckStop()
     # Convert from nAh to mAh.
     fuel_gauge_delta = (
         float((self._starting_fuel_gauge) -
         self._battery.GetFuelGaugeChargeCounter()) / 1000000)
-    self._battery.SetCharging(True)
-
-    voltage = self._battery.GetBatteryInfo().get('voltage')
-    if voltage is None:
-      # Converting at a nominal voltage of 4.0V, as those values are obtained by
-      # a heuristic, and 4.0V is the voltage we set when using a monsoon device.
-      voltage = 4.0
-      logging.warning('Unable to get device voltage. Using %s.', voltage)
-    else:
-      voltage = float(voltage) / 1000
-
+    self._ChargingOn(self._battery)
+    voltage = self._ParseVoltage(self._battery.GetBatteryInfo().get('voltage'))
     return self.ProcessPowerData(voltage, fuel_gauge_delta)
 
   @staticmethod
   def ProcessPowerData(voltage, fuel_gauge_delta):
-    power_results = {'identifier': 'fuel_gauge'}
-    power_results['fuel_gauge_energy_consumption_mwh'] = (
-        fuel_gauge_delta * voltage)
-    return power_results
+    return {'identifier': 'fuel_gauge',
+            'fuel_gauge_energy_consumption_mwh': fuel_gauge_delta * voltage}
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/android_fuelgauge_power_monitor_unittest.py b/tools/telemetry/telemetry/internal/platform/power_monitor/android_fuelgauge_power_monitor_unittest.py
index f049f0e..a40bae8b8 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/android_fuelgauge_power_monitor_unittest.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/android_fuelgauge_power_monitor_unittest.py
@@ -6,6 +6,7 @@
 
 from telemetry.internal.platform.power_monitor import (
     android_fuelgauge_power_monitor)
+from telemetry.internal.platform.power_monitor import pm_mock
 
 
 class FuelGaugePowerMonitorMonitorTest(unittest.TestCase):
@@ -19,6 +20,32 @@
     self.assertEqual(
         results.get('fuel_gauge_energy_consumption_mwh'), 400)
 
+  def testMonitorCycle(self):
+    battery = pm_mock.MockBattery(None, voltage=5.0, fuelgauge=[5.e6, 3.e6])
+    backend = pm_mock.MockPlatformBackend()
+    pm = android_fuelgauge_power_monitor.FuelGaugePowerMonitor(battery, backend)
+    pm.StartMonitoringPower(None)
+    results = pm.StopMonitoringPower()
+    self.assertEqual(results['identifier'], 'fuel_gauge')
+    self.assertAlmostEqual(results['fuel_gauge_energy_consumption_mwh'], 10)
+
+  def testDoubleStop(self):
+    battery = pm_mock.MockBattery(None, voltage=5.0, fuelgauge=[5.e6, 3.e6])
+    backend = pm_mock.MockPlatformBackend()
+    pm = android_fuelgauge_power_monitor.FuelGaugePowerMonitor(battery, backend)
+    pm.StartMonitoringPower(None)
+    pm.StopMonitoringPower()
+    with self.assertRaises(AssertionError):
+      pm.StopMonitoringPower()
+
+  def testDoubleStart(self):
+    battery = pm_mock.MockBattery(None, voltage=5.0, fuelgauge=[5.e6, 3.e6])
+    backend = pm_mock.MockPlatformBackend()
+    pm = android_fuelgauge_power_monitor.FuelGaugePowerMonitor(battery, backend)
+    pm.StartMonitoringPower(None)
+    with self.assertRaises(AssertionError):
+      pm.StartMonitoringPower(None)
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/android_power_monitor_base.py b/tools/telemetry/telemetry/internal/platform/power_monitor/android_power_monitor_base.py
new file mode 100644
index 0000000..3bec7a3
--- /dev/null
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/android_power_monitor_base.py
@@ -0,0 +1,45 @@
+# Copyright 2014 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.
+
+import logging
+
+from telemetry.internal.platform import power_monitor
+
+
+class AndroidPowerMonitorBase(power_monitor.PowerMonitor):
+
+  # Abstract class.
+  # pylint: disable=abstract-method
+
+  def _ParseVoltage(self, millivolts):
+    # Parse voltage information.
+    # If voltage is None, use 4.0 as default.
+    # Otherwise, convert millivolts to volts.
+    if millivolts is None:
+      # Converting at a nominal voltage of 4.0V, as those values are obtained by
+      # a heuristic, and 4.0V is the voltage we set when using a monsoon device.
+      voltage = 4.0
+      logging.warning('Unable to get device voltage. Using %s.', voltage)
+    else:
+      voltage = float(millivolts) / 1000
+      logging.info('Device voltage at %s', voltage)
+      return voltage
+
+  def _LogPowerAnomalies(self, power_data, package):
+    # Log anomalies in power data.
+    if power_data['energy_consumption_mwh'] == 0:
+      logging.warning('Power data is returning 0 for system total usage. %s'
+                      % (power_data))
+      if power_data['application_energy_consumption_mwh'] == 0:
+        logging.warning('Power data is returning 0 usage for %s. %s'
+                        % (package, power_data))
+
+  def _ChargingOff(self, battery):
+    battery.SetCharging(False)
+
+  def _ChargingOn(self, battery):
+    if battery.GetCharging():
+      logging.warning('Charging re-enabled during test.'
+                      'Results may be inaccurate.')
+      battery.SetCharging(True)
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/android_temperature_monitor.py b/tools/telemetry/telemetry/internal/platform/power_monitor/android_temperature_monitor.py
index 436dac4..ebf5774e 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/android_temperature_monitor.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/android_temperature_monitor.py
@@ -2,6 +2,8 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+import logging
+
 from telemetry.internal.platform import power_monitor
 
 try:
@@ -25,35 +27,26 @@
     return self._GetBoardTemperatureCelsius() is not None
 
   def StartMonitoringPower(self, browser):
+    # don't call _CheckStart() because this is temperature, not power
+    # therefore, StartMonitoringPower and StopMonitoringPower
+    # do not need to be paired
     pass
 
   def StopMonitoringPower(self):
-    power_data = {'identifier': 'android_temperature_monitor'}
-
-    # Take the current temperature as average based on the assumption that the
-    # temperature changes slowly during measurement time.
-    average_temperature = self._GetBoardTemperatureCelsius()
-    if average_temperature is None:
-      return power_data
-
-    # Insert temperature into the appropriate position in the dictionary
-    # returned by StopMonitoringPower() creating appropriate sub-dictionaries on
-    # the way if necessary.
-    temperature_path = [
-        'platform_info', 'average_temperature_c']
-    temperature_insertion_point = power_data
-    for path_element in temperature_path[:-1]:
-      if not path_element in temperature_insertion_point:
-        temperature_insertion_point[path_element] = {}
-      temperature_insertion_point = temperature_insertion_point[path_element]
-    assert temperature_path[-1] not in temperature_insertion_point
-    temperature_insertion_point[temperature_path[-1]] = average_temperature
-
-    return power_data
+    avg_temp = self._GetBoardTemperatureCelsius()
+    if avg_temp is None:
+      return {'identifier': 'android_temperature_monitor'}
+    else:
+      return {'identifier': 'android_temperature_monitor',
+              'platform_info': {'average_temperature_c': avg_temp}}
 
   def _GetBoardTemperatureCelsius(self):
     try:
       contents = self._device.ReadFile(_TEMPERATURE_FILE)
       return float(contents) if contents else None
+    except ValueError:
+      logging.warning('String returned from device.ReadFile(_TEMPERATURE_FILE) '
+                      'in invalid format.')
+      return None
     except device_errors.CommandFailedError:
       return None
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/cros_power_monitor.py b/tools/telemetry/telemetry/internal/platform/power_monitor/cros_power_monitor.py
index 9a0ff1b8..586a2985 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/cros_power_monitor.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/cros_power_monitor.py
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import collections
+import logging
 import re
 
 from telemetry import decorators
@@ -32,13 +33,17 @@
     return super(CrosPowerMonitor, self).CanMonitorPower()
 
   def StartMonitoringPower(self, browser):
-    super(CrosPowerMonitor, self).StartMonitoringPower(browser)
+    self._CheckStart()
     if self._IsOnBatteryPower():
       sample = self._platform.RunCommand(['dump_power_status;', 'date', '+%s'])
       self._initial_power, self._start_time = CrosPowerMonitor.SplitSample(
           sample)
+    else:
+      logging.warning('Device not on battery power during power monitoring. '
+                      'Results may be incorrect.')
 
   def StopMonitoringPower(self):
+    self._CheckStop()
     cpu_stats = super(CrosPowerMonitor, self).StopMonitoringPower()
     power_stats = {}
     if self._IsOnBatteryPower():
@@ -48,6 +53,9 @@
       length_h = (end_time - self._start_time) / 3600.0
       power_stats = CrosPowerMonitor.ParsePower(self._initial_power,
                                                 final_power, length_h)
+    else:
+      logging.warning('Device not on battery power during power monitoring. '
+                      'Results may be incorrect.')
     return CrosPowerMonitor.CombineResults(cpu_stats, power_stats)
 
   @staticmethod
@@ -126,8 +134,6 @@
     Returns:
         Dictionary in the format returned by StopMonitoringPower().
     """
-    out_dict = {'identifier': 'dump_power_status'}
-    component_utilization = {}
     initial = CrosPowerMonitor.ParsePowerStatus(initial_stats)
     final = CrosPowerMonitor.ParsePowerStatus(final_stats)
     # The charge value reported by 'dump_power_status' is not precise enough to
@@ -136,8 +142,6 @@
     initial_power_mw = float(initial['battery_energy_rate']) * 10 ** 3
     final_power_mw = float(final['battery_energy_rate']) * 10 ** 3
     average_power_mw = (initial_power_mw + final_power_mw) / 2.0
-    out_dict['power_samples_mw'] = [initial_power_mw, final_power_mw]
-    out_dict['energy_consumption_mwh'] = average_power_mw * length_h
 
     # Duplicating CrOS battery fields where applicable.
     def CopyFinalState(field, key):
@@ -154,6 +158,7 @@
     CopyFinalState('battery_energy_rate', 'energy_rate')
     CopyFinalState('battery_voltage', 'voltage_now')
 
-    component_utilization['battery'] = battery
-    out_dict['component_utilization'] = component_utilization
-    return out_dict
+    return {'identifier': 'dump_power_status',
+            'power_samples_mw': [initial_power_mw, final_power_mw],
+            'energy_consumption_mwh': average_power_mw * length_h,
+            'component_utilization': {'battery': battery}}
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/monsoon_power_monitor.py b/tools/telemetry/telemetry/internal/platform/power_monitor/monsoon_power_monitor.py
index a9537e0..abbd9f4 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/monsoon_power_monitor.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/monsoon_power_monitor.py
@@ -3,12 +3,13 @@
 # found in the LICENSE file.
 
 import json
+import logging
 import multiprocessing
 import tempfile
 import time
 
 from telemetry.core import exceptions
-from telemetry.internal.platform import power_monitor
+from telemetry.internal.platform.power_monitor import android_power_monitor_base
 from telemetry.internal.platform.profiler import monsoon
 
 
@@ -42,7 +43,8 @@
     }
     json.dump(result, output)
 
-class MonsoonPowerMonitor(power_monitor.PowerMonitor):
+
+class MonsoonPowerMonitor(android_power_monitor_base.AndroidPowerMonitorBase):
   def __init__(self, _, platform_backend):
     super(MonsoonPowerMonitor, self).__init__()
     self._powermonitor_process = None
@@ -64,8 +66,7 @@
     return self._monsoon is not None
 
   def StartMonitoringPower(self, browser):
-    assert not self._powermonitor_process, (
-        'Must call StopMonitoringPower().')
+    self._CheckStart()
     self._powermonitor_output_file = tempfile.TemporaryFile()
     self._is_collecting = multiprocessing.Event()
     self._powermonitor_process = multiprocessing.Process(
@@ -81,8 +82,7 @@
       raise exceptions.ProfilingException('Failed to start data collection.')
 
   def StopMonitoringPower(self):
-    assert self._powermonitor_process, (
-        'StartMonitoringPower() not called.')
+    self._CheckStop()
     try:
       # Tell powermonitor to take an immediate sample and join.
       self._is_collecting.clear()
@@ -104,20 +104,17 @@
     Returns:
         Dictionary in the format returned by StopMonitoringPower().
     """
-    power_samples = []
-    total_energy_consumption_mwh = 0
-
     result = json.loads(powermonitor_output)
     if result['samples']:
-      timedelta_h = result['duration_s'] / len(result['samples']) / 3600
-      for (current_a, voltage_v) in result['samples']:
-        energy_consumption_mw = current_a * voltage_v * 10**3
-        total_energy_consumption_mwh += energy_consumption_mw * timedelta_h
-        power_samples.append(energy_consumption_mw)
+      timedelta_h = (result['duration_s'] / len(result['samples'])) / 3600.0
+      power_samples = [current_a * voltage_v * 10**3
+                       for (current_a, voltage_v) in result['samples']]
+      total_energy_consumption_mwh = sum(power_samples) * timedelta_h
+    else:
+      logging.warning('Sample information not available.')
+      power_samples = []
+      total_energy_consumption_mwh = 0
 
-    out_dict = {}
-    out_dict['identifier'] = 'monsoon'
-    out_dict['power_samples_mw'] = power_samples
-    out_dict['monsoon_energy_consumption_mwh'] = total_energy_consumption_mwh
-
-    return out_dict
+    return {'identifier':'monsoon',
+            'power_samples_mw':power_samples,
+            'monsoon_energy_consumption_mwh':total_energy_consumption_mwh}
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/msr_power_monitor.py b/tools/telemetry/telemetry/internal/platform/power_monitor/msr_power_monitor.py
index 4214add..5cf3d16 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/msr_power_monitor.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/msr_power_monitor.py
@@ -42,15 +42,12 @@
     raise NotImplementedError()
 
   def StartMonitoringPower(self, browser):
-    assert self._start_energy_j is None and self._start_temp_c is None, (
-        'Called StartMonitoringPower() twice.')
+    self._CheckStart()
     self._start_energy_j = self._PackageEnergyJoules()
     self._start_temp_c = self._TemperatureCelsius()
 
   def StopMonitoringPower(self):
-    assert not(self._start_energy_j is None or self._start_temp_c is None), (
-        'Called StopMonitoringPower() before StartMonitoringPower().')
-
+    self._CheckStop()
     energy_consumption_j = self._PackageEnergyJoules() - self._start_energy_j
     average_temp_c = (self._TemperatureCelsius() + self._start_temp_c) / 2.
     if energy_consumption_j < 0:  # Correct overflow.
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/pm_mock.py b/tools/telemetry/telemetry/internal/platform/power_monitor/pm_mock.py
new file mode 100644
index 0000000..d9bbab5
--- /dev/null
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/pm_mock.py
@@ -0,0 +1,61 @@
+# Copyright 2014 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.
+
+class MockBrowserBackend(object):
+  def __init__(self, package):
+    self.package = package
+
+class MockBrowser(object):
+  def __init__(self, package):
+    self._browser_backend = MockBrowserBackend(package)
+
+class MockBattery(object):
+  def __init__(self,
+               power_results,
+               starts_charging=True,
+               voltage=4.0,
+               fuelgauge=None):
+    # voltage in millivolts
+    self._power_results = power_results
+    self._charging = starts_charging
+    self._voltage = voltage
+    self._fuelgauge = fuelgauge if fuelgauge else []
+    self._fuel_idx = 0
+
+  def SupportsFuelGauge(self):
+    return len(self._fuelgauge) >= 0
+
+  def GetFuelGaugeChargeCounter(self):
+    try:
+      x = self._fuelgauge[self._fuel_idx]
+      self._fuel_idx += 1
+      return x
+    except IndexError:
+      assert False, "Too many GetFuelGaugeChargeCounter() calls."
+
+  def GetCharging(self):
+    return self._charging
+
+  def SetCharging(self, charging):
+    if charging:
+      assert not self._charging, "Mock battery already charging."
+      self._charging = True
+    else:
+      assert self._charging, "Mock battery already not charging."
+      self._charging = False
+
+  def GetPowerData(self):
+    return self._power_results
+
+  def GetBatteryInfo(self):
+    # the voltage returned by GetBatteryInfo() is in millivolts
+    return {'voltage': int(self._voltage*1000)}
+
+class MockPlatformBackend(object):
+  def __init__(self, command_dict=None):
+    self._cdict = (command_dict if command_dict else {})
+
+  def RunCommand(self, command):
+    assert command in self._cdict, "Mock platform error: Unexpected command."
+    return self._cdict[command]
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/power_monitor_controller.py b/tools/telemetry/telemetry/internal/platform/power_monitor/power_monitor_controller.py
index 7c5aefd..5b42c5e 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/power_monitor_controller.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/power_monitor_controller.py
@@ -34,7 +34,7 @@
       logging.warning('StopMonitoringPower() not called when expected. Last '
                       'results are likely not reported.')
       self.StopMonitoringPower()
-
+    self._CheckStart()
     self._active_monitors = (
         [m for m in self._candidate_power_monitors if m.CanMonitorPower()])
     assert self._active_monitors, 'No available monitor.'
@@ -51,14 +51,14 @@
       for key in dict_one:
         if key in dict_two and key not in ignore_list:
           logging.warning('Found multiple instances of %s in power monitor '
-                          'enteries. Using newest one.', key)
-    # Sub level power enteries.
+                          'entries. Using newest one.', key)
+    # Sub level power entries.
     for part in ['platform_info', 'component_utilization']:
       if part in monitor_results:
         _CheckDuplicateKeys(combined_results[part], monitor_results[part])
         combined_results[part].update(monitor_results[part])
 
-    # Top level power enteries.
+    # Top level power entries.
     platform_info = combined_results['platform_info'].copy()
     comp_utilization = combined_results['component_utilization'].copy()
     _CheckDuplicateKeys(
@@ -69,7 +69,7 @@
     combined_results['component_utilization'] = comp_utilization
 
   def StopMonitoringPower(self):
-    assert self._active_monitors, 'StartMonitoringPower() not called.'
+    self._CheckStop()
     try:
       results = {'platform_info': {}, 'component_utilization': {}}
       for monitor in self._active_monitors:
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/power_monitor_controller_unittest.py b/tools/telemetry/telemetry/internal/platform/power_monitor/power_monitor_controller_unittest.py
index c0f6b87..2794f342 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/power_monitor_controller_unittest.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/power_monitor_controller_unittest.py
@@ -22,6 +22,7 @@
 
     class P2(power_monitor.PowerMonitor):
       def __init__(self, value):
+        super(P2, self).__init__()
         self._value = {'P2': value}
       def CanMonitorPower(self):
         return True
@@ -32,6 +33,7 @@
 
     class P3(power_monitor.PowerMonitor):
       def __init__(self, value):
+        super(P3, self).__init__()
         self._value = {'P3': value}
       def CanMonitorPower(self):
         return True
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/powermetrics_power_monitor.py b/tools/telemetry/telemetry/internal/platform/power_monitor/powermetrics_power_monitor.py
index f43578c..d800e60 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/powermetrics_power_monitor.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/powermetrics_power_monitor.py
@@ -16,6 +16,7 @@
 from telemetry.internal.platform import power_monitor
 
 
+# TODO: rename this class (seems like this is used by mac)
 class PowerMetricsPowerMonitor(power_monitor.PowerMonitor):
 
   def __init__(self, backend):
@@ -30,8 +31,7 @@
     return '/usr/bin/powermetrics'
 
   def StartMonitoringPower(self, browser):
-    assert not self._powermetrics_process, (
-        'Must call StopMonitoringPower().')
+    self._CheckStart()
     # Empirically powermetrics creates an empty output file immediately upon
     # starting.  We detect file creation as a signal that measurement has
     # started.  In order to avoid various race conditions in tempfile creation
@@ -254,8 +254,7 @@
           elevate_privilege=True)
 
   def StopMonitoringPower(self):
-    assert self._powermetrics_process, (
-        'StartMonitoringPower() not called.')
+    self._CheckStop()
     # Tell powermetrics to take an immediate sample.
     try:
       self._KillPowerMetricsProcess()
diff --git a/tools/telemetry/telemetry/internal/platform/power_monitor/sysfs_power_monitor.py b/tools/telemetry/telemetry/internal/platform/power_monitor/sysfs_power_monitor.py
index 8d43be5c..1802937 100644
--- a/tools/telemetry/telemetry/internal/platform/power_monitor/sysfs_power_monitor.py
+++ b/tools/telemetry/telemetry/internal/platform/power_monitor/sysfs_power_monitor.py
@@ -46,7 +46,6 @@
     self._initial_freq = None
     self._platform = linux_based_platform_backend
     self._standalone = standalone
-    self._is_monitoring_power = False
 
   @decorators.Cache
   def CanMonitorPower(self):
@@ -54,18 +53,16 @@
         'if [ -e %s ]; then echo true; fi' % CPU_PATH))
 
   def StartMonitoringPower(self, _browser):
-    # |_browser| is unused, can be None.
-    assert not self._is_monitoring_power, 'Must call StopMonitoringPower().'
+    self._CheckStart()
     if self.CanMonitorPower():
       self._cpus = filter(  # pylint: disable=deprecated-lambda
           lambda x: re.match(r'^cpu[0-9]+', x),
           self._platform.RunCommand('ls %s' % CPU_PATH).split())
       self._initial_freq = self.GetCpuFreq()
       self._initial_cstate = self.GetCpuState()
-      self._is_monitoring_power = True
 
   def StopMonitoringPower(self):
-    assert self._is_monitoring_power, 'StartMonitoringPower() not called.'
+    self._CheckStop()
     try:
       out = {}
       if SysfsPowerMonitor.CanMonitorPower(self):
@@ -84,7 +81,6 @@
         return self.CombineResults(out, {})
       return out
     finally:
-      self._is_monitoring_power = False
       self._initial_cstate = None
       self._initial_freq = None
 
diff --git a/tools/telemetry/telemetry/internal/util/webpagereplay.py b/tools/telemetry/telemetry/internal/util/webpagereplay.py
index e5941b7a..87f83a0b 100644
--- a/tools/telemetry/telemetry/internal/util/webpagereplay.py
+++ b/tools/telemetry/telemetry/internal/util/webpagereplay.py
@@ -278,7 +278,7 @@
             '************************** WPR LOG *****************************',
             f.read(),
             '************************** END OF WPR LOG **********************'])
-      logging.info(wpr_log_content)
+      logging.debug(wpr_log_content)
     os.remove(self._temp_log_file_path)
     self._temp_log_file_path = None
 
diff --git a/tools/valgrind/memcheck/suppressions_linux.txt b/tools/valgrind/memcheck/suppressions_linux.txt
index 46b7ce2..21e0368c 100644
--- a/tools/valgrind/memcheck/suppressions_linux.txt
+++ b/tools/valgrind/memcheck/suppressions_linux.txt
@@ -89,3 +89,22 @@
    fun:_ZN4base6Thread10ThreadMainEv
    fun:_ZN4base12_GLOBAL__N_110ThreadFuncEPv
 }
+{
+   b_555798_a
+   Memcheck:Leak
+   fun:malloc
+   fun:strdup
+   obj:*
+   ...
+   fun:*LoadNativeLibrary*
+   fun:*CdmAdapterTest*
+}
+{
+   b_555798_b
+   Memcheck:Leak
+   fun:_Znw*
+   obj:*
+   ...
+   fun:*LoadNativeLibrary*
+   fun:*CdmAdapterTest*
+}
diff --git a/ui/android/java/src/org/chromium/ui/autofill/AutofillKeyboardAccessory.java b/ui/android/java/src/org/chromium/ui/autofill/AutofillKeyboardAccessory.java
index d7a5cca6..4e0bb54 100644
--- a/ui/android/java/src/org/chromium/ui/autofill/AutofillKeyboardAccessory.java
+++ b/ui/android/java/src/org/chromium/ui/autofill/AutofillKeyboardAccessory.java
@@ -72,10 +72,8 @@
             AutofillSuggestion suggestion = suggestions[i];
             assert !TextUtils.isEmpty(suggestion.getLabel());
 
-            // Negative suggestion ID indiciates a tool like "settings" or "scan credit card."
-            // Non-negative suggestion ID indicates suggestions that can be filled into the form.
             View touchTarget;
-            if (suggestion.getSuggestionId() < 0 && suggestion.getIconId() != 0) {
+            if (!suggestion.isFillable() && suggestion.getIconId() != 0) {
                 touchTarget = LayoutInflater.from(getContext()).inflate(
                         R.layout.autofill_keyboard_accessory_icon, this, false);
 
@@ -90,7 +88,11 @@
 
                 TextView label = (TextView) touchTarget.findViewById(
                         R.id.autofill_keyboard_accessory_item_label);
-                label.setMaxWidth(mMaximumLabelWidthPx);
+
+                if (suggestion.isFillable()) {
+                    label.setMaxWidth(mMaximumLabelWidthPx);
+                }
+
                 label.setText(suggestion.getLabel());
                 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                     label.setTypeface(Typeface.DEFAULT_BOLD);
@@ -102,6 +104,7 @@
                 }
 
                 if (!TextUtils.isEmpty(suggestion.getSublabel())) {
+                    assert suggestion.isFillable();
                     TextView sublabel = (TextView) touchTarget.findViewById(
                             R.id.autofill_keyboard_accessory_item_sublabel);
                     sublabel.setText(suggestion.getSublabel());
diff --git a/ui/android/java/src/org/chromium/ui/autofill/AutofillSuggestion.java b/ui/android/java/src/org/chromium/ui/autofill/AutofillSuggestion.java
index df91823..9403658 100644
--- a/ui/android/java/src/org/chromium/ui/autofill/AutofillSuggestion.java
+++ b/ui/android/java/src/org/chromium/ui/autofill/AutofillSuggestion.java
@@ -64,4 +64,10 @@
     public boolean isDeletable() {
         return mDeletable;
     }
+
+    public boolean isFillable() {
+        // Negative suggestion ID indiciates a tool like "settings" or "scan credit card."
+        // Non-negative suggestion ID indicates suggestions that can be filled into the form.
+        return mSuggestionId >= 0;
+    }
 }
diff --git a/ui/compositor/test/in_process_context_provider.cc b/ui/compositor/test/in_process_context_provider.cc
index 6b907c4..dc7deaf4 100644
--- a/ui/compositor/test/in_process_context_provider.cc
+++ b/ui/compositor/test/in_process_context_provider.cc
@@ -161,8 +161,8 @@
   g_gles2_initializer.Get();
   gles2::SetGLContext(ContextGL());
 
-  skia::RefPtr<GrGLInterface> interface =
-      skia::AdoptRef(skia_bindings::CreateCommandBufferSkiaGLBinding());
+  skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(new GrGLInterface);
+  skia_bindings::InitCommandBufferSkiaGLBinding(interface.get());
   interface->fCallback = BindGrContextCallback;
   interface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(this);
 
diff --git a/ui/file_manager/file_manager/background/js/app_window_wrapper.js b/ui/file_manager/file_manager/background/js/app_window_wrapper.js
index 79d8b7c5..e256056 100644
--- a/ui/file_manager/file_manager/background/js/app_window_wrapper.js
+++ b/ui/file_manager/file_manager/background/js/app_window_wrapper.js
@@ -136,8 +136,10 @@
     // Apply the last bounds.
     if (lastBounds)
       this.options_.bounds = lastBounds;
-    if (isMaximized)
-      this.options_.state = 'maximized';
+
+    // Overwrite maximized state with remembered last window state.
+    if (isMaximized !== undefined)
+      this.options_.state = isMaximized ? 'maximized' : undefined;
 
     // Create a window.
     chrome.app.window.create(this.url_, this.options_, function(appWindow) {
diff --git a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
index d6902d5..e4d2778 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/directory_tree.js
@@ -254,7 +254,6 @@
     return;
   }
 
-  cr.dispatchSimpleEvent(this, 'click-tree-item', true);
   this.directoryModel_.activateDirectoryEntry(this.entry);
 };
 
@@ -786,8 +785,6 @@
   if (e.button === 2)
     return;
 
-  cr.dispatchSimpleEvent(this, 'click-tree-item', true);
-
   this.activate();
   // Resets file selection when a volume is clicked.
   this.parentTree_.directoryModel.clearSelection();
diff --git a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
index 662cef28..a4d0418 100644
--- a/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
+++ b/ui/file_manager/file_manager/foreground/js/ui/file_manager_ui.js
@@ -396,11 +396,6 @@
   observer.observe(this.progressCenterPanel.element,
                    /** @type {MutationObserverInit} */
                    ({subtree: true, attributes: true, childList: true}));
-
-  // Focus the file list pane when a directory item is clicked/tapped.
-  this.directoryTree.addEventListener('click-tree-item', function(event) {
-    this.listContainer.focus();
-  }.bind(this));
 };
 
 /**
diff --git a/ui/file_manager/integration_tests/file_manager/background.js b/ui/file_manager/integration_tests/file_manager/background.js
index a7d1c6a..d8d8797 100644
--- a/ui/file_manager/integration_tests/file_manager/background.js
+++ b/ui/file_manager/integration_tests/file_manager/background.js
@@ -268,15 +268,6 @@
               'selectVolume', windowId, [volumeName]);
         }).
         then(function() {
-          // Previous 'selectVolume' changed the focus state of this dialog.
-          // To simulate the dialog as if the volume was selected without
-          // clicking the volume list, bring back the focus state here.
-          var queryForDefaultFocus = dialogParams.type === 'saveFile' ?
-              '#filename-input-textbox' : '#file-list';
-          return remoteCall.callRemoteTestUtil(
-              'focus', windowId, [queryForDefaultFocus]);
-        }).
-        then(function() {
           var expectedRows = TestEntryInfo.getExpectedRows(expectedSet);
           return remoteCall.waitForFiles(windowId, expectedRows);
         }).
diff --git a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
index fbb6ec46..f07fa32e5 100644
--- a/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
+++ b/ui/file_manager/integration_tests/file_manager/directory_tree_context_menu.js
@@ -108,11 +108,6 @@
     // Wait until Files.app is navigated to the path.
     return remoteCall.waitUntilCurrentDirectoryIsChanged(
         windowId, `/Downloads${path}`);
-  }).then(function() {
-    // Bring back the focus to directory tree, since the content pane has been
-    // focused by clicking the directory item.
-    return remoteCall.callRemoteTestUtil(
-        'focus', windowId, ['#directory-tree']);
   });
 }
 
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index 0541264..5c9a1c5 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -2523,7 +2523,7 @@
                 SIGNIN_UI_STATE.GAIA_SIGNIN &&
             emptyPodRow &&
             this.pods.length > 0) {
-          login.GaiaSigninScreen.updateCancelButtonState();
+          login.GaiaSigninScreen.updateControlsState();
         }
       }
     },
diff --git a/ui/ozone/ozone.gni b/ui/ozone/ozone.gni
index 15e909de..a1fe2f8 100644
--- a/ui/ozone/ozone.gni
+++ b/ui/ozone/ozone.gni
@@ -30,16 +30,21 @@
 
   if (ozone_auto_platforms) {
     if (is_chromecast) {
-      # The default platform used at runtime is "cast".
-      ozone_platform = "cast"
-      ozone_platform_cast = true
       ozone_platform_headless = true
+      if (disable_display) {
+        # Audio-only builds should use the "headless" platform by default.
+        ozone_platform = "headless"
+      } else {
+        # Builds with video should default to the "cast" platform.
+        ozone_platform_cast = true
+        ozone_platform = "cast"
 
-      # For desktop Chromecast builds, override the default "cast" platform with
-      # --ozone_platform=egltest
-      if (target_os == "linux" && target_cpu != "arm") {
-        ozone_platform_egltest = true
-        ozone_platform_ozonex = true
+        # For desktop Chromecast builds, override the default "cast" platform with
+        # --ozone_platform=egltest
+        if (target_os == "linux" && target_cpu != "arm") {
+          ozone_platform_egltest = true
+          ozone_platform_ozonex = true
+        }
       }
     } else {
       # Use headless as the default platform.
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn
index 852dcc5..de94bab4 100644
--- a/ui/views/mus/BUILD.gn
+++ b/ui/views/mus/BUILD.gn
@@ -4,7 +4,7 @@
 
 import("//tools/grit/repack.gni")
 
-source_set("mus") {
+component("mus") {
   sources = [
     "aura_init.cc",
     "aura_init.h",
@@ -12,6 +12,7 @@
     "display_converter.h",
     "input_method_mus.cc",
     "input_method_mus.h",
+    "mus_export.h",
     "native_widget_mus.cc",
     "native_widget_mus.h",
     "platform_window_mus.cc",
@@ -27,6 +28,8 @@
     "window_tree_host_mus.h",
   ]
 
+  defines = [ "VIEWS_MUS_IMPLEMENTATION" ]
+
   public_deps = [
     ":resources",
     "//components/mus/public/cpp",
@@ -66,6 +69,14 @@
     "//ui/wm",
   ]
 
+  if (is_component_build) {
+    deps += [
+      "//mojo/gles2",
+      "//mojo/platform_handle:platform_handle_impl",
+      "//third_party/mojo/src/mojo/edk/system",
+    ]
+  }
+
   data_deps = [
     "//components/resource_provider",
   ]
diff --git a/ui/views/mus/aura_init.h b/ui/views/mus/aura_init.h
index f82a95b3..0b16cb99 100644
--- a/ui/views/mus/aura_init.h
+++ b/ui/views/mus/aura_init.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "skia/ext/refptr.h"
+#include "ui/views/mus/mus_export.h"
 
 namespace font_service {
 class FontLoader;
@@ -24,7 +25,7 @@
 
 // Sets up necessary state for aura when run with the viewmanager.
 // |resource_file| is the path to the apk file containing the resources.
-class AuraInit {
+class VIEWS_MUS_EXPORT AuraInit {
  public:
   AuraInit(mojo::ApplicationImpl* app, const std::string& resource_file);
   ~AuraInit();
diff --git a/ui/views/mus/display_converter.h b/ui/views/mus/display_converter.h
index a747455..6e61bf3 100644
--- a/ui/views/mus/display_converter.h
+++ b/ui/views/mus/display_converter.h
@@ -8,6 +8,7 @@
 #include <vector>
 
 #include "ui/gfx/display.h"
+#include "ui/views/mus/mus_export.h"
 
 namespace mus {
 class Window;
@@ -15,7 +16,8 @@
 
 namespace views {
 
-std::vector<gfx::Display> GetDisplaysFromWindow(mus::Window* window);
+std::vector<gfx::Display> VIEWS_MUS_EXPORT GetDisplaysFromWindow(
+    mus::Window* window);
 
 }  // namespace views
 
diff --git a/ui/views/mus/input_method_mus.h b/ui/views/mus/input_method_mus.h
index a9be768..fe9ab13 100644
--- a/ui/views/mus/input_method_mus.h
+++ b/ui/views/mus/input_method_mus.h
@@ -7,13 +7,15 @@
 #ifndef UI_VIEWS_MUS_INPUT_METHOD_MUS_H_
 #define UI_VIEWS_MUS_INPUT_METHOD_MUS_H_
 
+#include "ui/views/mus/mus_export.h"
+
 namespace mus {
 class Window;
 }  // namespace mojo
 
 namespace views {
 
-class InputMethodMUS : public ui::InputMethodBase {
+class VIEWS_MUS_EXPORT InputMethodMUS : public ui::InputMethodBase {
  public:
   InputMethodMUS(ui::internal::InputMethodDelegate* delegate,
                  mus::Window* window);
diff --git a/ui/views/mus/mus_export.h b/ui/views/mus/mus_export.h
new file mode 100644
index 0000000..9d5ff8b
--- /dev/null
+++ b/ui/views/mus/mus_export.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2015 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.
+
+#ifndef UI_VIEWS_MUS_MUS_EXPORT_H_
+#define UI_VIEWS_MUS_MUS_EXPORT_H_
+
+// Defines VIEWS_EXPORT so that functionality implemented by the Views module
+// can be exported to consumers.
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(VIEWS_MUS_IMPLEMENTATION)
+#define VIEWS_MUS_EXPORT __declspec(dllexport)
+#else
+#define VIEWS_MUS_EXPORT __declspec(dllimport)
+#endif  // defined(VIEWS_MUS_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(VIEWS_MUS_IMPLEMENTATION)
+#define VIEWS_MUS_EXPORT __attribute__((visibility("default")))
+#else
+#define VIEWS_MUS_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define VIEWS_MUS_EXPORT
+#endif
+
+#endif  // UI_VIEWS_MUS_MUS_EXPORT_H_
diff --git a/ui/views/mus/native_widget_mus.h b/ui/views/mus/native_widget_mus.h
index 81e9624..79496f6 100644
--- a/ui/views/mus/native_widget_mus.h
+++ b/ui/views/mus/native_widget_mus.h
@@ -13,6 +13,7 @@
 #include "components/mus/public/interfaces/window_manager.mojom.h"
 #include "ui/aura/window_delegate.h"
 #include "ui/platform_window/platform_window_delegate.h"
+#include "ui/views/mus/mus_export.h"
 #include "ui/views/widget/native_widget_private.h"
 
 namespace aura {
@@ -49,8 +50,9 @@
 // aura::Window in a hierarchy is created without a delegate by the
 // aura::WindowTreeHost, we must create a child aura::Window in this class
 // (content_) and attach it to the root.
-class NativeWidgetMus : public internal::NativeWidgetPrivate,
-                        public aura::WindowDelegate {
+class VIEWS_MUS_EXPORT NativeWidgetMus
+    : public internal::NativeWidgetPrivate,
+      public aura::WindowDelegate {
  public:
   NativeWidgetMus(internal::NativeWidgetDelegate* delegate,
                   mojo::Shell* shell,
diff --git a/ui/views/mus/platform_window_mus.h b/ui/views/mus/platform_window_mus.h
index 6628cf9b..d1323a9 100644
--- a/ui/views/mus/platform_window_mus.h
+++ b/ui/views/mus/platform_window_mus.h
@@ -11,11 +11,13 @@
 #include "base/macros.h"
 #include "components/mus/public/cpp/window_observer.h"
 #include "ui/platform_window/platform_window.h"
+#include "ui/views/mus/mus_export.h"
 
 namespace views {
 
-class PlatformWindowMus : public ui::PlatformWindow,
-                          public mus::WindowObserver {
+class VIEWS_MUS_EXPORT PlatformWindowMus
+    : public NON_EXPORTED_BASE(ui::PlatformWindow),
+      public mus::WindowObserver {
  public:
   PlatformWindowMus(ui::PlatformWindowDelegate* delegate,
                     mus::Window* mus_window);
diff --git a/ui/views/mus/surface_binding.h b/ui/views/mus/surface_binding.h
index 3ae2ed9..1adab1a 100644
--- a/ui/views/mus/surface_binding.h
+++ b/ui/views/mus/surface_binding.h
@@ -8,6 +8,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
+#include "ui/views/mus/mus_export.h"
 
 namespace cc {
 class OutputSurface;
@@ -28,7 +29,7 @@
 // Internally SurfaceBinding manages one connection (and related structures) per
 // WindowTree. That is, all Windows from a particular WindowTree share the same
 // connection.
-class SurfaceBinding {
+class VIEWS_MUS_EXPORT SurfaceBinding {
  public:
   SurfaceBinding(mojo::Shell* shell,
                  mus::Window* window,
diff --git a/ui/views/mus/surface_context_factory.h b/ui/views/mus/surface_context_factory.h
index c9f71bb..8cc6117 100644
--- a/ui/views/mus/surface_context_factory.h
+++ b/ui/views/mus/surface_context_factory.h
@@ -9,6 +9,7 @@
 #include "components/mus/gles2/raster_thread_helper.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "ui/compositor/compositor.h"
+#include "ui/views/mus/mus_export.h"
 #include "ui/views/mus/surface_binding.h"
 
 namespace mojo {
@@ -21,7 +22,7 @@
 
 namespace views {
 
-class SurfaceContextFactory : public ui::ContextFactory {
+class VIEWS_MUS_EXPORT SurfaceContextFactory : public ui::ContextFactory {
  public:
   SurfaceContextFactory(mojo::Shell* shell,
                         mus::Window* window,
diff --git a/ui/views/mus/window_manager_client_area_insets.h b/ui/views/mus/window_manager_client_area_insets.h
index 20a27f6..afc420f 100644
--- a/ui/views/mus/window_manager_client_area_insets.h
+++ b/ui/views/mus/window_manager_client_area_insets.h
@@ -6,10 +6,11 @@
 #define UI_VIEWS_MUS_WINDOW_MANAGER_CLIENT_AREA_INSETS_H_
 
 #include "ui/gfx/geometry/insets.h"
+#include "ui/views/mus/mus_export.h"
 
 namespace views {
 
-struct WindowManagerClientAreaInsets {
+struct VIEWS_MUS_EXPORT WindowManagerClientAreaInsets {
   gfx::Insets normal_insets;
   gfx::Insets maximized_insets;
 };
diff --git a/ui/views/mus/window_manager_connection.h b/ui/views/mus/window_manager_connection.h
index 497bbb9..7c60b49 100644
--- a/ui/views/mus/window_manager_connection.h
+++ b/ui/views/mus/window_manager_connection.h
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "components/mus/public/cpp/window_tree_delegate.h"
 #include "components/mus/public/interfaces/window_manager.mojom.h"
+#include "ui/views/mus/mus_export.h"
 #include "ui/views/widget/widget.h"
 
 namespace mojo {
@@ -28,7 +29,8 @@
 
 // Establishes a connection to the window manager for use by views within an
 // application, and performs Aura initialization.
-class WindowManagerConnection : public mus::WindowTreeDelegate {
+class VIEWS_MUS_EXPORT WindowManagerConnection
+    : public NON_EXPORTED_BASE(mus::WindowTreeDelegate) {
  public:
   static void Create(mus::mojom::WindowManagerPtr window_manager,
                      mojo::ApplicationImpl* app);
diff --git a/ui/views/mus/window_tree_host_mus.h b/ui/views/mus/window_tree_host_mus.h
index 73fc425..9efccfd 100644
--- a/ui/views/mus/window_tree_host_mus.h
+++ b/ui/views/mus/window_tree_host_mus.h
@@ -8,6 +8,7 @@
 #include "base/macros.h"
 #include "components/mus/public/interfaces/window_tree.mojom.h"
 #include "ui/aura/window_tree_host_platform.h"
+#include "ui/views/mus/mus_export.h"
 
 class SkBitmap;
 
@@ -30,7 +31,7 @@
 class PlatformWindowMus;
 class SurfaceContextFactory;
 
-class WindowTreeHostMus : public aura::WindowTreeHostPlatform {
+class VIEWS_MUS_EXPORT WindowTreeHostMus : public aura::WindowTreeHostPlatform {
  public:
   WindowTreeHostMus(mojo::Shell* shell,
                     NativeWidgetMus* native_widget_,